/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import * as fs from 'node:fs/promises';
import { z } from 'zod';
import { parse as parseIgnoringComments } from 'comment-json';
import { isNodeError, Storage } from '@google/gemini-cli-core';
export var Command;
(function (Command) {
    // Basic Controls
    Command["RETURN"] = "basic.confirm";
    Command["ESCAPE"] = "basic.cancel";
    Command["QUIT"] = "basic.quit";
    Command["EXIT"] = "basic.exit";
    // Cursor Movement
    Command["HOME"] = "cursor.home";
    Command["END"] = "cursor.end";
    Command["MOVE_UP"] = "cursor.up";
    Command["MOVE_DOWN"] = "cursor.down";
    Command["MOVE_LEFT"] = "cursor.left";
    Command["MOVE_RIGHT"] = "cursor.right";
    Command["MOVE_WORD_LEFT"] = "cursor.wordLeft";
    Command["MOVE_WORD_RIGHT"] = "cursor.wordRight";
    // Editing
    Command["KILL_LINE_RIGHT"] = "edit.deleteRightAll";
    Command["KILL_LINE_LEFT"] = "edit.deleteLeftAll";
    Command["CLEAR_INPUT"] = "edit.clear";
    Command["DELETE_WORD_BACKWARD"] = "edit.deleteWordLeft";
    Command["DELETE_WORD_FORWARD"] = "edit.deleteWordRight";
    Command["DELETE_CHAR_LEFT"] = "edit.deleteLeft";
    Command["DELETE_CHAR_RIGHT"] = "edit.deleteRight";
    Command["UNDO"] = "edit.undo";
    Command["REDO"] = "edit.redo";
    // Scrolling
    Command["SCROLL_UP"] = "scroll.up";
    Command["SCROLL_DOWN"] = "scroll.down";
    Command["SCROLL_HOME"] = "scroll.home";
    Command["SCROLL_END"] = "scroll.end";
    Command["PAGE_UP"] = "scroll.pageUp";
    Command["PAGE_DOWN"] = "scroll.pageDown";
    // History & Search
    Command["HISTORY_UP"] = "history.previous";
    Command["HISTORY_DOWN"] = "history.next";
    Command["REVERSE_SEARCH"] = "history.search.start";
    Command["SUBMIT_REVERSE_SEARCH"] = "history.search.submit";
    Command["ACCEPT_SUGGESTION_REVERSE_SEARCH"] = "history.search.accept";
    // Navigation
    Command["NAVIGATION_UP"] = "nav.up";
    Command["NAVIGATION_DOWN"] = "nav.down";
    Command["DIALOG_NAVIGATION_UP"] = "nav.dialog.up";
    Command["DIALOG_NAVIGATION_DOWN"] = "nav.dialog.down";
    Command["DIALOG_NEXT"] = "nav.dialog.next";
    Command["DIALOG_PREV"] = "nav.dialog.previous";
    // Suggestions & Completions
    Command["ACCEPT_SUGGESTION"] = "suggest.accept";
    Command["COMPLETION_UP"] = "suggest.focusPrevious";
    Command["COMPLETION_DOWN"] = "suggest.focusNext";
    Command["EXPAND_SUGGESTION"] = "suggest.expand";
    Command["COLLAPSE_SUGGESTION"] = "suggest.collapse";
    // Text Input
    Command["SUBMIT"] = "input.submit";
    Command["NEWLINE"] = "input.newline";
    Command["OPEN_EXTERNAL_EDITOR"] = "input.openExternalEditor";
    Command["PASTE_CLIPBOARD"] = "input.paste";
    // App Controls
    Command["SHOW_ERROR_DETAILS"] = "app.showErrorDetails";
    Command["SHOW_FULL_TODOS"] = "app.showFullTodos";
    Command["SHOW_IDE_CONTEXT_DETAIL"] = "app.showIdeContextDetail";
    Command["TOGGLE_MARKDOWN"] = "app.toggleMarkdown";
    Command["TOGGLE_COPY_MODE"] = "app.toggleCopyMode";
    Command["TOGGLE_YOLO"] = "app.toggleYolo";
    Command["CYCLE_APPROVAL_MODE"] = "app.cycleApprovalMode";
    Command["SHOW_MORE_LINES"] = "app.showMoreLines";
    Command["EXPAND_PASTE"] = "app.expandPaste";
    Command["FOCUS_SHELL_INPUT"] = "app.focusShellInput";
    Command["UNFOCUS_SHELL_INPUT"] = "app.unfocusShellInput";
    Command["CLEAR_SCREEN"] = "app.clearScreen";
    Command["RESTART_APP"] = "app.restart";
    Command["SUSPEND_APP"] = "app.suspend";
    Command["SHOW_SHELL_INPUT_UNFOCUS_WARNING"] = "app.showShellUnfocusWarning";
    // Background Shell Controls
    Command["BACKGROUND_SHELL_ESCAPE"] = "background.escape";
    Command["BACKGROUND_SHELL_SELECT"] = "background.select";
    Command["TOGGLE_BACKGROUND_SHELL"] = "background.toggle";
    Command["TOGGLE_BACKGROUND_SHELL_LIST"] = "background.toggleList";
    Command["KILL_BACKGROUND_SHELL"] = "background.kill";
    Command["UNFOCUS_BACKGROUND_SHELL"] = "background.unfocus";
    Command["UNFOCUS_BACKGROUND_SHELL_LIST"] = "background.unfocusList";
    Command["SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING"] = "background.unfocusWarning";
})(Command || (Command = {}));
/**
 * Data-driven key binding structure for user configuration
 */
