Merge pull request #347 from BasaiCorp/main

 Major Enhancements: Improved Cursor AI Reset & Automated GitHub + Cursor Registration
This commit is contained in:
Pin Studios 2025-03-21 23:44:59 +08:00 committed by GitHub
commit 8f47801dad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 241 additions and 474 deletions

135
github_cursor_register.py Normal file
View File

@ -0,0 +1,135 @@
import os
import time
import uuid
import json
import random
import string
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
def generate_temp_email():
"""Generates a temporary email and returns the email and inbox ID."""
response = requests.get("https://www.1secmail.com/api/v1/?action=genRandomMailbox&count=1")
email = response.json()[0]
print(f"✅ Generated temp email: {email}")
return email
def extract_inbox(email, retries=5):
"""Extracts the inbox for the temp email with retries."""
domain = email.split('@')[1]
login = email.split('@')[0]
inbox_url = f"https://www.1secmail.com/api/v1/?action=getMessages&login={login}&domain={domain}"
for attempt in range(retries):
time.sleep(10) # Allow email to arrive
messages = requests.get(inbox_url).json()
if messages:
print(f"✅ Inbox found on attempt {attempt + 1}")
return messages[0]['id']
print(f"🔄 Retry {attempt + 1}/{retries}: No email yet...")
return None
def get_verification_link(email, message_id):
"""Retrieves the verification link from the email inbox."""
domain = email.split('@')[1]
login = email.split('@')[0]
msg_url = f"https://www.1secmail.com/api/v1/?action=readMessage&login={login}&domain={domain}&id={message_id}"
message = requests.get(msg_url).json()
for line in message['body'].splitlines():
if "https://github.com/" in line:
print(f"✅ Verification link found: {line}")
return line.strip()
return None
def reset_machine_id():
"""Resets the machine ID to bypass Cursor AI's free trial detection."""
new_id = str(uuid.uuid4())
if os.name == 'nt': # Windows
os.system(f'reg add "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid /d {new_id} /f')
else: # Linux/macOS
os.system(f'echo {new_id} | sudo tee /etc/machine-id')
print(f"✅ Machine ID reset: {new_id}")
def register_github(email):
"""Automates GitHub registration with temp email."""
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
driver.get("https://github.com/join")
# Fill in the registration form
username = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
password = ''.join(random.choices(string.ascii_letters + string.digits, k=15))
driver.find_element(By.ID, "user_login").send_keys(username)
driver.find_element(By.ID, "user_email").send_keys(email)
driver.find_element(By.ID, "user_password").send_keys(password)
driver.find_element(By.ID, "signup_button").click()
time.sleep(5)
driver.quit()
print(f"✅ GitHub account created: {username} | {email}")
return username, password
def register_cursor_with_github(driver):
"""Logs into Cursor AI using GitHub authentication."""
driver.get("https://cursor.sh")
time.sleep(5)
driver.find_element(By.LINK_TEXT, "Sign in with GitHub").click()
time.sleep(5)
print("✅ Registered Cursor with GitHub")
def save_credentials(email, github_username, github_password):
"""Saves the credentials in a log file."""
with open("github_cursor_accounts.txt", "a") as f:
f.write(json.dumps({
"email": email,
"github_username": github_username,
"github_password": github_password,
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}) + "\n")
print("✅ Credentials saved")
def main():
print("\n🚀 Automating GitHub + Cursor AI Registration...\n")
email = generate_temp_email()
github_username, github_password = register_github(email)
inbox_id = extract_inbox(email)
if inbox_id:
verify_link = get_verification_link(email, inbox_id)
if verify_link:
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
driver.get(verify_link)
print("✅ Verified GitHub Email")
driver.quit()
else:
print("❌ Verification link not found")
else:
print("❌ Email verification failed")
# Automate Cursor AI registration with GitHub
options = Options()
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
register_cursor_with_github(driver)
# Reset Machine ID
reset_machine_id()
# Save credentials
save_credentials(email, github_username, github_password)
print("✅ All steps completed!")
if __name__ == '__main__':
main()

