CursorPro 后台管理系统 v1.0
功能: - 激活码管理 (Pro/Auto 两种类型) - 账号池管理 - 设备绑定记录 - 使用日志 - 搜索/筛选功能 - 禁用/启用功能 (支持退款参考) - 全局设置 (换号间隔、额度消耗等) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
228
extension/LICENSE.txt
Normal file
228
extension/LICENSE.txt
Normal file
@@ -0,0 +1,228 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 CursorPro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
5
extension/media/icon.svg
Normal file
5
extension/media/icon.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
||||
<path d="M2 17l10 5 10-5"/>
|
||||
<path d="M2 12l10 5 10-5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 266 B |
1
extension/out/api/client.js
Normal file
1
extension/out/api/client.js
Normal file
File diff suppressed because one or more lines are too long
1
extension/out/extension.js
Normal file
1
extension/out/extension.js
Normal file
File diff suppressed because one or more lines are too long
1
extension/out/utils/account.js
Normal file
1
extension/out/utils/account.js
Normal file
File diff suppressed because one or more lines are too long
1
extension/out/utils/sqlite.js
Normal file
1
extension/out/utils/sqlite.js
Normal file
File diff suppressed because one or more lines are too long
1
extension/out/webview/provider.js
Normal file
1
extension/out/webview/provider.js
Normal file
File diff suppressed because one or more lines are too long
76
extension/package.json
Normal file
76
extension/package.json
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"name": "cursorpro",
|
||||
"displayName": "CursorPro",
|
||||
"description": "Cursor 账号管理与换号工具",
|
||||
"version": "0.4.5",
|
||||
"publisher": "cursorpro",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cursorpro/cursorpro-extension"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.80.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"extensionKind": [
|
||||
"ui"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onStartupFinished"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "cursorpro.showPanel",
|
||||
"title": "CursorPro: 打开控制面板"
|
||||
},
|
||||
{
|
||||
"command": "cursorpro.switchAccount",
|
||||
"title": "CursorPro: 立即换号"
|
||||
}
|
||||
],
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "cursorpro-sidebar",
|
||||
"title": "CursorPro",
|
||||
"icon": "media/icon.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"cursorpro-sidebar": [
|
||||
{
|
||||
"type": "webview",
|
||||
"id": "cursorpro.mainView",
|
||||
"name": "控制面板"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "CursorPro",
|
||||
"properties": {
|
||||
"cursorpro.cursorPath": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "手动设置 Cursor 安装路径(如果自动检测失败)。例如:C:\\Program Files\\cursor 或 /Applications/Cursor.app"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"watch": "tsc -watch -p ./",
|
||||
"lint": "eslint src --ext ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/vscode": "^1.80.0",
|
||||
"esbuild": "^0.27.0",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
280
extension/scripts/reset_cursor_macos.sh
Normal file
280
extension/scripts/reset_cursor_macos.sh
Normal file
@@ -0,0 +1,280 @@
|
||||
#!/bin/bash
|
||||
# ==============================================
|
||||
# CursorPro - macOS 机器码重置脚本
|
||||
# 一次授权,永久免密
|
||||
# 纯 Shell 实现,不依赖 Python
|
||||
# ==============================================
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 路径定义
|
||||
CURSOR_APP="/Applications/Cursor.app"
|
||||
CURSOR_OUT="$CURSOR_APP/Contents/Resources/app/out"
|
||||
MAIN_JS="$CURSOR_OUT/main.js"
|
||||
UUID_PLIST="/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist"
|
||||
|
||||
# 用户数据路径
|
||||
USER_HOME="$HOME"
|
||||
CURSOR_DATA="$USER_HOME/Library/Application Support/Cursor"
|
||||
STORAGE_JSON="$CURSOR_DATA/User/globalStorage/storage.json"
|
||||
STATE_VSCDB="$CURSOR_DATA/User/globalStorage/state.vscdb"
|
||||
MACHINEID_FILE="$CURSOR_DATA/machineid"
|
||||
|
||||
# 备份目录
|
||||
BACKUP_DIR="$USER_HOME/CursorPro_backups"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}======================================${NC}"
|
||||
echo -e "${BLUE} CursorPro macOS 机器码重置工具${NC}"
|
||||
echo -e "${BLUE}======================================${NC}"
|
||||
echo ""
|
||||
|
||||
# 检查 Cursor 是否安装
|
||||
if [ ! -d "$CURSOR_APP" ]; then
|
||||
echo -e "${RED}错误: 未找到 Cursor 应用${NC}"
|
||||
echo "请确保 Cursor 安装在 /Applications/Cursor.app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建备份目录
|
||||
mkdir -p "$BACKUP_DIR" 2>/dev/null
|
||||
|
||||
# ============================================
|
||||
# 第一步:检测并设置权限(一次性)
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 1/7] 检查权限...${NC}"
|
||||
|
||||
NEED_SUDO=false
|
||||
|
||||
# 检查 main.js 权限
|
||||
if [ ! -w "$MAIN_JS" ] 2>/dev/null; then
|
||||
NEED_SUDO=true
|
||||
echo " - main.js: 需要授权"
|
||||
else
|
||||
echo -e " - main.js: ${GREEN}已有权限${NC}"
|
||||
fi
|
||||
|
||||
# 检查 UUID plist 权限(文件可能不存在)
|
||||
if [ -f "$UUID_PLIST" ]; then
|
||||
if [ ! -w "$UUID_PLIST" ] 2>/dev/null; then
|
||||
NEED_SUDO=true
|
||||
echo " - UUID plist: 需要授权"
|
||||
else
|
||||
echo -e " - UUID plist: ${GREEN}已有权限${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e " - UUID plist: ${YELLOW}文件不存在,跳过${NC}"
|
||||
fi
|
||||
|
||||
# 如果需要授权
|
||||
if [ "$NEED_SUDO" = true ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}首次运行,需要管理员权限${NC}"
|
||||
echo -e "${YELLOW}授权后以后重置不再需要输入密码${NC}"
|
||||
echo ""
|
||||
|
||||
# 请求 sudo 权限
|
||||
sudo -v || { echo -e "${RED}授权失败${NC}"; exit 1; }
|
||||
|
||||
# 修改 Cursor 目录权限
|
||||
if [ ! -w "$MAIN_JS" ] 2>/dev/null; then
|
||||
echo " 正在修改 Cursor 目录权限..."
|
||||
sudo chown -R $(whoami) "$CURSOR_OUT" 2>/dev/null || true
|
||||
sudo chmod -R u+rw "$CURSOR_OUT" 2>/dev/null || true
|
||||
echo -e " ${GREEN}✓ Cursor 目录权限已修改${NC}"
|
||||
fi
|
||||
|
||||
# 修改 UUID plist 权限(如果文件存在)
|
||||
if [ -f "$UUID_PLIST" ] && [ ! -w "$UUID_PLIST" ] 2>/dev/null; then
|
||||
echo " 正在修改 UUID plist 权限..."
|
||||
sudo chown $(whoami) "$UUID_PLIST" 2>/dev/null || true
|
||||
echo -e " ${GREEN}✓ UUID plist 权限已修改${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 权限设置完成!以后重置不再需要密码${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# 第二步:关闭 Cursor
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 2/7] 关闭 Cursor...${NC}"
|
||||
|
||||
if pgrep -x "Cursor" > /dev/null; then
|
||||
killall Cursor 2>/dev/null || true
|
||||
echo " 等待 Cursor 完全退出..."
|
||||
sleep 3
|
||||
echo -e " ${GREEN}✓ Cursor 已关闭${NC}"
|
||||
else
|
||||
echo -e " ${GREEN}✓ Cursor 未运行${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# 第三步:Patch main.js
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 3/7] Patch main.js...${NC}"
|
||||
|
||||
if [ ! -f "$MAIN_JS" ]; then
|
||||
echo -e " ${RED}警告: 未找到 main.js${NC}"
|
||||
else
|
||||
# 检查是否已经 patch 过
|
||||
if grep -q 'uuidgen' "$MAIN_JS" 2>/dev/null; then
|
||||
echo -e " ${GREEN}✓ main.js 已经 Patch 过,跳过${NC}"
|
||||
else
|
||||
# 检查目标字符串
|
||||
if grep -q 'ioreg -rd1 -c IOPlatformExpertDevice' "$MAIN_JS"; then
|
||||
# 备份到用户目录
|
||||
BACKUP_FILE="$BACKUP_DIR/main.js.backup_$(date +%s)"
|
||||
cp "$MAIN_JS" "$BACKUP_FILE" 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo " 备份已创建: $BACKUP_FILE"
|
||||
fi
|
||||
|
||||
# 使用 perl 替换(macOS 自带,比 sed 更可靠处理特殊字符)
|
||||
perl -i -pe 's/ioreg -rd1 -c IOPlatformExpertDevice/UUID=\$(uuidgen | tr '"'"'[:upper:]'"'"' '"'"'[:lower:]'"'"');echo "IOPlatformUUID = "\$UUID";/g' "$MAIN_JS" 2>/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e " ${GREEN}✓ main.js Patch 成功${NC}"
|
||||
else
|
||||
echo -e " ${RED}✗ main.js Patch 失败${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e " ${YELLOW}警告: 未找到目标字符串,可能已 patch 或版本不兼容${NC}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# 第四步:重置系统 UUID
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 4/7] 重置系统 UUID...${NC}"
|
||||
|
||||
if [ ! -f "$UUID_PLIST" ]; then
|
||||
echo -e " ${YELLOW}提示: UUID plist 文件不存在,跳过${NC}"
|
||||
else
|
||||
NEW_SYS_UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
||||
/usr/libexec/PlistBuddy -c "Set :IOPlatformUUID $NEW_SYS_UUID" "$UUID_PLIST" 2>/dev/null || \
|
||||
/usr/libexec/PlistBuddy -c "Add :IOPlatformUUID string $NEW_SYS_UUID" "$UUID_PLIST" 2>/dev/null || true
|
||||
echo -e " ${GREEN}✓ 系统 UUID 已重置: $NEW_SYS_UUID${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# 第五步:重置 storage.json
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 5/7] 重置 storage.json...${NC}"
|
||||
|
||||
# 生成新的机器码(64位十六进制)
|
||||
NEW_MACHINE_ID=$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]')$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]')
|
||||
NEW_MAC_MACHINE_ID=$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]')$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]')
|
||||
NEW_DEV_DEVICE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
||||
NEW_SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
|
||||
|
||||
if [ -f "$STORAGE_JSON" ]; then
|
||||
# 备份
|
||||
cp "$STORAGE_JSON" "$BACKUP_DIR/storage.json.backup_$(date +%s)" 2>/dev/null
|
||||
|
||||
# 使用 sed 替换 JSON 中的值(macOS sed 语法)
|
||||
# machineId
|
||||
sed -i '' "s/\"telemetry\.machineId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.machineId\": \"$NEW_MACHINE_ID\"/g" "$STORAGE_JSON" 2>/dev/null
|
||||
|
||||
# macMachineId
|
||||
sed -i '' "s/\"telemetry\.macMachineId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.macMachineId\": \"$NEW_MAC_MACHINE_ID\"/g" "$STORAGE_JSON" 2>/dev/null
|
||||
|
||||
# devDeviceId
|
||||
sed -i '' "s/\"telemetry\.devDeviceId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.devDeviceId\": \"$NEW_DEV_DEVICE_ID\"/g" "$STORAGE_JSON" 2>/dev/null
|
||||
|
||||
# sqmId
|
||||
sed -i '' "s/\"telemetry\.sqmId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.sqmId\": \"$NEW_SQM_ID\"/g" "$STORAGE_JSON" 2>/dev/null
|
||||
|
||||
echo -e " ${GREEN}✓ storage.json 已更新 (4个ID)${NC}"
|
||||
else
|
||||
echo -e " ${YELLOW}警告: 未找到 storage.json${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# 第六步:重置 SQLite 数据库
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 6/7] 重置 SQLite 数据库...${NC}"
|
||||
|
||||
NEW_SERVICE_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
if [ -f "$STATE_VSCDB" ]; then
|
||||
# 备份
|
||||
cp "$STATE_VSCDB" "$BACKUP_DIR/state.vscdb.backup_$(date +%s)" 2>/dev/null
|
||||
|
||||
# 使用 sqlite3 命令(macOS 自带)
|
||||
sqlite3 "$STATE_VSCDB" "UPDATE ItemTable SET value = '$NEW_SERVICE_MACHINE_ID' WHERE key = 'storage.serviceMachineId';" 2>/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e " ${GREEN}✓ state.vscdb 已更新 (serviceMachineId)${NC}"
|
||||
else
|
||||
# 如果更新失败,尝试插入
|
||||
sqlite3 "$STATE_VSCDB" "INSERT OR REPLACE INTO ItemTable (key, value) VALUES ('storage.serviceMachineId', '$NEW_SERVICE_MACHINE_ID');" 2>/dev/null
|
||||
echo -e " ${GREEN}✓ state.vscdb 已更新${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e " ${YELLOW}警告: 未找到 state.vscdb${NC}"
|
||||
fi
|
||||
|
||||
# 更新 machineid 文件
|
||||
echo ""
|
||||
if [ -d "$(dirname "$MACHINEID_FILE")" ]; then
|
||||
echo "${NEW_MACHINE_ID:0:64}" > "$MACHINEID_FILE"
|
||||
echo -e " ${GREEN}✓ machineid 文件已更新${NC}"
|
||||
else
|
||||
echo -e " ${YELLOW}警告: 未找到 machineid 目录${NC}"
|
||||
fi
|
||||
|
||||
# 清理缓存
|
||||
rm -rf "$CURSOR_DATA/Cache" 2>/dev/null || true
|
||||
rm -rf "$CURSOR_DATA/CachedData" 2>/dev/null || true
|
||||
rm -rf "$CURSOR_DATA/GPUCache" 2>/dev/null || true
|
||||
echo -e " ${GREEN}✓ 缓存已清理${NC}"
|
||||
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# 第七步:重新打开 Cursor
|
||||
# ============================================
|
||||
echo -e "${YELLOW}[步骤 7/7] 重新打开 Cursor...${NC}"
|
||||
|
||||
sleep 1
|
||||
open "$CURSOR_APP"
|
||||
echo -e " ${GREEN}✓ Cursor 已启动${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}======================================${NC}"
|
||||
echo -e "${GREEN} ✅ 机器码重置完成!${NC}"
|
||||
echo -e "${GREEN}======================================${NC}"
|
||||
echo ""
|
||||
echo "已重置的内容:"
|
||||
echo " ✓ main.js (ioreg patch)"
|
||||
echo " ✓ storage.json (4个ID)"
|
||||
echo " ✓ state.vscdb (serviceMachineId)"
|
||||
echo " ✓ machineid 文件"
|
||||
echo " ✓ 缓存已清理"
|
||||
echo ""
|
||||
echo "新机器码信息:"
|
||||
echo " machineId: ${NEW_MACHINE_ID:0:32}..."
|
||||
echo " devDeviceId: $NEW_DEV_DEVICE_ID"
|
||||
echo " serviceMachineId: $NEW_SERVICE_MACHINE_ID"
|
||||
echo ""
|
||||
echo "备份位置: $BACKUP_DIR"
|
||||
echo ""
|
||||
echo -e "${BLUE}此窗口可以关闭${NC}"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user