export class KeyBinding {
    static VALID_LONG_KEYS = new Set([
        ...Array.from({ length: 35 }, (_, i) => `f${i + 1}`), // Function Keys
        ...Array.from({ length: 10 }, (_, i) => `numpad${i}`), // Numpad Numbers
        // Navigation & Actions
        'left',
        'up',
        'right',
        'down',
        'pageup',
        'pagedown',
        'end',
        'home',
        'tab',
        'enter',
        'escape',
        'space',
        'backspace',
        'delete',
        'clear',
        'pausebreak',
        'capslock',
        'insert',
        'numlock',
        'scrolllock',
        'printscreen',
        'numpad_multiply',
        'numpad_add',
        'numpad_separator',
        'numpad_subtract',
        'numpad_decimal',
        'numpad_divide',
    ]);
    /** The key name (e.g., 'a', 'enter', 'tab', 'escape') */
    name;
    shift;
    alt;
    ctrl;
    cmd;
    constructor(pattern) {
        let remains = pattern.trim();
        let shift = false;
        let alt = false;
        let ctrl = false;
        let cmd = false;
        let matched;
        do {
            matched = false;
            const lowerRemains = remains.toLowerCase();
            if (lowerRemains.startsWith('ctrl+')) {
                ctrl = true;
                remains = remains.slice(5);
                matched = true;
            }
            else if (lowerRemains.startsWith('shift+')) {
                shift = true;
                remains = remains.slice(6);
                matched = true;
            }
            else if (lowerRemains.startsWith('alt+')) {
                alt = true;
                remains = remains.slice(4);
                matched = true;
            }
            else if (lowerRemains.startsWith('option+')) {
                alt = true;
                remains = remains.slice(7);
                matched = true;
            }
            else if (lowerRemains.startsWith('opt+')) {
                alt = true;
                remains = remains.slice(4);
                matched = true;
            }
            else if (lowerRemains.startsWith('cmd+')) {
                cmd = true;
                remains = remains.slice(4);
                matched = true;
            }
            else if (lowerRemains.startsWith('meta+')) {
                cmd = true;
                remains = remains.slice(5);
                matched = true;
            }
        } while (matched);
        const key = remains;
        const isSingleChar = [...key].length === 1;
        if (!isSingleChar && !KeyBinding.VALID_LONG_KEYS.has(key.toLowerCase())) {
            throw new Error(`Invalid keybinding key: "${key}" in "${pattern}".` +
                ` Must be a single character or one of: ${[...KeyBinding.VALID_LONG_KEYS].join(', ')}`);
        }
        this.name = key.toLowerCase();
        this.shift = shift || (isSingleChar && this.name !== key);
        this.alt = alt;
        this.ctrl = ctrl;
        this.cmd = cmd;
    }
    matches(key) {
        return (key.name === this.name &&
            !!key.shift === !!this.shift &&
            !!key.alt === !!this.alt &&
            !!key.ctrl === !!this.ctrl &&
            !!key.cmd === !!this.cmd);
    }
    equals(other) {
        return (this.name === other.name &&
            this.shift === other.shift &&
            this.alt === other.alt &&
            this.ctrl === other.ctrl &&
            this.cmd === other.cmd);
    }
}
/**
 * Default key binding configuration
 * Matches the original hard-coded logic exactly
 */