View File

@ -2,508 +2,140 @@ import os
import shutil import shutil
import platform import platform
import time import time
import sys
import glob
import json
import uuid import uuid
import random
import string
import re
from datetime import datetime
import subprocess import subprocess
from colorama import Fore, Style, init
from main import translator
from main import EMOJI
# Initialize colorama
init()
# Define emoji and color constants
EMOJI = {
"FILE": "📄",
"BACKUP": "💾",
"SUCCESS": "",
"ERROR": "",
"INFO": "",
"RESET": "🔄",
"MENU": "📋",
"ARROW": "",
"LANG": "🌐",
"UPDATE": "🔄",
"ADMIN": "🔐",
"STOP": "🛑",
"DISCLAIMER": "⚠️",
"WARNING": "⚠️"
}
def display_banner():
"""Displays a stylized banner for the tool."""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['STOP']} {translator.get('totally_reset.title')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
def display_features():
"""Displays the features of the Cursor AI Reset Tool."""
print(f"\n{Fore.CYAN}{EMOJI['MENU']} {translator.get('totally_reset.feature_title')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_1')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_2')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_3')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_4')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_5')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_6')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_7')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_8')} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.feature_9')} {Style.RESET_ALL}\n")
def display_disclaimer():
"""Displays a disclaimer for the user."""
print(f"\n{Fore.RED}{EMOJI['DISCLAIMER']} {translator.get('totally_reset.disclaimer_title')}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_1')} {Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_2')} {Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_3')} {Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_4')} {Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_5')} {Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_6')} {Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.disclaimer_7')} {Style.RESET_ALL} \n")
def get_confirmation():
"""Gets confirmation from the user to proceed."""
while True:
choice = input(f"{Fore.RED}{EMOJI['WARNING']} {translator.get('totally_reset.confirm_title')} (Y/n): ").strip().lower()
if choice == "y" or choice == "":
return True
elif choice == "n":
return False
else:
print(f"{EMOJI['ERROR']} {translator.get('totally_reset.invalid_choice')}")
def remove_dir(path):
"""Removes a directory if it exists and logs the action."""
# Safety check to ensure we're only deleting Cursor-related directories
if not is_cursor_related(path):
print(f"{Fore.RED}{EMOJI['WARNING']} {translator.get('totally_reset.skipped_for_safety', path=path)} {Style.RESET_ALL}")
return
def delete_directory(path):
"""Deletes a directory and all its contents."""
if os.path.exists(path): if os.path.exists(path):
try: try:
shutil.rmtree(path, ignore_errors=True) shutil.rmtree(path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('totally_reset.deleted', path=path)} {Style.RESET_ALL}") print(f"✅ Removed: {path}")
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.error_deleting', path=path, error=str(e))} {Style.RESET_ALL}") print(f"❌ Failed to remove: {path} -> {e}")
else: else:
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.not_found', path=path)} {Style.RESET_ALL}") print(f"🔍 Not found: {path}")
def remove_file(path):
"""Removes a file if it exists and logs the action."""
# Safety check to ensure we're only deleting Cursor-related files
if not is_cursor_related(path):
print(f"{Fore.RED}{EMOJI['WARNING']} {translator.get('totally_reset.skipped_for_safety', path=path)} {Style.RESET_ALL}")
return
def delete_file(path):
"""Deletes a file if it exists."""
if os.path.isfile(path): if os.path.isfile(path):
try: try:
os.remove(path) os.remove(path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('totally_reset.deleted', path=path)} {Style.RESET_ALL}") print(f"✅ Removed file: {path}")
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.error_deleting', path=path, error=str(e))} {Style.RESET_ALL}") print(f"❌ Failed to remove file: {path} -> {e}")
else: else:
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.not_found', path=path)} {Style.RESET_ALL}") print(f"🔍 Not found: {path}")
def is_cursor_related(path): def reset_machine_id():
""" """Resets the machine ID to a new UUID."""
Safety function to verify a path is related to Cursor before deletion. new_id = str(uuid.uuid4())
Returns True if the path appears to be related to Cursor AI. if platform.system() == "Windows":
"""
# Skip .vscode check as it's shared with VS Code
if path.endswith(".vscode"):
return False
# Check if path contains cursor-related terms
cursor_terms = ["cursor", "cursorai", "cursor-electron"]
# Convert path to lowercase for case-insensitive matching
lower_path = path.lower()
# Return True if any cursor term is present in the path
for term in cursor_terms:
if term in lower_path:
return True
# Check specific known Cursor file patterns
cursor_patterns = [
r"\.cursor_.*$",
r"cursor-.*\.json$",
r"cursor_.*\.json$",
r"cursor-machine-id$",
r"trial_info\.json$",
r"license\.json$"
]
for pattern in cursor_patterns:
if re.search(pattern, lower_path):
return True
# If it's a specific file that we know is only for Cursor
if os.path.basename(lower_path) in [
"cursor_trial_data",
"cursor-state.json",
"cursor-machine-id",
"ai-settings.json",
"cursor.desktop"
]:
return True
return False
def find_cursor_license_files(base_path, pattern):
"""Finds files matching a pattern that might contain license information."""
try: try:
matches = [] subprocess.run(
for root, dirnames, filenames in os.walk(base_path): ["reg", "add", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid", "/d", new_id, "/f"],
for filename in filenames: check=True,
# Check if filename matches any pattern before adding to matches stdout=subprocess.PIPE,
if any(p.lower() in filename.lower() for p in pattern): stderr=subprocess.PIPE
full_path = os.path.join(root, filename) )
# Extra safety check to ensure it's cursor-related print(f"✅ MachineGuid reset to: {new_id}")
if is_cursor_related(full_path): except subprocess.CalledProcessError as e:
matches.append(full_path) print(f"❌ Failed to reset MachineGuid: {e}")
return matches elif platform.system() == "Linux":
except Exception as e: machine_id_paths = ["/etc/machine-id", "/var/lib/dbus/machine-id"]
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.error_searching', path=base_path, error=str(e))} {Style.RESET_ALL}") for path in machine_id_paths:
return [] if os.path.exists(path):
def generate_new_machine_id():
"""Generates a new random machine ID."""
return str(uuid.uuid4())
def create_fake_machine_id(path):
"""Creates a new machine ID file with random ID."""
if not is_cursor_related(path):
return
try: try:
new_id = generate_new_machine_id()
directory = os.path.dirname(path)
# Ensure directory exists
if not os.path.exists(directory):
os.makedirs(directory)
with open(path, 'w') as f: with open(path, 'w') as f:
f.write(new_id) f.write(new_id)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('totally_reset.created_machine_id', path=path)} {Style.RESET_ALL}") print(f"✅ Reset machine ID at: {path}")
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.error_creating_machine_id', path=path, error=str(e))} {Style.RESET_ALL}") print(f"❌ Failed to reset machine ID at {path}: {e}")
elif platform.system() == "Darwin": # macOS
def reset_machine_id(system, home): # macOS typically doesn't use a machine-id file like Linux
"""Resets machine ID in all possible locations.""" print(" macOS does not use a machine-id file. Skipping machine ID reset.")
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.resetting_machine_id')} {Style.RESET_ALL}") else:
print("❌ Unsupported operating system for machine ID reset.")
# Common machine ID locations based on OS
if system == "Windows":
machine_id_paths = [
os.path.join(home, "AppData", "Roaming", "Cursor", "cursor-machine-id"),
os.path.join(home, "AppData", "Local", "Cursor", "cursor-machine-id"),
os.path.join(home, "AppData", "Roaming", "cursor-electron", "cursor-machine-id"),
os.path.join(home, "AppData", "Local", "cursor-electron", "cursor-machine-id"),
os.path.join(home, ".cursor-machine-id"),
]
elif system == "Darwin": # macOS
machine_id_paths = [
os.path.join(home, "Library", "Application Support", "Cursor", "cursor-machine-id"),
os.path.join(home, "Library", "Application Support", "cursor-electron", "cursor-machine-id"),
os.path.join(home, ".cursor-machine-id"),
]
elif system == "Linux":
machine_id_paths = [
os.path.join(home, ".config", "Cursor", "cursor-machine-id"),
os.path.join(home, ".config", "cursor-electron", "cursor-machine-id"),
os.path.join(home, ".cursor-machine-id"),
]
# First remove existing machine IDs
for path in machine_id_paths:
remove_file(path)
# Then create new randomized IDs
for path in machine_id_paths:
create_fake_machine_id(path)
# Try to reset system machine ID if possible (with appropriate permissions)
if system == "Windows":
try:
# Windows: Create a temporary VBS script to reset machine GUID
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.note_complete_machine_id_reset_may_require_running_as_administrator')} {Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.windows_machine_id_modification_skipped', error=str(e))} {Style.RESET_ALL}")
elif system == "Linux":
try:
# Linux: Create a random machine-id in /etc/ (needs sudo)
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.note_complete_system_machine_id_reset_may_require_sudo_privileges')} {Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.linux_machine_id_modification_skipped', error=str(e))} {Style.RESET_ALL}")
def create_fake_trial_info(path, system, home):
"""Creates fake trial information to extend trial period."""
if not is_cursor_related(path):
return
try:
# Generate future expiry date (90 days from now)
future_date = (datetime.now().timestamp() + (90 * 24 * 60 * 60)) * 1000 # milliseconds
# Create fake trial info
fake_trial = {
"trialStartTimestamp": datetime.now().timestamp() * 1000,
"trialEndTimestamp": future_date,
"hasUsedTrial": False,
"machineId": generate_new_machine_id()
}
directory = os.path.dirname(path)
# Ensure directory exists
if not os.path.exists(directory):
os.makedirs(directory)
with open(path, 'w') as f:
json.dump(fake_trial, f)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('totally_reset.created_extended_trial_info', path=path)} {Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.error_creating_trial_info', path=path, error=str(e))} {Style.RESET_ALL}")
def reset_cursor(): def reset_cursor():
"""Completely resets Cursor AI by removing all settings, caches, and extensions.""" print("\n🚀 Resetting Cursor AI...\n")
system = platform.system()
home = os.path.expanduser("~")
display_banner() # Platform-specific paths
display_features() paths = []
display_disclaimer() if platform.system() == "Linux":
paths = [
if not get_confirmation(): os.path.expanduser("~/.cursor"),
print(f"\n{Fore.CYAN}{EMOJI['STOP']} {translator.get('totally_reset.reset_cancelled')} {Style.RESET_ALL}") os.path.expanduser("~/.local/share/cursor"),
return os.path.expanduser("~/.config/cursor"),
os.path.expanduser("~/.cache/cursor"),
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.resetting_cursor_ai_editor')} {Style.RESET_ALL}") "/usr/local/bin/cursor",
"/opt/cursor",
# Define paths based on OS "/usr/bin/cursor",
if system == "Windows": os.path.expanduser("~/.cursor/machine-id.db"),
cursor_paths = [ os.path.expanduser("~/.local/share/Cursor"),
os.path.join(home, "AppData", "Roaming", "Cursor"), os.path.expanduser("~/.config/Cursor"),
os.path.join(home, "AppData", "Local", "Cursor"), os.path.expanduser("~/.cache/Cursor")
os.path.join(home, "AppData", "Roaming", "cursor-electron"), ]
os.path.join(home, "AppData", "Local", "cursor-electron"), elif platform.system() == "Darwin": # macOS
os.path.join(home, "AppData", "Local", "CursorAI"), paths = [
os.path.join(home, "AppData", "Roaming", "CursorAI"), os.path.expanduser("~/Library/Application Support/Cursor"),
# os.path.join(home, ".vscode"), # Removed to avoid affecting VS Code os.path.expanduser("~/Library/Caches/Cursor"),
os.path.join(home, "AppData", "Local", "Temp", "Cursor"), # Temporary data "/Applications/Cursor.app",
os.path.join(home, "AppData", "Local", "Temp", "cursor-updater"), os.path.expanduser("~/Library/Preferences/com.cursor.app.plist"),
os.path.join(home, "AppData", "Local", "Programs", "cursor"), ]
elif platform.system() == "Windows":
paths = [
os.path.expanduser("~\\AppData\\Local\\Cursor"),
os.path.expanduser("~\\AppData\\Roaming\\Cursor"),
os.path.expanduser("~\\.cursor"),
os.path.expanduser("~\\.config\\Cursor"),
os.path.expanduser("~\\.cache\\Cursor"),
"C:\\Program Files\\Cursor",
"C:\\Program Files (x86)\\Cursor",
"C:\\Users\\%USERNAME%\\AppData\\Local\\Cursor",
"C:\\Users\\%USERNAME%\\AppData\\Roaming\\Cursor",
] ]
# Additional locations for license/trial files on Windows # Remove directories
license_search_paths = [ for path in paths:
os.path.join(home, "AppData", "Roaming"), delete_directory(path)
os.path.join(home, "AppData", "Local"),
os.path.join(home, "AppData", "LocalLow"), # Remove common files related to Cursor
files = [
os.path.expanduser("~/.cursor/machine-id.db"),
os.path.expanduser("~/.local/share/cursor.db"),
os.path.expanduser("~/.config/cursor/preferences.json"),
os.path.expanduser("~/.cache/cursor.log"),
] ]
# Registry instructions for Windows for file in files:
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.windows_registry_instructions')} {Style.RESET_ALL}") delete_file(file)
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.windows_registry_instructions_2')} {Style.RESET_ALL}")
elif system == "Darwin": # macOS # Extra cleanup (wildcard search)
cursor_paths = [ print("\n🔍 Deep scanning for hidden Cursor files...")
os.path.join(home, "Library", "Application Support", "Cursor"), base_dirs = ["/tmp", "/var/tmp", os.path.expanduser("~")] # Linux and macOS
os.path.join(home, "Library", "Application Support", "cursor-electron"), if platform.system() == "Windows":
os.path.join(home, "Library", "Caches", "Cursor"), base_dirs = ["C:\\Temp", "C:\\Windows\\Temp", os.path.expanduser("~")] # Windows
os.path.join(home, "Library", "Caches", "cursor-electron"),
os.path.join(home, "Library", "Preferences", "Cursor"),
os.path.join(home, "Library", "Preferences", "cursor-electron"),
os.path.join(home, "Library", "Saved Application State", "com.cursor.Cursor.savedState"),
os.path.join(home, "Library", "HTTPStorages", "com.cursor.Cursor"),
os.path.join(home, "Library", "WebKit", "com.cursor.Cursor"),
# os.path.join(home, ".vscode"), # Removed to avoid affecting VS Code
"/Applications/Cursor.app", # Main application location
]
# Additional locations for license/trial files on macOS for base in base_dirs:
license_search_paths = [ for root, dirs, files in os.walk(base):
os.path.join(home, "Library", "Application Support"), for dir in dirs:
os.path.join(home, "Library", "Preferences"), if "cursor" in dir.lower():
os.path.join(home, "Library", "Caches"), delete_directory(os.path.join(root, dir))
] for file in files:
if "cursor" in file.lower():
delete_file(os.path.join(root, file))
elif system == "Linux": # Reset machine ID
cursor_paths = [ reset_machine_id()
os.path.join(home, ".config", "Cursor"),
os.path.join(home, ".config", "cursor-electron"),
os.path.join(home, ".cache", "Cursor"),
os.path.join(home, ".cache", "cursor-electron"),
os.path.join(home, ".local", "share", "Cursor"),
os.path.join(home, ".local", "share", "cursor-electron"),
# os.path.join(home, ".vscode"), # Removed to avoid affecting VS Code
os.path.join(home, ".local", "share", "applications", "cursor.desktop"),
os.path.join("/usr", "share", "applications", "cursor.desktop"),
os.path.join("/opt", "Cursor"),
]
# Additional locations for license/trial files on Linux print("\n✅ Cursor AI has been completely reset!")
license_search_paths = [
os.path.join(home, ".config"),
os.path.join(home, ".local", "share"),
os.path.join(home, ".cache"),
]
else: def main():
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.unsupported_os')} {Style.RESET_ALL}") start_time = time.time()
return
# Remove main Cursor directories
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.removing_main_cursor_directories_and_files')} {Style.RESET_ALL}")
for path in cursor_paths:
remove_dir(path)
# Reset machine identifiers (this creates new ones)
reset_machine_id(system, home)
# Known trial/license file patterns
file_patterns = [
".cursor_trial_data",
"trial_info.json",
"license.json",
"cursor-license",
"cursor_license",
"cursor-auth",
"cursor_auth",
"cursor_subscription",
"cursor-subscription",
"cursor-state",
"cursorstate",
"cursorsettings",
"cursor-settings",
"ai-settings.json",
"cursor-machine-id",
"cursor_machine_id",
"cursor-storage"
]
# Direct known trial file paths
cursor_trial_files = [
os.path.join(home, ".cursor_trial_data"),
os.path.join(home, ".cursor_license"),
os.path.join(home, ".cursor-machine-id"),
os.path.join(home, ".cursor-state.json"),
]
# OS-specific known trial/license files
if system == "Windows":
cursor_trial_files.extend([
os.path.join(home, "AppData", "Local", "Cursor", "trial_info.json"),
os.path.join(home, "AppData", "Local", "Cursor", "license.json"),
os.path.join(home, "AppData", "Roaming", "Cursor", "trial_info.json"),
os.path.join(home, "AppData", "Roaming", "Cursor", "license.json"),
os.path.join(home, "AppData", "Roaming", "Cursor", "cursor-machine-id"),
os.path.join(home, "AppData", "Local", "Cursor", "cursor-machine-id"),
os.path.join(home, "AppData", "Local", "Cursor", "ai-settings.json"),
os.path.join(home, "AppData", "Roaming", "Cursor", "ai-settings.json"),
])
elif system == "Darwin": # macOS
cursor_trial_files.extend([
os.path.join(home, "Library", "Application Support", "Cursor", "trial_info.json"),
os.path.join(home, "Library", "Application Support", "Cursor", "license.json"),
os.path.join(home, "Library", "Preferences", "Cursor", "trial_info.json"),
os.path.join(home, "Library", "Preferences", "Cursor", "license.json"),
os.path.join(home, "Library", "Application Support", "Cursor", "cursor-machine-id"),
os.path.join(home, "Library", "Application Support", "Cursor", "ai-settings.json"),
])
elif system == "Linux":
cursor_trial_files.extend([
os.path.join(home, ".config", "Cursor", "trial_info.json"),
os.path.join(home, ".config", "Cursor", "license.json"),
os.path.join(home, ".local", "share", "Cursor", "trial_info.json"),
os.path.join(home, ".local", "share", "Cursor", "license.json"),
os.path.join(home, ".config", "Cursor", "cursor-machine-id"),
os.path.join(home, ".config", "Cursor", "ai-settings.json"),
])
# Remove known trial/license files
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.removing_known')} {Style.RESET_ALL}")
for path in cursor_trial_files:
remove_file(path)
# Deep search for additional trial/license files
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.performing_deep_scan')} {Style.RESET_ALL}")
all_found_files = []
for base_path in license_search_paths:
if os.path.exists(base_path):
found_files = find_cursor_license_files(base_path, file_patterns)
all_found_files.extend(found_files)
if all_found_files:
print(f"\n🔎 {translator.get('totally_reset.found_additional_potential_license_trial_files', count=len(all_found_files))}\n")
for file_path in all_found_files:
remove_file(file_path)
else:
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.no_additional_license_trial_files_found_in_deep_scan')} {Style.RESET_ALL}")
# Check for and remove localStorage files that might contain settings
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.checking_for_electron_localstorage_files')} {Style.RESET_ALL}")
if system == "Windows":
local_storage_paths = glob.glob(os.path.join(home, "AppData", "Roaming", "*cursor*", "Local Storage", "leveldb", "*"))
local_storage_paths += glob.glob(os.path.join(home, "AppData", "Local", "*cursor*", "Local Storage", "leveldb", "*"))
elif system == "Darwin":
local_storage_paths = glob.glob(os.path.join(home, "Library", "Application Support", "*cursor*", "Local Storage", "leveldb", "*"))
elif system == "Linux":
local_storage_paths = glob.glob(os.path.join(home, ".config", "*cursor*", "Local Storage", "leveldb", "*"))
for path in local_storage_paths:
if is_cursor_related(path):
remove_file(path)
# Create new trial files with extended expiration
print(f"\n{Fore.CYAN}{EMOJI['RESET']} {translator.get('totally_reset.creating_new_trial_information_with_extended_period')} {Style.RESET_ALL}")
if system == "Windows":
create_fake_trial_info(os.path.join(home, "AppData", "Local", "Cursor", "trial_info.json"), system, home)
create_fake_trial_info(os.path.join(home, "AppData", "Roaming", "Cursor", "trial_info.json"), system, home)
elif system == "Darwin":
create_fake_trial_info(os.path.join(home, "Library", "Application Support", "Cursor", "trial_info.json"), system, home)
elif system == "Linux":
create_fake_trial_info(os.path.join(home, ".config", "Cursor", "trial_info.json"), system, home)
print(f"\n{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('totally_reset.reset_log_1')}")
print(f" {translator.get('totally_reset.reset_log_2')}")
print(f" {translator.get('totally_reset.reset_log_3')}")
print(f"\n{Fore.GREEN}{EMOJI['INFO']} {translator.get('totally_reset.reset_log_4')} {Style.RESET_ALL}")
print(f" {translator.get('totally_reset.reset_log_5')} {Style.RESET_ALL}")
print(f" {translator.get('totally_reset.reset_log_6')} {Style.RESET_ALL}")
print(f" {translator.get('totally_reset.reset_log_7')} {Style.RESET_ALL}")
print(f" {translator.get('totally_reset.reset_log_8')} {Style.RESET_ALL}")
print(f"\n{Fore.RED}{EMOJI['INFO']} {translator.get('totally_reset.reset_log_9')} {Style.RESET_ALL}")
if __name__ == "__main__":
try:
reset_cursor() reset_cursor()
except KeyboardInterrupt: end_time = time.time()
print(f"\n\n{Fore.RED}{EMOJI['STOP']} {translator.get('totally_reset.keyboard_interrupt')} {Style.RESET_ALL}") print(f"\n⏱️ Completed in {end_time - start_time:.2f} seconds.")
sys.exit(1)
except Exception as e:
print(f"\n{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.unexpected_error', error=str(e))}{Style.RESET_ALL}")
print(f" {translator.get('totally_reset.report_issue')}")
sys.exit(1)
def run(translator=None): if __name__ == '__main__':
"""Entry point for the totally reset cursor functionality when called from the main menu.""" main()
try:
reset_cursor()
input(f"\n\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.return_to_main_menu')} {Style.RESET_ALL}")
except KeyboardInterrupt:
print(f"\n\n{Fore.RED}{EMOJI['STOP']} {translator.get('totally_reset.process_interrupted')} {Style.RESET_ALL}")
except Exception as e:
print(f"\n{Fore.RED}{EMOJI['ERROR']} {translator.get('totally_reset.unexpected_error', error=str(e))}{Style.RESET_ALL}")
print(f" {translator.get('totally_reset.report_issue')}")
input(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('totally_reset.press_enter_to_return_to_main_menu')} {Style.RESET_ALL}")