您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
One‑click wipe for Claude.ai Recents. Press once; script keeps looping across reloads until nothing is left.
// ==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(); }); })();