export const defaultKeyBindingConfig = new Map([
    // Basic Controls
    [Command.RETURN, [new KeyBinding('enter')]],
    [Command.ESCAPE, [new KeyBinding('escape'), new KeyBinding('ctrl+[')]],
    [Command.QUIT, [new KeyBinding('ctrl+c')]],
    [Command.EXIT, [new KeyBinding('ctrl+d')]],
    // Cursor Movement
    [Command.HOME, [new KeyBinding('ctrl+a'), new KeyBinding('home')]],
    [Command.END, [new KeyBinding('ctrl+e'), new KeyBinding('end')]],
    [Command.MOVE_UP, [new KeyBinding('up')]],
    [Command.MOVE_DOWN, [new KeyBinding('down')]],
    [Command.MOVE_LEFT, [new KeyBinding('left')]],
    [Command.MOVE_RIGHT, [new KeyBinding('right'), new KeyBinding('ctrl+f')]],
    [
        Command.MOVE_WORD_LEFT,
        [
            new KeyBinding('ctrl+left'),
            new KeyBinding('alt+left'),
            new KeyBinding('alt+b'),
        ],
    ],
    [
        Command.MOVE_WORD_RIGHT,
        [
            new KeyBinding('ctrl+right'),
            new KeyBinding('alt+right'),
            new KeyBinding('alt+f'),
        ],
    ],
    // Editing
    [Command.KILL_LINE_RIGHT, [new KeyBinding('ctrl+k')]],
    [Command.KILL_LINE_LEFT, [new KeyBinding('ctrl+u')]],
    [Command.CLEAR_INPUT, [new KeyBinding('ctrl+c')]],
    [
        Command.DELETE_WORD_BACKWARD,
        [
            new KeyBinding('ctrl+backspace'),
            new KeyBinding('alt+backspace'),
            new KeyBinding('ctrl+w'),
        ],
    ],
    [
        Command.DELETE_WORD_FORWARD,
        [
            new KeyBinding('ctrl+delete'),
            new KeyBinding('alt+delete'),
            new KeyBinding('alt+d'),
        ],
    ],
    [
        Command.DELETE_CHAR_LEFT,
        [new KeyBinding('backspace'), new KeyBinding('ctrl+h')],
    ],
    [
        Command.DELETE_CHAR_RIGHT,
        [new KeyBinding('delete'), new KeyBinding('ctrl+d')],
    ],
    [Command.UNDO, [new KeyBinding('cmd+z'), new KeyBinding('alt+z')]],
    [
        Command.REDO,
        [
            new KeyBinding('ctrl+shift+z'),
            new KeyBinding('cmd+shift+z'),
            new KeyBinding('alt+shift+z'),
        ],
    ],
    // Scrolling
    [Command.SCROLL_UP, [new KeyBinding('shift+up')]],
    [Command.SCROLL_DOWN, [new KeyBinding('shift+down')]],
    [
        Command.SCROLL_HOME,
        [new KeyBinding('ctrl+home'), new KeyBinding('shift+home')],
    ],
    [
        Command.SCROLL_END,
        [new KeyBinding('ctrl+end'), new KeyBinding('shift+end')],
    ],
    [Command.PAGE_UP, [new KeyBinding('pageup')]],
    [Command.PAGE_DOWN, [new KeyBinding('pagedown')]],
    // History & Search
    [Command.HISTORY_UP, [new KeyBinding('ctrl+p')]],
    [Command.HISTORY_DOWN, [new KeyBinding('ctrl+n')]],
    [Command.REVERSE_SEARCH, [new KeyBinding('ctrl+r')]],
    [Command.SUBMIT_REVERSE_SEARCH, [new KeyBinding('enter')]],
    [Command.ACCEPT_SUGGESTION_REVERSE_SEARCH, [new KeyBinding('tab')]],
    // Navigation
    [Command.NAVIGATION_UP, [new KeyBinding('up')]],
    [Command.NAVIGATION_DOWN, [new KeyBinding('down')]],
    // Navigation shortcuts appropriate for dialogs where we do not need to accept
    // text input.
    [Command.DIALOG_NAVIGATION_UP, [new KeyBinding('up'), new KeyBinding('k')]],
    [
        Command.DIALOG_NAVIGATION_DOWN,
        [new KeyBinding('down'), new KeyBinding('j')],
    ],
    [Command.DIALOG_NEXT, [new KeyBinding('tab')]],
    [Command.DIALOG_PREV, [new KeyBinding('shift+tab')]],
    // Suggestions & Completions
    [Command.ACCEPT_SUGGESTION, [new KeyBinding('tab'), new KeyBinding('enter')]],
    [Command.COMPLETION_UP, [new KeyBinding('up'), new KeyBinding('ctrl+p')]],
    [Command.COMPLETION_DOWN, [new KeyBinding('down'), new KeyBinding('ctrl+n')]],
    [Command.EXPAND_SUGGESTION, [new KeyBinding('right')]],
    [Command.COLLAPSE_SUGGESTION, [new KeyBinding('left')]],
    // Text Input
    // Must also exclude shift to allow shift+enter for newline
    [Command.SUBMIT, [new KeyBinding('enter')]],
    [
        Command.NEWLINE,
        [
            new KeyBinding('ctrl+enter'),
            new KeyBinding('cmd+enter'),
            new KeyBinding('alt+enter'),
            new KeyBinding('shift+enter'),
            new KeyBinding('ctrl+j'),
        ],
    ],
    [Command.OPEN_EXTERNAL_EDITOR, [new KeyBinding('ctrl+x')]],
    [
        Command.PASTE_CLIPBOARD,
        [
            new KeyBinding('ctrl+v'),
            new KeyBinding('cmd+v'),
            new KeyBinding('alt+v'),
        ],
    ],
    // App Controls
    [Command.SHOW_ERROR_DETAILS, [new KeyBinding('f12')]],
    [Command.SHOW_FULL_TODOS, [new KeyBinding('ctrl+t')]],
    [Command.SHOW_IDE_CONTEXT_DETAIL, [new KeyBinding('ctrl+g')]],
    [Command.TOGGLE_MARKDOWN, [new KeyBinding('alt+m')]],
    [Command.TOGGLE_COPY_MODE, [new KeyBinding('ctrl+s')]],
    [Command.TOGGLE_YOLO, [new KeyBinding('ctrl+y')]],
    [Command.CYCLE_APPROVAL_MODE, [new KeyBinding('shift+tab')]],
    [Command.SHOW_MORE_LINES, [new KeyBinding('ctrl+o')]],
    [Command.EXPAND_PASTE, [new KeyBinding('ctrl+o')]],
    [Command.FOCUS_SHELL_INPUT, [new KeyBinding('tab')]],
    [Command.UNFOCUS_SHELL_INPUT, [new KeyBinding('shift+tab')]],
    [Command.CLEAR_SCREEN, [new KeyBinding('ctrl+l')]],
    [Command.RESTART_APP, [new KeyBinding('r'), new KeyBinding('shift+r')]],
    [Command.SUSPEND_APP, [new KeyBinding('ctrl+z')]],
    [Command.SHOW_SHELL_INPUT_UNFOCUS_WARNING, [new KeyBinding('tab')]],
    // Background Shell Controls
    [Command.BACKGROUND_SHELL_ESCAPE, [new KeyBinding('escape')]],
    [Command.BACKGROUND_SHELL_SELECT, [new KeyBinding('enter')]],
    [Command.TOGGLE_BACKGROUND_SHELL, [new KeyBinding('ctrl+b')]],
    [Command.TOGGLE_BACKGROUND_SHELL_LIST, [new KeyBinding('ctrl+l')]],
    [Command.KILL_BACKGROUND_SHELL, [new KeyBinding('ctrl+k')]],
    [Command.UNFOCUS_BACKGROUND_SHELL, [new KeyBinding('shift+tab')]],
    [Command.UNFOCUS_BACKGROUND_SHELL_LIST, [new KeyBinding('tab')]],
    [Command.SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING, [new KeyBinding('tab')]],
]);
/**
 * Presentation metadata for grouping commands in documentation or UI.
 */
