Automatically clicks Allow on Gemini Spark tool confirmation cards.
// ==UserScript==
// @name Gemini Spark MCP Auto Allow
// @namespace https://gemini.google.com/
// @version 1.0.0
// @description Automatically clicks Allow on Gemini Spark tool confirmation cards.
// @author codex
// @match https://gemini.google.com/spark*
// @run-at document-idle
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const CARD_SELECTOR = 'remy-confirmation-card';
const PRIMARY_BUTTON_SELECTOR =
'gem-button[data-test-id="primary-button"]:not([inert]) button:not([disabled])';
const SECONDARY_BUTTON_SELECTOR =
'gem-button[data-test-id="secondary-button"] button';
const ALLOW_TEXT = /^(allow|允许)$/i;
const DENY_TEXT = /^(deny|拒绝)$/i;
const CLICK_DELAY_MS = 120;
const scheduledButtons = new WeakSet();
let scanScheduled = false;
function getText(element) {
return element?.textContent?.trim() ?? '';
}
function isVisible(element) {
if (!element.isConnected) {
return false;
}
const style = window.getComputedStyle(element);
return style.display !== 'none' && style.visibility !== 'hidden';
}
function isToolConfirmation(card, allowButton) {
const denyButton = card.querySelector(SECONDARY_BUTTON_SELECTOR);
return ALLOW_TEXT.test(getText(allowButton)) && DENY_TEXT.test(getText(denyButton));
}
function clickAllow(card) {
const allowButton = card.querySelector(PRIMARY_BUTTON_SELECTOR);
if (
!allowButton ||
scheduledButtons.has(allowButton) ||
!isVisible(allowButton) ||
!isToolConfirmation(card, allowButton)
) {
return;
}
scheduledButtons.add(allowButton);
window.setTimeout(() => {
if (
allowButton.isConnected &&
!allowButton.disabled &&
isVisible(allowButton) &&
isToolConfirmation(card, allowButton)
) {
allowButton.click();
console.info('[Gemini Spark Auto Allow] 已自动点击 Allow。');
}
}, CLICK_DELAY_MS);
}
function scan() {
scanScheduled = false;
document.querySelectorAll(CARD_SELECTOR).forEach(clickAllow);
}
function scheduleScan() {
if (scanScheduled) {
return;
}
scanScheduled = true;
window.requestAnimationFrame(scan);
}
const observer = new MutationObserver(scheduleScan);
observer.observe(document.documentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['disabled', 'inert', 'class', 'style'],
});
scheduleScan();
})();