Greasy Fork

Greasy Fork is available in English.

Claude.ai Bulk Delete Automation

One‑click wipe for Claude.ai Recents. Press once; script keeps looping across reloads until nothing is left.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Claude.ai Bulk Delete Automation
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  One‑click wipe for Claude.ai Recents. Press once; script keeps looping across reloads until nothing is left.
// @match        https://claude.ai/recents*
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
  'use strict';

  /* ========= CONFIG ========= */
  const CLICK_DELAY  = 1500;  // ms between each UI click
  const RELOAD_DELAY = 5000;  // ms to wait after confirming delete before reload
  const START_DELAY  = 2000;  // ms after page load before auto-resume kicks in
  const BUTTON_LABEL = 'Bulk Delete';
  /* ========================== */

  // Use sessionStorage so the flag clears when the last Claude tab closes
  const storage  = sessionStorage;
  const FLAG_KEY = '__bulkDeleteActive';   // key to persist automation state within the session

  const wait = ms => new Promise(r => setTimeout(r, ms));

  /**
   * Clicks the first <button> that satisfies the predicate, polling until timeout.
   * @returns {boolean} true if clicked; false on timeout.
   */
  async function clickWhenAvailable(predicate, timeout = 10000) {
    const start = performance.now();
    while (performance.now() - start < timeout) {
      const btn = [...document.querySelectorAll('button')].find(predicate);
      if (btn) {
        btn.click();
        return true;
      }
      await wait(250);
    }
    return false;
  }

  /**
   * Runs a single delete cycle. Returns true if it executed (items were present),
   * false if it found nothing to delete (Select button missing) so we can stop.
   */
  async function runOnce(btnEl) {
    if (btnEl) btnEl.textContent = 'Running…';

    // 1) "Select" (first conversation row)
    if (!await clickWhenAvailable(b => b.textContent.trim() === 'Select')) return false;
    await wait(CLICK_DELAY);

    // 2) "Select all"
    if (!await clickWhenAvailable(b => b.textContent.trim() === 'Select all')) return false;
    await wait(CLICK_DELAY);

    // 3) "Delete Selected"
    if (!await clickWhenAvailable(b => /Delete\s+Selected/i.test(b.textContent))) return false;
    await wait(CLICK_DELAY);

    // 4) Modal confirm "Delete"
    if (!await clickWhenAvailable(b => b.dataset.testid === 'delete-modal-confirm')) return false;

    // 5) Wait for backend, then refresh to pick up next batch
    setTimeout(() => location.reload(), RELOAD_DELAY);
    return true;  // a reload is imminent; automation continues on next page load
  }

  /** Inject a floating control button (once) */
  function addControlButton() {
    if (document.getElementById('__bulkDeleteBtn')) return;

    const btn = document.createElement('button');
    btn.id = '__bulkDeleteBtn';
    btn.textContent = BUTTON_LABEL;
    Object.assign(btn.style, {
      position: 'fixed',
      top: '1rem',
      right: '1rem',
      zIndex: 9999,
      background: '#d32f2f',
      color: '#fff',
      border: 'none',
      padding: '0.5rem 1rem',
      borderRadius: '6px',
      fontSize: '14px',
      cursor: 'pointer',
      boxShadow: '0 2px 6px rgba(0,0,0,0.3)'
    });

    btn.addEventListener('click', async () => {
      if (storage.getItem(FLAG_KEY)) return;   // already running
      storage.setItem(FLAG_KEY, '1');
      btn.disabled = true;
      await runOnce(btn);  // may trigger reload
    });

    document.body.appendChild(btn);
  }

  /** Auto-resume if the flag is set (user already started automation earlier) */
  async function autoResume() {
    if (!storage.getItem(FLAG_KEY)) return;            // not active
    const btn = document.getElementById('__bulkDeleteBtn');
    if (btn) {
      btn.disabled = true;
      btn.textContent = 'Running…';
    }

    await wait(START_DELAY);
    const worked = await runOnce(btn);
    if (!worked) {
      // No more items — stop automation
      storage.removeItem(FLAG_KEY);
      if (btn) {
        btn.disabled = false;
        btn.textContent = 'Done';
      }
    }
  }

  window.addEventListener('load', () => {
    addControlButton();
    autoResume();
  });
})();