export const commandCategories = [
    {
        title: 'Basic Controls',
        commands: [Command.RETURN, Command.ESCAPE, Command.QUIT, Command.EXIT],
    },
    {
        title: 'Cursor Movement',
        commands: [
            Command.HOME,
            Command.END,
            Command.MOVE_UP,
            Command.MOVE_DOWN,
            Command.MOVE_LEFT,
            Command.MOVE_RIGHT,
            Command.MOVE_WORD_LEFT,
            Command.MOVE_WORD_RIGHT,
        ],
    },
    {
        title: 'Editing',
        commands: [
            Command.KILL_LINE_RIGHT,
            Command.KILL_LINE_LEFT,
            Command.CLEAR_INPUT,
            Command.DELETE_WORD_BACKWARD,
            Command.DELETE_WORD_FORWARD,
            Command.DELETE_CHAR_LEFT,
            Command.DELETE_CHAR_RIGHT,
            Command.UNDO,
            Command.REDO,
        ],
    },
    {
        title: 'Scrolling',
        commands: [
            Command.SCROLL_UP,
            Command.SCROLL_DOWN,
            Command.SCROLL_HOME,
            Command.SCROLL_END,
            Command.PAGE_UP,
            Command.PAGE_DOWN,
        ],
    },
    {
        title: 'History & Search',
        commands: [
            Command.HISTORY_UP,
            Command.HISTORY_DOWN,
            Command.REVERSE_SEARCH,
            Command.SUBMIT_REVERSE_SEARCH,
            Command.ACCEPT_SUGGESTION_REVERSE_SEARCH,
        ],
    },
    {
        title: 'Navigation',
        commands: [
            Command.NAVIGATION_UP,
            Command.NAVIGATION_DOWN,
            Command.DIALOG_NAVIGATION_UP,
            Command.DIALOG_NAVIGATION_DOWN,
            Command.DIALOG_NEXT,
            Command.DIALOG_PREV,
        ],
    },
    {
        title: 'Suggestions & Completions',
        commands: [
            Command.ACCEPT_SUGGESTION,
            Command.COMPLETION_UP,
            Command.COMPLETION_DOWN,
            Command.EXPAND_SUGGESTION,
            Command.COLLAPSE_SUGGESTION,
        ],
    },
    {
        title: 'Text Input',
        commands: [
            Command.SUBMIT,
            Command.NEWLINE,
            Command.OPEN_EXTERNAL_EDITOR,
            Command.PASTE_CLIPBOARD,
        ],
    },
    {
        title: 'App Controls',
        commands: [
            Command.SHOW_ERROR_DETAILS,
            Command.SHOW_FULL_TODOS,
            Command.SHOW_IDE_CONTEXT_DETAIL,
            Command.TOGGLE_MARKDOWN,
            Command.TOGGLE_COPY_MODE,
            Command.TOGGLE_YOLO,
            Command.CYCLE_APPROVAL_MODE,
            Command.SHOW_MORE_LINES,
            Command.EXPAND_PASTE,
            Command.FOCUS_SHELL_INPUT,
            Command.UNFOCUS_SHELL_INPUT,
            Command.CLEAR_SCREEN,
            Command.RESTART_APP,
            Command.SUSPEND_APP,
            Command.SHOW_SHELL_INPUT_UNFOCUS_WARNING,
        ],
    },
    {
        title: 'Background Shell Controls',
        commands: [
            Command.BACKGROUND_SHELL_ESCAPE,
            Command.BACKGROUND_SHELL_SELECT,
            Command.TOGGLE_BACKGROUND_SHELL,
            Command.TOGGLE_BACKGROUND_SHELL_LIST,
            Command.KILL_BACKGROUND_SHELL,
            Command.UNFOCUS_BACKGROUND_SHELL,
            Command.UNFOCUS_BACKGROUND_SHELL_LIST,
            Command.SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING,
        ],
    },
];
/**
 * Human-readable descriptions for each command, used in docs/tooling.
 */
