fix: Improve Cursor Version Check and Configuration Handling

- Enhance version checking in `reset_machine_manual.py` with more robust error handling
- Add detailed error messages and logging for version detection
- Update configuration paths in `new_signup.py` to include Cursor application path
- Add configuration initialization in `main.py`
- Update localization files with new error and version-related messages
This commit is contained in:
yeongpin 2025-03-10 17:41:07 +08:00
parent 54ecf2d752
commit 4f6f3fe814
9 changed files with 161 additions and 53 deletions

4
.env
View File

@ -1,2 +1,2 @@
version=1.7.04 version=1.7.05
VERSION=1.7.04 VERSION=1.7.05

View File

@ -6,7 +6,7 @@ on:
version: version:
description: 'Version number (e.g. 1.0.9)' description: 'Version number (e.g. 1.0.9)'
required: true required: true
default: '1.7.04' default: '1.7.05'
permissions: permissions:
contents: write contents: write

View File

@ -1,5 +1,10 @@
# Change Log # Change Log
## v1.7.05
1. Fix: Cursor Version Check | 修復Cursor版本檢查
2. Fix: Small Problem | 修復一些小問題
## v1.7.04 ## v1.7.04
1. Hotfix: Small Problem | 修復一些小問題 1. Hotfix: Small Problem | 修復一些小問題

View File

@ -72,7 +72,20 @@
"permission_denied": "Permission Denied: {error}", "permission_denied": "Permission Denied: {error}",
"backup_created": "Backup Created", "backup_created": "Backup Created",
"update_success": "Update Success", "update_success": "Update Success",
"update_failed": "Update Failed: {error}" "update_failed": "Update Failed: {error}",
"windows_machine_guid_updated": "Windows Machine GUID Updated Successfully",
"reading_package_json": "Reading package.json {path}",
"invalid_json_object": "Invalid JSON Object",
"no_version_field": "No Version Field Found in package.json",
"version_field_empty": "Version Field is Empty",
"invalid_version_format": "Invalid Version Format: {version}",
"found_version": "Found Version: {version}",
"version_parse_error": "Version Parse Error: {error}",
"package_not_found": "Package.json Not Found: {path}",
"check_version_failed": "Check Version Failed: {error}",
"stack_trace": "Stack Trace",
"version_too_low": "Cursor Version Too Low: {version} < 0.45.0"
}, },
"register": { "register": {
"title": "Cursor Registration Tool", "title": "Cursor Registration Tool",

View File

@ -72,7 +72,19 @@
"permission_denied": "权限拒绝: {error}", "permission_denied": "权限拒绝: {error}",
"backup_created": "备份已创建", "backup_created": "备份已创建",
"update_success": "更新成功", "update_success": "更新成功",
"update_failed": "更新失败: {error}" "update_failed": "更新失败: {error}",
"windows_machine_guid_updated": "Windows机器GUID更新成功",
"reading_package_json": "读取package.json {path}",
"invalid_json_object": "JSON对象无效",
"no_version_field": "package.json中没有版本字段",
"version_field_empty": "版本字段为空",
"invalid_version_format": "版本格式无效: {version}",
"found_version": "找到版本: {version}",
"version_parse_error": "版本解析错误: {error}",
"package_not_found": "package.json未找到: {path}",
"check_version_failed": "检查版本失败: {error}",
"stack_trace": "堆栈跟踪",
"version_too_low": "Cursor版本太低: {version} < 0.45.0"
}, },
"register": { "register": {
"title": "Cursor 注册工具", "title": "Cursor 注册工具",

View File

@ -72,8 +72,21 @@
"permission_denied": "權限拒絕: {error}", "permission_denied": "權限拒絕: {error}",
"backup_created": "備份已創建", "backup_created": "備份已創建",
"update_success": "更新成功", "update_success": "更新成功",
"update_failed": "更新失敗: {error}" "update_failed": "更新失敗: {error}",
"windows_machine_guid_updated": "Windows機器GUID更新成功",
"reading_package_json": "讀取package.json {path}",
"invalid_json_object": "JSON對象無效",
"no_version_field": "package.json中沒有版本字段",
"version_field_empty": "版本字段為空",
"invalid_version_format": "版本格式無效: {version}",
"found_version": "找到版本: {version}",
"version_parse_error": "版本解析錯誤: {error}",
"package_not_found": "package.json未找到: {path}",
"check_version_failed": "檢查版本失敗: {error}",
"stack_trace": "堆疊跟踪",
"version_too_low": "Cursor版本太低: {version} < 0.45.0"
}, },
"register": { "register": {
"title": "Cursor 註冊工具", "title": "Cursor 註冊工具",
"start": "正在啟動註冊流程...", "start": "正在啟動註冊流程...",

View File

@ -285,6 +285,14 @@ def check_latest_version():
def main(): def main():
print_logo() print_logo()
# 初始化配置
from new_signup import setup_config
config = setup_config(translator)
if not config:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.config_init_failed')}{Style.RESET_ALL}")
return
check_latest_version() # Add version check before showing menu check_latest_version() # Add version check before showing menu
print_menu() print_menu()

View File

@ -207,21 +207,25 @@ def setup_config(translator=None):
default_config['WindowsPaths'] = { default_config['WindowsPaths'] = {
'storage_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "storage.json"), 'storage_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "storage.json"),
'sqlite_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "state.vscdb"), 'sqlite_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "state.vscdb"),
'machine_id_path': os.path.join(os.getenv("APPDATA"), "Cursor", "machineId") 'machine_id_path': os.path.join(os.getenv("APPDATA"), "Cursor", "machineId"),
'cursor_path': os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app")
} }
elif sys.platform == "darwin": elif sys.platform == "darwin":
default_config['MacPaths'] = { default_config['MacPaths'] = {
'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")), 'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")),
'sqlite_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/state.vscdb")), 'sqlite_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/state.vscdb")),
'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId") 'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId"),
'cursor_path': "/Applications/Cursor.app/Contents/Resources/app"
} }
elif sys.platform == "linux": elif sys.platform == "linux":
sudo_user = os.environ.get('SUDO_USER') sudo_user = os.environ.get('SUDO_USER')
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~") actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
default_config['LinuxPaths'] = { default_config['LinuxPaths'] = {
'storage_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/storage.json")), 'storage_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/storage.json")),
'sqlite_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/state.vscdb")), 'sqlite_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/state.vscdb")),
'machine_id_path': os.path.expanduser("~/.config/Cursor/machineId") 'machine_id_path': os.path.expanduser("~/.config/Cursor/machineId"),
'cursor_path': "/opt/Cursor/resources/app" # 默認路徑
} }
if os.path.exists(config_file): if os.path.exists(config_file):

