ChatGPT Auto-Confirm Delete

Automatically clicks the delete confirmation button when it appears on chatgpt.com

// ==UserScript==
// @name         ChatGPT Auto-Confirm Delete
// @namespace    aravvn.tools
// @version      1.0.0
// @description  Automatically clicks the delete confirmation button when it appears on chatgpt.com
// @author       Aravvn
// @license      MIT
// @match        https://chatgpt.com/*
// @match        https://*.chatgpt.com/*
// @run-at       document-idle
// @noframes
// @grant        none
// ==/UserScript==

(() => {
  'use strict';

  const SELECTOR = '[data-testid="delete-conversation-confirm-button"]';

  function clickIfReady(btn) {
    if (!btn || btn.dataset._autoClicked === '1') return;
    const disabled = btn.disabled || btn.getAttribute('aria-disabled') === 'true';
    if (disabled) return;

    const rect = btn.getBoundingClientRect?.();
    const visible = rect && rect.width > 0 && rect.height > 0;

    if (visible) {
      btn.dataset._autoClicked = '1';
      btn.click();
    }
  }

  function scan() {
    document.querySelectorAll(SELECTOR).forEach(clickIfReady);
  }

  let rafId = 0;
  const scheduleScan = () => {
    if (rafId) return;
    rafId = requestAnimationFrame(() => {
      rafId = 0;
      scan();
    });
  };

  const obs = new MutationObserver(scheduleScan);
  const start = () => {
    if (!document.body) {
      // If body isn't ready yet, try again soon.
      setTimeout(start, 50);
      return;
    }
    obs.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-testid', 'aria-disabled', 'disabled'] });
    scan();
  };

  const poller = setInterval(scan, 1000);

  window.addEventListener('beforeunload', () => {
    obs.disconnect();
    clearInterval(poller);
    if (rafId) cancelAnimationFrame(rafId);
  });

  start();
})();