11 Commits

Author SHA1 Message Date
huangzhenpc
10523de040 优化更新: 1. 修复版本显示和检查逻辑 2. 优化打包目录结构为两位版本号(3.4.4 -> 3.4) 2025-02-13 20:38:49 +08:00
huangzhenpc
dd0a307ff4 优化更新: 1. 隐藏命令行窗口弹出 2. 优化打包目录结构按版本号分类 3. 使用subprocess替代os.system 2025-02-13 18:19:06 +08:00
huangzhenpc
b5cbf0779b feat: 优化更新下载界面 v3.4.2 #patch - 1.优化下载进度对话框布局和样式 2.增大信息显示区域,提升可读性 3.美化进度条和状态显示 4.添加实时下载速度和剩余时间显示 5.更新版本截图 2025-02-13 16:27:25 +08:00
huangzhenpc
d81244c7e4 feat: 完善版本管理功能 1. 优化使用步骤说明的样式,调整行高和字体大小,提升可读性 2. 新增版本截图 3. 更新依赖包版本 4. 添加版本管理相关文件 2025-02-13 15:16:55 +08:00
huangzhenpc
e3b5820d8b 界面优化: 简化UI设计和布局 1. 界面布局优化 - 移除多余的框架,使用分隔线代替 - 统一输入框和文本框样式 - 优化整体边距和间距 2. 视觉效果改进 - 添加渐变背景 - 保留重要信息的视觉强调 - 简化界面层次结构 3. 其他改进 - 优化使用说明的显示效果 - 更新版本截图 2025-02-13 11:06:36 +08:00
huangzhenpc
4ee3ac066e 功能优化: 系统托盘与测试版本构建 1. 系统托盘功能增强 - 添加托盘右键菜单刷新重置功能 - 优化托盘图标显示和管理 - 改进最小化到托盘的处理逻辑 2. 测试版本构建系统 - 新增 testbuild.bat 测试版本构建脚本 - 实现测试版本号自动递增 - 配置测试版本专用输出目录 3. 其他优化 - 优化 SSL 警告全局处理 - 改进加载对话框显示逻辑 - 完善版本号管理机制 2025-02-13 10:44:58 +08:00
huangzhenpc
30aab5f9b2 优化: 1. 修复SSL警告问题 2. 优化加载对话框显示逻辑 3. 添加API测试工具 2025-02-13 10:13:22 +08:00
huangzhenpc
207c3c604e v3.3.9版本更新: 1.优化UI界面和按钮样式 2.改进使用说明文字,增加颜色标注 3.优化加载对话框样式 4.添加请求节流机制,防止重复提交 5.完善错误处理和提示信息 6.优化会员状态检查逻辑 7.改进禁用更新功能的实现 2025-02-12 21:15:58 +08:00
huangzhenpc
4e11deb530 优化界面提示:1. 统一所有提示框样式,使用自定义美观对话框 2. 添加复制按钮功能,方便用户操作 3. 优化未激活会员时的提示信息展示 2025-02-12 14:57:23 +08:00
huangzhenpc
4531f12c0d feat: 优化GUI界面和用户体验
1. 优化按钮样式和布局:增加按钮尺寸和内边距,使用不同颜色区分功能按钮,添加按钮悬停和点击效果,优化按钮间距和对齐方式

2. 添加会员状态检查:实现状态缓存机制减少API请求,添加状态自动更新定时器,根据剩余时间动态调整更新间隔

3. 改进加载提示:添加加载对话框组件,实现异步API请求机制,优化加载状态显示

4. 优化购买提示界面:美化提示框样式和排版,添加多个购买渠道信息,优化文本对齐和间距

5. 其他改进:修复tkinter相关打包问题,优化错误提示信息,改进日志记录,完善异常处理
2025-02-12 14:39:50 +08:00
huangzhenpc
e3058b9e39 feat: 完成PyQt5 GUI实现,支持系统托盘和图标显示
1. 实现了基于PyQt5的GUI界面 2. 添加系统托盘功能,支持最小化到托盘 3. 修复了图标显示问题,包括窗口图标和任务栏图标 4. 优化了打包配置,支持PyInstaller打包 5. 版本更新到v3.3.1
2025-02-12 14:18:08 +08:00
25 changed files with 2967 additions and 1429 deletions

4
.gitignore vendored
View File

@@ -17,4 +17,6 @@ venv/
env/
# Local development settings
.env
.env
testversion.txt

View File

