Google AI Studio - Enhanced Actions

Adds multi-select/delete (Checkbox, Ctrl+A, Shift+Click, Ctrl+Click, Delete key) and "Delete Thoughts" (Shift+F2) to Chat.

当前为 2025-10-19 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Google AI Studio - Enhanced Actions
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Adds multi-select/delete (Checkbox, Ctrl+A, Shift+Click, Ctrl+Click, Delete key) and "Delete Thoughts" (Shift+F2) to Chat.
// @author       User
// @match        https://aistudio.google.com/prompts/*
// @match        https://aistudio.google.com/library
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant        GM_addStyle
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // --- Configuration & Constants ---
    const C = {
        CLASSES: {
            CHAT_CHECKBOX: 'gm-chat-select-checkbox',
            CHAT_SELECTED: 'gm-chat-selected',
            CHAT_DELETE_BEFORE: 'gm-chat-delete-before-item',
            LIB_CHECKBOX: 'gm-lib-select-checkbox',
            LIB_HEADER_CHECKBOX: 'gm-lib-header-select-checkbox',
            LIB_SELECTED: 'gm-lib-selected',
            LIB_CHECKBOX_CELL: 'gm-lib-checkbox-cell',
            LIB_CHECKBOX_HEADER: 'gm-lib-checkbox-header',
            ENABLED: 'enabled'
        },
        IDS: {
            CHAT_MULTI_DELETE_BTN: 'gm-chat-multi-delete-button',
            LIB_MULTI_DELETE_BTN: 'gm-lib-multi-delete-button'
        },
        SELECTORS: {
            CHAT_TURN: 'ms-chat-turn',
            CHAT_SESSION: 'ms-chat-session',
            CHAT_TURN_CONTAINER: '.chat-turn-container',
            CHAT_MORE_OPTIONS_BTN: 'ms-chat-turn-options button.mat-mdc-menu-trigger',
            CHAT_MORE_ACTIONS_BTN: 'button[aria-label="View more actions"]',
            MENU_PANEL: 'div.cdk-overlay-container div.mat-mdc-menu-panel',
            MENU_ITEM: 'button.mat-mdc-menu-item',
            OVERLAY_BACKDROP: 'div.cdk-overlay-backdrop',
            LIBRARY_TABLE: 'ms-library-table table.mat-mdc-table',
            LIBRARY_HEADER_ROW: 'thead tr.mat-mdc-header-row',
            LIBRARY_ROW: 'tbody tr.mat-mdc-row',
            LIBRARY_ACTIONS_WRAPPER: 'div.lib-header div.actions-wrapper',
            LIBRARY_MORE_OPTIONS_BTN: 'button[aria-label="Show overflow"]',
            DIALOG_CONTAINER: 'mat-dialog-container',
            DIALOG_ACTIONS: 'mat-dialog-actions button'
        },
        TIMEOUTS: {
            ELEMENT_WAIT: 5000,
            ELEMENT_DISAPPEAR: 5000,
            MENU_APPEAR_DELAY: 150
        }
    };

    // --- State Variables ---
    let selectedChatTurns = new Set();
    let selectedLibraryItems = new Set();
    let isDeleting = false;
    let lastClickedTurn = null;

    // --- Styles ---
    GM_addStyle(`
        ms-chat-turn .chat-turn-container { position: relative; padding-left: 35px !important; }
        .${C.CLASSES.CHAT_CHECKBOX} { position: absolute; left: 8px; top: 12px; z-index: 10; cursor: pointer; transform: scale(1.2); }
        ms-chat-turn.${C.CLASSES.CHAT_SELECTED} > div { background-color: rgba(0, 100, 255, 0.1) !important; border: 1px solid rgba(0, 100, 255, 0.3); border-radius: 8px; }
        #${C.IDS.CHAT_MULTI_DELETE_BTN} { margin-left: 10px; background-color: #dc3545; color: white; border: none; padding: 5px 10px; border-radius: 4px; font-size: 14px; opacity: 0.5; pointer-events: none; transition: opacity 0.2s; }
        #${C.IDS.CHAT_MULTI_DELETE_BTN}.${C.CLASSES.ENABLED} { opacity: 1; pointer-events: auto; cursor: pointer; }
        #${C.IDS.CHAT_MULTI_DELETE_BTN}:hover.${C.CLASSES.ENABLED} { background-color: #c82333; }
        #${C.IDS.CHAT_MULTI_DELETE_BTN}:disabled { background-color: #a0a0a0; cursor: not-allowed; }
        .${C.CLASSES.CHAT_DELETE_BEFORE} .mat-mdc-menu-item-text { display: flex; align-items: center; }
        .${C.CLASSES.CHAT_DELETE_BEFORE} .delete-before-marker { margin-right: 8px; font-weight: bold; }
        th.${C.CLASSES.LIB_CHECKBOX_HEADER}, td.${C.CLASSES.LIB_CHECKBOX_CELL} { width: 40px !important; padding: 0 8px 0 16px !important; }
        tr.${C.CLASSES.LIB_SELECTED} { background-color: rgba(0, 100, 255, 0.08) !important; }
        #${C.IDS.LIB_MULTI_DELETE_BTN} { margin-left: 8px; background-color: #dc3545; color: white; border: none; padding: 0 12px; height: 36px; line-height: 36px; border-radius: 18px; font-weight: 500; opacity: 0.5; pointer-events: none; transition: opacity 0.2s; display: inline-flex; align-items: center; }
        #${C.IDS.LIB_MULTI_DELETE_BTN} .material-symbols-outlined { font-size: 18px; margin-right: 6px; }
        #${C.IDS.LIB_MULTI_DELETE_BTN}.${C.CLASSES.ENABLED} { opacity: 1; pointer-events: auto; cursor: pointer; }
        #${C.IDS.LIB_MULTI_DELETE_BTN}:hover.${C.CLASSES.ENABLED} { background-color: #c82333; }
        #${C.IDS.LIB_MULTI_DELETE_BTN}:disabled { background-color: #cccccc; cursor: not-allowed; opacity: 0.6; }
    `);

    // --- Utility Functions ---
    function robustClick(element) {
        if (!element) return;
        const ownerDoc = element.ownerDocument;
        const ownerWindow = ownerDoc?.defaultView;
        if (!ownerWindow) return;
        ['pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click'].forEach(type =>
            element.dispatchEvent(new ownerWindow.MouseEvent(type, { bubbles: true, cancelable: true, view: ownerWindow }))
        );
    }

    function waitForElement(selector, timeout = C.TIMEOUTS.ELEMENT_WAIT) {
        return new Promise((resolve, reject) => {
            let el = document.querySelector(selector);
            if (el) return resolve(el);
            const observer = new MutationObserver(() => {
                el = document.querySelector(selector);
                if (el) {
                    observer.disconnect();
                    resolve(el);
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
            setTimeout(() => {
                observer.disconnect();
                reject(new Error(`Element "${selector}" not found.`));
            }, timeout);
        });
    }

    function waitForElementToDisappear(element, timeout = C.TIMEOUTS.ELEMENT_DISAPPEAR) {
        return new Promise(resolve => {
            if (!element || !document.body.contains(element)) return resolve();
            const observer = new MutationObserver(() => {
                if (!document.body.contains(element)) {
                    observer.disconnect();
                    resolve();
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
            setTimeout(() => { observer.disconnect(); resolve(); }, timeout);
        });
    }

    async function withSuppressedConfirm(action) {
        const originalConfirm = window.confirm;
        window.confirm = () => true;
        try {
            await action();
        } finally {
            window.confirm = originalConfirm;
        }
    }

    // --- Chat View Functions ---
    function addChatCheckbox(turnElement) {
        if (turnElement.querySelector(`.${C.CLASSES.CHAT_CHECKBOX}`)) return;
        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.className = C.CLASSES.CHAT_CHECKBOX;
        checkbox.title = 'Select this turn (Shift+Click for range, Ctrl+Click to multi-select)';
        const container = turnElement.querySelector(C.SELECTORS.CHAT_TURN_CONTAINER);
        container?.insertBefore(checkbox, container.firstChild);
    }

    function setupChatMoreOptionsListener(turnElement) {
        const moreOptionsButton = turnElement.querySelector(C.SELECTORS.CHAT_MORE_OPTIONS_BTN);
        if (!moreOptionsButton || moreOptionsButton.dataset.hasGmListener) return;
        moreOptionsButton.dataset.hasGmListener = 'true';
        moreOptionsButton.addEventListener('click', () => {
            if (isDeleting) return;
            setTimeout(() => {
                const menu = document.querySelector(C.SELECTORS.MENU_PANEL);
                if (menu) addChatDeleteBeforeMenuItem(menu, turnElement);
            }, C.TIMEOUTS.MENU_APPEAR_DELAY);
        });
    }

    function addChatDeleteBeforeMenuItem(menuPanel, targetTurnElement) {
        if (menuPanel.querySelector(`.${C.CLASSES.CHAT_DELETE_BEFORE}`)) return;
        const menuContent = menuPanel.querySelector('.mat-mdc-menu-content');
        if (!menuContent) return;
        const deleteItem = Array.from(menuPanel.querySelectorAll(C.SELECTORS.MENU_ITEM)).find(
            btn => btn.textContent.trim().toLowerCase() === 'delete'
        );
        const btn = document.createElement('button');
        btn.className = `mat-mdc-menu-item mat-focus-indicator ${C.CLASSES.CHAT_DELETE_BEFORE}`;
        btn.innerHTML = `<span class="mat-mdc-menu-item-text"><span class="delete-before-marker">[X]</span><span>Delete Before</span></span>`;
        btn.addEventListener('click', (e) => {
            e.stopPropagation();
            handleChatDeleteBefore(targetTurnElement);
        });
        if (deleteItem) menuContent.insertBefore(btn, deleteItem);
        else menuContent.appendChild(btn);
    }

    function handleChatClick(event) {
        const checkbox = event.target;
        if (!checkbox.matches(`.${C.CLASSES.CHAT_CHECKBOX}`)) return;
        const turnElement = checkbox.closest(C.SELECTORS.CHAT_TURN);
        if (!turnElement || isDeleting) {
            if (isDeleting) event.preventDefault();
            return;
        }
        if (lastClickedTurn && !document.body.contains(lastClickedTurn)) lastClickedTurn = null;
        const allTurns = Array.from(document.querySelectorAll(`${C.SELECTORS.CHAT_SESSION} ${C.SELECTORS.CHAT_TURN}`));
        if (event.shiftKey && lastClickedTurn) {
            const start = allTurns.indexOf(lastClickedTurn);
            const end = allTurns.indexOf(turnElement);
            if (start === -1 || end === -1) return;
            const range = allTurns.slice(Math.min(start, end), Math.max(start, end) + 1);
            if (!event.ctrlKey) deselectAllTurns(false);
            range.forEach(turn => selectTurn(turn, true));
        } else {
            const isSelected = selectedChatTurns.has(turnElement);
            if (!event.ctrlKey) {
                deselectAllTurns(false);
                if (!isSelected) selectTurn(turnElement, true);
            } else {
                selectTurn(turnElement, !isSelected);
            }
        }
        lastClickedTurn = turnElement;
        updateChatMultiDeleteButtonState();
    }

    function selectTurn(turnElement, shouldBeSelected) {
        const checkbox = turnElement.querySelector(`.${C.CLASSES.CHAT_CHECKBOX}`);
        if (shouldBeSelected) {
            selectedChatTurns.add(turnElement);
            turnElement.classList.add(C.CLASSES.CHAT_SELECTED);
            if (checkbox) checkbox.checked = true;
        } else {
            selectedChatTurns.delete(turnElement);
            turnElement.classList.remove(C.CLASSES.CHAT_SELECTED);
            if (checkbox) checkbox.checked = false;
        }
    }

    function deselectAllTurns(updateButtonState = true) {
        selectedChatTurns.forEach(turn => selectTurn(turn, false));
        selectedChatTurns.clear();
        if (updateButtonState) updateChatMultiDeleteButtonState();
    }

    async function deleteSingleChatTurn(turnElement) {
        const moreOptionsButton = turnElement.querySelector(C.SELECTORS.CHAT_MORE_OPTIONS_BTN);
        if (!moreOptionsButton) return false;
        robustClick(moreOptionsButton);
        try {
            const menu = await waitForElement(`${C.SELECTORS.MENU_PANEL}:has(${C.SELECTORS.MENU_ITEM})`);
            const deleteButton = Array.from(menu.querySelectorAll(C.SELECTORS.MENU_ITEM)).find(btn => {
                const text = btn.textContent.trim().toLowerCase();
                return text.includes('delete') && !text.includes('before');
            });
            if (deleteButton) {
                robustClick(deleteButton);
                await waitForElementToDisappear(turnElement);
                return true;
            }
            return false;
        } catch (error) {
            const backdrop = document.querySelector(C.SELECTORS.OVERLAY_BACKDROP);
            if (backdrop) robustClick(backdrop);
            return false;
        }
    }

    async function performChatDeletion(turnsToDelete) {
        if (isDeleting || turnsToDelete.length === 0) return;
        const turnsArray = [...turnsToDelete].sort((a, b) => b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING ? 1 : -1);
        await withSuppressedConfirm(async () => {
            isDeleting = true;
            updateChatMultiDeleteButtonState();
            try {
                for (const turn of turnsArray) {
                    if (document.body.contains(turn)) await deleteSingleChatTurn(turn);
                }
            } finally {
                isDeleting = false;
                updateChatMultiDeleteButtonState();
            }
        });
    }

    async function handleChatDeleteSelected() {
        const turnsToDelete = [...selectedChatTurns];
        if (turnsToDelete.length === 0) return;
        deselectAllTurns(false);
        await performChatDeletion(turnsToDelete);
    }

    async function handleChatDeleteBefore(targetTurnElement) {
        if (!targetTurnElement?.isConnected) return;
        const allTurns = Array.from(document.querySelectorAll(`${C.SELECTORS.CHAT_SESSION} ${C.SELECTORS.CHAT_TURN}`));
        const idx = allTurns.indexOf(targetTurnElement);
        if (idx <= 0) return;
        const turnsToDelete = allTurns.slice(0, idx);
        if (turnsToDelete.length > 0) {
            deselectAllTurns(false);
            await performChatDeletion(turnsToDelete);
        }
    }

    async function handleDeleteThoughts() {
        const thoughtTurns = Array.from(document.querySelectorAll(C.SELECTORS.CHAT_TURN)).filter(turn =>
            turn.querySelector('mat-expansion-panel-header')?.textContent.trim().startsWith('Thoughts')
        );
        if (thoughtTurns.length > 0) await performChatDeletion(thoughtTurns);
    }

    function addChatMultiDeleteButton() {
        if (document.getElementById(C.IDS.CHAT_MULTI_DELETE_BTN)) return;
        const moreButton = document.querySelector(C.SELECTORS.CHAT_MORE_ACTIONS_BTN);
        if (!moreButton?.parentElement) return;
        const btn = document.createElement('button');
        btn.id = C.IDS.CHAT_MULTI_DELETE_BTN;
        btn.addEventListener('click', handleChatDeleteSelected);
        moreButton.parentElement.insertBefore(btn, moreButton);
        updateChatMultiDeleteButtonState();
    }

    function updateChatMultiDeleteButtonState() {
        const btn = document.getElementById(C.IDS.CHAT_MULTI_DELETE_BTN);
        if (!btn) return;
        const count = selectedChatTurns.size;
        btn.textContent = isDeleting ? 'Deleting...' : `Delete Selected (${count})`;
        const enabled = count > 0 && !isDeleting;
        btn.classList.toggle(C.CLASSES.ENABLED, enabled);
        btn.disabled = !enabled;
    }

    function observeChatArea() {
        const container = document.querySelector(C.SELECTORS.CHAT_SESSION);
        if (!container) return;
        container.addEventListener('click', handleChatClick);
        document.querySelectorAll(`${C.SELECTORS.CHAT_SESSION} ${C.SELECTORS.CHAT_TURN}`).forEach(turn => {
            addChatCheckbox(turn);
            setupChatMoreOptionsListener(turn);
        });
        addChatMultiDeleteButton();
        const observer = new MutationObserver(mutations => {
            for (const m of mutations) {
                m.addedNodes.forEach(n => {
                    if (n.nodeType === Node.ELEMENT_NODE) {
                        const turns = n.matches(C.SELECTORS.CHAT_TURN) ? [n] : n.querySelectorAll(C.SELECTORS.CHAT_TURN);
                        turns.forEach(turn => {
                            addChatCheckbox(turn);
                            setupChatMoreOptionsListener(turn);
                        });
                    }
                });
                m.removedNodes.forEach(n => {
                    if (n.nodeType === Node.ELEMENT_NODE && selectedChatTurns.has(n)) {
                        selectedChatTurns.delete(n);
                        updateChatMultiDeleteButtonState();
                    }
                });
            }
        });
        observer.observe(container, { childList: true, subtree: true });
    }

    // --- Library View Functions ---
    function addLibraryCheckbox(rowElement) {
        if (rowElement.querySelector(`.${C.CLASSES.LIB_CHECKBOX_CELL}`)) return;
        const cell = document.createElement('td');
        cell.className = `mat-mdc-cell mdc-data-table__cell cdk-cell ${C.CLASSES.LIB_CHECKBOX_CELL}`;
        cell.innerHTML = `<input type="checkbox" class="${C.CLASSES.LIB_CHECKBOX}">`;
        rowElement.insertBefore(cell, rowElement.firstChild);
    }

    function addLibraryHeaderCheckbox(headerRow) {
        if (headerRow.querySelector(`.${C.CLASSES.LIB_CHECKBOX_HEADER}`)) return;
        const headerCell = document.createElement('th');
        headerCell.className = `mat-mdc-header-cell mdc-data-table__header-cell cdk-header-cell ${C.CLASSES.LIB_CHECKBOX_HEADER}`;
        headerCell.innerHTML = `<input type="checkbox" class="${C.CLASSES.LIB_HEADER_CHECKBOX}" title="Select/Deselect All Visible">`;
        headerRow.insertBefore(headerCell, headerRow.firstChild);
    }

    function handleLibraryClick(event) {
        const target = event.target;
        if (target.matches(`.${C.CLASSES.LIB_HEADER_CHECKBOX}`)) {
            const isChecked = target.checked;
            document.querySelectorAll(C.SELECTORS.LIBRARY_ROW).forEach(row => {
                const rowCheckbox = row.querySelector(`input.${C.CLASSES.LIB_CHECKBOX}`);
                if (rowCheckbox) rowCheckbox.checked = isChecked;
                row.classList.toggle(C.CLASSES.LIB_SELECTED, isChecked);
                if (isChecked) selectedLibraryItems.add(row);
                else selectedLibraryItems.delete(row);
            });
        } else if (target.matches(`.${C.CLASSES.LIB_CHECKBOX}`)) {
            const row = target.closest('tr');
            if (row) {
                row.classList.toggle(C.CLASSES.LIB_SELECTED, target.checked);
                if (target.checked) selectedLibraryItems.add(row);
                else selectedLibraryItems.delete(row);
            }
        }
        updateLibraryMultiDeleteButtonState();
    }

    function addLibraryMultiDeleteButton() {
        if (document.getElementById(C.IDS.LIB_MULTI_DELETE_BTN)) return;
        const actionsWrapper = document.querySelector(C.SELECTORS.LIBRARY_ACTIONS_WRAPPER);
        if (!actionsWrapper) return;
        const button = document.createElement('button');
        button.id = C.IDS.LIB_MULTI_DELETE_BTN;
        button.innerHTML = `<span class="material-symbols-outlined">delete</span><span class="button-text">Delete Selected (0)</span>`;
        button.addEventListener('click', handleLibraryDeleteSelected);
        actionsWrapper.appendChild(button);
        updateLibraryMultiDeleteButtonState();
    }

    function updateLibraryMultiDeleteButtonState() {
        const button = document.getElementById(C.IDS.LIB_MULTI_DELETE_BTN);
        if (!button) return;
        const count = selectedLibraryItems.size;
        button.querySelector('.button-text').textContent = `Delete Selected (${count})`;
        const enabled = count > 0 && !isDeleting;
        button.classList.toggle(C.CLASSES.ENABLED, enabled);
        button.disabled = !enabled;
    }

    async function deleteSingleLibraryItem(rowElement) {
        const moreOptionsButton = rowElement.querySelector(C.SELECTORS.LIBRARY_MORE_OPTIONS_BTN);
        if (!moreOptionsButton) return false;
        robustClick(moreOptionsButton);
        try {
            const menu = await waitForElement(`${C.SELECTORS.MENU_PANEL}:has(${C.SELECTORS.MENU_ITEM})`);
            const deletePromptButton = Array.from(menu.querySelectorAll(C.SELECTORS.MENU_ITEM)).find(
                btn => btn.textContent.trim().toLowerCase().includes('delete prompt')
            );
            if (!deletePromptButton) return false;
            robustClick(deletePromptButton);
            const dialog = await waitForElement(C.SELECTORS.DIALOG_CONTAINER);
            const finalDeleteButton = Array.from(dialog.querySelectorAll(C.SELECTORS.DIALOG_ACTIONS)).find(
                btn => btn.textContent.trim().toLowerCase() === 'delete'
            );
            if (!finalDeleteButton) return false;
            robustClick(finalDeleteButton);
            await waitForElementToDisappear(rowElement);
            return true;
        } catch (error) {
            const backdrop = document.querySelector(C.SELECTORS.OVERLAY_BACKDROP);
            if (backdrop) robustClick(backdrop);
            return false;
        }
    }

    async function handleLibraryDeleteSelected() {
        if (isDeleting || selectedLibraryItems.size === 0) return;
        await withSuppressedConfirm(async () => {
            isDeleting = true;
            updateLibraryMultiDeleteButtonState();
            try {
                const itemsToDelete = [...selectedLibraryItems];
                selectedLibraryItems.clear();
                for (const row of itemsToDelete) {
                    if (row.isConnected) await deleteSingleLibraryItem(row);
                }
            } finally {
                isDeleting = false;
                updateLibraryMultiDeleteButtonState();
            }
        });
    }

    function observeLibraryTable() {
        const table = document.querySelector(C.SELECTORS.LIBRARY_TABLE);
        if (!table) return;
        table.addEventListener('click', handleLibraryClick);
        const headerRow = table.querySelector(C.SELECTORS.LIBRARY_HEADER_ROW);
        if (headerRow) addLibraryHeaderCheckbox(headerRow);
        table.querySelectorAll(C.SELECTORS.LIBRARY_ROW).forEach(addLibraryCheckbox);
        addLibraryMultiDeleteButton();
        const observer = new MutationObserver(() => {
            table.querySelectorAll(`${C.SELECTORS.LIBRARY_ROW}:not(:has(.${C.CLASSES.LIB_CHECKBOX_CELL}))`).forEach(addLibraryCheckbox);
        });
        const tbody = table.querySelector('tbody');
        if (tbody) observer.observe(tbody, { childList: true });
    }

    // --- Global Listeners & Initialization ---
    function setupGlobalListeners() {
        document.addEventListener('keydown', (event) => {
            const activeEl = document.activeElement;
            const isTyping = activeEl && (activeEl.tagName === 'TEXTAREA' || activeEl.isContentEditable || (activeEl.tagName === 'INPUT' && /^(text|search|password|tel|url)$/i.test(activeEl.type)));
            if (isTyping || isDeleting) return;

            if (window.location.pathname.startsWith('/prompts/')) {
                if (event.ctrlKey && event.key.toLowerCase() === 'a') {
                    event.preventDefault();
                    const allTurns = document.querySelectorAll(`${C.SELECTORS.CHAT_SESSION} ${C.SELECTORS.CHAT_TURN}`);
                    const allSelected = selectedChatTurns.size === allTurns.length && allTurns.length > 0;
                    deselectAllTurns(false);
                    if (!allSelected) allTurns.forEach(turn => selectTurn(turn, true));
                    updateChatMultiDeleteButtonState();
                } else if (event.key === 'Escape') {
                    if (selectedChatTurns.size > 0) {
                        event.preventDefault();
                        deselectAllTurns();
                        lastClickedTurn = null;
                    }
                } else if (event.key === 'Delete') {
                    if (selectedChatTurns.size > 0) {
                        event.preventDefault();
                        document.getElementById(C.IDS.CHAT_MULTI_DELETE_BTN)?.click();
                    }
                } else if (event.shiftKey && event.key === 'F2') {
                    event.preventDefault();
                    handleDeleteThoughts();
                }
            }
        });

        document.addEventListener('click', (event) => {
            if (window.location.pathname.startsWith('/prompts/') && selectedChatTurns.size > 0 && !event.target.closest(`${C.SELECTORS.CHAT_TURN}, #${C.IDS.CHAT_MULTI_DELETE_BTN}`)) {
                deselectAllTurns();
                lastClickedTurn = null;
            }
        });
    }

    async function initialize() {
        const currentPath = window.location.pathname;
        try {
            if (currentPath.startsWith('/prompts/')) {
                await waitForElement(C.SELECTORS.CHAT_SESSION);
                observeChatArea();
            } else if (currentPath === '/library') {
                await waitForElement(C.SELECTORS.LIBRARY_TABLE);
                observeLibraryTable();
            }
            setupGlobalListeners();
        } catch (error) {
            console.error('[Enhanced Actions] Initialization failed:', error);
        }
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }
})();