diff --git a/scripts/cursor_id_modifier.pot b/scripts/cursor_id_modifier.pot new file mode 100644 index 0000000..54f4417 --- /dev/null +++ b/scripts/cursor_id_modifier.pot @@ -0,0 +1,318 @@ +msgid "" +msgstr "" +"Project-Id-Version: cursor_id_modifier\n" +"POT-Creation-Date: 2025-04-25 12:00+0000\n" +"PO-Revision-Date: 2025-04-25 12:00+0000\n" +"Language-Team: None\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Error: No translation file found for domain 'cursor_id_modifier' in {}/zh_CN/LC_MESSAGES/" +msgstr "" + +msgid "========== Cursor ID modification tool log start {} ==========" +msgstr "" + +msgid "[INFO] {} {}" +msgstr "" + +msgid "[WARN] {} {}" +msgstr "" + +msgid "[ERROR] {} {}" +msgstr "" + +msgid "[DEBUG] {} {}" +msgstr "" + +msgid "[CMD] {} Executing command: {}" +msgstr "" + +msgid "[CMD] {}:" +msgstr "" + +msgid "Unable to get username" +msgstr "" + +msgid "Finding Cursor installation path..." +msgstr "" + +msgid "Found Cursor installation path: {}" +msgstr "" + +msgid "Found Cursor via which: {}" +msgstr "" + +msgid "Cursor executable not found, will try using config directory" +msgstr "" + +msgid "Found Cursor via search: {}" +msgstr "" + +msgid "Finding Cursor resource directory..." +msgstr "" + +msgid "Found Cursor resource directory: {}" +msgstr "" + +msgid "Found resource directory via binary path: {}" +msgstr "" + +msgid "Cursor resource directory not found" +msgstr "" + +msgid "Please run this script with sudo" +msgstr "" + +msgid "Example: sudo {}" +msgstr "" + +msgid "Checking Cursor processes..." +msgstr "" + +msgid "Getting process details for {}:" +msgstr "" + +msgid "No running Cursor processes found" +msgstr "" + +msgid "Found running Cursor processes" +msgstr "" + +msgid "Attempting to terminate Cursor processes..." +msgstr "" + +msgid "Attempting to forcefully terminate processes..." +msgstr "" + +msgid "Waiting for processes to terminate, attempt {}/{}..." +msgstr "" + +msgid "Cursor processes successfully terminated" +msgstr "" + +msgid "Unable to terminate Cursor processes after {} attempts" +msgstr "" + +msgid "Please manually terminate the processes and try again" +msgstr "" + +msgid "Configuration file does not exist, skipping backup" +msgstr "" + +msgid "Configuration backed up to: {}" +msgstr "" + +msgid "Backup failed" +msgstr "" + +msgid "File does not exist: {}" +msgstr "" + +msgid "Unable to modify file permissions: {}" +msgstr "" + +msgid "Generated temporary file is empty" +msgstr "" + +msgid "Unable to write to file: {}" +msgstr "" + +msgid "Machine code reset options" +msgstr "" + +msgid "Do you need to reset the machine code? (Usually, modifying JS files is sufficient):" +msgstr "" + +msgid "Don't reset - only modify JS files" +msgstr "" + +msgid "Reset - modify both config file and machine code" +msgstr "" + +msgid "[INPUT_DEBUG] Machine code reset option selected: {}" +msgstr "" + +msgid "You chose to reset the machine code" +msgstr "" + +msgid "Found existing configuration file: {}" +msgstr "" + +msgid "Setting new device and machine IDs..." +msgstr "" + +msgid "New device ID: {}" +msgstr "" + +msgid "New machine ID: {}" +msgstr "" + +msgid "Configuration file modified successfully" +msgstr "" + +msgid "Configuration file modification failed" +msgstr "" + +msgid "Configuration file not found, this is normal, skipping ID modification" +msgstr "" + +msgid "You chose not to reset the machine code, will only modify JS files" +msgstr "" + +msgid "Configuration processing completed" +msgstr "" + +msgid "Finding Cursor's JS files..." +msgstr "" + +msgid "Searching for JS files in resource directory: {}" +msgstr "" + +msgid "Found JS file: {}" +msgstr "" + +msgid "No JS files found in resource directory, trying other directories..." +msgstr "" + +msgid "Searching directory: {}" +msgstr "" + +msgid "No modifiable JS files found" +msgstr "" + +msgid "Found {} JS files to modify" +msgstr "" + +msgid "Starting to modify Cursor's JS files..." +msgstr "" + +msgid "Unable to find modifiable JS files" +msgstr "" + +msgid "Processing file: {}" +msgstr "" + +msgid "Unable to create backup for file: {}" +msgstr "" + +msgid "Found x-cursor-checksum setting code" +msgstr "" + +msgid "Successfully modified x-cursor-checksum setting code" +msgstr "" + +msgid "Failed to modify x-cursor-checksum setting code" +msgstr "" + +msgid "Found IOPlatformUUID keyword" +msgstr "" + +msgid "Successfully injected randomUUID call into a$ function" +msgstr "" + +msgid "Failed to modify a$ function" +msgstr "" + +msgid "Successfully injected randomUUID call into v5 function" +msgstr "" + +msgid "Failed to modify v5 function" +msgstr "" + +msgid "Completed universal modification" +msgstr "" + +msgid "File already contains custom injection code, skipping modification" +msgstr "" + +msgid "Completed most universal injection" +msgstr "" + +msgid "File has already been modified, skipping modification" +msgstr "" + +msgid "Failed to modify any JS files" +msgstr "" + +msgid "Successfully modified {} JS files" +msgstr "" + +msgid "Disabling Cursor auto-update..." +msgstr "" + +msgid "Found update configuration file: {}" +msgstr "" + +msgid "Disabled update configuration file: {}" +msgstr "" + +msgid "Found updater: {}" +msgstr "" + +msgid "Disabled updater: {}" +msgstr "" + +msgid "No update configuration files or updaters found" +msgstr "" + +msgid "Successfully disabled auto-update" +msgstr "" + +msgid "You selected: {}" +msgstr "" + +msgid "This script only supports Linux systems" +msgstr "" + +msgid "Script started..." +msgstr "" + +msgid "System information: {}" +msgstr "" + +msgid "Current user: {}" +msgstr "" + +msgid "System version information" +msgstr "" + +msgid "Cursor Linux startup tool" +msgstr "" + +msgid "Important notice" +msgstr "" + +msgid "This tool prioritizes modifying JS files, which is safer and more reliable" +msgstr "" + +msgid "Modifying Cursor JS files..." +msgstr "" + +msgid "JS files modified successfully!" +msgstr "" + +msgid "JS file modification failed, but configuration file modification may have succeeded" +msgstr "" + +msgid "If Cursor still indicates the device is disabled after restarting, please rerun this script" +msgstr "" + +msgid "Please restart Cursor to apply the new configuration" +msgstr "" + +msgid "Follow the WeChat public account [Pancake AI] to discuss more Cursor tips and AI knowledge (script is free, join the group via the public account for more tips and experts)" +msgstr "" + +msgid "Script execution completed" +msgstr "" + +msgid "========== Cursor ID modification tool log end {} ==========" +msgstr "" + +msgid "Detailed log saved to: {}" +msgstr "" + +msgid "If you encounter issues, please provide this log file to the developer for troubleshooting" +msgstr "" diff --git a/scripts/cursor_id_modifier.py b/scripts/cursor_id_modifier.py new file mode 100644 index 0000000..bf51be2 --- /dev/null +++ b/scripts/cursor_id_modifier.py @@ -0,0 +1,1021 @@ +# -*- coding: utf-8 -*- +""" +AppImage instructions: +mkdir -p ~/Downloads/Cursor +cd ~/Downloads/Cursor +cd Cursor && ./Cursor-0.49.5-x86_64.AppImage --appimage-extract +mkdir -p ~/.local +rsync -rt ~/Downloads/Cursor/squashfs-root/usr/ ~/.local +# ^ copy the subfolders not usr itself, so the resulting executable should be ~/.local/bin/cursor +""" +import subprocess +import os + +SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__)) +# repo_dir = os.path.dirname(SCRIPTS_DIR) +repo_dir = SCRIPTS_DIR +locales_dir = os.path.join(repo_dir, 'locales') +t_domain = "cursor_id_modifier" + +def compile_messages(): + global _ + languages = ['en_US', 'zh_CN'] + for lang in languages: + lang_dir = os.path.join(locales_dir, lang, 'LC_MESSAGES') + if os.path.isdir(lang_dir): + # Change the directory to the LC_MESSAGES folder + os.chdir(lang_dir) + # Run msgfmt command + out_name = 'cursor_id_modifier.mo' + subprocess.run(['msgfmt', '-o', out_name, 'cursor_id_modifier.po'], check=True) + print(os.path.abspath(out_name)) + else: + print(f"Directory not found: {lang_dir}") + +import sys +import subprocess +import datetime +import tempfile +import shutil +import uuid +import hashlib +import re +import getpass +import time +import select +import tty +import termios +import signal +import json +from pathlib import Path +import glob +import pwd + +import gettext + +# 设置语言环境 +# Set language environment + +# lang = 'zh' if '--en' not in sys.argv else 'en' +lang = 'en' + +assert os.path.isdir(locales_dir) +# gettext.bindtextdomain(t_domain, localedir=locales_dir) +if lang == 'zh': + translation = gettext.translation( + t_domain, + localedir=locales_dir, + languages=['en_US', 'zh_CN'], + ) +else: + translation = gettext.NullTranslations() +translation.install() +_ = translation.gettext + +# 设置错误处理 +# Set error handling +def set_error_handling(): + global _ + # 在 Python 中,我们使用 try/except 来处理错误,而不是 bash 的 set -e + # In Python, we use try/except to handle errors instead of bash's set -e + pass + +set_error_handling() + +# 定义日志文件路径 +# Define log file path +LOG_FILE = "/tmp/cursor_linux_id_modifier.log" + +# 初始化日志文件 +# Initialize log file +def initialize_log(): + with open(LOG_FILE, 'w') as f: + f.write(_("========== Cursor ID modification tool log start {} ==========").format(datetime.datetime.now()) + "\n") + os.chmod(LOG_FILE, 0o644) + +# 颜色定义 +# Color definitions +RED = '\033[0;31m' +GREEN = '\033[0;32m' +YELLOW = '\033[1;33m' +BLUE = '\033[0;34m' +NC = '\033[0m' # No Color + +# 日志函数 - 同时输出到终端和日志文件 +# Log functions - output to terminal and log file simultaneously +def log_info(message): + global _ + print(f"{GREEN}[INFO]{NC} {_(message)}") + with open(LOG_FILE, 'a') as f: + f.write(_("[INFO] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n") + +def log_warn(message): + global _ + print(f"{YELLOW}[WARN]{NC} {_(message)}") + with open(LOG_FILE, 'a') as f: + f.write(_("[WARN] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n") + +def log_error(message): + global _ + print(f"{RED}[ERROR]{NC} {_(message)}") + with open(LOG_FILE, 'a') as f: + f.write(_("[ERROR] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n") + +def log_debug(message): + global _ + print(f"{BLUE}[DEBUG]{NC} {_(message)}") + with open(LOG_FILE, 'a') as f: + f.write(_("[DEBUG] {} {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _(message)) + "\n") + +# 记录命令输出到日志文件 +# Log command output to log file +def log_cmd_output(cmd, msg): + global _ + with open(LOG_FILE, 'a') as f: + f.write(_("[CMD] {} Executing command: {}").format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), cmd) + "\n") + f.write(_("[CMD] {}:").format(_(msg)) + "\n") + process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) + with open(LOG_FILE, 'a') as f: + for line in process.stdout: + print(line, end='') + f.write(line) + process.wait() + with open(LOG_FILE, 'a') as f: + f.write("\n") + +# 获取当前用户 +# Get current user +def get_current_user(): + global _ + if os.geteuid() == 0: + return os.environ.get('SUDO_USER', '') + return getpass.getuser() + +CURRENT_USER = get_current_user() +if not CURRENT_USER: + log_error(_("Unable to get username")) + sys.exit(1) + +# 定义Linux下的Cursor路径 +# Define Cursor paths on Linux +CURSOR_CONFIG_DIR = os.path.expanduser("~/.config/Cursor") +STORAGE_FILE = os.path.join(CURSOR_CONFIG_DIR, "User/globalStorage/storage.json") +BACKUP_DIR = os.path.join(CURSOR_CONFIG_DIR, "User/globalStorage/backups") + +# 可能的Cursor二进制路径 +# Possible Cursor binary paths +CURSOR_BIN_PATHS = [ + "/usr/bin/cursor", + "/usr/local/bin/cursor", + os.path.expanduser("~/.local/bin/cursor"), + "/opt/cursor/cursor", + "/snap/bin/cursor", +] + +# 找到Cursor安装路径 +# Find Cursor installation path +def find_cursor_path(): + global _ + log_info(_("Finding Cursor installation path...")) + + for path in CURSOR_BIN_PATHS: + if os.path.isfile(path): + log_info(_("Found Cursor installation path: {}").format(path)) + os.environ['CURSOR_PATH'] = path + return True + + # 尝试通过which命令定位 + # Try locating via which command + try: + result = subprocess.run(['which', 'cursor'], capture_output=True, text=True) + if result.returncode == 0: + os.environ['CURSOR_PATH'] = result.stdout.strip() + log_info(_("Found Cursor via which: {}").format(os.environ['CURSOR_PATH'])) + return True + except subprocess.CalledProcessError: + pass + + # 尝试查找可能的安装路径 + # Try finding possible installation paths + search_dirs = ['/usr', '/opt', os.path.expanduser('~/.local')] + for dir in search_dirs: + try: + for root, _1, files in os.walk(dir): + if 'cursor' in files: + path = os.path.join(root, 'cursor') + if os.access(path, os.X_OK): + os.environ['CURSOR_PATH'] = path + log_info(_("Found Cursor via search: {}").format(os.environ['CURSOR_PATH'])) + return True + except PermissionError: + continue + log_warn(_("Cursor executable not found, will try using config directory")) + return False + +# 查找并定位Cursor资源文件目录 +# Find and locate Cursor resource directory +def find_cursor_resources(): + global _ + log_info(_("Finding Cursor resource directory...")) + + # 可能的资源目录路径 + # Possible resource directory paths + resource_paths = [ + "/usr/lib/cursor", + "/usr/share/cursor", + "/opt/cursor", + os.path.expanduser("~/.local/share/cursor"), + ] + + for path in resource_paths: + if os.path.isdir(path): + log_info(_("Found Cursor resource directory: {}").format(path)) + os.environ['CURSOR_RESOURCES'] = path + return True + + # 如果有CURSOR_PATH,尝试从它推断 + # If CURSOR_PATH exists, try to infer from it + if os.environ.get('CURSOR_PATH'): + base_dir = os.path.dirname(os.environ['CURSOR_PATH']) + resource_dir = os.path.join(base_dir, 'resources') + if os.path.isdir(resource_dir): + os.environ['CURSOR_RESOURCES'] = resource_dir + log_info(_("Found resource directory via binary path: {}").format(os.environ['CURSOR_RESOURCES'])) + return True + + log_warn(_("Cursor resource directory not found")) + return False + +# 检查权限 +# Check permissions +def check_permissions(): + global _ + if os.geteuid() != 0: + log_error(_("Please run this script with sudo")) + print(_("Example: sudo {}").format(sys.argv[0])) + sys.exit(1) + +# 检查并关闭 Cursor 进程 +# Check and kill Cursor processes +def check_and_kill_cursor(): + global _ + log_info(_("Checking Cursor processes...")) + + attempt = 1 + max_attempts = 5 + + # 函数:获取进程详细信息 + # Function: Get process details + def get_process_details(process_name): + log_debug(_("Getting process details for {}:").format(process_name)) + try: + result = subprocess.run( + 'ps aux | grep -i "cursor" | grep -v grep | grep -v "cursor_id_modifier.py"', + shell=True, capture_output=True, text=True + ) + print(result.stdout) + except subprocess.CalledProcessError: + pass + + while attempt <= max_attempts: + # 使用更精确的匹配来获取 Cursor 进程,排除当前脚本和grep进程 + # Use more precise matching to get Cursor processes, excluding current script and grep + try: + result = subprocess.run( + 'ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_id_modifier.py" | awk \'{print $2}\'', + shell=True, capture_output=True, text=True + ) + CURSOR_PIDS = result.stdout.strip().split('\n') + CURSOR_PIDS = [pid for pid in CURSOR_PIDS if pid] + except subprocess.CalledProcessError: + CURSOR_PIDS = [] + + if not CURSOR_PIDS: + log_info(_("No running Cursor processes found")) + return True + + log_warn(_("Found running Cursor processes")) + get_process_details("cursor") + + log_warn(_("Attempting to terminate Cursor processes...")) + + for pid in CURSOR_PIDS: + try: + if attempt == max_attempts: + log_warn(_("Attempting to forcefully terminate processes...")) + os.kill(int(pid), signal.SIGKILL) + else: + os.kill(int(pid), signal.SIGTERM) + except (OSError, ValueError): + continue + + time.sleep(1) + + # 再次检查进程是否还在运行 + # Check again if processes are still running + try: + result = subprocess.run( + 'ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_id_modifier.py"', + shell=True, capture_output=True, text=True + ) + if not result.stdout.strip(): + log_info(_("Cursor processes successfully terminated")) + return True + except subprocess.CalledProcessError: + log_info(_("Cursor processes successfully terminated")) + return True + + log_warn(_("Waiting for processes to terminate, attempt {}/{}...").format(attempt, max_attempts)) + attempt += 1 + + log_error(_("Unable to terminate Cursor processes after {} attempts").format(max_attempts)) + get_process_details("cursor") + log_error(_("Please manually terminate the processes and try again")) + sys.exit(1) + +# 备份配置文件 +# Backup configuration file +def backup_config(): + global _ + if not os.path.isfile(STORAGE_FILE): + log_warn(_("Configuration file does not exist, skipping backup")) + return True + + os.makedirs(BACKUP_DIR, exist_ok=True) + backup_file = os.path.join(BACKUP_DIR, "storage.json.backup_{}".format(datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))) + + try: + shutil.copy(STORAGE_FILE, backup_file) + os.chmod(backup_file, 0o644) + os.chown(backup_file, pwd.getpwnam(CURRENT_USER).pw_uid, -1) + log_info(_("Configuration backed up to: {}").format(backup_file)) + except (OSError, shutil.Error): + log_error(_("Backup failed")) + sys.exit(1) + +# 生成随机 ID +# Generate random ID +def generate_random_id(): + global _ + # 生成32字节(64个十六进制字符)的随机数 + # Generate 32 bytes (64 hexadecimal characters) of random data + return hashlib.sha256(os.urandom(32)).hexdigest() + +# 生成随机 UUID +# Generate random UUID +def generate_uuid(): + global _ + # 在Linux上使用uuid模块生成UUID + # Use uuid module to generate UUID on Linux + try: + return str(uuid.uuid1()).lower() + except Exception: + # 备选方案:生成类似UUID的字符串 + # Fallback: Generate UUID-like string + rand_bytes = os.urandom(16) + rand_hex = rand_bytes.hex() + return f"{rand_hex[:8]}-{rand_hex[8:12]}-{rand_hex[12:16]}-{rand_hex[16:20]}-{rand_hex[20:]}" + +# 修改现有文件 +# Modify or add to configuration file +def modify_or_add_config(key, value, file): + global _ + if not os.path.isfile(file): + log_error(_("File does not exist: {}").format(file)) + return False + + # 确保文件可写 + # Ensure file is writable + try: + os.chmod(file, 0o644) + except OSError: + log_error(_("Unable to modify file permissions: {}").format(file)) + return False + + # 创建临时文件 + # Create temporary file + with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file: + temp_path = temp_file.name + + # 读取原始文件 + # Read original file + with open(file, 'r') as f: + content = f.read() + + # 检查key是否存在 + # Check if key exists + if f'"{key}":' in content: + # key存在,执行替换 + # Key exists, perform replacement + pattern = f'"{key}":\\s*"[^"]*"' + replacement = f'"{key}": "{value}"' + new_content = re.sub(pattern, replacement, content) + else: + # key不存在,添加新的key-value对 + # Key does not exist, add new key-value pair + new_content = content.rstrip('}\n') + f',\n "{key}": "{value}"\n}}' + + # 写入临时文件 + # Write to temporary file + with open(temp_path, 'w') as f: + f.write(new_content) + + # 检查临时文件是否为空 + # Check if temporary file is empty + if os.path.getsize(temp_path) == 0: + log_error(_("Generated temporary file is empty")) + os.unlink(temp_path) + return False + + # 替换原文件 + # Replace original file + try: + shutil.move(temp_path, file) + except OSError: + log_error(_("Unable to write to file: {}").format(file)) + os.unlink(temp_path) + return False + + # 恢复文件权限 + # Restore file permissions + os.chmod(file, 0o444) + return True + +# 生成新的配置 +# Generate new configuration +def generate_new_config(): + global _ + print() + log_warn(_("Machine code reset options")) + + # 使用菜单选择函数询问用户是否重置机器码 + # Use menu selection function to ask user whether to reset machine code + reset_choice = select_menu_option( + _("Do you need to reset the machine code? (Usually, modifying JS files is sufficient):"), + [_("Don't reset - only modify JS files"), _("Reset - modify both config file and machine code")], + 0 + ) + + # 记录日志以便调试 + # Log for debugging + with open(LOG_FILE, 'a') as f: + f.write(_("[INPUT_DEBUG] Machine code reset option selected: {}").format(reset_choice) + "\n") + + # 处理用户选择 + # Handle user selection + if reset_choice == 1: + log_info(_("You chose to reset the machine code")) + + # 确保配置文件目录存在 + # Ensure configuration file directory exists + if os.path.isfile(STORAGE_FILE): + log_info(_("Found existing configuration file: {}").format(STORAGE_FILE)) + + # 备份现有配置 + # Backup existing configuration + backup_config() + + # 生成并设置新的设备ID + # Generate and set new device ID + new_device_id = generate_uuid() + new_machine_id = "auth0|user_{}".format(hashlib.sha256(os.urandom(16)).hexdigest()[:32]) + + log_info(_("Setting new device and machine IDs...")) + log_debug(_("New device ID: {}").format(new_device_id)) + log_debug(_("New machine ID: {}").format(new_machine_id)) + + # 修改配置文件 + # Modify configuration file + if (modify_or_add_config("deviceId", new_device_id, STORAGE_FILE) and + modify_or_add_config("machineId", new_machine_id, STORAGE_FILE)): + log_info(_("Configuration file modified successfully")) + else: + log_error(_("Configuration file modification failed")) + else: + log_warn(_("Configuration file not found, this is normal, skipping ID modification")) + else: + log_info(_("You chose not to reset the machine code, will only modify JS files")) + + # 确保配置文件目录存在 + # Ensure configuration file directory exists + if os.path.isfile(STORAGE_FILE): + log_info(_("Found existing configuration file: {}").format(STORAGE_FILE)) + + # 备份现有配置 + # Backup existing configuration + backup_config() + else: + log_warn(_("Configuration file not found, this is normal, skipping ID modification")) + + print() + log_info(_("Configuration processing completed")) + +# 查找Cursor的JS文件 +# Find Cursor's JS files +def find_cursor_js_files(): + global _ + log_info(_("Finding Cursor's JS files...")) + + js_files = [] + found = False + + # 如果找到了资源目录,在资源目录中搜索 + # If resource directory is found, search in it + if os.environ.get('CURSOR_RESOURCES'): + log_debug(_("Searching for JS files in resource directory: {}").format(os.environ['CURSOR_RESOURCES'])) + + # 在资源目录中递归搜索特定JS文件 + # Recursively search for specific JS files in resource directory + js_patterns = [ + "*/extensionHostProcess.js", + "*/main.js", + "*/cliProcessMain.js", + "*/app/out/vs/workbench/api/node/extensionHostProcess.js", + "*/app/out/main.js", + "*/app/out/vs/code/node/cliProcessMain.js", + ] + + for pattern in js_patterns: + try: + files = glob.glob(os.path.join(os.environ['CURSOR_RESOURCES'], pattern), recursive=True) + for file in files: + log_info(_("Found JS file: {}").format(file)) + js_files.append(file) + found = True + except Exception: + continue + + # 如果还没找到,尝试在/usr和$HOME目录下搜索 + # If not found, try searching in /usr and $HOME directories + if not found: + log_warn(_("No JS files found in resource directory, trying other directories...")) + + search_dirs = [ + "/usr/lib/cursor", + "/usr/share/cursor", + "/opt/cursor", + os.path.expanduser("~/.config/Cursor"), + os.path.expanduser("~/.local/share/cursor"), + ] + + for dir in search_dirs: + if os.path.isdir(dir): + log_debug(_("Searching directory: {}").format(dir)) + try: + for root, _1, files in os.walk(dir): + for file in files: + if file.endswith('.js'): + file_path = os.path.join(root, file) + with open(file_path, 'r', errors='ignore') as f: + content = f.read() + if "IOPlatformUUID" in content or "x-cursor-checksum" in content: + log_info(_("Found JS file: {}").format(file_path)) + js_files.append(file_path) + found = True + except Exception: + continue + + if not found: + log_error(_("No modifiable JS files found")) + return False, [] + + # 保存找到的文件列表到环境变量 + # Save found files to environment variable + os.environ['CURSOR_JS_FILES'] = json.dumps(js_files) + log_info(_("Found {} JS files to modify").format(len(js_files))) + return True, js_files + +# 修改Cursor的JS文件 +# Modify Cursor's JS files +def modify_cursor_js_files(): + global _ + log_info(_("Starting to modify Cursor's JS files...")) + + # 先查找需要修改的JS文件 + # First find JS files to modify + success, js_files = find_cursor_js_files() + if not success: + log_error(_("Unable to find modifiable JS files")) + return False + + modified_count = 0 + + for file in js_files: + log_info(_("Processing file: {}").format(file)) + + # 创建文件备份 + # Create file backup + backup_file = f"{file}.backup_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}" + try: + shutil.copy(file, backup_file) + except OSError: + log_error(_("Unable to create backup for file: {}").format(file)) + continue + + # 确保文件可写 + # Ensure file is writable + try: + os.chmod(file, 0o644) + except OSError: + log_error(_("Unable to modify file permissions: {}").format(file)) + continue + + # 读取文件内容 + # Read file content + with open(file, 'r', errors='ignore') as f: + content = f.read() + + # 检查文件内容并进行相应修改 + # Check file content and make appropriate modifications + if 'i.header.set("x-cursor-checksum' in content: + log_debug(_("Found x-cursor-checksum setting code")) + new_content = content.replace( + 'i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}/${e}`)', + 'i.header.set("x-cursor-checksum",e===void 0?`${p}${t}`:`${p}${t}/${p}`)' + ) + if new_content != content: + with open(file, 'w') as f: + f.write(new_content) + log_info(_("Successfully modified x-cursor-checksum setting code")) + modified_count += 1 + else: + log_error(_("Failed to modify x-cursor-checksum setting code")) + shutil.copy(backup_file, file) + elif "IOPlatformUUID" in content: + log_debug(_("Found IOPlatformUUID keyword")) + if "function a$" in content and "return crypto.randomUUID()" not in content: + new_content = content.replace( + "function a$(t){switch", + "function a$(t){return crypto.randomUUID(); switch" + ) + if new_content != content: + with open(file, 'w') as f: + f.write(new_content) + log_debug(_("Successfully injected randomUUID call into a$ function")) + modified_count += 1 + else: + log_error(_("Failed to modify a$ function")) + shutil.copy(backup_file, file) + elif "async function v5" in content and "return crypto.randomUUID()" not in content: + new_content = content.replace( + "async function v5(t){let e=", + "async function v5(t){return crypto.randomUUID(); let e=" + ) + if new_content != content: + with open(file, 'w') as f: + f.write(new_content) + log_debug(_("Successfully injected randomUUID call into v5 function")) + modified_count += 1 + else: + log_error(_("Failed to modify v5 function")) + shutil.copy(backup_file, file) + else: + # 通用注入方法 + # Universal injection method + if "// Cursor ID 修改工具注入" not in content: + timestamp = datetime.datetime.now().strftime('%s') + datetime_s = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + inject_code = f""" +// Cursor ID 修改工具注入 - {datetime_s} +// 随机设备ID生成器注入 - {timestamp} +const randomDeviceId_{timestamp} = () => {{ + try {{ + return require('crypto').randomUUID(); + }} catch (e) {{ + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {{ + const r = Math.random() * 16 | 0; + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }}); + }} +}}; +""" + # NOTE: double {{ or }} is literal, so code matches: + old_bash_inject_code = """ +// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S) +// 随机设备ID生成器注入 - $(date +%s) +const randomDeviceId_$(date +%s) = () => { + try { + return require('crypto').randomUUID(); + } catch (e) { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = Math.random() * 16 | 0; + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); + } +}; +""" + new_content = inject_code + content + new_content = new_content.replace(f"await v5(!1)", f"randomDeviceId_{timestamp}()") + new_content = new_content.replace(f"a$(t)", f"randomDeviceId_{timestamp}()") + with open(file, 'w') as f: + f.write(new_content) + log_debug(_("Completed universal modification")) + modified_count += 1 + else: + log_info(_("File already contains custom injection code, skipping modification")) + else: + # 未找到关键字,尝试通用方法 + # No keywords found, try universal method + if "return crypto.randomUUID()" not in content and "// Cursor ID 修改工具注入" not in content: + if "function t$()" in content or "async function y5" in content: + new_content = content + if "function t$()" in new_content: + new_content = new_content.replace( + "function t$(){", + 'function t$(){return "00:00:00:00:00:00";' + ) + if "async function y5" in new_content: + new_content = new_content.replace( + "async function y5(t){", + "async function y5(t){return crypto.randomUUID();" + ) + if new_content != content: + with open(file, 'w') as f: + f.write(new_content) + modified_count += 1 + else: + # 最通用的注入方法 + # Most universal injection method + new_uuid = generate_uuid() + machine_id = f"auth0|user_{hashlib.sha256(os.urandom(16)).hexdigest()[:32]}" + device_id = generate_uuid() + mac_machine_id = hashlib.sha256(os.urandom(32)).hexdigest() + timestamp = datetime.datetime.now().strftime('%s') + datetime_s = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + inject_universal_code = f""" +// Cursor ID 修改工具注入 - {datetime_s} +// 全局拦截设备标识符 - {timestamp} +const originalRequire_{timestamp} = require; +require = function(module) {{ + const result = originalRequire_{timestamp}(module); + if (module === 'crypto' && result.randomUUID) {{ + const originalRandomUUID_{timestamp} = result.randomUUID; + result.randomUUID = function() {{ + return '{new_uuid}'; + }}; + }} + return result; +}}; + +// 覆盖所有可能的系统ID获取函数 +global.getMachineId = function() {{ return '{machine_id}'; }}; +global.getDeviceId = function() {{ return '{device_id}'; }}; +global.macMachineId = '{mac_machine_id}'; +""" + # NOTE: Double {{ or }} is literal, so matches: + old_bash_inject_code = """ +// Cursor ID 修改工具注入 - $(date +%Y%m%d%H%M%S) +// 全局拦截设备标识符 - $(date +%s) +const originalRequire_$(date +%s) = require; +require = function(module) { + const result = originalRequire_$(date +%s)(module); + if (module === 'crypto' && result.randomUUID) { + const originalRandomUUID_$(date +%s) = result.randomUUID; + result.randomUUID = function() { + return '$new_uuid'; + }; + } + return result; +}; + +// 覆盖所有可能的系统ID获取函数 +global.getMachineId = function() { return '$machine_id'; }; +global.getDeviceId = function() { return '$device_id'; }; +global.macMachineId = '$mac_machine_id'; +""" + new_content = inject_universal_code + content + with open(file, 'w') as f: + f.write(new_content) + log_debug(_("Completed most universal injection")) + modified_count += 1 + else: + log_info(_("File has already been modified, skipping modification")) + + # 恢复文件权限 + # Restore file permissions + os.chmod(file, 0o444) + + if modified_count == 0: + log_error(_("Failed to modify any JS files")) + return False + + log_info(_("Successfully modified {} JS files").format(modified_count)) + return True + +# 禁用自动更新 +# Disable auto-update +def disable_auto_update(): + global _ + log_info(_("Disabling Cursor auto-update...")) + + # 查找可能的更新配置文件 + # Find possible update configuration files + update_configs = [ + os.path.join(CURSOR_CONFIG_DIR, "update-config.json"), + os.path.expanduser("~/.local/share/cursor/update-config.json"), + "/opt/cursor/resources/app-update.yml", + ] + + disabled = False + + for config in update_configs: + if os.path.isfile(config): + log_info(_("Found update configuration file: {}").format(config)) + try: + shutil.copy(config, f"{config}.bak") + with open(config, 'w') as f: + json.dump({"autoCheck": False, "autoDownload": False}, f) + os.chmod(config, 0o444) + log_info(_("Disabled update configuration file: {}").format(config)) + disabled = True + except (OSError, shutil.Error): + continue + + # 尝试查找updater可执行文件并禁用 + # Try to find and disable updater executable + updater_paths = [ + os.path.join(CURSOR_CONFIG_DIR, "updater"), + "/opt/cursor/updater", + "/usr/lib/cursor/updater", + ] + + for updater in updater_paths: + if os.path.exists(updater): + log_info(_("Found updater: {}").format(updater)) + try: + if os.path.isfile(updater): + shutil.move(updater, f"{updater}.bak") + else: + Path(f"{updater}.disabled").touch() + log_info(_("Disabled updater: {}").format(updater)) + disabled = True + except (OSError, shutil.Error): + continue + + if not disabled: + log_warn(_("No update configuration files or updaters found")) + else: + log_info(_("Successfully disabled auto-update")) + +# 新增:通用菜单选择函数 +# New: Universal menu selection function +def select_menu_option(prompt, options, default_index=0): + global _ + # 保存终端设置 + # Save terminal settings + old_settings = termios.tcgetattr(sys.stdin) + selected_index = default_index + + try: + # 设置终端为非缓冲模式 + # Set terminal to non-buffered mode + tty.setcbreak(sys.stdin.fileno()) + + # 显示提示信息 + # Display prompt + print(_(prompt)) + + # 第一次显示菜单 + # Display menu initially + for i, option in enumerate(options): + if i == selected_index: + print(f" {GREEN}►{NC} {_(option)}") + else: + print(f" {_(option)}") + + while True: + # 读取键盘输入 + # Read keyboard input + rlist, _1, _2 = select.select([sys.stdin], [], [], 0.1) + if rlist: + key = sys.stdin.read(1) + # 上箭头键 + # Up arrow key + if key == '\033': + next_char = sys.stdin.read(2) + if next_char == '[A' and selected_index > 0: + selected_index -= 1 + # 下箭头键 + # Down arrow key + elif next_char == '[B' and selected_index < len(options) - 1: + selected_index += 1 + # Enter键 + # Enter key + elif key == '\n': + print() + log_info(_("You selected: {}").format(options[selected_index])) + return selected_index + + # 清除当前菜单 + # Clear current menu + sys.stdout.write('\033[{}A\033[J'.format(len(options) + 1)) + sys.stdout.flush() + + # 重新显示提示和菜单 + # Redisplay prompt and menu + print(_(prompt)) + for i, option in enumerate(options): + if i == selected_index: + print(f" {GREEN}►{NC} {_(option)}") + else: + print(f" {_(option)}") + sys.stdout.flush() + + finally: + # 恢复终端设置 + # Restore terminal settings + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) + +# 主函数 +# Main function +def main(): + global _ + # 检查系统环境 + # Check system environment + if sys.platform != "linux": + log_error(_("This script only supports Linux systems")) + sys.exit(1) + + # 初始化日志文件 + # Initialize log file + initialize_log() + log_info(_("Script started...")) + + # 记录系统信息 + # Log system information + log_info(_("System information: {}").format(subprocess.getoutput("uname -a"))) + log_info(_("Current user: {}").format(CURRENT_USER)) + log_cmd_output( + "lsb_release -a 2>/dev/null || cat /etc/*release 2>/dev/null || cat /etc/issue", + _("System version information") + ) + + # 清除终端 + # Clear terminal + os.system('clear') + + # 显示 Logo + # Display Logo + print(""" + ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗ + ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗ + ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝ + ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗ + ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║ + ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ + """) + print(f"{BLUE}================================{NC}") + print(f"{GREEN} {_('Cursor Linux startup tool')} {NC}") + print(f"{BLUE}================================{NC}") + print() + print(f"{YELLOW}[{_('Important notice')}] {NC} {_('This tool prioritizes modifying JS files, which is safer and more reliable')}") + print() + + # 执行主要功能 + # Execute main functions + check_permissions() + find_cursor_path() + find_cursor_resources() + check_and_kill_cursor() + backup_config() + generate_new_config() + + # 修改JS文件 + # Modify JS files + log_info(_("Modifying Cursor JS files...")) + if modify_cursor_js_files(): + log_info(_("JS files modified successfully!")) + else: + log_warn(_("JS file modification failed, but configuration file modification may have succeeded")) + log_warn(_("If Cursor still indicates the device is disabled after restarting, please rerun this script")) + + # 禁用自动更新 + # Disable auto-update + disable_auto_update() + + log_info(_("Please restart Cursor to apply the new configuration")) + + # 显示最后的提示信息 + # Display final prompt + print() + print(f"{GREEN}================================{NC}") + print(f"{YELLOW} {_('Follow the WeChat public account [Pancake AI] to discuss more Cursor tips and AI knowledge (script is free, join the group via the public account for more tips and experts)')} {NC}") + print("WeChat account: [煎饼果子卷AI]") + print(f"{GREEN}================================{NC}") + print() + + # 记录脚本完成信息 + # Log script completion information + log_info(_("Script execution completed")) + with open(LOG_FILE, 'a') as f: + f.write(_("========== Cursor ID modification tool log end {} ==========").format(datetime.datetime.now()) + "\n") + + # 显示日志文件位置 + # Display log file location + print() + log_info(_("Detailed log saved to: {}").format(LOG_FILE)) + print(_("If you encounter issues, please provide this log file to the developer for troubleshooting")) + print() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/git-actions.sh b/scripts/git-actions.sh new file mode 100755 index 0000000..632e312 --- /dev/null +++ b/scripts/git-actions.sh @@ -0,0 +1,9 @@ +#!/bin/bash +REPO_DIR="$PWD" +LOCALES_DIR="$REPO_DIR/locales" +msginit -i cursor_id_modifier.pot -o $LOCALES_DIR/en_US/LC_MESSAGES/cursor_id_modifier.po -l en_US +for lang in en_US zh_CN; do + cd $LOCALES_DIR/$lang/LC_MESSAGES + msgfmt -o cursor_id_modifier.mo cursor_id_modifier.po +done + diff --git a/scripts/locales/en_US/LC_MESSAGES/cursor_id_modifier.po b/scripts/locales/en_US/LC_MESSAGES/cursor_id_modifier.po new file mode 100644 index 0000000..f51010b --- /dev/null +++ b/scripts/locales/en_US/LC_MESSAGES/cursor_id_modifier.po @@ -0,0 +1,349 @@ +msgid "" +msgstr "" +"Project-Id-Version: cursor_id_modifier\n" +"POT-Creation-Date: 2025-04-25 12:00+0000\n" +"PO-Revision-Date: 2025-04-25 09:25-0400\n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Poikilos using Grok <7557867+poikilos@users.noreply.github.com>\n" +"Language: en_US\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "" +"Error: No translation file found for domain 'cursor_id_modifier' in {}/zh_CN/" +"LC_MESSAGES/" +msgstr "" +"Error: No translation file found for domain 'cursor_id_modifier' in {}/zh_CN/" +"LC_MESSAGES/" + +msgid "========== Cursor ID modification tool log start {} ==========" +msgstr "========== Cursor ID modification tool log start {} ==========" + +msgid "[INFO] {} {}" +msgstr "[INFO] {} {}" + +msgid "[WARN] {} {}" +msgstr "[WARN] {} {}" + +msgid "[ERROR] {} {}" +msgstr "[ERROR] {} {}" + +msgid "[DEBUG] {} {}" +msgstr "[DEBUG] {} {}" + +msgid "[CMD] {} Executing command: {}" +msgstr "[CMD] {} Executing command: {}" + +msgid "[CMD] {}:" +msgstr "[CMD] {}:" + +msgid "Unable to get username" +msgstr "Unable to get username" + +msgid "Finding Cursor installation path..." +msgstr "Finding Cursor installation path..." + +msgid "Found Cursor installation path: {}" +msgstr "Found Cursor installation path: {}" + +msgid "Found Cursor via which: {}" +msgstr "Found Cursor via which: {}" + +msgid "Cursor executable not found, will try using config directory" +msgstr "Cursor executable not found, will try using config directory" + +msgid "Found Cursor via search: {}" +msgstr "Found Cursor via search: {}" + +msgid "Finding Cursor resource directory..." +msgstr "Finding Cursor resource directory..." + +msgid "Found Cursor resource directory: {}" +msgstr "Found Cursor resource directory: {}" + +msgid "Found resource directory via binary path: {}" +msgstr "Found resource directory via binary path: {}" + +msgid "Cursor resource directory not found" +msgstr "Cursor resource directory not found" + +msgid "Please run this script with sudo" +msgstr "Please run this script with sudo" + +msgid "Example: sudo {}" +msgstr "Example: sudo {}" + +msgid "Checking Cursor processes..." +msgstr "Checking Cursor processes..." + +msgid "Getting process details for {}:" +msgstr "Getting process details for {}:" + +msgid "No running Cursor processes found" +msgstr "No running Cursor processes found" + +msgid "Found running Cursor processes" +msgstr "Found running Cursor processes" + +msgid "Attempting to terminate Cursor processes..." +msgstr "Attempting to terminate Cursor processes..." + +msgid "Attempting to forcefully terminate processes..." +msgstr "Attempting to forcefully terminate processes..." + +msgid "Waiting for processes to terminate, attempt {}/{}..." +msgstr "Waiting for processes to terminate, attempt {}/{}..." + +msgid "Cursor processes successfully terminated" +msgstr "Cursor processes successfully terminated" + +msgid "Unable to terminate Cursor processes after {} attempts" +msgstr "Unable to terminate Cursor processes after {} attempts" + +msgid "Please manually terminate the processes and try again" +msgstr "Please manually terminate the processes and try again" + +msgid "Configuration file does not exist, skipping backup" +msgstr "Configuration file does not exist, skipping backup" + +msgid "Configuration backed up to: {}" +msgstr "Configuration backed up to: {}" + +msgid "Backup failed" +msgstr "Backup failed" + +msgid "File does not exist: {}" +msgstr "File does not exist: {}" + +msgid "Unable to modify file permissions: {}" +msgstr "Unable to modify file permissions: {}" + +msgid "Generated temporary file is empty" +msgstr "Generated temporary file is empty" + +msgid "Unable to write to file: {}" +msgstr "Unable to write to file: {}" + +msgid "Machine code reset options" +msgstr "Machine code reset options" + +msgid "" +"Do you need to reset the machine code? (Usually, modifying JS files is " +"sufficient):" +msgstr "" +"Do you need to reset the machine code? (Usually, modifying JS files is " +"sufficient):" + +msgid "Don't reset - only modify JS files" +msgstr "Don't reset - only modify JS files" + +msgid "Reset - modify both config file and machine code" +msgstr "Reset - modify both config file and machine code" + +msgid "[INPUT_DEBUG] Machine code reset option selected: {}" +msgstr "[INPUT_DEBUG] Machine code reset option selected: {}" + +msgid "You chose to reset the machine code" +msgstr "You chose to reset the machine code" + +msgid "Found existing configuration file: {}" +msgstr "Found existing configuration file: {}" + +msgid "Setting new device and machine IDs..." +msgstr "Setting new device and machine IDs..." + +msgid "New device ID: {}" +msgstr "New device ID: {}" + +msgid "New machine ID: {}" +msgstr "New machine ID: {}" + +msgid "Configuration file modified successfully" +msgstr "Configuration file modified successfully" + +msgid "Configuration file modification failed" +msgstr "Configuration file modification failed" + +msgid "Configuration file not found, this is normal, skipping ID modification" +msgstr "Configuration file not found, this is normal, skipping ID modification" + +msgid "You chose not to reset the machine code, will only modify JS files" +msgstr "You chose not to reset the machine code, will only modify JS files" + +msgid "Configuration processing completed" +msgstr "Configuration processing completed" + +msgid "Finding Cursor's JS files..." +msgstr "Finding Cursor's JS files..." + +msgid "Searching for JS files in resource directory: {}" +msgstr "Searching for JS files in resource directory: {}" + +msgid "Found JS file: {}" +msgstr "Found JS file: {}" + +msgid "No JS files found in resource directory, trying other directories..." +msgstr "No JS files found in resource directory, trying other directories..." + +msgid "Searching directory: {}" +msgstr "Searching directory: {}" + +msgid "No modifiable JS files found" +msgstr "No modifiable JS files found" + +msgid "Found {} JS files to modify" +msgstr "Found {} JS files to modify" + +msgid "Starting to modify Cursor's JS files..." +msgstr "Starting to modify Cursor's JS files..." + +msgid "Unable to find modifiable JS files" +msgstr "Unable to find modifiable JS files" + +msgid "Processing file: {}" +msgstr "Processing file: {}" + +msgid "Unable to create backup for file: {}" +msgstr "Unable to create backup for file: {}" + +msgid "Found x-cursor-checksum setting code" +msgstr "Found x-cursor-checksum setting code" + +msgid "Successfully modified x-cursor-checksum setting code" +msgstr "Successfully modified x-cursor-checksum setting code" + +msgid "Failed to modify x-cursor-checksum setting code" +msgstr "Failed to modify x-cursor-checksum setting code" + +msgid "Found IOPlatformUUID keyword" +msgstr "Found IOPlatformUUID keyword" + +msgid "Successfully injected randomUUID call into a$ function" +msgstr "Successfully injected randomUUID call into a$ function" + +msgid "Failed to modify a$ function" +msgstr "Failed to modify a$ function" + +msgid "Successfully injected randomUUID call into v5 function" +msgstr "Successfully injected randomUUID call into v5 function" + +msgid "Failed to modify v5 function" +msgstr "Failed to modify v5 function" + +msgid "Completed universal modification" +msgstr "Completed universal modification" + +msgid "File already contains custom injection code, skipping modification" +msgstr "File already contains custom injection code, skipping modification" + +msgid "Completed most universal injection" +msgstr "Completed most universal injection" + +msgid "File has already been modified, skipping modification" +msgstr "File has already been modified, skipping modification" + +msgid "Failed to modify any JS files" +msgstr "Failed to modify any JS files" + +msgid "Successfully modified {} JS files" +msgstr "Successfully modified {} JS files" + +msgid "Disabling Cursor auto-update..." +msgstr "Disabling Cursor auto-update..." + +msgid "Found update configuration file: {}" +msgstr "Found update configuration file: {}" + +msgid "Disabled update configuration file: {}" +msgstr "Disabled update configuration file: {}" + +msgid "Found updater: {}" +msgstr "Found updater: {}" + +msgid "Disabled updater: {}" +msgstr "Disabled updater: {}" + +msgid "No update configuration files or updaters found" +msgstr "No update configuration files or updaters found" + +msgid "Successfully disabled auto-update" +msgstr "Successfully disabled auto-update" + +msgid "You selected: {}" +msgstr "You selected: {}" + +msgid "This script only supports Linux systems" +msgstr "This script only supports Linux systems" + +msgid "Script started..." +msgstr "Script started..." + +msgid "System information: {}" +msgstr "System information: {}" + +msgid "Current user: {}" +msgstr "Current user: {}" + +msgid "System version information" +msgstr "System version information" + +msgid "Cursor Linux startup tool" +msgstr "Cursor Linux startup tool" + +msgid "Important notice" +msgstr "Important notice" + +msgid "" +"This tool prioritizes modifying JS files, which is safer and more reliable" +msgstr "" +"This tool prioritizes modifying JS files, which is safer and more reliable" + +msgid "Modifying Cursor JS files..." +msgstr "Modifying Cursor JS files..." + +msgid "JS files modified successfully!" +msgstr "JS files modified successfully!" + +msgid "" +"JS file modification failed, but configuration file modification may have " +"succeeded" +msgstr "" +"JS file modification failed, but configuration file modification may have " +"succeeded" + +msgid "" +"If Cursor still indicates the device is disabled after restarting, please " +"rerun this script" +msgstr "" +"If Cursor still indicates the device is disabled after restarting, please " +"rerun this script" + +msgid "Please restart Cursor to apply the new configuration" +msgstr "Please restart Cursor to apply the new configuration" + +msgid "" +"Follow the WeChat public account [Pancake AI] to discuss more Cursor tips " +"and AI knowledge (script is free, join the group via the public account for " +"more tips and experts)" +msgstr "" +"Follow the WeChat public account [Pancake AI] to discuss more Cursor tips " +"and AI knowledge (script is free, join the group via the public account for " +"more tips and experts)" + +msgid "Script execution completed" +msgstr "Script execution completed" + +msgid "========== Cursor ID modification tool log end {} ==========" +msgstr "========== Cursor ID modification tool log end {} ==========" + +msgid "Detailed log saved to: {}" +msgstr "Detailed log saved to: {}" + +msgid "" +"If you encounter issues, please provide this log file to the developer for " +"troubleshooting" +msgstr "" +"If you encounter issues, please provide this log file to the developer for " +"troubleshooting" diff --git a/scripts/locales/zh_CN/LC_MESSAGES/cursor_id_modifier.mo b/scripts/locales/zh_CN/LC_MESSAGES/cursor_id_modifier.mo new file mode 100644 index 0000000..010075e Binary files /dev/null and b/scripts/locales/zh_CN/LC_MESSAGES/cursor_id_modifier.mo differ diff --git a/scripts/locales/zh_CN/LC_MESSAGES/cursor_id_modifier.po b/scripts/locales/zh_CN/LC_MESSAGES/cursor_id_modifier.po new file mode 100644 index 0000000..565878f --- /dev/null +++ b/scripts/locales/zh_CN/LC_MESSAGES/cursor_id_modifier.po @@ -0,0 +1,320 @@ +msgid "" +msgstr "" +"Project-Id-Version: cursor_id_modifier\n" +"POT-Creation-Date: 2025-04-25 12:00+0000\n" +"PO-Revision-Date: 2025-04-25 12:00+0000\n" +"Last-Translator: None\n" +"Language-Team: Chinese\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Error: No translation file found for domain 'cursor_id_modifier' in {}/zh_CN/LC_MESSAGES/" +msgstr "错误:未在 {}/zh_CN/LC_MESSAGES/ 中找到域 'cursor_id_modifier' 的翻译文件" + +msgid "========== Cursor ID modification tool log start {} ==========" +msgstr "========== Cursor ID 修改工具日志开始 {} ==========" + +msgid "[INFO] {} {}" +msgstr "[INFO] {} {}" + +msgid "[WARN] {} {}" +msgstr "[WARN] {} {}" + +msgid "[ERROR] {} {}" +msgstr "[ERROR] {} {}" + +msgid "[DEBUG] {} {}" +msgstr "[DEBUG] {} {}" + +msgid "[CMD] {} Executing command: {}" +msgstr "[CMD] {} 执行命令: {}" + +msgid "[CMD] {}:" +msgstr "[CMD] {}:" + +msgid "Unable to get username" +msgstr "无法获取用户名" + +msgid "Finding Cursor installation path..." +msgstr "查找Cursor安装路径..." + +msgid "Found Cursor installation path: {}" +msgstr "找到Cursor安装路径: {}" + +msgid "Found Cursor via which: {}" +msgstr "通过which找到Cursor: {}" + +msgid "Cursor executable not found, will try using config directory" +msgstr "未找到Cursor可执行文件,将尝试使用配置目录" + +msgid "Found Cursor via search: {}" +msgstr "通过查找找到Cursor: {}" + +msgid "Finding Cursor resource directory..." +msgstr "查找Cursor资源目录..." + +msgid "Found Cursor resource directory: {}" +msgstr "找到Cursor资源目录: {}" + +msgid "Found resource directory via binary path: {}" +msgstr "通过二进制路径找到资源目录: {}" + +msgid "Cursor resource directory not found" +msgstr "未找到Cursor资源目录" + +msgid "Please run this script with sudo" +msgstr "请使用 sudo 运行此脚本" + +msgid "Example: sudo {}" +msgstr "示例: sudo {}" + +msgid "Checking Cursor processes..." +msgstr "检查 Cursor 进程..." + +msgid "Getting process details for {}:" +msgstr "正在获取 {} 进程详细信息:" + +msgid "No running Cursor processes found" +msgstr "未发现运行中的 Cursor 进程" + +msgid "Found running Cursor processes" +msgstr "发现 Cursor 进程正在运行" + +msgid "Attempting to terminate Cursor processes..." +msgstr "尝试关闭 Cursor 进程..." + +msgid "Attempting to forcefully terminate processes..." +msgstr "尝试强制终止进程..." + +msgid "Waiting for processes to terminate, attempt {}/{}..." +msgstr "等待进程关闭,尝试 {}/{}..." + +msgid "Cursor processes successfully terminated" +msgstr "Cursor 进程已成功关闭" + +msgid "Unable to terminate Cursor processes after {} attempts" +msgstr "在 {} 次尝试后仍无法关闭 Cursor 进程" + +msgid "Please manually terminate the processes and try again" +msgstr "请手动关闭进程后重试" + +msgid "Configuration file does not exist, skipping backup" +msgstr "配置文件不存在,跳过备份" + +msgid "Configuration backed up to: {}" +msgstr "配置已备份到: {}" + +msgid "Backup failed" +msgstr "备份失败" + +msgid "File does not exist: {}" +msgstr "文件不存在: {}" + +msgid "Unable to modify file permissions: {}" +msgstr "无法修改文件权限: {}" + +msgid "Generated temporary file is empty" +msgstr "生成的临时文件为空" + +msgid "Unable to write to file: {}" +msgstr "无法写入文件: {}" + +msgid "Machine code reset options" +msgstr "机器码重置选项" + +msgid "Do you need to reset the machine code? (Usually, modifying JS files is sufficient):" +msgstr "是否需要重置机器码? (通常情况下,只修改js文件即可):" + +msgid "Don't reset - only modify JS files" +msgstr "不重置 - 仅修改js文件即可" + +msgid "Reset - modify both config file and machine code" +msgstr "重置 - 同时修改配置文件和机器码" + +msgid "[INPUT_DEBUG] Machine code reset option selected: {}" +msgstr "[INPUT_DEBUG] 机器码重置选项选择: {}" + +msgid "You chose to reset the machine code" +msgstr "您选择了重置机器码" + +msgid "Found existing configuration file: {}" +msgstr "发现已有配置文件: {}" + +msgid "Setting new device and machine IDs..." +msgstr "正在设置新的设备和机器ID..." + +msgid "New device ID: {}" +msgstr "新设备ID: {}" + +msgid "New machine ID: {}" +msgstr "新机器ID: {}" + +msgid "Configuration file modified successfully" +msgstr "配置文件修改成功" + +msgid "Configuration file modification failed" +msgstr "配置文件修改失败" + +msgid "Configuration file not found, this is normal, skipping ID modification" +msgstr "未找到配置文件,这是正常的,脚本将跳过ID修改" + +msgid "You chose not to reset the machine code, will only modify JS files" +msgstr "您选择了不重置机器码,将仅修改js文件" + +msgid "Configuration processing completed" +msgstr "配置处理完成" + +msgid "Finding Cursor's JS files..." +msgstr "查找Cursor的JS文件..." + +msgid "Searching for JS files in resource directory: {}" +msgstr "在资源目录中搜索JS文件: {}" + +msgid "Found JS file: {}" +msgstr "找到JS文件: {}" + +msgid "No JS files found in resource directory, trying other directories..." +msgstr "在资源目录中未找到JS文件,尝试在其他目录中搜索..." + +msgid "Searching directory: {}" +msgstr "搜索目录: {}" + +msgid "No modifiable JS files found" +msgstr "未找到任何可修改的JS文件" + +msgid "Found {} JS files to modify" +msgstr "找到 {} 个JS文件需要修改" + +msgid "Starting to modify Cursor's JS files..." +msgstr "开始修改Cursor的JS文件..." + +msgid "Unable to find modifiable JS files" +msgstr "无法找到可修改的JS文件" + +msgid "Processing file: {}" +msgstr "处理文件: {}" + +msgid "Unable to create backup for file: {}" +msgstr "无法创建文件备份: {}" + +msgid "Found x-cursor-checksum setting code" +msgstr "找到 x-cursor-checksum 设置代码" + +msgid "Successfully modified x-cursor-checksum setting code" +msgstr "成功修改 x-cursor-checksum 设置代码" + +msgid "Failed to modify x-cursor-checksum setting code" +msgstr "修改 x-cursor-checksum 设置代码失败" + +msgid "Found IOPlatformUUID keyword" +msgstr "找到 IOPlatformUUID 关键字" + +msgid "Successfully injected randomUUID call into a$ function" +msgstr "成功注入 randomUUID 调用到 a$ 函数" + +msgid "Failed to modify a$ function" +msgstr "修改 a$ 函数失败" + +msgid "Successfully injected randomUUID call into v5 function" +msgstr "成功注入 randomUUID 调用到 v5 函数" + +msgid "Failed to modify v5 function" +msgstr "修改 v5 函数失败" + +msgid "Completed universal modification" +msgstr "完成通用修改" + +msgid "File already contains custom injection code, skipping modification" +msgstr "文件已经包含自定义注入代码,跳过修改" + +msgid "Completed most universal injection" +msgstr "完成最通用注入" + +msgid "File has already been modified, skipping modification" +msgstr "文件已经被修改过,跳过修改" + +msgid "Failed to modify any JS files" +msgstr "未能成功修改任何JS文件" + +msgid "Successfully modified {} JS files" +msgstr "成功修改了 {} 个JS文件" + +msgid "Disabling Cursor auto-update..." +msgstr "正在禁用 Cursor 自动更新..." + +msgid "Found update configuration file: {}" +msgstr "找到更新配置文件: {}" + +msgid "Disabled update configuration file: {}" +msgstr "已禁用更新配置文件: {}" + +msgid "Found updater: {}" +msgstr "找到更新程序: {}" + +msgid "Disabled updater: {}" +msgstr "已禁用更新程序: {}" + +msgid "No update configuration files or updaters found" +msgstr "未找到任何更新配置文件或更新程序" + +msgid "Successfully disabled auto-update" +msgstr "成功禁用了自动更新" + +msgid "You selected: {}" +msgstr "您选择了: {}" + +msgid "This script only supports Linux systems" +msgstr "本脚本仅支持 Linux 系统" + +msgid "Script started..." +msgstr "脚本启动..." + +msgid "System information: {}" +msgstr "系统信息: {}" + +msgid "Current user: {}" +msgstr "当前用户: {}" + +msgid "System version information" +msgstr "系统版本信息" + +msgid "Cursor Linux startup tool" +msgstr "Cursor Linux 启动工具" + +msgid "Important notice" +msgstr "重要提示" + +msgid "This tool prioritizes modifying JS files, which is safer and more reliable" +msgstr "本工具优先修改js文件,更加安全可靠" + +msgid "Modifying Cursor JS files..." +msgstr "正在修改Cursor JS文件..." + +msgid "JS files modified successfully!" +msgstr "JS文件修改成功!" + +msgid "JS file modification failed, but configuration file modification may have succeeded" +msgstr "JS文件修改失败,但配置文件修改可能已成功" + +msgid "If Cursor still indicates the device is disabled after restarting, please rerun this script" +msgstr "如果重启后 Cursor 仍然提示设备被禁用,请重新运行此脚本" + +msgid "Please restart Cursor to apply the new configuration" +msgstr "请重启 Cursor 以应用新的配置" + +msgid "Follow the WeChat public account [Pancake AI] to discuss more Cursor tips and AI knowledge (script is free, join the group via the public account for more tips and experts)" +msgstr "关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬)" + +msgid "Script execution completed" +msgstr "脚本执行完成" + +msgid "========== Cursor ID modification tool log end {} ==========" +msgstr "========== Cursor ID 修改工具日志结束 {} ==========" + +msgid "Detailed log saved to: {}" +msgstr "详细日志已保存到: {}" + +msgid "If you encounter issues, please provide this log file to the developer for troubleshooting" +msgstr "如遇问题请将此日志文件提供给开发者以协助排查"