export const commandDescriptions = {
    // Basic Controls
    [Command.RETURN]: 'Confirm the current selection or choice.',
    [Command.ESCAPE]: 'Dismiss dialogs or cancel the current focus.',
    [Command.QUIT]: 'Cancel the current request or quit the CLI when input is empty.',
    [Command.EXIT]: 'Exit the CLI when the input buffer is empty.',
    // Cursor Movement
    [Command.HOME]: 'Move the cursor to the start of the line.',
    [Command.END]: 'Move the cursor to the end of the line.',
    [Command.MOVE_UP]: 'Move the cursor up one line.',
    [Command.MOVE_DOWN]: 'Move the cursor down one line.',
    [Command.MOVE_LEFT]: 'Move the cursor one character to the left.',
    [Command.MOVE_RIGHT]: 'Move the cursor one character to the right.',
    [Command.MOVE_WORD_LEFT]: 'Move the cursor one word to the left.',
    [Command.MOVE_WORD_RIGHT]: 'Move the cursor one word to the right.',
    // Editing
    [Command.KILL_LINE_RIGHT]: 'Delete from the cursor to the end of the line.',
    [Command.KILL_LINE_LEFT]: 'Delete from the cursor to the start of the line.',
    [Command.CLEAR_INPUT]: 'Clear all text in the input field.',
    [Command.DELETE_WORD_BACKWARD]: 'Delete the previous word.',
    [Command.DELETE_WORD_FORWARD]: 'Delete the next word.',
    [Command.DELETE_CHAR_LEFT]: 'Delete the character to the left.',
    [Command.DELETE_CHAR_RIGHT]: 'Delete the character to the right.',
    [Command.UNDO]: 'Undo the most recent text edit.',
    [Command.REDO]: 'Redo the most recent undone text edit.',
    // Scrolling
    [Command.SCROLL_UP]: 'Scroll content up.',
    [Command.SCROLL_DOWN]: 'Scroll content down.',
    [Command.SCROLL_HOME]: 'Scroll to the top.',
    [Command.SCROLL_END]: 'Scroll to the bottom.',
    [Command.PAGE_UP]: 'Scroll up by one page.',
    [Command.PAGE_DOWN]: 'Scroll down by one page.',
    // History & Search
    [Command.HISTORY_UP]: 'Show the previous entry in history.',
    [Command.HISTORY_DOWN]: 'Show the next entry in history.',
    [Command.REVERSE_SEARCH]: 'Start reverse search through history.',
    [Command.SUBMIT_REVERSE_SEARCH]: 'Submit the selected reverse-search match.',
    [Command.ACCEPT_SUGGESTION_REVERSE_SEARCH]: 'Accept a suggestion while reverse searching.',
    // Navigation
    [Command.NAVIGATION_UP]: 'Move selection up in lists.',
    [Command.NAVIGATION_DOWN]: 'Move selection down in lists.',
    [Command.DIALOG_NAVIGATION_UP]: 'Move up within dialog options.',
    [Command.DIALOG_NAVIGATION_DOWN]: 'Move down within dialog options.',
    [Command.DIALOG_NEXT]: 'Move to the next item or question in a dialog.',
    [Command.DIALOG_PREV]: 'Move to the previous item or question in a dialog.',
    // Suggestions & Completions
    [Command.ACCEPT_SUGGESTION]: 'Accept the inline suggestion.',
    [Command.COMPLETION_UP]: 'Move to the previous completion option.',
    [Command.COMPLETION_DOWN]: 'Move to the next completion option.',
    [Command.EXPAND_SUGGESTION]: 'Expand an inline suggestion.',
    [Command.COLLAPSE_SUGGESTION]: 'Collapse an inline suggestion.',
    // Text Input
    [Command.SUBMIT]: 'Submit the current prompt.',
    [Command.NEWLINE]: 'Insert a newline without submitting.',
    [Command.OPEN_EXTERNAL_EDITOR]: 'Open the current prompt or the plan in an external editor.',
    [Command.PASTE_CLIPBOARD]: 'Paste from the clipboard.',
    // App Controls
    [Command.SHOW_ERROR_DETAILS]: 'Toggle detailed error information.',
    [Command.SHOW_FULL_TODOS]: 'Toggle the full TODO list.',
    [Command.SHOW_IDE_CONTEXT_DETAIL]: 'Show IDE context details.',
    [Command.TOGGLE_MARKDOWN]: 'Toggle Markdown rendering.',
    [Command.TOGGLE_COPY_MODE]: 'Toggle copy mode when in alternate buffer mode.',
    [Command.TOGGLE_YOLO]: 'Toggle YOLO (auto-approval) mode for tool calls.',
    [Command.CYCLE_APPROVAL_MODE]: 'Cycle through approval modes: default (prompt), auto_edit (auto-approve edits), and plan (read-only). Plan mode is skipped when the agent is busy.',
    [Command.SHOW_MORE_LINES]: 'Expand and collapse blocks of content when not in alternate buffer mode.',
    [Command.EXPAND_PASTE]: 'Expand or collapse a paste placeholder when cursor is over placeholder.',
    [Command.FOCUS_SHELL_INPUT]: 'Move focus from Gemini to the active shell.',
    [Command.UNFOCUS_SHELL_INPUT]: 'Move focus from the shell back to Gemini.',
    [Command.CLEAR_SCREEN]: 'Clear the terminal screen and redraw the UI.',
    [Command.RESTART_APP]: 'Restart the application.',
    [Command.SUSPEND_APP]: 'Suspend the CLI and move it to the background.',
    [Command.SHOW_SHELL_INPUT_UNFOCUS_WARNING]: 'Show warning when trying to move focus away from shell input.',
    // Background Shell Controls
    [Command.BACKGROUND_SHELL_ESCAPE]: 'Dismiss background shell list.',
    [Command.BACKGROUND_SHELL_SELECT]: 'Confirm selection in background shell list.',
    [Command.TOGGLE_BACKGROUND_SHELL]: 'Toggle current background shell visibility.',
    [Command.TOGGLE_BACKGROUND_SHELL_LIST]: 'Toggle background shell list.',
    [Command.KILL_BACKGROUND_SHELL]: 'Kill the active background shell.',
    [Command.UNFOCUS_BACKGROUND_SHELL]: 'Move focus from background shell to Gemini.',
    [Command.UNFOCUS_BACKGROUND_SHELL_LIST]: 'Move focus from background shell list to Gemini.',
    [Command.SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING]: 'Show warning when trying to move focus away from background shell.',
};
const keybindingsSchema = z.array(z
    .object({
    command: z.string().transform((val, ctx) => {
        const negate = val.startsWith('-');
        const commandId = negate ? val.slice(1) : val;
        const result = z.nativeEnum(Command).safeParse(commandId);
        if (!result.success) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: `Invalid command: "${val}".`,
            });
            return z.NEVER;
        }
        return {
            command: result.data,
            negate,
        };
    }),
    key: z.string(),
})
    .transform((val) => ({
    commandEntry: val.command,
    key: val.key,
})));
/**
 * Loads custom keybindings from the user's keybindings.json file.
 * Keybindings are merged with the default bindings.
 */