@@ -50,9 +50,41 @@ class AccountSwitcher:
self.package_json = self.app_path / "package.json"
self.auth_manager = CursorAuthManager()
self.config = Config()
self.hardware_id = get_hardware_id()
self.hardware_id = self.get_hardware_id() # 先获取硬件ID
self.registry = CursorRegistry() # 添加注册表操作工具类
logging.info(f"初始化硬件ID: {self.hardware_id}")
def get_hardware_id(self) -> str:
"""获取硬件唯一标识"""
try:
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = None
if sys.platform == "win32":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 获取CPU信息
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
cpu_id = cpu_info.split('\n')[1].strip()
# 获取主板序列号
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
board_id = board_info.split('\n')[1].strip()
# 获取BIOS序列号
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
bios_id = bios_info.split('\n')[1].strip()
# 组合信息并生成哈希
combined = f"{cpu_id}:{board_id}:{bios_id}"
return hashlib.md5(combined.encode()).hexdigest()
except Exception as e:
logging.error(f"获取硬件ID失败: {str(e)}")
# 如果获取失败使用UUID作为备选方案
return str(uuid.uuid4())
def get_cursor_version(self) -> str:
"""获取Cursor版本号"""
try:
@@ -71,206 +103,143 @@ class AccountSwitcher:
import platform
import socket
import requests
import subprocess
# 获取操作系统信息
os_info = f"{platform.system()} {platform.version()}"
os_info = f"{platform.system()} {platform.release()}"
# 获取设备名称
device_name = platform.node()
# 获取地理位置(可选)
try:
ip_info = requests.get('https://ipapi.co/json/', timeout=5).json()
# 在Windows上使用wmic获取更详细的计算机名称
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
computer_info = subprocess.check_output('wmic computersystem get model', startupinfo=startupinfo).decode()
device_name = computer_info.split('\n')[1].strip()
else:
device_name = platform.node()
except:
device_name = platform.node()
# 获取IP地址
try:
ip_response = requests.get('https://api.ipify.org?format=json', timeout=5)
ip_address = ip_response.json()['ip']
except:
ip_address = "未知"
# 获取地理位置
try:
ip_info = requests.get(f'https://ipapi.co/{ip_address}/json/', timeout=5).json()
location = f"{ip_info.get('country_name', '')}-{ip_info.get('region', '')}-{ip_info.get('city', '')}"
except:
location = ""
location = "未知"
return {
"os": os_info,
"device_name": device_name,
"ip": ip_address,
"location": location
}
except Exception as e:
logging.error(f"获取设备信息失败: {str(e)}")
return {
"os": "Windows 10",
"os": "Windows",
"device_name": "未知设备",
"location": ""
"ip": "未知",
"location": "未知"
}
def check_activation_code(self, code: str) -> Tuple[bool, str, Optional[Dict]]:
"""验证激活码
def check_activation_code(self, code: str) -> tuple:
"""检查激活码
Args:
code: 激活码
Returns:
Tuple[bool, str, Optional[Dict]]: (是否成功, 提示消息, 账号信息)
tuple: (成功标志, 消息, 账号信息)
"""
try:
# 获取当前状态和历史记录
member_info = self.config.load_member_info()
activation_history = member_info.get("activation_records", []) if member_info else []
data = {
"machine_id": self.hardware_id,
"code": code
}
# 分割多个激活码
codes = [c.strip() for c in code.split(',')]
success_codes = []
failed_codes = []
activation_results = []
# 获取设备信息
device_info = self.get_device_info()
# 逐个验证激活码
for single_code in codes:
if not single_code:
continue
# 验证激活码
endpoint = "https://cursorapi.nosqli.com/admin/api.member/activate"
data = {
"code": single_code,
"machine_id": self.hardware_id,
"os": device_info["os"],
"device_name": device_info["device_name"],
"location": device_info["location"]
}
headers = {
"Content-Type": "application/json"
}
try:
response = requests.post(
endpoint,
json=data,
headers=headers,
timeout=10
)
response_data = response.json()
if response_data.get("code") == 200:
result_data = response_data.get("data", {})
logging.info(f"激活码 {single_code} 验证成功: {response_data.get('msg', '')}")
activation_results.append(result_data)
success_codes.append(single_code)
elif response_data.get("code") == 400:
error_msg = response_data.get("msg", "参数错误")
if "已被使用" in error_msg or "已激活" in error_msg:
logging.warning(f"激活码 {single_code} 已被使用")
failed_codes.append(f"{single_code} (已被使用)")
else:
logging.error(f"激活码 {single_code} 验证失败: {error_msg}")
failed_codes.append(f"{single_code} ({error_msg})")
elif response_data.get("code") == 500:
error_msg = response_data.get("msg", "系统错误")
logging.error(f"激活码 {single_code} 验证失败: {error_msg}")
failed_codes.append(f"{single_code} ({error_msg})")
else:
error_msg = response_data.get("msg", "未知错误")
logging.error(f"激活码 {single_code} 验证失败: {error_msg}")
failed_codes.append(f"{single_code} ({error_msg})")
except requests.RequestException as e:
logging.error(f"激活码 {single_code} 请求失败: {str(e)}")
failed_codes.append(f"{single_code} (网络请求失败)")
except Exception as e:
logging.error(f"激活码 {single_code} 处理失败: {str(e)}")
failed_codes.append(f"{single_code} (处理失败)")
if not success_codes:
failed_msg = "\n".join(failed_codes)
return False, f"激活失败:\n{failed_msg}", None
# 禁用SSL警告
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# 设置请求参数
request_kwargs = {
"json": data,
"headers": {"Content-Type": "application/json"},
"timeout": 5, # 减少超时时间从10秒到5秒
"verify": False # 禁用SSL验证
}
# 尝试发送请求
try:
# 使用最后一次激活的结果作为最终状态
final_result = activation_results[-1]
response = requests.post(
self.config.get_api_url("activate"),
**request_kwargs
)
except requests.exceptions.SSLError:
# 如果发生SSL错误创建自定义SSL上下文
import ssl
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# 合并历史记录
new_activation_records = final_result.get("activation_records", [])
if activation_history:
# 保留旧的激活记录,避免重复
existing_codes = {record.get("code") for record in activation_history}
for record in new_activation_records:
if record.get("code") not in existing_codes:
activation_history.append(record)
else:
activation_history = new_activation_records
# 保存会员信息,包含完整的历史记录
member_info = {
"hardware_id": final_result.get("machine_id", self.hardware_id),
"expire_time": final_result.get("expire_time", ""),
"days_left": final_result.get("days_left", 0),
"total_days": final_result.get("total_days", 0),
"status": final_result.get("status", "inactive"),
"device_info": final_result.get("device_info", device_info),
"activation_time": final_result.get("activation_time", ""),
"activation_records": activation_history # 使用合并后的历史记录
# 使用自定义SSL上下文重试请求
session = requests.Session()
session.verify = False
response = session.post(
self.config.get_api_url("activate"),
**request_kwargs
)
result = response.json()
# 激活成功
if result["code"] == 200:
api_data = result["data"]
# 构造标准的返回数据结构
account_info = {
"status": "active",
"expire_time": api_data.get("expire_time", ""),
"total_days": api_data.get("total_days", 0),
"days_left": api_data.get("days_left", 0),
"device_info": self.get_device_info()
}
self.config.save_member_info(member_info)
# 生成结果消息
message = f"激活成功\n"
# 显示每个成功激活码的信息
for i, result in enumerate(activation_results, 1):
message += f"\n{i}个激活码:\n"
message += f"- 新增天数: {result.get('added_days', 0)}\n"
activation_time = result.get('activation_time', '')
if activation_time:
try:
from datetime import datetime
dt = datetime.strptime(activation_time, "%Y-%m-%d %H:%M:%S")
activation_time = dt.strftime("%Y-%m-%d %H:%M:%S")
except:
pass
message += f"- 激活时间: {activation_time}\n"
message += f"\n最终状态:"
message += f"\n- 总天数: {final_result.get('total_days', 0)}"
message += f"\n- 剩余天数: {final_result.get('days_left', 0)}"
# 格式化到期时间显示
expire_time = final_result.get('expire_time', '')
if expire_time:
try:
dt = datetime.strptime(expire_time, "%Y-%m-%d %H:%M:%S")
expire_time = dt.strftime("%Y-%m-%d %H:%M:%S")
except:
pass
message += f"\n- 到期时间: {expire_time}"
# 显示完整的激活记录历史
message += "\n\n历史激活记录:"
for record in activation_history:
activation_time = record.get('activation_time', '')
if activation_time:
try:
dt = datetime.strptime(activation_time, "%Y-%m-%d %H:%M:%S")
activation_time = dt.strftime("%Y-%m-%d %H:%M:%S")
except:
pass
message += f"\n- 激活码: {record.get('code', '')}"
message += f"\n 天数: {record.get('days', 0)}"
message += f"\n 时间: {activation_time}\n"
if failed_codes:
message += f"\n\n以下激活码验证失败:\n" + "\n".join(failed_codes)
return True, message, member_info
except Exception as e:
logging.error(f"处理激活结果时出错: {str(e)}")
return False, f"处理激活结果时出错: {str(e)}", None
return True, result["msg"], account_info
# 激活码无效或已被使用
elif result["code"] == 400:
logging.warning(f"激活码无效或已被使用: {result.get('msg', '未知错误')}")
return False, result.get("msg", "激活码无效或已被使用"), None
# 其他错误情况
else:
logging.error(f"激活失败: {result.get('msg', '未知错误')}")
return False, result["msg"], None # 返回 None 而不是空的账号信息
except Exception as e:
logging.error(f"验证激活码时出错: {str(e)}")
return False, f"验证激活码时出错: {str(e)}", None
logging.error(f"激活失败: {str(e)}")
return False, f"激活失败: {str(e)}", None # 返回 None 而不是空的账号信息
def reset_machine_id(self) -> bool:
"""重置机器码"""
try:
# 1. 先关闭所有Cursor进程
if sys.platform == "win32":
os.system("taskkill /f /im Cursor.exe >nul 2>&1")
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 使用subprocess.run来执行命令并隐藏窗口
subprocess.run(
"taskkill /f /im Cursor.exe >nul 2>&1",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 2. 清理注册表(包括更新系统 MachineGuid
@@ -325,7 +294,17 @@ class AccountSwitcher:
try:
# 1. 先关闭所有Cursor进程
if sys.platform == "win32":
os.system("taskkill /f /im Cursor.exe >nul 2>&1")
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 关闭Cursor
subprocess.run(
"taskkill /f /im Cursor.exe >nul 2>&1",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 2. 重置机器码
@@ -356,93 +335,86 @@ class AccountSwitcher:
logging.error(f"激活过程出错: {str(e)}")
return False, f"激活失败: {str(e)}"
def get_member_status(self) -> Optional[Dict]:
def get_member_status(self) -> dict:
"""获取会员状态
Returns:
Optional[Dict]: 会员状态信息
dict: 会员状态信息,包含:
- status: 状态(active/inactive/expired)
- expire_time: 到期时间
- total_days: 总天数
- days_left: 剩余天数
- device_info: 设备信息
"""
try:
# 读取保存的会员信息
member_info = self.config.load_member_info()
# 构造状态检查请求
endpoint = "https://cursorapi.nosqli.com/admin/api.member/status"
data = {
"machine_id": self.hardware_id
}
headers = {
"Content-Type": "application/json"
api_url = self.config.get_api_url("status")
logging.info(f"正在检查会员状态...")
# 设置请求参数
request_kwargs = {
"json": data,
"headers": {"Content-Type": "application/json"},
"timeout": 2, # 减少超时时间到2秒
"verify": False
}
try:
response = requests.post(endpoint, json=data, headers=headers, timeout=10)
response_data = response.json()
if response_data.get("code") == 200:
# 正常状态
data = response_data.get("data", {})
status = data.get("status", "inactive")
# 构造会员信息
member_info = {
"hardware_id": data.get("machine_id", self.hardware_id),
"expire_time": data.get("expire_time", ""),
"days_left": data.get("days_left", 0), # 使用days_left
"total_days": data.get("total_days", 0), # 使用total_days
"status": status,
"activation_records": data.get("activation_records", []) # 保存激活记录
}
# 打印调试信息
logging.info(f"API返回数据: {data}")
logging.info(f"处理后的会员信息: {member_info}")
self.config.save_member_info(member_info)
return member_info
elif response_data.get("code") == 401:
# 未激活或已过期
logging.warning("会员未激活或已过期")
return self._get_inactive_status()
elif response_data.get("code") == 400:
# 参数错误
error_msg = response_data.get("msg", "参数错误")
logging.error(f"获取会员状态失败: {error_msg}")
return self._get_inactive_status()
elif response_data.get("code") == 500:
# 系统错误
error_msg = response_data.get("msg", "系统错误")
logging.error(f"获取会员状态失败: {error_msg}")
return self._get_inactive_status()
else:
# 其他未知错误
error_msg = response_data.get("msg", "未知错误")
logging.error(f"获取会员状态失败: {error_msg}")
return self._get_inactive_status()
except requests.RequestException as e:
logging.error(f"请求会员状态失败: {str(e)}")
return self._get_inactive_status()
except Exception as e:
logging.error(f"获取会员状态出错: {str(e)}")
return self._get_inactive_status()
# 使用session来复用连接
session = requests.Session()
session.verify = False
def _get_inactive_status(self) -> Dict:
"""获取未激活状态的默认信息"""
return {
"hardware_id": self.hardware_id,
"expire_time": "",
"days": 0,
"total_days": 0,
"status": "inactive",
"last_activation": {},
"activation_records": []
}
# 尝试发送请求
try:
response = session.post(api_url, **request_kwargs)
except requests.exceptions.Timeout:
# 超时后快速重试一次
logging.warning("首次请求超时,正在重试...")
response = session.post(api_url, **request_kwargs)
result = response.json()
logging.info(f"状态检查响应: {result}")
if result.get("code") in [1, 200]:
api_data = result.get("data", {})
return {
"status": api_data.get("status", "inactive"),
"expire_time": api_data.get("expire_time", ""),
"total_days": api_data.get("total_days", 0),
"days_left": api_data.get("days_left", 0),
"device_info": self.get_device_info()
}
else:
error_msg = result.get("msg", "未知错误")
logging.error(f"获取状态失败: {error_msg}")
return {
"status": "inactive",
"expire_time": "",
"total_days": 0,
"days_left": 0,
"device_info": self.get_device_info()
}
except requests.exceptions.RequestException as e:
logging.error(f"API请求失败: {str(e)}")
return {
"status": "inactive",
"expire_time": "",
"total_days": 0,
"days_left": 0,
"device_info": self.get_device_info()
}
except Exception as e:
logging.error(f"获取会员状态失败: {str(e)}")
return {
"status": "inactive",
"expire_time": "",
"total_days": 0,
"days_left": 0,
"device_info": self.get_device_info()
}
def restart_cursor(self) -> bool:
"""重启Cursor编辑器
@@ -454,9 +426,19 @@ class AccountSwitcher:
logging.info("正在重启Cursor...")
if sys.platform == "win32":
# Windows系统
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 关闭Cursor
os.system("taskkill /f /im Cursor.exe 2>nul")
subprocess.run(
"taskkill /f /im Cursor.exe 2>nul",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 获取Cursor安装路径
cursor_exe = self.cursor_path / "Cursor.exe"
if cursor_exe.exists():
@@ -469,16 +451,16 @@ class AccountSwitcher:
return False
elif sys.platform == "darwin":
# macOS系统
os.system("killall Cursor 2>/dev/null")
subprocess.run("killall Cursor 2>/dev/null", shell=True)
time.sleep(2)
os.system("open -a Cursor")
subprocess.run("open -a Cursor", shell=True)
logging.info("Cursor重启成功")
return True
elif sys.platform == "linux":
# Linux系统
os.system("pkill -f cursor")
subprocess.run("pkill -f cursor", shell=True)
time.sleep(2)
os.system("cursor &")
subprocess.run("cursor &", shell=True)
logging.info("Cursor重启成功")
return True
else:
@@ -495,12 +477,7 @@ class AccountSwitcher:
Tuple[bool, str]: (是否成功, 提示消息)
"""
try:
# 1. 先关闭所有Cursor进程
if sys.platform == "win32":
os.system("taskkill /f /im Cursor.exe >nul 2>&1")
time.sleep(2)
# 2. 获取未使用的账号
# 1. 获取未使用的账号
endpoint = "https://cursorapi.nosqli.com/admin/api.account/getUnused"
data = {
"machine_id": self.hardware_id
@@ -509,17 +486,33 @@ class AccountSwitcher:
"Content-Type": "application/json"
}
# 禁用SSL警告
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# 设置请求参数
request_kwargs = {
"json": data,
"headers": headers,
"timeout": 30, # 增加超时时间
"verify": False # 禁用SSL验证
}
try:
# 添加SSL验证选项和超时设置
response = requests.post(
endpoint,
json=data,
headers=headers,
timeout=30, # 增加超时时间
verify=False, # 禁用SSL验证
)
# 禁用SSL警告
requests.packages.urllib3.disable_warnings()
# 尝试发送请求
try:
response = requests.post(endpoint, **request_kwargs)
except requests.exceptions.SSLError:
# 如果发生SSL错误创建自定义SSL上下文
import ssl
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# 使用自定义SSL上下文重试请求
session = requests.Session()
session.verify = False
response = session.post(endpoint, **request_kwargs)
response_data = response.json()
@@ -536,11 +529,26 @@ class AccountSwitcher:
if not all([email, access_token, refresh_token]):
return False, "获取账号信息不完整"
# 2. 先关闭Cursor进程
if sys.platform == "win32":
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 使用subprocess.run来执行命令并隐藏窗口
subprocess.run(
"taskkill /f /im Cursor.exe >nul 2>&1",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 3. 更新Cursor认证信息
if not self.auth_manager.update_auth(email, access_token, refresh_token):
return False, "更新Cursor认证信息失败"
# 4. 重置机器码(包含了清理注册表、文件和重启操作
# 4. 重置机器码(使用现有的reset_machine_id方法
if not self.reset_machine_id():
return False, "重置机器码失败"
@@ -578,7 +586,17 @@ class AccountSwitcher:
try:
# 1. 先关闭所有Cursor进程
if sys.platform == "win32":
os.system("taskkill /f /im Cursor.exe >nul 2>&1")
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 关闭Cursor
subprocess.run(
"taskkill /f /im Cursor.exe >nul 2>&1",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 2. 删除updater目录并创建同名文件以阻止更新

View File

@@ -1,202 +0,0 @@
{
"package_json": {
"C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": {
"homepage": "https://cursor.so",
"author": {
"name": "Cursor AI, Inc.",
"email": "hiring@cursor.so"
},
"productName": "Cursor",
"description": "Cursor is an AI-first coding environment.",
"main": "./out/main.js",
"dependencies": {
"@todesktop/runtime": "=1.6.1",
"@electron/asar": "^3.2.3",
"@anysphere/file-service": "0.0.0-73d604b6",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.5.0",
"@sentry/electron": "5.7.0",
"@sentry/node": "8.35.0",
"@types/semver": "^7.5.8",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/policy-watcher": "^1.1.8",
"@vscode/proxy-agent": "^0.27.0",
"@vscode/ripgrep": "^1.15.10",
"@vscode/spdlog": "^0.15.0",
"@vscode/sqlite3": "5.1.8-vscode",
"@vscode/sudo-prompt": "9.3.1",
"@vscode/tree-sitter-wasm": "^0.0.4",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-clipboard": "^0.2.0-beta.53",
"@xterm/addon-image": "^0.9.0-beta.70",
"@xterm/addon-ligatures": "^0.10.0-beta.70",
"@xterm/addon-search": "^0.16.0-beta.70",
"@xterm/addon-serialize": "^0.14.0-beta.70",
"@xterm/addon-unicode11": "^0.9.0-beta.70",
"@xterm/addon-webgl": "^0.19.0-beta.70",
"@xterm/headless": "^5.6.0-beta.70",
"@xterm/xterm": "^5.6.0-beta.70",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"jschardet": "3.1.4",
"kerberos": "2.1.1",
"minimist": "^1.2.6",
"multiformats": "^13.3.1",
"native-is-elevated": "0.7.0",
"native-keymap": "^3.3.5",
"native-watchdog": "^1.4.1",
"node-fetch": "2.7.0",
"node-pty": "1.1.0-beta22",
"open": "^8.4.2",
"tas-client-umd": "0.2.0",
"v8-inspect-profiler": "^0.1.1",
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "9.1.0",
"yauzl": "^3.0.0",
"yazl": "^2.4.3"
},
"name": "cursor",
"version": "0.45.11",
"type": "module",
"desktopName": "cursor-url-handler.desktop",
"overrides": {},
"tdBuildId": "250207y6nbaw5qc",
"email": "jrxqnsoz250264@nosqli.com",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc"
}
},
"storage_json": {
"telemetry.machineId": "758a7f7f7f79078f9f2c690514878ea3e8f064c0a49e837dd396db89df58429c",
"telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}",
"telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"backupWorkspaces": {
"workspaces": [],
"folders": [
{
"folderUri": "file:///d%3A/W/python/001cursro.app/interactive"
}
],
"emptyWindows": [
{
"backupFolder": "1739332115293"
}
]
},
"windowControlHeight": 35,
"profileAssociations": {
"workspaces": {
"file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__"
},
"emptyWindows": {
"1739332115293": "__default__profile__"
}
},
"theme": "vs-dark",
"themeBackground": "#1f1f1f",
"windowSplash": {
"zoomLevel": 0,
"baseTheme": "vs-dark",
"colorInfo": {
"foreground": "#cccccc",
"background": "#1f1f1f",
"editorBackground": "#1f1f1f",
"titleBarBackground": "#181818",
"titleBarBorder": "#2b2b2b",
"activityBarBackground": "#181818",
"activityBarBorder": "#2b2b2b",
"sideBarBackground": "#181818",
"sideBarBorder": "#2b2b2b",
"statusBarBackground": "#181818",
"statusBarBorder": "#2b2b2b",
"statusBarNoFolderBackground": "#1f1f1f"
},
"layoutInfo": {
"sideBarSide": "left",
"editorPartMinWidth": 220,
"titleBarHeight": 35,
"activityBarWidth": 0,
"sideBarWidth": 170,
"statusBarHeight": 22,
"windowBorder": false
}
}
},
"registry": {
"HKLM_MachineGuid": {
"exists": true,
"value": "776c6b6c-195f-42dc-94d6-72b70c3aca74"
},
"HKCU_cursor_shell": {
"exists": false,
"values": {}
},
"HKCU_cursor_command": {
"exists": false,
"values": {}
},
"HKCU_cursor_auth": {
"exists": false,
"values": {}
},
"HKCU_cursor_updates": {
"exists": false,
"values": {}
},
"HKCU_cursor_main": {
"exists": false,
"values": {}
}
},
"files": {
"storage": {
"exists": true,
"is_dir": false,
"size": 1891,
"modified_time": "2025-02-12T11:48:42.627574"
},
"storage_backup": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:48:26.403770"
},
"user_data": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"global_storage": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:48:47.490659"
},
"cache": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"updater": {
"exists": true,
"is_dir": false,
"size": 0,
"modified_time": "2025-02-10T17:19:39.071580"
}
},
"telemetry": {
"machineId": "758a7f7f7f79078f9f2c690514878ea3e8f064c0a49e837dd396db89df58429c",
"macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}"
}
}

View File

@@ -1,216 +0,0 @@
{
"package_json": {
"C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": {
"homepage": "https://cursor.so",
"author": {
"name": "Cursor AI, Inc.",
"email": "hiring@cursor.so"
},
"productName": "Cursor",
"description": "Cursor is an AI-first coding environment.",
"main": "./out/main.js",
"dependencies": {
"@todesktop/runtime": "=1.6.1",
"@electron/asar": "^3.2.3",
"@anysphere/file-service": "0.0.0-73d604b6",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.5.0",
"@sentry/electron": "5.7.0",
"@sentry/node": "8.35.0",
"@types/semver": "^7.5.8",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/policy-watcher": "^1.1.8",
"@vscode/proxy-agent": "^0.27.0",
"@vscode/ripgrep": "^1.15.10",
"@vscode/spdlog": "^0.15.0",
"@vscode/sqlite3": "5.1.8-vscode",
"@vscode/sudo-prompt": "9.3.1",
"@vscode/tree-sitter-wasm": "^0.0.4",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-clipboard": "^0.2.0-beta.53",
"@xterm/addon-image": "^0.9.0-beta.70",
"@xterm/addon-ligatures": "^0.10.0-beta.70",
"@xterm/addon-search": "^0.16.0-beta.70",
"@xterm/addon-serialize": "^0.14.0-beta.70",
"@xterm/addon-unicode11": "^0.9.0-beta.70",
"@xterm/addon-webgl": "^0.19.0-beta.70",
"@xterm/headless": "^5.6.0-beta.70",
"@xterm/xterm": "^5.6.0-beta.70",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"jschardet": "3.1.4",
"kerberos": "2.1.1",
"minimist": "^1.2.6",
"multiformats": "^13.3.1",
"native-is-elevated": "0.7.0",
"native-keymap": "^3.3.5",
"native-watchdog": "^1.4.1",
"node-fetch": "2.7.0",
"node-pty": "1.1.0-beta22",
"open": "^8.4.2",
"tas-client-umd": "0.2.0",
"v8-inspect-profiler": "^0.1.1",
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "9.1.0",
"yauzl": "^3.0.0",
"yazl": "^2.4.3"
},
"name": "cursor",
"version": "0.45.11",
"type": "module",
"desktopName": "cursor-url-handler.desktop",
"overrides": {},
"tdBuildId": "250207y6nbaw5qc",
"email": "jrxqnsoz250264@nosqli.com",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc",
"updateUrl": "",
"disableUpdate": true,
"enableNodeApiUncaughtExceptionPolicy": true,
"nodeOptions": [
"--force-node-api-uncaught-exceptions-policy=true"
]
}
},
"storage_json": {
"telemetry.machineId": "b0cbb2d13ca4c983be40d31e010819f16adb3d6083598f1457094837bdaa3def",
"telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}",
"telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"backupWorkspaces": {
"workspaces": [],
"folders": [
{
"folderUri": "file:///d%3A/W/python/001cursro.app/interactive"
}
],
"emptyWindows": []
},
"windowControlHeight": 35,
"profileAssociations": {
"workspaces": {
"file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__"
},
"emptyWindows": {}
},
"theme": "vs-dark",
"themeBackground": "#1f1f1f",
"windowSplash": {
"zoomLevel": 0,
"baseTheme": "vs-dark",
"colorInfo": {
"foreground": "#cccccc",
"background": "#1f1f1f",
"editorBackground": "#1f1f1f",
"titleBarBackground": "#181818",
"titleBarBorder": "#2b2b2b",
"activityBarBackground": "#181818",
"activityBarBorder": "#2b2b2b",
"sideBarBackground": "#181818",
"sideBarBorder": "#2b2b2b",
"statusBarBackground": "#181818",
"statusBarBorder": "#2b2b2b",
"statusBarNoFolderBackground": "#1f1f1f"
},
"layoutInfo": {
"sideBarSide": "left",
"editorPartMinWidth": 220,
"titleBarHeight": 35,
"activityBarWidth": 0,
"sideBarWidth": 300,
"statusBarHeight": 22,
"windowBorder": false
}
},
"windowsState": {
"lastActiveWindow": {
"folder": "file:///d%3A/W/python/001cursro.app/interactive",
"backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235",
"uiState": {
"mode": 0,
"x": 512,
"y": 192,
"width": 1024,
"height": 768
}
},
"openedWindows": []
}
},
"registry": {
"HKLM_MachineGuid": {
"exists": true,
"value": "1deb25e7-cdd4-4367-a347-fba8b33b9b03"
},
"HKCU_cursor_shell": {
"exists": false,
"values": {}
},
"HKCU_cursor_command": {
"exists": false,
"values": {}
},
"HKCU_cursor_auth": {
"exists": false,
"values": {}
},
"HKCU_cursor_updates": {
"exists": false,
"values": {}
},
"HKCU_cursor_main": {
"exists": false,
"values": {}
}
},
"files": {
"storage": {
"exists": true,
"is_dir": false,
"size": 1980,
"modified_time": "2025-02-12T12:37:17.428609"
},
"storage_backup": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T12:37:17.371311"
},
"user_data": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"global_storage": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T12:37:14.253083"
},
"cache": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"updater": {
"exists": true,
"is_dir": false,
"size": 0,
"modified_time": "2025-02-10T17:19:39.071580"
}
},
"telemetry": {
"machineId": "b0cbb2d13ca4c983be40d31e010819f16adb3d6083598f1457094837bdaa3def",
"macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}"
}
}

BIN
banbenjietu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -1,244 +0,0 @@
{
"package_json": {
"C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": {
"homepage": "https://cursor.so",
"author": {
"name": "Cursor AI, Inc.",
"email": "hiring@cursor.so"
},
"productName": "Cursor",
"description": "Cursor is an AI-first coding environment.",
"main": "./out/main.js",
"dependencies": {
"@todesktop/runtime": "=1.6.1",
"@electron/asar": "^3.2.3",
"@anysphere/file-service": "0.0.0-73d604b6",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.5.0",
"@sentry/electron": "5.7.0",
"@sentry/node": "8.35.0",
"@types/semver": "^7.5.8",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/policy-watcher": "^1.1.8",
"@vscode/proxy-agent": "^0.27.0",
"@vscode/ripgrep": "^1.15.10",
"@vscode/spdlog": "^0.15.0",
"@vscode/sqlite3": "5.1.8-vscode",
"@vscode/sudo-prompt": "9.3.1",
"@vscode/tree-sitter-wasm": "^0.0.4",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-clipboard": "^0.2.0-beta.53",
"@xterm/addon-image": "^0.9.0-beta.70",
"@xterm/addon-ligatures": "^0.10.0-beta.70",
"@xterm/addon-search": "^0.16.0-beta.70",
"@xterm/addon-serialize": "^0.14.0-beta.70",
"@xterm/addon-unicode11": "^0.9.0-beta.70",
"@xterm/addon-webgl": "^0.19.0-beta.70",
"@xterm/headless": "^5.6.0-beta.70",
"@xterm/xterm": "^5.6.0-beta.70",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"jschardet": "3.1.4",
"kerberos": "2.1.1",
"minimist": "^1.2.6",
"multiformats": "^13.3.1",
"native-is-elevated": "0.7.0",
"native-keymap": "^3.3.5",
"native-watchdog": "^1.4.1",
"node-fetch": "2.7.0",
"node-pty": "1.1.0-beta22",
"open": "^8.4.2",
"tas-client-umd": "0.2.0",
"v8-inspect-profiler": "^0.1.1",
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "9.1.0",
"yauzl": "^3.0.0",
"yazl": "^2.4.3"
},
"name": "cursor",
"version": "0.45.11",
"type": "module",
"desktopName": "cursor-url-handler.desktop",
"overrides": {},
"tdBuildId": "250207y6nbaw5qc",
"email": "jrxqnsoz250264@nosqli.com",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc"
}
},
"storage_json": {
"telemetry.machineId": "31b3701f1790cdb754bd8a02bad4913a9f8a3f04c9e19c519996be8c7b8cb561",
"telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}",
"telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"backupWorkspaces": {
"workspaces": [],
"folders": [
{
"folderUri": "file:///d%3A/W/python/001cursro.app/interactive"
},
{
"folderUri": "file:///d%3A/W/python/003cursorapiadmin"
}
],
"emptyWindows": [
{
"backupFolder": "1739329218500"
},
{
"backupFolder": "1739329245089"
}
]
},
"windowControlHeight": 35,
"profileAssociations": {
"workspaces": {
"file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__",
"file:///d%3A/W/python/003cursorapiadmin": "__default__profile__"
},
"emptyWindows": {}
},
"theme": "vs-dark",
"themeBackground": "#1f1f1f",
"windowSplash": {
"zoomLevel": 0,
"baseTheme": "vs-dark",
"colorInfo": {
"foreground": "#cccccc",
"background": "#1f1f1f",
"editorBackground": "#1f1f1f",
"titleBarBackground": "#181818",
"titleBarBorder": "#2b2b2b",
"activityBarBackground": "#181818",
"activityBarBorder": "#2b2b2b",
"sideBarBackground": "#181818",
"sideBarBorder": "#2b2b2b",
"statusBarBackground": "#181818",
"statusBarBorder": "#2b2b2b",
"statusBarNoFolderBackground": "#1f1f1f"
},
"layoutInfo": {
"sideBarSide": "left",
"editorPartMinWidth": 220,
"titleBarHeight": 35,
"activityBarWidth": 0,
"sideBarWidth": 170,
"statusBarHeight": 22,
"windowBorder": false
}
},
"windowsState": {
"lastActiveWindow": {
"folder": "file:///d%3A/W/python/001cursro.app/interactive",
"backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235",
"uiState": {
"mode": 0,
"x": 512,
"y": 192,
"width": 1024,
"height": 768
}
},
"openedWindows": [
{
"folder": "file:///d%3A/W/python/001cursro.app/interactive",
"backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235",
"uiState": {
"mode": 0,
"x": 512,
"y": 192,
"width": 1024,
"height": 768
}
},
{
"folder": "file:///d%3A/W/python/003cursorapiadmin",
"backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\b6b8cfb24ed2ddb05d90d45cce5443e7",
"uiState": {
"mode": 0,
"x": 512,
"y": 192,
"width": 1024,
"height": 768
}
}
]
}
},
"registry": {
"HKLM_MachineGuid": {
"exists": true,
"value": "d890ab3d-43cd-40c8-a9ef-f5683b5a64e3"
},
"HKCU_cursor_shell": {
"exists": false,
"values": {}
},
"HKCU_cursor_command": {
"exists": false,
"values": {}
},
"HKCU_cursor_auth": {
"exists": false,
"values": {}
},
"HKCU_cursor_updates": {
"exists": false,
"values": {}
},
"HKCU_cursor_main": {
"exists": false,
"values": {}
}
},
"files": {
"storage": {
"exists": true,
"is_dir": false,
"size": 3427,
"modified_time": "2025-02-12T11:40:57.046415"
},
"storage_backup": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:00:01.555876"
},
"user_data": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"global_storage": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:47:27.627883"
},
"cache": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"updater": {
"exists": true,
"is_dir": false,
"size": 0,
"modified_time": "2025-02-10T17:19:39.071580"
}
},
"telemetry": {
"machineId": "31b3701f1790cdb754bd8a02bad4913a9f8a3f04c9e19c519996be8c7b8cb561",
"macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}"
}
}

View File

@@ -1,216 +0,0 @@
{
"package_json": {
"C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": {
"homepage": "https://cursor.so",
"author": {
"name": "Cursor AI, Inc.",
"email": "hiring@cursor.so"
},
"productName": "Cursor",
"description": "Cursor is an AI-first coding environment.",
"main": "./out/main.js",
"dependencies": {
"@todesktop/runtime": "=1.6.1",
"@electron/asar": "^3.2.3",
"@anysphere/file-service": "0.0.0-73d604b6",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "2.5.0",
"@sentry/electron": "5.7.0",
"@sentry/node": "8.35.0",
"@types/semver": "^7.5.8",
"@vscode/deviceid": "^0.1.1",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/policy-watcher": "^1.1.8",
"@vscode/proxy-agent": "^0.27.0",
"@vscode/ripgrep": "^1.15.10",
"@vscode/spdlog": "^0.15.0",
"@vscode/sqlite3": "5.1.8-vscode",
"@vscode/sudo-prompt": "9.3.1",
"@vscode/tree-sitter-wasm": "^0.0.4",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.5.0",
"@vscode/windows-process-tree": "^0.6.0",
"@vscode/windows-registry": "^1.1.0",
"@xterm/addon-clipboard": "^0.2.0-beta.53",
"@xterm/addon-image": "^0.9.0-beta.70",
"@xterm/addon-ligatures": "^0.10.0-beta.70",
"@xterm/addon-search": "^0.16.0-beta.70",
"@xterm/addon-serialize": "^0.14.0-beta.70",
"@xterm/addon-unicode11": "^0.9.0-beta.70",
"@xterm/addon-webgl": "^0.19.0-beta.70",
"@xterm/headless": "^5.6.0-beta.70",
"@xterm/xterm": "^5.6.0-beta.70",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"jschardet": "3.1.4",
"kerberos": "2.1.1",
"minimist": "^1.2.6",
"multiformats": "^13.3.1",
"native-is-elevated": "0.7.0",
"native-keymap": "^3.3.5",
"native-watchdog": "^1.4.1",
"node-fetch": "2.7.0",
"node-pty": "1.1.0-beta22",
"open": "^8.4.2",
"tas-client-umd": "0.2.0",
"v8-inspect-profiler": "^0.1.1",
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "9.1.0",
"yauzl": "^3.0.0",
"yazl": "^2.4.3"
},
"name": "cursor",
"version": "0.45.11",
"type": "module",
"desktopName": "cursor-url-handler.desktop",
"overrides": {},
"tdBuildId": "250207y6nbaw5qc",
"email": "jrxqnsoz250264@nosqli.com",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc",
"updateUrl": "",
"disableUpdate": true,
"enableNodeApiUncaughtExceptionPolicy": true,
"nodeOptions": [
"--force-node-api-uncaught-exceptions-policy=true"
]
}
},
"storage_json": {
"telemetry.machineId": "9eb67b11924f32572a67e6480ce4f1cabf3f61503aa4918af506b259527a4745",
"telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}",
"telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"backupWorkspaces": {
"workspaces": [],
"folders": [
{
"folderUri": "file:///d%3A/W/python/001cursro.app/interactive"
}
],
"emptyWindows": []
},
"windowControlHeight": 35,
"profileAssociations": {
"workspaces": {
"file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__"
},
"emptyWindows": {}
},
"theme": "vs-dark",
"themeBackground": "#1f1f1f",
"windowSplash": {
"zoomLevel": 0,
"baseTheme": "vs-dark",
"colorInfo": {
"foreground": "#cccccc",
"background": "#1f1f1f",
"editorBackground": "#1f1f1f",
"titleBarBackground": "#181818",
"titleBarBorder": "#2b2b2b",
"activityBarBackground": "#181818",
"activityBarBorder": "#2b2b2b",
"sideBarBackground": "#181818",
"sideBarBorder": "#2b2b2b",
"statusBarBackground": "#181818",
"statusBarBorder": "#2b2b2b",
"statusBarNoFolderBackground": "#1f1f1f"
},
"layoutInfo": {
"sideBarSide": "left",
"editorPartMinWidth": 220,
"titleBarHeight": 35,
"activityBarWidth": 0,
"sideBarWidth": 300,
"statusBarHeight": 22,
"windowBorder": false
}
},
"windowsState": {
"lastActiveWindow": {
"folder": "file:///d%3A/W/python/001cursro.app/interactive",
"backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235",
"uiState": {
"mode": 0,
"x": 512,
"y": 192,
"width": 1024,
"height": 768
}
},
"openedWindows": []
}
},
"registry": {
"HKLM_MachineGuid": {
"exists": true,
"value": "948b93c1-ee34-4a48-95d0-a2fce9af92b1"
},
"HKCU_cursor_shell": {
"exists": false,
"values": {}
},
"HKCU_cursor_command": {
"exists": false,
"values": {}
},
"HKCU_cursor_auth": {
"exists": false,
"values": {}
},
"HKCU_cursor_updates": {
"exists": false,
"values": {}
},
"HKCU_cursor_main": {
"exists": false,
"values": {}
}
},
"files": {
"storage": {
"exists": true,
"is_dir": false,
"size": 2214,
"modified_time": "2025-02-12T12:36:27.187387"
},
"storage_backup": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T12:33:10.408749"
},
"user_data": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"global_storage": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T12:37:14.253083"
},
"cache": {
"exists": false,
"is_dir": null,
"size": null,
"modified_time": null
},
"updater": {
"exists": true,
"is_dir": false,
"size": 0,
"modified_time": "2025-02-10T17:19:39.071580"
}
},
"telemetry": {
"machineId": "9eb67b11924f32572a67e6480ce4f1cabf3f61503aa4918af506b259527a4745",
"macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e",
"devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05",
"sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}"
}
}

View File

@@ -5,8 +5,61 @@ echo 开始打包流程...
:: 更新版本号
python update_version.py
:: 读取版本号
set /p VERSION=<version.txt
echo 当前版本: %VERSION%
:: 提取主版本号和次版本号 (3.4.4 -> 3.4)
for /f "tokens=1,2 delims=." %%a in ("%VERSION%") do (
set MAJOR_VERSION=%%a.%%b
)
echo 主版本目录: %MAJOR_VERSION%
:: 创建版本目录
set VERSION_DIR=dist\%MAJOR_VERSION%
if not exist "%VERSION_DIR%" (
mkdir "%VERSION_DIR%"
echo 创建目录: %VERSION_DIR%
)
:: 使用新的spec文件进行打包
pyinstaller --noconfirm build_nezha.spec
:: 检查源文件是否存在
echo 检查文件: dist\听泉cursor助手%VERSION%.exe
if not exist "dist\听泉cursor助手%VERSION%.exe" (
echo 错误: 打包后的文件不存在
echo 预期文件路径: dist\听泉cursor助手%VERSION%.exe
dir /b dist
pause
exit /b 1
)
:: 检查目标目录是否存在
echo 检查目标目录: %VERSION_DIR%
if not exist "%VERSION_DIR%" (
echo 错误: 目标目录不存在
pause
exit /b 1
)
:: 移动文件到版本目录
echo 移动文件:
echo 源文件: dist\听泉cursor助手%VERSION%.exe
echo 目标文件: %VERSION_DIR%\听泉cursor助手v%VERSION%.exe
move "dist\听泉cursor助手%VERSION%.exe" "%VERSION_DIR%\听泉cursor助手v%VERSION%.exe"
if errorlevel 1 (
echo 移动文件失败,请检查:
echo 1. 源文件是否存在: dist\听泉cursor助手%VERSION%.exe
echo 2. 目标目录是否可写: %VERSION_DIR%
echo 3. 目标文件是否已存在: %VERSION_DIR%\听泉cursor助手v%VERSION%.exe
dir /b dist
dir /b "%VERSION_DIR%"
pause
exit /b 1
)
echo.
echo 打包完成!
echo 文件保存在: %VERSION_DIR%\听泉cursor助手v%VERSION%.exe
pause

View File

@@ -1,5 +1,7 @@
# -*- mode: python ; coding: utf-8 -*-
import os
import sys
from PyInstaller.utils.hooks import collect_all
def get_version():
with open('version.txt', 'r', encoding='utf-8') as f:
@@ -8,26 +10,43 @@ def get_version():
version = get_version()
# 收集所有需要的依赖
datas = [('icon', 'icon'), ('version.txt', '.')]
binaries = []
hiddenimports = [
'win32gui', 'win32con', 'win32process', 'psutil', # Windows API 相关
'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWidgets', # GUI 相关
'PyQt5.sip', # PyQt5 必需
'PyQt5.QtNetwork', # 网络相关
'PIL', # Pillow 相关
'PIL._imaging', # Pillow 核心
'requests', 'urllib3', 'certifi', # 网络请求相关
'json', 'uuid', 'hashlib', 'logging', # 基础功能相关
'importlib', # 导入相关
'pkg_resources', # 包资源
]
# 主要的分析对象
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[('icon', 'icon'), ('version.txt', '.')],
hiddenimports=[
'win32gui', 'win32con', 'win32process', 'psutil', # Windows API 相关
'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWidgets', # GUI 相关
'requests', 'urllib3', 'certifi', # 网络请求相关
'json', 'uuid', 'hashlib', 'logging' # 基础功能相关
],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
excludes=['_tkinter', 'tkinter', 'Tkinter'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
noarchive=False,
optimize=0,
module_collection_mode={'PyQt5': 'pyz+py'},
)
# 创建PYZ
pyz = PYZ(a.pure)
# 创建EXE
exe = EXE(
pyz,
a.scripts,

View File

@@ -5,6 +5,7 @@ import time
import logging
import sqlite3
from pathlib import Path
import subprocess
class CursorAuthManager:
"""Cursor认证信息管理器"""
@@ -99,9 +100,19 @@ class CursorAuthManager:
logging.info("正在重启Cursor...")
if sys.platform == "win32":
# Windows系统
# 创建startupinfo对象来隐藏命令行窗口
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
# 关闭Cursor
os.system("taskkill /f /im Cursor.exe 2>nul")
subprocess.run(
"taskkill /f /im Cursor.exe 2>nul",
startupinfo=startupinfo,
shell=True
)
time.sleep(2)
# 获取Cursor安装路径
cursor_exe = self.cursor_path / "Cursor.exe"
if cursor_exe.exists():
@@ -114,16 +125,16 @@ class CursorAuthManager:
return False
elif sys.platform == "darwin":
# macOS系统
os.system("killall Cursor 2>/dev/null")
subprocess.run("killall Cursor 2>/dev/null", shell=True)
time.sleep(2)
os.system("open -a Cursor")
subprocess.run("open -a Cursor", shell=True)
logging.info("Cursor重启成功")
return True
elif sys.platform == "linux":
# Linux系统
os.system("pkill -f cursor")
subprocess.run("pkill -f cursor", shell=True)
time.sleep(2)
os.system("cursor &")
subprocess.run("cursor &", shell=True)
logging.info("Cursor重启成功")
return True
else:

View File

@@ -1,59 +0,0 @@
{
"package_json_changes": {},
"registry_changes": {
"HKLM_MachineGuid": {
"before": {
"exists": true,
"value": "d890ab3d-43cd-40c8-a9ef-f5683b5a64e3"
},
"after": {
"exists": true,
"value": "776c6b6c-195f-42dc-94d6-72b70c3aca74"
}
}
},
"file_changes": {
"storage": {
"before": {
"exists": true,
"is_dir": false,
"size": 3427,
"modified_time": "2025-02-12T11:40:57.046415"
},
"after": {
"exists": true,
"is_dir": false,
"size": 1891,
"modified_time": "2025-02-12T11:48:42.627574"
}
},
"storage_backup": {
"before": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:00:01.555876"
},
"after": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:48:26.403770"
}
},
"global_storage": {
"before": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:47:27.627883"
},
"after": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:48:47.490659"
}
}
}
}

File diff suppressed because it is too large Load Diff

BIN
icon/logo1.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
icon/logo2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
icon/logo3.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

57
main.py
View File

@@ -5,10 +5,17 @@ import os
import atexit
import shutil
import tempfile
import urllib3
from pathlib import Path
from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtWidgets import QApplication, QMessageBox, QSystemTrayIcon, QMenu
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
from gui.main_window import MainWindow
# 禁用所有 SSL 相关警告
urllib3.disable_warnings()
logging.getLogger('urllib3').setLevel(logging.ERROR)
def cleanup_temp():
"""清理临时文件"""
try:
@@ -50,6 +57,18 @@ def main():
# 注册退出时的清理函数
atexit.register(cleanup_temp)
# 创建QApplication实例
app = QApplication(sys.argv)
# 检查系统托盘是否可用
if not QSystemTrayIcon.isSystemTrayAvailable():
logging.error("系统托盘不可用")
QMessageBox.critical(None, "错误", "系统托盘不可用,程序无法正常运行。")
return 1
# 设置应用程序不会在最后一个窗口关闭时退出
app.setQuitOnLastWindowClosed(False)
setup_logging()
# 检查Python版本
@@ -64,20 +83,46 @@ def main():
logging.info(f" - {p}")
logging.info("正在初始化主窗口...")
app = QApplication(sys.argv)
# 设置应用程序ID (在设置图标之前)
if sys.platform == "win32":
import ctypes
myappid = u'nezha.cursor.helper.v3'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
logging.info(f"设置应用程序ID: {myappid}")
# 设置应用程序图标
try:
icon_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "icon", "two.ico")
if os.path.exists(icon_path):
app_icon = QIcon(icon_path)
if not app_icon.isNull():
app.setWindowIcon(app_icon)
logging.info(f"成功设置应用程序图标: {icon_path}")
else:
logging.error("图标文件加载失败")
else:
logging.error(f"图标文件不存在: {icon_path}")
except Exception as e:
logging.error(f"设置应用程序图标失败: {str(e)}")
window = MainWindow()
window.setWindowIcon(app.windowIcon()) # 确保窗口使用相同的图标
logging.info("正在启动主窗口...")
window.show()
sys.exit(app.exec_())
return app.exec_()
except Exception as e:
error_msg = f"程序运行出错: {str(e)}\n{traceback.format_exc()}"
logging.error(error_msg)
# 使用 QMessageBox 显示错误
app = QApplication(sys.argv)
if QApplication.instance() is None:
app = QApplication(sys.argv)
QMessageBox.critical(None, "错误", error_msg)
sys.exit(1)
return 1
if __name__ == "__main__":
main()
sys.exit(main())

View File

@@ -1,4 +1,11 @@
# Use Tsinghua mirror for faster download in China:
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
requests==2.31.0
setuptools>=68.0.0
altgraph>=0.17.4
pyinstaller==6.3.0
pillow==10.2.0 # 用于处理图标
setuptools==65.5.1 # 解决pkg_resources.extern问题
pillow==10.2.0
PyQt5==5.15.10
pywin32==306
packaging>=23.2

View File

@@ -1,106 +0,0 @@
{
"github_changes": {
"package_json_changes": {},
"registry_changes": {
"HKLM_MachineGuid": {
"before": {
"exists": true,
"value": "d890ab3d-43cd-40c8-a9ef-f5683b5a64e3"
},
"after": {
"exists": true,
"value": "776c6b6c-195f-42dc-94d6-72b70c3aca74"
}
}
},
"file_changes": {
"storage": {
"before": {
"exists": true,
"is_dir": false,
"size": 3427,
"modified_time": "2025-02-12T11:40:57.046415"
},
"after": {
"exists": true,
"is_dir": false,
"size": 1891,
"modified_time": "2025-02-12T11:48:42.627574"
}
},
"storage_backup": {
"before": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:00:01.555876"
},
"after": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:48:26.403770"
}
},
"global_storage": {
"before": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:47:27.627883"
},
"after": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T11:48:47.490659"
}
}
}
},
"our_changes": {
"package_json_changes": {},
"registry_changes": {
"HKLM_MachineGuid": {
"before": {
"exists": true,
"value": "948b93c1-ee34-4a48-95d0-a2fce9af92b1"
},
"after": {
"exists": true,
"value": "1deb25e7-cdd4-4367-a347-fba8b33b9b03"
}
}
},
"file_changes": {
"storage_backup": {
"before": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T12:33:10.408749"
},
"after": {
"exists": true,
"is_dir": true,
"size": null,
"modified_time": "2025-02-12T12:37:17.371311"
}
},
"storage": {
"before": {
"exists": true,
"is_dir": false,
"size": 2214,
"modified_time": "2025-02-12T12:36:27.187387"
},
"after": {
"exists": true,
"is_dir": false,
"size": 1980,
"modified_time": "2025-02-12T12:37:17.428609"
}
}
}
}
}

63
test_version_manager.py Normal file
View File

@@ -0,0 +1,63 @@
import logging
import sys
from pathlib import Path
from utils.version_manager import VersionManager
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler('version_check.log')
]
)
def test_version_manager():
"""测试版本管理器功能"""
try:
vm = VersionManager()
logging.info(f"当前版本: {vm.current_version}")
logging.info(f"当前平台: {vm.platform}")
# 测试获取最新版本
logging.info("\n=== 测试获取最新版本 ===")
latest = vm.get_latest_version()
logging.info(f"最新版本信息: {latest}")
# 测试检查更新
logging.info("\n=== 测试检查更新 ===")
update_info = vm.check_update()
logging.info(f"更新检查结果: {update_info}")
# 测试是否需要更新
logging.info("\n=== 测试是否需要更新 ===")
has_update, is_force, version_info = vm.needs_update()
logging.info(f"是否有更新: {has_update}")
logging.info(f"是否强制更新: {is_force}")
logging.info(f"版本信息: {version_info}")
# 如果有更新,测试下载功能
if has_update and version_info:
logging.info("\n=== 测试下载更新 ===")
download_url = version_info.get('download_url')
if download_url:
save_path = Path.home() / "Downloads" / "CursorHelper" / "test_update.exe"
save_path.parent.mkdir(parents=True, exist_ok=True)
logging.info(f"下载地址: {download_url}")
logging.info(f"保存路径: {save_path}")
success = vm.download_update(download_url, str(save_path))
logging.info(f"下载结果: {'成功' if success else '失败'}")
if success:
logging.info(f"文件大小: {save_path.stat().st_size} 字节")
else:
logging.warning("未找到下载地址")
except Exception as e:
logging.error(f"测试过程中发生错误: {str(e)}", exc_info=True)
if __name__ == "__main__":
test_version_manager()

84
testbuild.bat Normal file
View File

@@ -0,0 +1,84 @@
@echo off
chcp 65001 >nul
setlocal EnableDelayedExpansion
REM 激活虚拟环境
call venv\Scripts\activate.bat
REM 确保安装了必要的包
pip install -r requirements.txt
REM 读取当前版本号
set /p VERSION=<version.txt
echo 当前正式版本: %VERSION%
REM 提取主版本号和次版本号 (3.4.4 -> 3.4)
for /f "tokens=1,2 delims=." %%a in ("%VERSION%") do (
set MAJOR_VERSION=%%a.%%b
)
echo 主版本目录: %MAJOR_VERSION%
REM 读取测试版本号(如果存在)
if exist testversion.txt (
set /p TEST_VERSION=<testversion.txt
) else (
set TEST_VERSION=0
)
REM 增加测试版本号
set /a TEST_VERSION+=1
echo !TEST_VERSION!>testversion.txt
echo 测试版本号: !TEST_VERSION!
REM 组合完整版本号
set FULL_VERSION=%VERSION%.!TEST_VERSION!
echo 完整版本号: !FULL_VERSION!
REM 创建测试版本输出目录
set TEST_DIR=dist\test\%MAJOR_VERSION%
if not exist "!TEST_DIR!" (
mkdir "!TEST_DIR!"
echo 创建目录: !TEST_DIR!
)
REM 清理旧文件
if exist "dist\听泉cursor助手%VERSION%.exe" del "dist\听泉cursor助手%VERSION%.exe"
if exist "build" rmdir /s /q "build"
REM 执行打包
venv\Scripts\python.exe -m PyInstaller build_nezha.spec --clean
REM 检查源文件是否存在
echo 检查文件: dist\听泉cursor助手%VERSION%.exe
if not exist "dist\听泉cursor助手%VERSION%.exe" (
echo 错误: 打包后的文件不存在
echo 预期文件路径: dist\听泉cursor助手%VERSION%.exe
dir /b dist
pause
exit /b 1
)
REM 移动并重命名文件
echo 移动文件:
echo 源文件: dist\听泉cursor助手%VERSION%.exe
echo 目标文件: !TEST_DIR!\听泉cursor助手v!FULL_VERSION!.exe
move "dist\听泉cursor助手%VERSION%.exe" "!TEST_DIR!\听泉cursor助手v!FULL_VERSION!.exe"
if errorlevel 1 (
echo 移动文件失败,请检查:
echo 1. 源文件是否存在: dist\听泉cursor助手%VERSION%.exe
echo 2. 目标目录是否可写: !TEST_DIR!
echo 3. 目标文件是否已存在: !TEST_DIR!\听泉cursor助手v!FULL_VERSION!.exe
dir /b dist
dir /b "!TEST_DIR!"
pause
exit /b 1
)
echo.
echo 测试版本构建完成!
echo 版本号: v!FULL_VERSION!
echo 文件位置: !TEST_DIR!\听泉cursor助手v!FULL_VERSION!.exe
REM 退出虚拟环境
deactivate
pause

View File

@@ -4,8 +4,15 @@ import logging
from pathlib import Path
class Config:
"""配置类"""
def __init__(self):
self.api_base_url = "https://cursorapi.nosqli.com/admin"
self.base_url = "https://cursorapi.nosqli.com"
self.api_endpoints = {
"activate": f"{self.base_url}/admin/api.member/activate",
"status": f"{self.base_url}/admin/api.member/status",
"get_unused": f"{self.base_url}/admin/api.account/getUnused"
}
self.config_dir = Path(os.path.expanduser("~")) / ".cursor_switcher"
self.config_file = self.config_dir / "config.json"
self.member_file = self.config_dir / "member.json"
@@ -64,4 +71,15 @@ class Config:
}
with open(self.config_file, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2, ensure_ascii=False)
self.api_token = api_token
self.api_token = api_token
def get_api_url(self, endpoint_name: str) -> str:
"""获取API端点URL
Args:
endpoint_name: 端点名称
Returns:
str: 完整的API URL
"""
return self.api_endpoints.get(endpoint_name, "")

303
utils/version_manager.py Normal file
View File

@@ -0,0 +1,303 @@
import os
import sys
import requests
from packaging import version
from typing import Optional, Dict, Any
import json
import logging
from urllib.parse import quote, unquote
from pathlib import Path
class VersionManager:
"""版本管理器
错误码说明:
- 0: 成功
- 1: 一般性错误
- 401: 未授权或授权失败
- 404: 请求的资源不存在
- 500: 服务器内部错误
"""
def __init__(self):
self.base_url = "https://cursorapi.nosqli.com"
# 获取项目根目录路径
self.root_path = Path(__file__).parent.parent
self.current_version = self._get_current_version()
self.platform = "windows" if sys.platform.startswith("win") else "mac" if sys.platform.startswith("darwin") else "linux"
def _get_current_version(self) -> str:
"""获取当前版本号"""
try:
version_file = self.root_path / "version.txt"
if not version_file.exists():
logging.error(f"版本文件不存在: {version_file}")
return "0.0.0"
with open(version_file, "r", encoding="utf-8") as f:
version = f.read().strip()
logging.info(f"当前版本: {version}")
return version
except Exception as e:
logging.error(f"读取版本号失败: {str(e)}")
return "0.0.0"
def _handle_response(self, response: requests.Response) -> Dict[str, Any]:
"""处理API响应
Args:
response: API响应对象
Returns:
Dict[str, Any]: 处理后的响应数据
Raises:
Exception: API调用失败时抛出异常
"""
try:
data = response.json()
code = data.get("code")
msg = data.get("msg") or data.get("info", "未知错误") # 兼容 info 字段
if code == 0 or code == 1: # 兼容 code=1 的情况
# 处理空数据情况
if not data.get("data"):
logging.warning("API返回空数据")
return {
"code": 0,
"msg": msg,
"data": {
"has_update": False,
"is_force": False,
"version_info": None
}
}
return {
"code": 0, # 统一返回 code=0
"msg": msg,
"data": data.get("data")
}
elif code == 401:
raise Exception("未授权或授权失败")
elif code == 404:
raise Exception("请求的资源不存在")
elif code == 500:
raise Exception("服务器内部错误")
else:
raise Exception(msg)
except requests.exceptions.JSONDecodeError:
raise Exception("服务器响应格式错误")
def check_update(self) -> Dict[str, Any]:
"""检查是否有更新"""
try:
url = f"{self.base_url}/admin/api.version/check"
current_version = self.current_version.lstrip('v') # 移除可能存在的v前缀
params = {
"version": current_version,
"platform": self.platform
}
logging.info(f"正在请求: {url}")
logging.info(f"参数: {params}")
response = requests.get(
url,
params=params,
timeout=10
)
logging.info(f"状态码: {response.status_code}")
logging.info(f"响应头: {dict(response.headers)}")
logging.info(f"响应内容: {response.text}")
result = self._handle_response(response)
# 确保返回的数据包含版本信息
if result["code"] == 0 and result.get("data"):
data = result["data"]
if "version_info" in data:
version_info = data["version_info"]
# 确保版本号格式一致
if "version_no" in version_info:
version_info["version_no"] = version_info["version_no"].lstrip('v')
return result
except requests.exceptions.Timeout:
logging.error("检查更新超时")
return {"code": -1, "msg": "请求超时,请检查网络连接", "data": None}
except requests.exceptions.ConnectionError as e:
logging.error(f"检查更新连接失败: {str(e)}")
return {"code": -1, "msg": "连接服务器失败,请检查网络连接", "data": None}
except Exception as e:
logging.error(f"检查更新失败: {str(e)}")
return {"code": -1, "msg": str(e), "data": None}
def get_latest_version(self) -> Dict[str, Any]:
"""获取最新版本信息"""
try:
url = f"{self.base_url}/admin/api.version/latest"
params = {"platform": self.platform}
logging.info(f"正在请求: {url}")
logging.info(f"参数: {params}")
response = requests.get(
url,
params=params,
timeout=10
)
logging.info(f"状态码: {response.status_code}")
logging.info(f"响应头: {dict(response.headers)}")
logging.info(f"响应内容: {response.text}")
return self._handle_response(response)
except requests.exceptions.Timeout:
logging.error("获取最新版本超时")
return {"code": -1, "msg": "请求超时,请检查网络连接", "data": None}
except requests.exceptions.ConnectionError as e:
logging.error(f"获取最新版本连接失败: {str(e)}")
return {"code": -1, "msg": "连接服务器失败,请检查网络连接", "data": None}
except Exception as e:
logging.error(f"获取最新版本失败: {str(e)}")
return {"code": -1, "msg": str(e), "data": None}
def needs_update(self) -> tuple[bool, bool, Optional[Dict[str, Any]]]:
"""检查是否需要更新
Returns:
tuple: (是否有更新, 是否强制更新, 版本信息)
"""
try:
result = self.check_update()
if result["code"] == 0 and result["data"]:
data = result["data"]
version_info = data.get("version_info", {})
# 比较版本号(移除v前缀)
current = self.current_version.lstrip('v')
latest = version_info.get("version_no", "0.0.0").lstrip('v')
# 使用packaging.version进行版本比较
has_update = version.parse(latest) > version.parse(current)
return (
has_update,
bool(data.get("is_force")),
version_info
)
return False, False, None
except Exception as e:
logging.error(f"检查更新失败: {str(e)}")
return False, False, None
def download_update(self, download_url: str, save_path: str) -> tuple[bool, str]:
"""下载更新文件
Args:
download_url: 下载地址
save_path: 保存路径
Returns:
tuple[bool, str]: (是否下载成功, 错误信息)
"""
try:
if not download_url:
error_msg = "下载地址为空,请联系管理员"
logging.error(error_msg)
return False, error_msg
# 处理下载地址中的中文字符
url_parts = download_url.split('/')
# 只对最后一部分(文件名)进行编码
url_parts[-1] = quote(url_parts[-1])
encoded_url = '/'.join(url_parts)
logging.info(f"原始下载地址: {download_url}")
logging.info(f"编码后的地址: {encoded_url}")
# 设置请求头,模拟浏览器行为
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive'
}
response = requests.get(
encoded_url,
stream=True,
headers=headers,
timeout=30 # 增加下载超时时间
)
# 检查响应状态
if response.status_code == 404:
error_msg = "下载地址无效,请联系管理员更新下载地址"
logging.error(error_msg)
return False, error_msg
response.raise_for_status()
total_size = int(response.headers.get('content-length', 0))
if total_size == 0:
error_msg = "无法获取文件大小,下载地址可能无效,请联系管理员"
logging.error(error_msg)
return False, error_msg
block_size = 8192
downloaded_size = 0
logging.info(f"开始下载文件,总大小: {total_size} 字节")
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=block_size):
if chunk:
f.write(chunk)
downloaded_size += len(chunk)
# 打印下载进度
if total_size > 0:
progress = (downloaded_size / total_size) * 100
logging.info(f"下载进度: {progress:.2f}%")
# 验证文件大小
actual_size = os.path.getsize(save_path)
if actual_size != total_size:
error_msg = f"文件下载不完整: 预期{total_size}字节,实际{actual_size}字节,请重试或联系管理员"
logging.error(error_msg)
# 删除不完整文件
try:
os.remove(save_path)
logging.info(f"已删除不完整的下载文件: {save_path}")
except Exception as clean_e:
logging.error(f"清理不完整文件失败: {str(clean_e)}")
return False, error_msg
logging.info(f"文件下载完成: {save_path}")
return True, "下载成功"
except requests.exceptions.Timeout:
error_msg = "下载超时,请检查网络连接后重试"
logging.error(error_msg)
return False, error_msg
except requests.exceptions.ConnectionError as e:
error_msg = "下载连接失败,请检查网络连接后重试"
logging.error(f"{error_msg}: {str(e)}")
return False, error_msg
except requests.exceptions.HTTPError as e:
error_msg = f"下载地址无效或服务器错误,请联系管理员 (HTTP {e.response.status_code})"
logging.error(error_msg)
return False, error_msg
except Exception as e:
error_msg = f"下载失败,请联系管理员: {str(e)}"
logging.error(error_msg)
# 如果下载失败,删除可能存在的不完整文件
try:
if os.path.exists(save_path):
os.remove(save_path)
logging.info(f"已删除不完整的下载文件: {save_path}")
except Exception as clean_e:
logging.error(f"清理不完整文件失败: {str(clean_e)}")
return False, error_msg

View File

@@ -1 +1 @@
3.2.8
3.4.5

127
version_check.log Normal file
View File

@@ -0,0 +1,127 @@
2025-02-13 13:30:48,255 - INFO - <20><>ǰ<EFBFBD>汾: 3.4.1
2025-02-13 13:30:48,255 - INFO - <20><>ǰƽ̨: windows
2025-02-13 13:30:48,255 - INFO -
=== <20><><EFBFBD>Ի<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>°汾 ===
2025-02-13 13:30:49,989 - INFO - <20><><EFBFBD>°汾<C2B0><E6B1BE>Ϣ: {'code': 0, 'info': '<27><><EFBFBD>ް汾<DEB0><E6B1BE>Ϣ', 'data': {}}
2025-02-13 13:30:49,989 - INFO -
=== <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
2025-02-13 13:30:51,712 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:30:51,713 - INFO - <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:30:51,713 - INFO -
=== <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> ===
2025-02-13 13:30:53,394 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:30:53,395 - INFO - <20>Ƿ<EFBFBD><C7B7>и<EFBFBD><D0B8><EFBFBD>: False
2025-02-13 13:30:53,395 - INFO - <20>Ƿ<EFBFBD>ǿ<EFBFBD>Ƹ<EFBFBD><C6B8><EFBFBD>: False
2025-02-13 13:30:53,395 - INFO - <20><EFBFBD><E6B1BE>Ϣ: None
2025-02-13 13:49:13,952 - INFO - <20><>ǰ<EFBFBD>汾: 3.4.1
2025-02-13 13:49:13,952 - INFO - <20><>ǰƽ̨: windows
2025-02-13 13:49:13,952 - INFO -
=== <20><><EFBFBD>Ի<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>°汾 ===
2025-02-13 13:49:15,718 - ERROR - <20><>ȡ<EFBFBD><C8A1><EFBFBD>°汾ʧ<E6B1BE><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:49:15,720 - INFO - <20><><EFBFBD>°汾<C2B0><E6B1BE>Ϣ: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:49:15,720 - INFO -
=== <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
2025-02-13 13:49:17,452 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:49:17,454 - INFO - <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:49:17,454 - INFO -
=== <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> ===
2025-02-13 13:49:19,277 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:49:19,278 - INFO - <20>Ƿ<EFBFBD><C7B7>и<EFBFBD><D0B8><EFBFBD>: False
2025-02-13 13:49:19,278 - INFO - <20>Ƿ<EFBFBD>ǿ<EFBFBD>Ƹ<EFBFBD><C6B8><EFBFBD>: False
2025-02-13 13:49:19,278 - INFO - <20><EFBFBD><E6B1BE>Ϣ: None
2025-02-13 13:53:02,577 - INFO - <20><>ǰ<EFBFBD>汾: 3.4.1
2025-02-13 13:53:02,577 - INFO - <20><>ǰƽ̨: windows
2025-02-13 13:53:02,577 - INFO -
=== <20><><EFBFBD>Ի<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>°汾 ===
2025-02-13 13:53:02,578 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/latest
2025-02-13 13:53:02,578 - INFO - <20><><EFBFBD><EFBFBD>: {'platform': 'windows'}
2025-02-13 13:53:04,292 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:53:04,292 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:53:02 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=c6053c5e6170796bf1c5dde92415b981; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:53:04,292 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><>ȡ<EFBFBD>ɹ<EFBFBD>","data":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}
2025-02-13 13:53:04,292 - ERROR - <20><>ȡ<EFBFBD><C8A1><EFBFBD>°汾ʧ<E6B1BE><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:53:04,294 - INFO - <20><><EFBFBD>°汾<C2B0><E6B1BE>Ϣ: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:53:04,294 - INFO -
=== <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
2025-02-13 13:53:04,294 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/check
2025-02-13 13:53:04,294 - INFO - <20><><EFBFBD><EFBFBD>: {'version': '3.4.1', 'platform': 'windows'}
2025-02-13 13:53:06,028 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:53:06,028 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:53:04 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=cbb7943860ca50662d842719c53e7c73; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:53:06,028 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","data":{"has_update":true,"is_force":0,"version_info":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}}
2025-02-13 13:53:06,028 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:53:06,029 - INFO - <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:53:06,029 - INFO -
=== <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> ===
2025-02-13 13:53:06,029 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/check
2025-02-13 13:53:06,029 - INFO - <20><><EFBFBD><EFBFBD>: {'version': '3.4.1', 'platform': 'windows'}
2025-02-13 13:53:07,770 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:53:07,770 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:53:05 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=c8004bac4b2d4c5054b69dca0311d6f7; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:53:07,770 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","data":{"has_update":true,"is_force":0,"version_info":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}}
2025-02-13 13:53:07,771 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:53:07,774 - INFO - <20>Ƿ<EFBFBD><C7B7>и<EFBFBD><D0B8><EFBFBD>: False
2025-02-13 13:53:07,774 - INFO - <20>Ƿ<EFBFBD>ǿ<EFBFBD>Ƹ<EFBFBD><C6B8><EFBFBD>: False
2025-02-13 13:53:07,774 - INFO - <20><EFBFBD><E6B1BE>Ϣ: None
2025-02-13 13:53:33,800 - INFO - <20><>ǰ<EFBFBD>汾: 3.4.1
2025-02-13 13:53:33,801 - INFO - <20><>ǰƽ̨: windows
2025-02-13 13:53:33,801 - INFO -
=== <20><><EFBFBD>Ի<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>°汾 ===
2025-02-13 13:53:33,801 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/latest
2025-02-13 13:53:33,801 - INFO - <20><><EFBFBD><EFBFBD>: {'platform': 'windows'}
2025-02-13 13:53:35,509 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:53:35,510 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:53:33 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=16d07427624c6aaf6c89254d173fe273; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:53:35,510 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><>ȡ<EFBFBD>ɹ<EFBFBD>","data":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}
2025-02-13 13:53:35,510 - ERROR - <20><>ȡ<EFBFBD><C8A1><EFBFBD>°汾ʧ<E6B1BE><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:53:35,513 - INFO - <20><><EFBFBD>°汾<C2B0><E6B1BE>Ϣ: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:53:35,513 - INFO -
=== <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
2025-02-13 13:53:35,513 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/check
2025-02-13 13:53:35,513 - INFO - <20><><EFBFBD><EFBFBD>: {'version': '3.4.1', 'platform': 'windows'}
2025-02-13 13:53:37,280 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:53:37,281 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:53:35 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=489a85b5766d7a30c4ba9dccda6f4967; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:53:37,281 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","data":{"has_update":true,"is_force":0,"version_info":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}}
2025-02-13 13:53:37,281 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:53:37,283 - INFO - <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {'code': -1, 'msg': 'δ֪<CEB4><D6AA><EFBFBD><EFBFBD>', 'data': None}
2025-02-13 13:53:37,283 - INFO -
=== <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> ===
2025-02-13 13:53:37,283 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/check
2025-02-13 13:53:37,284 - INFO - <20><><EFBFBD><EFBFBD>: {'version': '3.4.1', 'platform': 'windows'}
2025-02-13 13:53:39,003 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:53:39,003 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:53:37 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=b3619976145458f7ffd03d0438958a73; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:53:39,004 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","data":{"has_update":true,"is_force":0,"version_info":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}}
2025-02-13 13:53:39,004 - ERROR - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
2025-02-13 13:53:39,005 - INFO - <20>Ƿ<EFBFBD><C7B7>и<EFBFBD><D0B8><EFBFBD>: False
2025-02-13 13:53:39,005 - INFO - <20>Ƿ<EFBFBD>ǿ<EFBFBD>Ƹ<EFBFBD><C6B8><EFBFBD>: False
2025-02-13 13:53:39,005 - INFO - <20><EFBFBD><E6B1BE>Ϣ: None
2025-02-13 13:54:24,914 - INFO - <20><>ǰ<EFBFBD>汾: 3.4.1
2025-02-13 13:54:24,915 - INFO - <20><>ǰƽ̨: windows
2025-02-13 13:54:24,915 - INFO -
=== <20><><EFBFBD>Ի<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>°汾 ===
2025-02-13 13:54:24,915 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/latest
2025-02-13 13:54:24,915 - INFO - <20><><EFBFBD><EFBFBD>: {'platform': 'windows'}
2025-02-13 13:54:26,652 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:54:26,652 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:54:24 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=fc779e7ca81172e81a4d03cab86876a1; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:54:26,652 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><>ȡ<EFBFBD>ɹ<EFBFBD>","data":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}
2025-02-13 13:54:26,654 - INFO - <20><><EFBFBD>°汾<C2B0><E6B1BE>Ϣ: {'code': 0, 'msg': '<27><>ȡ<EFBFBD>ɹ<EFBFBD>', 'data': {'id': 1, 'version_no': '3.4.1.4', 'version_name': 'cursor<6F><72><EFBFBD><EFBFBD>', 'download_url': 'https://cursorapi.nosqli.com/upload/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe', 'is_force': 0, 'min_version': '', 'platform': 'all', 'status': 1, 'description': '', 'create_time': '2025-02-13 13:32:35', 'update_time': '2025-02-13 13:32:35'}}
2025-02-13 13:54:26,654 - INFO -
=== <20><><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
2025-02-13 13:54:26,654 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/check
2025-02-13 13:54:26,654 - INFO - <20><><EFBFBD><EFBFBD>: {'version': '3.4.1', 'platform': 'windows'}
2025-02-13 13:54:28,445 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:54:28,445 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:54:26 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=f8a3f46919c8aaa4d8f34d361ea3386a; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:54:28,445 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","data":{"has_update":true,"is_force":0,"version_info":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}}
2025-02-13 13:54:28,447 - INFO - <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {'code': 0, 'msg': '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>', 'data': {'has_update': True, 'is_force': 0, 'version_info': {'id': 1, 'version_no': '3.4.1.4', 'version_name': 'cursor<6F><72><EFBFBD><EFBFBD>', 'download_url': 'https://cursorapi.nosqli.com/upload/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe', 'is_force': 0, 'min_version': '', 'platform': 'all', 'status': 1, 'description': '', 'create_time': '2025-02-13 13:32:35', 'update_time': '2025-02-13 13:32:35'}}}
2025-02-13 13:54:28,447 - INFO -
=== <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> ===
2025-02-13 13:54:28,447 - INFO - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: https://cursorapi.nosqli.com/admin/api.version/check
2025-02-13 13:54:28,447 - INFO - <20><><EFBFBD><EFBFBD>: {'version': '3.4.1', 'platform': 'windows'}
2025-02-13 13:54:30,144 - INFO - ״̬<D7B4><CCAC>: 200
2025-02-13 13:54:30,145 - INFO - <20><>Ӧͷ: {'Server': 'nginx', 'Date': 'Thu, 13 Feb 2025 05:54:28 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'X-Frame-Options': 'sameorigin', 'Set-Cookie': 'ssid=169a8bdefde9a16f0e9f3e32da4d8ba5; path=/; secure; HttpOnly, lang=zh-cn; path=/; secure; HttpOnly', 'Strict-Transport-Security': 'max-age=31536000', 'Alt-Svc': 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"', 'Content-Encoding': 'gzip'}
2025-02-13 13:54:30,145 - INFO - <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>: {"code":1,"info":"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","data":{"has_update":true,"is_force":0,"version_info":{"id":1,"version_no":"3.4.1.4","version_name":"cursor<6F><72><EFBFBD><EFBFBD>","download_url":"https:\/\/cursorapi.nosqli.com\/upload\/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe","is_force":0,"min_version":"","platform":"all","status":1,"description":"","create_time":"2025-02-13 13:32:35","update_time":"2025-02-13 13:32:35"}}}
2025-02-13 13:54:30,146 - INFO - <20>Ƿ<EFBFBD><C7B7>и<EFBFBD><D0B8><EFBFBD>: True
2025-02-13 13:54:30,146 - INFO - <20>Ƿ<EFBFBD>ǿ<EFBFBD>Ƹ<EFBFBD><C6B8><EFBFBD>: False
2025-02-13 13:54:30,146 - INFO - <20><EFBFBD><E6B1BE>Ϣ: {'id': 1, 'version_no': '3.4.1.4', 'version_name': 'cursor<6F><72><EFBFBD><EFBFBD>', 'download_url': 'https://cursorapi.nosqli.com/upload/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe', 'is_force': 0, 'min_version': '', 'platform': 'all', 'status': 1, 'description': '', 'create_time': '2025-02-13 13:32:35', 'update_time': '2025-02-13 13:32:35'}
2025-02-13 13:54:30,146 - INFO -
=== <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD> ===
2025-02-13 13:54:30,148 - INFO - <20><><EFBFBD>ص<EFBFBD>ַ: https://cursorapi.nosqli.com/upload/<2F><>Ȫcursor<6F><72><EFBFBD><EFBFBD>v3.4.1.4.exe
2025-02-13 13:54:30,148 - INFO - <20><><EFBFBD><EFBFBD>·<EFBFBD><C2B7>: C:\Users\huangzhen\Downloads\CursorHelper\test_update.exe
2025-02-13 13:54:31,822 - ERROR - <20><><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>ʧ<EFBFBD><CAA7>: 404 Client Error: Not Found for url: https://cursorapi.nosqli.com/upload/%E5%90%AC%E6%B3%89cursor%E5%8A%A9%E6%89%8Bv3.4.1.4.exe
2025-02-13 13:54:31,823 - INFO - <20><><EFBFBD>ؽ<EFBFBD><D8BD><EFBFBD>: ʧ<><CAA7>

70
versioncheck.doc Normal file
View File

@@ -0,0 +1,70 @@
版本更新API文档
域名
base_url: https://cursorapi.nosqli.com
# 版本更新API文档
#
* 公共返回参数:
* - code: 错误码0表示成功非0表示失败
* - msg: 提示信息
* - data: 返回的数据,请求失败时可能为空
*
* 错误码说明:
* - 0: 成功
* - 1: 一般性错误(具体错误信息见msg)
* - 401: 未授权或授权失败
* - 404: 请求的资源不存在
* - 500: 服务器内部错误
*
* 版本号格式x.x.x (例如: 3.4.1)
* 平台类型:
* - all: 全平台
* - windows: Windows平台
* - mac: Mac平台
* - linux: Linux平台
* ====================================================
*
* 1. 获取最新版本 [GET] /admin/api.version/latest
* 请求参数:
* - platform: 平台类型(all|windows|mac|linux), 默认为all
* 返回数据:
* {
* "code": 0,
* "msg": "获取成功",
* "data": {
* "id": "1",
* "version_no": "3.4.1.4",
* "version_name": "听泉cursor助手",
* "download_url": "http://domain/upload/xxx.exe",
* "is_force": 1, // 是否强制更新(1是,0否)
* "min_version": "3.4.0.0", // 最低要求版本
* "platform": "all", // 平台类型
* "description": "版本描述", // 版本描述
* "status": 1, // 状态(1启用,0禁用)
* "create_time": "2024-03-20 10:00:00"
* }
* }
*
* 2. 检查版本更新 [GET] /admin/api.version/check
* 请求参数:
* - version: 当前版本号(必填)
* - platform: 平台类型(all|windows|mac|linux), 默认为all
* 返回数据:
* {
* "code": 0,
* "msg": "检查完成",
* "data": {
* "has_update": true, // 是否有更新
* "is_force": 1, // 是否强制更新
* "version_info": { // 新版本信息(has_update为true时返回)
* // 同上面的版本信息
* }
* }
* }
*
* 错误返回示例:
* {
* "code": 1,
* "msg": "请提供当前版本号",
* "data": null
* }