View File

@ -12,6 +12,7 @@ from colorama import Fore, Style, init
from typing import Tuple from typing import Tuple
import configparser import configparser
from new_signup import get_user_documents_path from new_signup import get_user_documents_path
import traceback
# Initialize colorama # Initialize colorama
init() init()
@ -29,42 +30,45 @@ EMOJI = {
def get_cursor_paths(translator=None) -> Tuple[str, str]: def get_cursor_paths(translator=None) -> Tuple[str, str]:
""" Get Cursor related paths""" """ Get Cursor related paths"""
system = platform.system() system = platform.system()
paths_map = { # 讀取配置文件
"Darwin": { config = configparser.ConfigParser()
"base": "/Applications/Cursor.app/Contents/Resources/app", config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
"package": "package.json", config_file = os.path.join(config_dir, "config.ini")
"main": "out/main.js",
}, if not os.path.exists(config_file):
"Windows": { raise OSError(translator.get('reset.config_not_found') if translator else "找不到配置文件")
"base": os.path.join(
os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app" config.read(config_file)
),
"package": "package.json", # 根據系統獲取路徑
"main": "out/main.js", if system == "Darwin":
}, section = 'MacPaths'
"Linux": { elif system == "Windows":
"bases": ["/opt/Cursor/resources/app", "/usr/share/cursor/resources/app"], section = 'WindowsPaths'
"package": "package.json", elif system == "Linux":
"main": "out/main.js", section = 'LinuxPaths'
}, else:
}
if system not in paths_map:
raise OSError(translator.get('reset.unsupported_os', system=system) if translator else f"不支持的操作系统: {system}") raise OSError(translator.get('reset.unsupported_os', system=system) if translator else f"不支持的操作系统: {system}")
if system == "Linux": if not config.has_section(section) or not config.has_option(section, 'cursor_path'):
for base in paths_map["Linux"]["bases"]: raise OSError(translator.get('reset.path_not_configured') if translator else "未配置 Cursor 路徑")
pkg_path = os.path.join(base, paths_map["Linux"]["package"])
if os.path.exists(pkg_path): base_path = config.get(section, 'cursor_path')
return (pkg_path, os.path.join(base, paths_map["Linux"]["main"]))
raise OSError(translator.get('reset.linux_path_not_found') if translator else "在 Linux 系统上未找到 Cursor 安装路径") if not os.path.exists(base_path):
raise OSError(translator.get('reset.path_not_found', path=base_path) if translator else f"找不到 Cursor 路徑: {base_path}")
base_path = paths_map[system]["base"]
return ( pkg_path = os.path.join(base_path, "package.json")
os.path.join(base_path, paths_map[system]["package"]), main_path = os.path.join(base_path, "out/main.js")
os.path.join(base_path, paths_map[system]["main"]),
) # 檢查文件是否存在
if not os.path.exists(pkg_path):
raise OSError(translator.get('reset.package_not_found', path=pkg_path) if translator else f"找不到 package.json: {pkg_path}")
if not os.path.exists(main_path):
raise OSError(translator.get('reset.main_not_found', path=main_path) if translator else f"找不到 main.js: {main_path}")
return (pkg_path, main_path)
def get_cursor_machine_id_path(translator=None) -> str: def get_cursor_machine_id_path(translator=None) -> str:
""" """
@ -176,11 +180,60 @@ def check_cursor_version(translator) -> bool:
"""Check Cursor version""" """Check Cursor version"""
try: try:
pkg_path, _ = get_cursor_paths(translator) pkg_path, _ = get_cursor_paths(translator)
with open(pkg_path, "r", encoding="utf-8") as f: print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.reading_package_json', path=pkg_path)}{Style.RESET_ALL}")
version = json.load(f)["version"]
return version_check(version, min_version="0.45.0", translator=translator) try:
with open(pkg_path, "r", encoding="utf-8") as f:
data = json.load(f)
except UnicodeDecodeError:
# 如果 UTF-8 讀取失敗,嘗試其他編碼
with open(pkg_path, "r", encoding="latin-1") as f:
data = json.load(f)
if not isinstance(data, dict):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_json_object')}{Style.RESET_ALL}")
return False
if "version" not in data:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.no_version_field')}{Style.RESET_ALL}")
return False
version = str(data["version"]).strip()
if not version:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_field_empty')}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.found_version', version=version)}{Style.RESET_ALL}")
# 檢查版本格式
if not re.match(r"^\d+\.\d+\.\d+$", version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_version_format', version=version)}{Style.RESET_ALL}")
return False
# 比較版本
try:
current = tuple(map(int, version.split(".")))
min_ver = (0, 45, 0) # 直接使用元組而不是字符串
if current >= min_ver:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.version_check_passed', version=version, min_version='0.45.0')}{Style.RESET_ALL}")
return True
else:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('reset.version_too_low', version=version, min_version='0.45.0')}{Style.RESET_ALL}")
return False
except ValueError as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_parse_error', error=str(e))}{Style.RESET_ALL}")
return False
except FileNotFoundError as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.package_not_found', path=pkg_path)}{Style.RESET_ALL}")
return False
except json.JSONDecodeError as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_json_object')}{Style.RESET_ALL}")
return False
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('reset.stack_trace')}: {traceback.format_exc()}{Style.RESET_ALL}")
return False return False
def modify_workbench_js(file_path: str, translator=None) -> bool: def modify_workbench_js(file_path: str, translator=None) -> bool:
@ -576,12 +629,12 @@ class MachineIDResetter:
### Remove In v1.7.02 ### Remove In v1.7.02
# Check Cursor version and perform corresponding actions # Check Cursor version and perform corresponding actions
# greater_than_0_45 = check_cursor_version(self.translator) greater_than_0_45 = check_cursor_version(self.translator)
# if greater_than_0_45: if greater_than_0_45:
# print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}")
# patch_cursor_get_machine_id(self.translator) patch_cursor_get_machine_id(self.translator)
# else: else:
# print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}") print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")