export async function loadCustomKeybindings() {
    const errors = [];
    let config = defaultKeyBindingConfig;
    const userKeybindingsPath = Storage.getUserKeybindingsPath();
    try {
        const content = await fs.readFile(userKeybindingsPath, 'utf8');
        const parsedJson = parseIgnoringComments(content);
        const result = keybindingsSchema.safeParse(parsedJson);
        if (result.success) {
            config = new Map(defaultKeyBindingConfig);
            for (const { commandEntry, key } of result.data) {
                const { command, negate } = commandEntry;
                const currentBindings = config.get(command) ?? [];
                try {
                    const keyBinding = new KeyBinding(key);
                    if (negate) {
                        const updatedBindings = currentBindings.filter((b) => !b.equals(keyBinding));
                        if (updatedBindings.length === currentBindings.length) {
                            throw new Error(`cannot remove "${key}" since it is not bound`);
                        }
                        config.set(command, updatedBindings);
                    }
                    else {
                        // Add new binding (prepend so it's the primary one shown in UI)
                        config.set(command, [keyBinding, ...currentBindings]);
                    }
                }
                catch (e) {
                    errors.push(`Invalid keybinding for command "${negate ? '-' : ''}${command}": ${e}`);
                }
            }
        }
        else {
            errors.push(...result.error.issues.map((issue) => `Keybindings file "${userKeybindingsPath}" error at ${issue.path.join('.')}: ${issue.message}`));
        }
    }
    catch (error) {
        if (isNodeError(error) && error.code === 'ENOENT') {
            // File doesn't exist, use default bindings
        }
        else {
            errors.push(`Error reading keybindings file "${userKeybindingsPath}": ${error}`);
        }
    }
    return { config, errors };
}
//# sourceMappingURL=keyBindings.js.map