Last active
April 17, 2025 03:41
-
-
Save James-Lam/590aebd241a61d96254ef9b4bd1d9a02 to your computer and use it in GitHub Desktop.
Automatically remove members from Cursor team settings page whose email isn't in the allowed list.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Auto Remove Member (Cursor.com) | |
// @namespace http://tampermonkey.net/ | |
// @version 0.6 | |
// @description Automatically remove members from Cursor team settings page whose email isn't in the allowed list. | |
// @author James Lam | |
// @match https://www.cursor.com/settings | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
// Only keep members with emails in this list | |
const ALLOWED_EMAILS = [ | |
"[email protected]", | |
"[email protected]", | |
"[email protected]", | |
"[email protected]", | |
// Add more approved emails here | |
]; | |
const AUTO_REFRESH_INTERVAL = 30 * 1000; // 30 seconds | |
// Helper function to pause execution | |
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | |
// Wait for an element to appear in the DOM | |
async function waitForElement(selectorFn, timeout = 10000) { | |
const start = Date.now(); | |
while (Date.now() - start < timeout) { | |
const el = selectorFn(); | |
if (el) return el; | |
await sleep(200); | |
} | |
return null; | |
} | |
async function removeMember() { | |
// Select all member rows | |
const rows = document.querySelectorAll("div.cursor-pointer.flex-row.gap-4"); | |
for (const row of rows) { | |
// Find the email element - email is in a span inside the w-[240px] element | |
const emailContainer = row.querySelector("span.w-\\[240px\\]"); | |
const email = emailContainer?.querySelector("span")?.textContent?.trim(); | |
// Get name for logging purposes | |
const nameEl = row.querySelector("span.truncate[title]"); | |
const name = nameEl?.getAttribute("title")?.trim() || "Unknown"; | |
// Check if email is NOT in the allowed list | |
if (email && !ALLOWED_EMAILS.includes(email)) { | |
console.log( | |
`[Cursor Auto Remove] Found unauthorized email: "${email}" for user: "${name}"` | |
); | |
const moreBtn = row.querySelector("button"); | |
if (!moreBtn) { | |
console.warn('No "..." button found for', email); | |
continue; | |
} | |
moreBtn.click(); | |
console.log('[Cursor Auto Remove] Clicked "..." button'); | |
const removeBtn = await waitForElement(() => { | |
return Array.from(document.querySelectorAll("#dropdown button")).find( | |
(btn) => | |
btn.textContent.trim() === "Remove" && | |
btn.classList.contains("text-red-600") | |
); | |
}); | |
if (!removeBtn) { | |
console.warn('[Cursor Auto Remove] Dropdown "Remove" not found'); | |
continue; | |
} | |
removeBtn.click(); | |
console.log('[Cursor Auto Remove] Clicked dropdown "Remove"'); | |
const confirmRemoveBtn = await waitForElement(() => { | |
return Array.from( | |
document.querySelectorAll( | |
"span.cursor-pointer.text-red-600.underline" | |
) | |
).find((el) => el.textContent.trim().toLowerCase() === "remove"); | |
}); | |
if (!confirmRemoveBtn) { | |
console.warn('[Cursor Auto Remove] Confirmation "Remove" not found'); | |
continue; | |
} | |
confirmRemoveBtn.click(); | |
// Get current date/time for logging | |
const now = new Date().toLocaleString(); | |
console.log( | |
`[Cursor Auto Remove] ✅ Successfully removed "${name}" with email "${email}" at ${now}` | |
); | |
// Wait a bit before continuing to the next member | |
await sleep(1000); | |
} | |
} | |
} | |
// Initialize and run the script when member rows are loaded | |
const init = setInterval(() => { | |
const rows = document.querySelectorAll("div.cursor-pointer.flex-row.gap-4"); | |
if (rows.length > 0) { | |
clearInterval(init); | |
removeMember(); | |
} | |
}, 1000); | |
// 🔄 Auto-refresh periodically | |
setTimeout(() => { | |
console.log( | |
`[Cursor Auto Remove] Refreshing page to check for new members...` | |
); | |
location.reload(); | |
}, AUTO_REFRESH_INTERVAL); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment