Files
cursornew2026/deobfuscated_full/extension/out/webview/provider_cleaned.js

4307 lines
315 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
var __createBinding = this && this["__createBinding"] || (Object["create"] ? function (_0x426d51, _0x1fa101, _0xd56cbf, _0x584cf0) {
const _0x72e54d = {
'uKmJw': function (_0xdd80ed, _0x4bf4c4) {
return _0xdd80ed === _0x4bf4c4;
},
'TAoYL': function (_0x3d6ea4, _0x2c5cdc) {
return _0x3d6ea4 in _0x2c5cdc;
},
'aPyeo': "get"
};
if (_0x72e54d["uKmJw"](_0x584cf0, undefined)) {
_0x584cf0 = _0xd56cbf;
}
var _0x1907da = Object.getOwnPropertyDescriptor(_0x1fa101, _0xd56cbf);
if (!_0x1907da || (_0x72e54d.aPyeo in _0x1907da ? !_0x1fa101.__esModule : _0x1907da["writable"] || _0x1907da.configurable)) {
_0x1907da = {
'enumerable': true,
'get': function () {
return _0x1fa101[_0xd56cbf];
}
};
}
Object["defineProperty"](_0x426d51, _0x584cf0, _0x1907da);
} : function (_0x5f91d1, _0x9a02cb, _0x4b8c9f, _0x19d088) {
const _0x5f3f4d = {
'SeNEr': function (_0x5d446f, _0x23305b) {
return _0x5d446f === _0x23305b;
}
};
if (_0x5f3f4d["SeNEr"](_0x19d088, undefined)) {
_0x19d088 = _0x4b8c9f;
}
_0x5f91d1[_0x19d088] = _0x9a02cb[_0x4b8c9f];
});
var __setModuleDefault = this && this["__setModuleDefault"] || (Object["create"] ? function (_0x345a43, _0x11ae4c) {
const _0x4f212a = {
'FTXnn': "default"
};
Object["defineProperty"](_0x345a43, _0x4f212a.FTXnn, {
'enumerable': true,
'value': _0x11ae4c
});
} : function (_0x1d7e4a, _0x48365a) {
const _0x3780d5 = {
'kZOut': "default"
};
_0x1d7e4a[_0x3780d5["kZOut"]] = _0x48365a;
});
var __importStar = this && this.__importStar || function () {
const _0x4481b5 = {
'fsNNJ': function (_0x24a54e, _0x1bdb80) {
return _0x24a54e(_0x1bdb80);
},
'srHxh': '1|4|0|3|2',
'MoXZb': function (_0x3f36e7, _0x3a1c53) {
return _0x3f36e7 != _0x3a1c53;
},
'VqBsb': function (_0x32fe05, _0x1525ff) {
return _0x32fe05 < _0x1525ff;
},
'mymIw': function (_0x4a533c, _0x29a9b2) {
return _0x4a533c !== _0x29a9b2;
},
'zFOle': function (_0x3faee2, _0x31a6a7, _0x2bbca2, _0x53d668) {
return _0x3faee2(_0x31a6a7, _0x2bbca2, _0x53d668);
},
'zPdmk': function (_0x326a22, _0x578e64, _0x1ca450) {
return _0x326a22(_0x578e64, _0x1ca450);
}
};
var _0xb2a35b = function (_0x4d1aec) {
_0xb2a35b = Object["getOwnPropertyNames"] || function (_0x1a3c58) {
var _0x5ea703 = [];
for (var _0x185acc in _0x1a3c58) if (Object["prototype"]["hasOwnProperty"]["call"](_0x1a3c58, _0x185acc)) {
_0x5ea703[_0x5ea703["length"]] = _0x185acc;
}
return _0x5ea703;
};
return _0x4481b5["fsNNJ"](_0xb2a35b, _0x4d1aec);
};
return function (_0x31ac5f) {
const _0x3c765b = _0x4481b5["srHxh"]["split"]('|');
let _0x2fee3c = 0x0;
while (true) {
switch (_0x3c765b[_0x2fee3c++]) {
case '0':
if (_0x4481b5["MoXZb"](_0x31ac5f, null)) {
var _0x43241d = _0xb2a35b(_0x31ac5f);
for (var _0x27b692 = 0x0; _0x4481b5["VqBsb"](_0x27b692, _0x43241d["length"]); _0x27b692++) {
if (_0x4481b5["mymIw"](_0x43241d[_0x27b692], "default")) {
_0x4481b5["zFOle"](__createBinding, _0x23061d, _0x31ac5f, _0x43241d[_0x27b692]);
}
}
}
continue;
case '1':
if (_0x31ac5f && _0x31ac5f["__esModule"]) {
return _0x31ac5f;
}
continue;
case '2':
return _0x23061d;
case '3':
_0x4481b5["zPdmk"](__setModuleDefault, _0x23061d, _0x31ac5f);
continue;
case '4':
var _0x23061d = {};
continue;
}
break;
}
};
}();
Object["defineProperty"](exports, '__esModule', {
'value': true
});
exports.CursorProViewProvider = undefined;
const vscode = __importStar(require("vscode"));
const client_1 = require("../api/client");
const extension_1 = require("../extension");
const account_1 = require('../utils/account');
const path = __importStar(require("path"));
const fs = __importStar(require('fs'));
const child_process_1 = require('child_process');
const util_1 = require("util");
const sqlite_1 = require('../utils/sqlite');
0x0;
const execAsync = util_1["promisify"](child_process_1["exec"]);
class CursorProViewProvider {
constructor(_0x249e9c, _0x2abb89) {
const _0x22d112 = {
'dJwJk': "networkStatus",
'NNvQE': "154.36.154.163",
'HENcW': "api2.cursor.sh",
'vVEYg': "api3.cursor.sh",
'xOuBX': "# ===== CursorPro SNI Proxy Start =====",
'gbbhA': "# ===== CursorPro SNI Proxy End ====="
};
this["_extensionUri"] = _0x249e9c;
this["_context"] = _0x2abb89;
this._hostsPermissionGranted = false;
this.SNI_PROXY_IP = _0x22d112["NNvQE"];
this["CURSOR_DOMAINS"] = [_0x22d112.HENcW, _0x22d112["vVEYg"]];
this["HOSTS_MARKER_START"] = _0x22d112["xOuBX"];
this["HOSTS_MARKER_END"] = _0x22d112["gbbhA"];
this["_cachedCursorPath"] = null;
0x0;
this["_onlineStatusUnsubscribe"] = client_1["onOnlineStatusChange"](_0x11fa48 => {
this["_postMessage"]({
'type': _0x22d112["dJwJk"],
'online': _0x11fa48
});
});
}
["resolveWebviewView"](_0x3b70b5, _0x5282a8, _0x49a978) {
const _0x5b922e = {
'NRTxb': "没有写入权限",
'MCtQT': "seamlessRestored",
'RCwUS': "GfeNG",
'gHWzN': "LNoTP",
'HxMUq': 'switch',
'mVWLv': "disableUpdate",
'kIVSE': 'cleanEnv',
'ayNzd': 'disable',
'XJsJS': 'toggleProxy',
'TwlLk': "getState",
'Yecgn': "getSeamlessStatus",
'ekYOQ': "injectSeamless",
'sJjTI': 'toggleSeamless',
'FtmLf': 'getUserSwitchStatus',
'EflLA': "checkUsageBeforeSwitch",
'rXOaA': "confirmSwitch",
'OkEoz': "getCursorPath",
'SLxXS': 'getAccountUsage',
'ehEEN': 'checkVersion',
'myCHL': "getCursorRunningPath",
'KPDvL': "reloadWindow",
'LHHus': "workbench.action.reloadWindow",
'ozgjT': 'closeCursor'
};
this["_view"] = _0x3b70b5;
_0x3b70b5["webview"].options = {
'enableScripts': true,
'localResourceRoots': [this["_extensionUri"]]
};
_0x3b70b5["webview"]["html"] = this["_getHtmlContent"](_0x3b70b5["webview"]);
_0x3b70b5["webview"]["onDidReceiveMessage"](async _0x194d46 => {
const _0x275d91 = {
'WZyWQ': _0x5b922e["NRTxb"],
'ZXhkG': _0x5b922e["MCtQT"]
};
if (_0x5b922e["RCwUS"] !== _0x5b922e["gHWzN"]) {
switch (_0x194d46.type) {
case "activate":
await this._handleActivate(_0x194d46["key"]);
break;
case _0x5b922e["HxMUq"]:
await this["_handleSwitch"]();
break;
case "resetMachineId":
await this._handleResetMachineId();
break;
case _0x5b922e.mVWLv:
await this["_handleDisableUpdate"]();
break;
case _0x5b922e["kIVSE"]:
await this["_handleCleanEnv"]();
break;
case _0x5b922e["ayNzd"]:
await this._handleDisable();
break;
case _0x5b922e["XJsJS"]:
await this._handleToggleProxy(_0x194d46["enabled"], _0x194d46["url"]);
break;
case 'getProxyStatus':
await this["_handleGetProxyStatus"]();
break;
case _0x5b922e["TwlLk"]:
await this["_sendState"]();
break;
case "retryConnect":
await this["_handleRetryConnect"]();
break;
case _0x5b922e["Yecgn"]:
await this["_handleGetSeamlessStatus"]();
break;
case _0x5b922e.ekYOQ:
await this["_handleInjectSeamless"]();
break;
case "restoreSeamless":
await this._handleRestoreSeamless();
break;
case _0x5b922e["sJjTI"]:
await this["_handleToggleSeamless"](_0x194d46.enabled);
break;
case _0x5b922e["FtmLf"]:
await this["_handleGetUserSwitchStatus"]();
break;
case "manualSeamlessSwitch":
await this._handleManualSeamlessSwitch();
break;
case _0x5b922e.EflLA:
await this["_handleCheckUsageBeforeSwitch"](_0x194d46["email"]);
break;
case _0x5b922e["rXOaA"]:
await this["_handleManualSeamlessSwitch"]();
break;
case _0x5b922e.OkEoz:
await this._handleGetCursorPath();
break;
case 'getAccountUsage':
await this["_handleGetAccountUsage"](_0x194d46["email"]);
break;
case "getAnnouncement":
await this._handleGetAnnouncement();
break;
case _0x5b922e["ehEEN"]:
await this._handleCheckVersion();
break;
case _0x5b922e["myCHL"]:
await this["_handleGetCursorRunningPath"]();
break;
case _0x5b922e["KPDvL"]:
vscode["commands"].executeCommand(_0x5b922e["LHHus"]);
break;
case 'closeCursor':
0x0;
await account_1.closeCursor();
break;
}
} else {
const _0x282668 = _0x275d91["WZyWQ"];
this["_postMessage"]({
'type': _0x275d91["ZXhkG"],
'success': false,
'error': _0x282668,
'needAdmin': true
});
return;
}
});
this["_sendState"]();
this["_checkKeyStatus"]();
}
async ["_checkKeyStatus"]() {
const _0x4da3ff = {
'TLsxY': "utf-8",
'KqsKI': "cursorpro.key",
'OEKzo': function (_0x3f2189, _0x48838e) {
return _0x3f2189 !== _0x48838e;
},
'krxOp': "FAZar",
'lSeSm': "QlWcq",
'ubmNf': function (_0x29914e, _0x4e5d68) {
return _0x29914e === _0x4e5d68;
},
'yoPVW': 'EtMGw',
'UGSnZ': 'DVTND',
'jEejJ': 'cursorpro.expireDate',
'lpyMQ': 'cursorpro.switchRemaining',
'Auayd': "cursorpro.switchLimit",
'sbaFL': "keyStatusChecked",
'dyUVf': "激活码已过期或无效"
};
const _0x844666 = this["_context"]["globalState"].get(_0x4da3ff["KqsKI"]);
if (!_0x844666) {
if (_0x4da3ff["OEKzo"]('NCQkd', _0x4da3ff["krxOp"])) {
return;
} else {
this["_postMessage"]({
'type': "accountUsage",
'success': false,
'error': "未提供账号邮箱"
});
return;
}
}
try {
if (_0x4da3ff["lSeSm"] !== 'QlWcq') {
_0x24f700["writeFileSync"](_0x5ce57d, _0x2697d5, _0x4da3ff["TLsxY"]);
} else {
0x0;
const _0x439524 = await client_1.verifyKey(_0x844666);
if (_0x439524["success"] && _0x439524.valid) {
if (_0x4da3ff["ubmNf"](_0x4da3ff["yoPVW"], _0x4da3ff["UGSnZ"])) {
const _0x3a2e35 = _0x45d671["readFileSync"](_0x1f88e9, _0x4da3ff["TLsxY"]);
_0x2710ef = this["_checkInjected"](_0x3a2e35);
} else {
await this._context.globalState["update"](_0x4da3ff["jEejJ"], _0x439524["expire_date"]);
await this._context["globalState"]["update"](_0x4da3ff["lpyMQ"], _0x439524["switch_remaining"]);
await this._context["globalState"]["update"](_0x4da3ff["Auayd"], _0x439524["switch_limit"]);
this["_postMessage"]({
'type': _0x4da3ff["sbaFL"],
'valid': true,
'expireDate': _0x439524["expire_date"],
'switchRemaining': _0x439524["switch_remaining"],
'switchLimit': _0x439524["switch_limit"]
});
}
} else {
this._postMessage({
'type': _0x4da3ff["sbaFL"],
'valid': false,
'expired': true,
'error': _0x439524["error"] || _0x4da3ff["dyUVf"]
});
}
}
} catch (_0xe8e14c) {
console.error("[CursorPro] 检查激活码状态失败:", _0xe8e14c);
}
}
async ["_handleActivate"](_0x1c33b1) {
const _0x83ba47 = {
'cduDC': "utf-8",
'dWzRy': function (_0x2eb04a, _0x1a63c1) {
return _0x2eb04a(_0x1a63c1);
},
'yiKQp': "vscode",
'loOtc': "[CursorPro] 使用 VS Code API 获取版本:",
'fCoyb': function (_0x39f2f1, _0x5bc57a) {
return _0x39f2f1 === _0x5bc57a;
},
'hneyF': "ZPKij",
'MeNSD': "无感换号已启用,请先禁用后再更换授权码",
'jfGyX': function (_0x341f1e, _0x13166d) {
return _0x341f1e === _0x13166d;
},
'vAxgQ': 'ZyMNB',
'IStwX': "activated",
'RiXWk': "cursorpro.expireDate",
'tkwFD': "cursorpro.key",
'oRfTW': "cursorpro.switchLimit",
'lnDvM': "aVnan",
'bgJHu': "SOGed",
'lRVPz': "授权码无效",
'mbyBU': "连接服务器失败"
};
try {
const _0x3b1ee2 = await this["_isSeamlessInjected"]();
if (_0x3b1ee2) {
if (_0x83ba47["fCoyb"](_0x83ba47["hneyF"], "ZPKij")) {
this._postMessage({
'type': "activated",
'success': false,
'error': _0x83ba47.MeNSD
});
return;
} else {
const _0x5234a5 = this._getHostsPath();
if (_0x58e3ff["existsSync"](_0x5234a5)) {
return _0x490712["readFileSync"](_0x5234a5, _0x83ba47["cduDC"]);
}
}
}
this._cleanProxySettings();
0x0;
const _0x48d007 = await client_1["verifyKey"](_0x1c33b1);
if (_0x48d007["success"] && _0x48d007.valid) {
if (_0x83ba47["jfGyX"]('ZyMNB', _0x83ba47["vAxgQ"])) {
console.log("[CursorPro] 激活成功,后端返回:", {
'expire_date': _0x48d007["expire_date"],
'switch_remaining': _0x48d007["switch_remaining"],
'switch_limit': _0x48d007["switch_limit"]
});
await this["_context"].globalState["update"](_0x83ba47.tkwFD, _0x1c33b1);
await this._context["globalState"]["update"](_0x83ba47["RiXWk"], _0x48d007.expire_date);
await this["_context"]["globalState"]["update"]("cursorpro.switchRemaining", _0x48d007.switch_remaining);
await this._context["globalState"]["update"](_0x83ba47["oRfTW"], _0x48d007["switch_limit"]);
this["_postMessage"]({
'type': _0x83ba47["IStwX"],
'success': true,
'key': _0x1c33b1,
'expireDate': _0x48d007.expire_date,
'switchRemaining': _0x48d007["switch_remaining"],
'switchLimit': _0x48d007["switch_limit"]
});
0x0;
extension_1["showStatusBar"]();
await this._handleGetUserSwitchStatus();
} else {
_0x287901["warn"]("[CursorPro] 清理失败: " + _0x532653, _0x1db3e3);
}
} else {
if (_0x83ba47["lnDvM"] === _0x83ba47["bgJHu"]) {
const _0x1cf00a = _0x83ba47["dWzRy"](_0x931219, _0x83ba47["yiKQp"]);
if (_0x1cf00a["version"]) {
_0x4e3d1c["log"](_0x83ba47["loOtc"], _0x1cf00a.version);
return _0x1cf00a.version;
}
} else {
this._postMessage({
'type': _0x83ba47["IStwX"],
'success': false,
'error': _0x48d007["error"] || _0x83ba47["lRVPz"]
});
}
}
} catch (_0x40371b) {
this._postMessage({
'type': _0x83ba47["IStwX"],
'success': false,
'error': _0x83ba47["mbyBU"]
});
}
}
async ["_handleSwitch"]() {
const _0x3e408e = {
'QReae': "[CursorPro] WMIC 获取路径失败:",
'OVooV': "cursorpro.key",
'SpDeq': 'showToast',
'PTQOe': "请先激活授权码",
'YLEHJ': "cursorpro.switchRemaining",
'eBTDM': 'switched',
'kCeYh': "cursorpro.switchLimit",
'omFtC': "userSwitchStatus",
'XbTBi': function (_0x2bec63, _0x68602f) {
return _0x2bec63 > _0x68602f;
},
'pyrHY': function (_0x56ae50, _0xd521fd) {
return _0x56ae50 !== _0xd521fd;
},
'VqcBN': "kqrkg",
'bfgAG': "QcuMv"
};
const _0x11c87a = this["_context"]["globalState"]["get"](_0x3e408e["OVooV"]);
if (!_0x11c87a) {
this._postMessage({
'type': _0x3e408e["SpDeq"],
'message': _0x3e408e["PTQOe"],
'icon': '⚠️'
});
return;
}
try {
0x0;
const _0xbe1a2d = await client_1["switchSeamlessToken"](_0x11c87a);
if (_0xbe1a2d["switched"]) {
await this["_context"]["globalState"].update(_0x3e408e["YLEHJ"], _0xbe1a2d["switchRemaining"]);
this._postMessage({
'type': _0x3e408e["eBTDM"],
'success': true,
'email': _0xbe1a2d["email"],
'switchRemaining': _0xbe1a2d["switchRemaining"],
'switchLimit': this["_context"]["globalState"].get(_0x3e408e["kCeYh"]) || 0x64
});
const _0x4b2796 = _0xbe1a2d.switchRemaining ?? 0x0;
this["_postMessage"]({
'type': _0x3e408e["omFtC"],
'switchRemaining': _0x4b2796,
'canSwitch': _0x4b2796 > 0x0,
'lockedAccount': _0xbe1a2d["email"] ? {
'email': _0xbe1a2d["email"]
} : null
});
} else if (_0x3e408e["pyrHY"]("yFoId", _0x3e408e.VqcBN)) {
this["_postMessage"]({
'type': _0x3e408e["eBTDM"],
'success': false,
'error': _0xbe1a2d["message"] || '换号失败'
});
} else {
_0x5b771a = _0x1474f8[0x1];
}
} catch (_0x41fa19) {
if (_0x3e408e["pyrHY"]("CyYkO", _0x3e408e["bfgAG"])) {
this["_postMessage"]({
'type': 'switched',
'success': false,
'error': "连接服务器失败"
});
} else {
_0xb585cb["log"](_0x3e408e.QReae, _0x5d81f0);
}
}
}
async ["_writeAccountToLocal"](_0x51678f) {
const _0x5df214 = {
'jAygU': function (_0x1a9516, _0x14e09c) {
return _0x1a9516 === _0x14e09c;
},
'lWsen': "Contents",
'ujkvI': "app",
'nHvFA': 'out',
'WYIiR': "workbench",
'HukDC': "workbench.desktop.main.js",
'lAqMN': function (_0x4621bc, _0x5e828f) {
return _0x4621bc === _0x5e828f;
},
'uJtvK': "darwin",
'klERN': "没有写入权限,请在终端执行: sudo chmod -R 777 /Applications/Cursor.app",
'qVIKa': "linux",
'uJMyy': "没有写入权限,请使用 sudo 权限运行或修改文件权限",
'oogyg': 'usageCheckResult',
'UUaYi': "换号失败",
'NEcQR': "manualSeamlessSwitched",
'BPXIz': "proxyUpdated",
'tWJGN': "修改 hosts 文件失败,请确保有管理员权限",
'pgeAO': "showToast",
'yjRVE': function (_0x2c52bd, _0x27885e) {
return _0x2c52bd === _0x27885e;
},
'GXvhF': "hdUrt",
'tFDff': "Cursor",
'IFUbF': 'User',
'RqMFq': "globalStorage",
'tSjWJ': "state.vscdb",
'WnTYM': "machineid",
'ByhnO': "cursorAuth/accessToken",
'MPCdN': "cursorAuth/refreshToken",
'hrJHc': function (_0x223704, _0xb12866) {
return _0x223704 === _0xb12866;
},
'atmmx': "rmAmZ",
'qyuJo': "cursorAuth/cachedEmail",
'iOndu': "pAlKG",
'tfSWx': "cursorAuth/stripeMembershipType",
'UnRdA': function (_0x17b49d, _0x28b8c0) {
return _0x17b49d !== _0x28b8c0;
},
'FNcgD': "ptOKi",
'JVIPE': 'yLQZc',
'btARC': "cursorAuth/cachedSignUpType",
'pTffC': "eNCnU",
'taMeX': "storage.serviceMachineId",
'QhViN': function (_0x3ede25, _0x102e15) {
return _0x3ede25 === _0x102e15;
},
'IenCN': "xouQM",
'ktByd': "telemetry.machineId",
'ydHCU': 'telemetry.macMachineId',
'hYviy': "eBQqu",
'ltTAn': "hCBnO",
'WtTZw': "[CursorPro] storage.json 已更新",
'bohEI': "[CursorPro] machineid 文件已更新",
'tqMKz': 'win32',
'KhYFK': 'hhZyB',
'TPjZV': function (_0x4acd6e, _0x4cbd0e) {
return _0x4acd6e(_0x4cbd0e);
},
'dxmvV': "[CursorPro] 注册表写入失败(可能需要管理员权限):"
};
try {
if ("MClbP" === _0x5df214["GXvhF"]) {
let _0x9583b2;
if (_0x5df214["jAygU"](_0x48f1cd, "darwin")) {
_0x9583b2 = _0x3e2a77.join(this["_cachedCursorPath"], _0x5df214["lWsen"], 'Resources', _0x5df214["ujkvI"], _0x5df214["nHvFA"], 'vs', _0x5df214["WYIiR"], _0x5df214["HukDC"]);
} else {
_0x9583b2 = _0x4e0cd1.join(this["_cachedCursorPath"], "resources", _0x5df214["ujkvI"], _0x5df214["nHvFA"], 'vs', _0x5df214["WYIiR"], _0x5df214["HukDC"]);
}
if (_0x240b48["existsSync"](_0x9583b2)) {
return _0x9583b2;
}
} else {
const _0x33651c = process["env"]["APPDATA"] || '';
const _0x97018c = path["join"](_0x33651c, _0x5df214["tFDff"], _0x5df214["IFUbF"], _0x5df214.RqMFq, _0x5df214["tSjWJ"]);
const _0x155e62 = path["join"](_0x33651c, "Cursor", _0x5df214["IFUbF"], _0x5df214.RqMFq, 'storage.json');
const _0x392e23 = path["join"](_0x33651c, _0x5df214["tFDff"], _0x5df214.WnTYM);
if (fs["existsSync"](_0x97018c)) {
const _0x37f13d = [];
if (_0x51678f["accessToken"]) {
_0x37f13d["push"]([_0x5df214["ByhnO"], _0x51678f.accessToken]);
}
if (_0x51678f["refreshToken"]) {
_0x37f13d["push"]([_0x5df214["MPCdN"], _0x51678f["refreshToken"]]);
}
if (_0x51678f.email) {
if (_0x5df214["atmmx"] === 'mIiuu') {
_0xfb725b = _0x1931cc["dirname"](_0x2dba3b["trim"]());
} else {
_0x37f13d["push"]([_0x5df214.qyuJo, _0x51678f["email"]]);
}
}
if (_0x51678f["membership_type"]) {
if ('vhcuB' === _0x5df214["iOndu"]) {
const _0x637d29 = _0x1172a0["platform"];
let _0x5a842b = '没有写入权限';
if (_0x5df214["lAqMN"](_0x637d29, _0x5df214.uJtvK)) {
_0x5a842b = _0x5df214.klERN;
} else if (_0x5df214["lAqMN"](_0x637d29, _0x5df214["qVIKa"])) {
_0x5a842b = _0x5df214["uJMyy"];
}
this._postMessage({
'type': 'seamlessInjected',
'success': false,
'error': _0x5a842b,
'needAdmin': true,
'path': _0x24be1d
});
return;
} else {
_0x37f13d["push"]([_0x5df214.tfSWx, _0x51678f.membership_type]);
}
}
if (_0x51678f["sign_up_type"]) {
if (_0x5df214["UnRdA"](_0x5df214["FNcgD"], 'yLQZc')) {
_0x37f13d["push"]([_0x5df214["btARC"], _0x51678f["sign_up_type"]]);
} else {
_0x433bcf = _0x2003b8.dirname(_0x43cf7e);
}
}
if (_0x51678f["serviceMachineId"]) {
if ('fYfXI' !== _0x5df214["pTffC"]) {
_0x37f13d.push([_0x5df214["taMeX"], _0x51678f["serviceMachineId"]]);
} else {
this._postMessage({
'type': _0x5df214["oogyg"],
'success': true,
'needConfirm': true,
'costUSD': _0x2db93a["toFixed"](0x2),
'email': _0x28077f
});
}
}
0x0;
await sqlite_1["sqliteSetBatch"](_0x97018c, _0x37f13d);
console["log"]("[CursorPro] SQLite 数据库已更新");
}
if (fs["existsSync"](_0x155e62)) {
if (_0x5df214["QhViN"](_0x5df214["IenCN"], "nqqWG")) {
const _0xc468de = _0x12337e.message || _0x352413["error"] || _0x5df214.UUaYi;
this["_postMessage"]({
'type': _0x5df214.NEcQR,
'success': false,
'error': _0xc468de
});
} else {
const _0x589109 = JSON.parse(fs.readFileSync(_0x155e62, 'utf-8'));
if (_0x51678f.machineId) {
_0x589109[_0x5df214["ktByd"]] = _0x51678f["machineId"];
}
if (_0x51678f["macMachineId"]) {
_0x589109['telemetry.macMachineId'] = _0x51678f["macMachineId"];
}
if (_0x51678f["devDeviceId"]) {
_0x589109["telemetry.devDeviceId"] = _0x51678f.devDeviceId;
}
if (_0x51678f["sqmId"]) {
if (_0x5df214.hYviy === _0x5df214["ltTAn"]) {
this._postMessage({
'type': _0x5df214["BPXIz"],
'success': false,
'error': "修改 hosts 文件失败,请确保有管理员权限"
});
this["_postMessage"]({
'type': _0x5df214.pgeAO,
'message': "需要管理员权限修改 hosts 文件",
'icon': '⚠️'
});
} else {
_0x589109["telemetry.sqmId"] = _0x51678f["sqmId"];
}
}
fs["writeFileSync"](_0x155e62, JSON.stringify(_0x589109, null, 0x4));
console["log"](_0x5df214["WtTZw"]);
}
}
if (_0x51678f.machineId) {
fs["writeFileSync"](_0x392e23, _0x51678f["machineId"]);
console["log"](_0x5df214["bohEI"]);
}
if (_0x51678f["registryGuid"] && process.platform === _0x5df214["tqMKz"]) {
if (_0x5df214["KhYFK"] === _0x5df214["KhYFK"]) {
try {
const _0x256ef2 = 'reg add "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid /t REG_SZ /d "' + _0x51678f.registryGuid + '" /f';
await execAsync(_0x256ef2);
console.log("[CursorPro] 注册表 MachineGuid 已更新");
} catch (_0x5c0e6a) {
console.warn(_0x5df214["dxmvV"], _0x5c0e6a);
}
} else {
_0x1b21f9 = _0x5df214["uJMyy"];
}
}
return true;
}
} catch (_0x4bd56d) {
console.error("[CursorPro] 写入本地失败:", _0x4bd56d);
vscode["window"].showErrorMessage("写入失败: " + _0x4bd56d);
return false;
}
}
async ["_handleReset"]() {
const _0x178daf = {
'SWWgG': '4|0|3|5|2|1',
'uEcXh': 'reset',
'eMKRt': 'cursorpro.switchRemaining',
'FOwUP': "cursorpro.key"
};
const _0x46dec9 = '4|0|3|5|2|1'["split"]('|');
let _0x51aa2c = 0x0;
while (true) {
switch (_0x46dec9[_0x51aa2c++]) {
case '0':
await this._context.globalState["update"]("cursorpro.expireDate", undefined);
continue;
case '1':
vscode["window"]["showInformationMessage"]("插件已重置");
continue;
case '2':
this["_postMessage"]({
'type': 'reset',
'success': true
});
continue;
case '3':
await this["_context"]["globalState"].update(_0x178daf["eMKRt"], undefined);
continue;
case '4':
await this["_context"]["globalState"]["update"](_0x178daf["FOwUP"], undefined);
continue;
case '5':
0x0;
extension_1["hideStatusBar"]();
continue;
}
break;
}
}
async ._handleDisable() {
await this._handleReset();
vscode.window["showInformationMessage"]("插件已停用");
}
async ._checkAdminPrivilege() {
const _0x53e404 = {
'fAfUV': "Resources",
'Llgfj': function (_0x2ea46e, _0x597079) {
return _0x2ea46e !== _0x597079;
},
'pImJb': function (_0x3e6e32, _0x3b5f4c) {
return _0x3e6e32(_0x3b5f4c);
},
'wncyL': "net session 2>nul"
};
if (process.platform !== "win32") {
if ("FIUZS" === 'FIUZS') {
return true;
} else {
_0x2739b0 = _0x1385f5["join"](_0x2a3737, 'Contents', _0x53e404["fAfUV"], 'app', "package.json");
}
}
try {
await _0x53e404["pImJb"](execAsync, 'reg query "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid 2>nul');
const _0x41176e = await execAsync(_0x53e404["wncyL"])["catch"](() => ({
'stdout': '',
'stderr': 'error'
}));
return !_0x41176e.stderr;
} catch (_0x6d5696) {
return false;
}
}
async ["_handleResetMachineId"]() {
const _0x3dfa6c = {
'lElIk': function (_0x3fa0c5, _0x578287) {
return _0x3fa0c5 === _0x578287;
},
'yJQQD': "darwin",
'oTJSZ': 'Contents',
'sJMHZ': 'Resources',
'tIdJk': "app",
'rNqfB': "workbench",
'PaBhO': "workbench.desktop.main.js",
'cDXTK': "out",
'mseLD': function (_0x1a7b0a, _0x4298ee) {
return _0x1a7b0a(_0x4298ee);
},
'GpfdI': function (_0x561ce3, _0xd12af6) {
return _0x561ce3 != _0xd12af6;
},
'jGfgE': function (_0x4a5a60, _0x3f3e51) {
return _0x4a5a60 !== _0x3f3e51;
},
'SKKxx': "default",
'WWGrA': "[CursorPro] Retry connect failed:",
'zEnsI': 'networkStatus',
'VmkCj': "seamlessInjected",
'qukOr': "授权码无效",
'nczgV': "[CursorPro] where 命令获取路径失败",
'BmSwh': 'adminPermissionRequired',
'DUzlm': "crypto",
'iOJby': "hex",
'SizrD': "EIFLO",
'kVXre': "utf-8",
'OoOvL': "telemetry.macMachineId",
'NrAHw': "telemetry.devDeviceId",
'DYlNA': "[CursorPro] storage.json 已更新",
'oWHkO': function (_0xa487f2, _0x46d29e) {
return _0xa487f2 === _0x46d29e;
},
'hazjj': "OKDBI",
'sltuA': "[CursorPro] storage.json 更新失败:",
'kdlCx': "storage.json",
'yAadA': "AGUOM",
'dVXng': function (_0x52e3f9, _0x1824a1) {
return _0x52e3f9 > _0x1824a1;
},
'jVCTI': function (_0x36b294, _0x50a679) {
return _0x36b294 !== _0x50a679;
},
'NgEqy': "XygLc",
'JHBVl': "[CursorPro] machineid 文件已更新",
'ihOph': "machineid",
'CUSOw': function (_0x5dca29, _0x1c0e29) {
return _0x5dca29 > _0x1c0e29;
},
'DXmLl': 'UbSjF',
'XMamy': function (_0x56b6ca, _0x4d16fd) {
return _0x56b6ca !== _0x4d16fd;
},
'TStTT': "SxHmQ",
'xXEyx': function (_0x41e747, _0x456d1f) {
return _0x41e747 !== _0x456d1f;
},
'iiJFH': 'edqsV',
'dLXnX': function (_0x626dd4, _0x4c0c64) {
return _0x626dd4 === _0x4c0c64;
},
'IMEYC': function (_0x2f404e, _0x1aec5f) {
return _0x2f404e === _0x1aec5f;
},
'aYwpG': "EvLtz",
'EdOfO': "[CursorPro] SQLite 更新失败:",
'wSpvM': "win32",
'hhSrG': function (_0x247938, _0x48462e) {
return _0x247938 === _0x48462e;
},
'DAvAD': "uxdjv",
'BkSzQ': "qWEGL",
'WYomd': "[CursorPro] 注册表 MachineGuid 已更新",
'ZaPkC': function (_0x59cb29, _0x513094) {
return _0x59cb29 >= _0x513094;
},
'fVMJA': 'machineIdReset',
'HiGXJ': "机器码重置成功",
'SEsMN': function (_0x34e2fe, _0x135030) {
return _0x34e2fe === _0x135030;
},
'dGXfv': "gGIGL",
'pKuzu': function (_0x3f0c5f, _0xdc4a4f) {
return _0x3f0c5f !== _0xdc4a4f;
},
'YfRLt': "KokEE"
};
try {
const _0x5ca938 = process["platform"];
if (_0x3dfa6c["lElIk"](_0x5ca938, 'win32')) {
const _0x2196c3 = await this._checkAdminPrivilege();
if (!_0x2196c3) {
this["_postMessage"]({
'type': _0x3dfa6c["BmSwh"]
});
return;
}
}
0x0;
const _0x5e7765 = account_1["getCursorPaths"]();
const {
dbPath: _0x4aa0cd,
storagePath: _0x4a28ca,
machineidPath: _0x2ec82c
} = _0x5e7765;
const _0x2aee57 = _0x3dfa6c["mseLD"](require, _0x3dfa6c["DUzlm"]);
const _0x13d6be = _0x2aee57["randomBytes"](0x20).toString(_0x3dfa6c.iOJby);
const _0x4520aa = _0x2aee57.randomBytes(0x20).toString(_0x3dfa6c["iOJby"]);
const _0x5c9a5c = _0x2aee57["randomUUID"]();
const _0x295e98 = '{' + _0x2aee57["randomUUID"]()["toUpperCase"]() + '}';
let _0x42a386 = 0x0;
let _0x410d72 = [];
if (fs["existsSync"](_0x4a28ca)) {
if (_0x3dfa6c["SizrD"] !== "EIFLO") {
let _0x2d68ba;
if (_0x3dfa6c["lElIk"](_0x1eaffe, _0x3dfa6c["yJQQD"])) {
_0x2d68ba = _0x5e5bb2["join"](_0xae64c7, 'Contents', _0x3dfa6c["sJMHZ"], _0x3dfa6c["tIdJk"], "out", 'vs', _0x3dfa6c.rNqfB, _0x3dfa6c["PaBhO"]);
} else {
_0x2d68ba = _0x2996fd["join"](_0x5b8900, "resources", "app", _0x3dfa6c["cDXTK"], 'vs', _0x3dfa6c["rNqfB"], _0x3dfa6c.PaBhO);
}
if (_0xdd2a05.existsSync(_0x2d68ba)) {
return _0x2d68ba;
}
} else {
let _0x32a80e = 0x3;
while (_0x32a80e > 0x0) {
try {
const _0x34dbe5 = JSON["parse"](fs.readFileSync(_0x4a28ca, _0x3dfa6c["kVXre"]));
_0x34dbe5["telemetry.machineId"] = _0x13d6be;
_0x34dbe5[_0x3dfa6c["OoOvL"]] = _0x4520aa;
_0x34dbe5[_0x3dfa6c["NrAHw"]] = _0x5c9a5c;
_0x34dbe5["telemetry.sqmId"] = _0x295e98;
fs.writeFileSync(_0x4a28ca, JSON["stringify"](_0x34dbe5, null, 0x4));
console["log"](_0x3dfa6c.DYlNA);
_0x42a386++;
break;
} catch (_0x408e1a) {
_0x32a80e--;
if (_0x32a80e === 0x0) {
if (_0x3dfa6c["oWHkO"]("VbcUu", _0x3dfa6c["hazjj"])) {
_0x5162ea.rmSync(_0x9608e0, {
'recursive': true,
'force': true
});
_0x12202b++;
_0x22902f.log("[CursorPro] 已清理: " + _0x566ae7);
} else {
console["warn"](_0x3dfa6c["sltuA"], _0x408e1a["message"]);
_0x410d72["push"](_0x3dfa6c.kdlCx);
}
} else {
await new Promise(_0x1fb805 => setTimeout(_0x1fb805, 0x64));
}
}
}
}
}
{
if (_0x3dfa6c["oWHkO"](_0x3dfa6c.yAadA, "omtSK")) {
var _0x2a4a6e = [];
for (var _0x3716c4 in _0x3f83c7) if (_0x2daf25["prototype"]["hasOwnProperty"]["call"](_0x1170bb, _0x3716c4)) {
_0x2a4a6e[_0x2a4a6e.length] = _0x3716c4;
}
return _0x2a4a6e;
} else {
let _0x3e6f5a = 0x3;
while (_0x3e6f5a > 0x0) {
try {
const _0x91b94a = path.dirname(_0x2ec82c);
if (!fs["existsSync"](_0x91b94a)) {
if (_0x3dfa6c["jVCTI"]('UjEXX', _0x3dfa6c.NgEqy)) {
fs["mkdirSync"](_0x91b94a, {
'recursive': true
});
} else {
return _0x5ad776;
}
}
fs["writeFileSync"](_0x2ec82c, _0x13d6be);
console["log"](_0x3dfa6c["JHBVl"]);
_0x42a386++;
break;
} catch (_0x15034e) {
_0x3e6f5a--;
if (_0x3e6f5a === 0x0) {
console["warn"]("[CursorPro] machineid 更新失败:", _0x15034e["message"]);
_0x410d72.push(_0x3dfa6c["ihOph"]);
} else {
await new Promise(_0x128d98 => setTimeout(_0x128d98, 0x64));
}
}
}
}
}
if (fs["existsSync"](_0x4aa0cd)) {
let _0x46b5f7 = 0x3;
while (_0x3dfa6c["CUSOw"](_0x46b5f7, 0x0)) {
if ("UbSjF" === _0x3dfa6c["DXmLl"]) {
try {
if ("EvWMl" !== _0x3dfa6c["TStTT"]) {
const _0x49da25 = _0x2aee57.randomUUID();
0x0;
const _0x44bd41 = await sqlite_1.sqliteSetBatch(_0x4aa0cd, [['storage.serviceMachineId', _0x49da25]]);
if (_0x44bd41) {
console["log"]("[CursorPro] SQLite 数据库已更新");
_0x42a386++;
break;
} else {
if ('edqsV' !== "edqsV") {
const _0x480394 = {
'JDiGp': function (_0x296746, _0xe4a731) {
return _0x3dfa6c["GpfdI"](_0x296746, _0xe4a731);
},
'UJfLB': function (_0x5d0056, _0x5c568b) {
return _0x3dfa6c["jGfgE"](_0x5d0056, _0x5c568b);
},
'YIhbu': _0x3dfa6c["SKKxx"],
'hQSHL': function (_0x2ecb26, _0x249a15, _0x4919c7, _0x430d9c) {
return _0x2ecb26(_0x249a15, _0x4919c7, _0x430d9c);
},
'iFgQw': function (_0x3a1ffc, _0x7ebf92, _0x57e599) {
return _0x3a1ffc(_0x7ebf92, _0x57e599);
}
};
var _0x4b98ab = function (_0x111b39) {
_0x4b98ab = _0x2160f7.getOwnPropertyNames || function (_0x130daa) {
var _0x41f8fb = [];
for (var _0x670bc2 in _0x130daa) if (_0x75a24e.prototype["hasOwnProperty"]["call"](_0x130daa, _0x670bc2)) {
_0x41f8fb[_0x41f8fb["length"]] = _0x670bc2;
}
return _0x41f8fb;
};
return _0x3dfa6c["mseLD"](_0x4b98ab, _0x111b39);
};
return function (_0x20bb6b) {
if (_0x20bb6b && _0x20bb6b["__esModule"]) {
return _0x20bb6b;
}
var _0x2c00be = {};
if (_0x480394["JDiGp"](_0x20bb6b, null)) {
var _0x11069f = _0x4b98ab(_0x20bb6b);
for (var _0x2599df = 0x0; _0x2599df < _0x11069f["length"]; _0x2599df++) {
if (_0x3dfa6c["jGfgE"](_0x11069f[_0x2599df], _0x480394["YIhbu"])) {
_0x480394["hQSHL"](_0x674927, _0x2c00be, _0x20bb6b, _0x11069f[_0x2599df]);
}
}
}
_0x480394["iFgQw"](_0x240286, _0x2c00be, _0x20bb6b);
return _0x2c00be;
};
} else {
throw new Error("sqliteSetBatch 返回 false");
}
}
} else {
throw new _0x1a22ee("sqliteSetBatch 返回 false");
}
} catch (_0xfa28ae) {
_0x46b5f7--;
if (_0x3dfa6c["dLXnX"](_0x46b5f7, 0x0)) {
if (_0x3dfa6c["IMEYC"]('pUuQI', _0x3dfa6c["aYwpG"])) {
_0x964a59["error"](_0x3dfa6c["WWGrA"], _0x9baa98);
this["_postMessage"]({
'type': 'networkStatus',
'online': false
});
} else {
console["warn"](_0x3dfa6c["EdOfO"], _0xfa28ae["message"]);
_0x410d72["push"]("SQLite");
}
} else {
await new Promise(_0x1eb4ea => setTimeout(_0x1eb4ea, 0x1f4));
}
}
} else {
_0x38b61c = _0xf3fbd6["trim"]();
}
}
}
if (_0x5ca938 === _0x3dfa6c.wSpvM) {
if (_0x3dfa6c["DAvAD"] === 'uxdjv') {
const _0xc2bf8b = _0x2aee57["randomUUID"]();
try {
if (_0x3dfa6c["jVCTI"](_0x3dfa6c.BkSzQ, "lGcMr")) {
await execAsync('reg add "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid /t REG_SZ /d "' + _0xc2bf8b + '" /f');
console.log(_0x3dfa6c["WYomd"]);
_0x42a386++;
} else {
this["_postMessage"]({
'type': _0x3dfa6c["VmkCj"],
'success': false,
'error': _0x29f22d["error"] || _0x3dfa6c["qukOr"]
});
return;
}
} catch (_0x2a0e47) {
console.warn("[CursorPro] 注册表更新失败(需要管理员权限),已跳过");
_0x410d72["push"]("注册表");
}
} else {
_0x45c2d2 = _0x2be321["getOwnPropertyNames"] || function (_0x5aff3b) {
var _0x2ac6fe = [];
for (var _0x56e238 in _0x5aff3b) if (_0x17dada["prototype"]["hasOwnProperty"]["call"](_0x5aff3b, _0x56e238)) {
_0x2ac6fe[_0x2ac6fe.length] = _0x56e238;
}
return _0x2ac6fe;
};
return _0x6e782f(_0x5c5de0);
}
}
if (_0x3dfa6c["ZaPkC"](_0x42a386, 0x2)) {
this["_postMessage"]({
'type': _0x3dfa6c["fVMJA"],
'success': true,
'needRestart': true,
'message': _0x3dfa6c["dVXng"](_0x410d72["length"], 0x0) ? "机器码重置成功(" + _0x410d72["join"](", ") + " 更新失败,不影响使用)" : _0x3dfa6c["HiGXJ"]
});
} else if ("uIJXM" === _0x3dfa6c["dGXfv"]) {
_0xb3a25e["log"]("[CursorPro] 尝试路径失败:", _0x35bfac, _0x26703c);
} else {
this._postMessage({
'type': "showToast",
'message': "重置部分失败: " + _0x410d72["join"](", ") + "。请先完全关闭 Cursor 再试",
'icon': '⚠️'
});
}
} catch (_0x2bd1a8) {
if ("KokEE" !== _0x3dfa6c.YfRLt) {
_0x2757ce["log"](_0x3dfa6c["nczgV"]);
} else {
this["_postMessage"]({
'type': "showToast",
'message': "重置机器码失败: " + _0x2bd1a8,
'icon': '❌'
});
}
}
}
._generateRandomMAC() {
const _0x351246 = {
'gsyrk': function (_0x2456e7, _0x15dd24) {
return _0x2456e7(_0x15dd24);
},
'lYDrY': 'crypto',
'RmNIb': function (_0x562f1e, _0xc0a2a9) {
return _0x562f1e & _0xc0a2a9;
},
'WCBzn': function (_0x233015, _0x3ca3bf) {
return _0x233015 | _0x3ca3bf;
}
};
const _0x539ee8 = _0x351246["gsyrk"](require, _0x351246["lYDrY"]);
const _0x58dc79 = _0x539ee8["randomBytes"](0x6);
_0x58dc79[0x0] = _0x351246["RmNIb"](_0x351246["WCBzn"](_0x58dc79[0x0], 0x2), 0xfe);
return Array.from(_0x58dc79).map(_0x2d538f => _0x2d538f["toString"](0x10)["padStart"](0x2, '0'))["join"](':');
}
async ._handleDisableUpdate() {
const _0xcdd27f = {
'SlsxX': function (_0x2f9c04, _0x4c19d7) {
return _0x2f9c04 + _0x4c19d7;
},
'obUIO': "cursor-updater",
'MTNiO': function (_0x2e30f3, _0x4ab64b) {
return _0x2e30f3 !== _0x4ab64b;
},
'Bhmmc': 'Fkark',
'WHolg': "IvZQp",
'vJjHJ': 'showToast',
'KkOxm': "已禁用 Cursor 自动更新"
};
try {
const _0x24fe79 = process["env"]["LOCALAPPDATA"] || '';
const _0xac3e10 = path["join"](_0x24fe79, _0xcdd27f["obUIO"]);
if (fs["existsSync"](_0xac3e10)) {
if (_0xcdd27f["MTNiO"](_0xcdd27f["Bhmmc"], _0xcdd27f["Bhmmc"])) {
return false;
} else if (fs.statSync(_0xac3e10).isDirectory()) {
if (_0xcdd27f["MTNiO"](_0xcdd27f.WHolg, "IvZQp")) {
_0x5481a7 = _0x5e122b.substring(0x0, _0x4f63e3) + _0x214640["substring"](_0xcdd27f["SlsxX"](_0x5cc883, 0x7));
} else {
fs["rmSync"](_0xac3e10, {
'recursive': true,
'force': true
});
}
} else {
fs["unlinkSync"](_0xac3e10);
}
}
fs["writeFileSync"](_0xac3e10, '');
this["_postMessage"]({
'type': 'showToast',
'message': _0xcdd27f["KkOxm"],
'icon': '✅'
});
} catch (_0x387797) {
this._postMessage({
'type': _0xcdd27f["vJjHJ"],
'message': "禁用自动更新失败: " + _0x387797,
'icon': '❌'
});
}
}
async ["_handleCleanEnv"]() {
const _0x5d7007 = {
'QgDaW': "networkStatus",
'rCPOJ': "[CursorPro] WMIC 获取路径失败",
'FZidX': "[CursorPro] 找到 Cursor 版本:",
'nLBbF': "路径:",
'tRjSQ': "announcement",
'BlfQc': "获取公告失败",
'JlTFY': 'activated',
'cqICS': "授权码无效",
'JPunF': "[CursorPro] 注入失败,未找到任何注入点",
'KMKzx': "[CursorPro] 文件路径:",
'xFYQT': "[CursorPro] 文件大小:",
'hxRZC': "[CursorPro] 未找到的注入点:",
'SPguA': '_showNotification',
'IjZFI': "seamlessInjected",
'JiWRI': "Cursor 版本不兼容,注入点未找到",
'aPXBq': function (_0x449fed, _0x1e0222) {
return _0x449fed === _0x1e0222;
},
'pYIFs': function (_0x3cef7a, _0x51f2f4) {
return _0x3cef7a in _0x51f2f4;
},
'JBwTr': 'get',
'koIoR': function (_0x43e103, _0x5178fd) {
return _0x43e103 === _0x5178fd;
},
'PGlXD': "win32",
'GTTuL': function (_0x5b1681, _0x264692) {
return _0x5b1681 === _0x264692;
},
'Psmij': "rhIFB",
'gYxAu': 'xYuSE',
'MuQDV': function (_0x4cb02b, _0x14cda9) {
return _0x4cb02b(_0x14cda9);
},
'IKcBt': "pkill -f Cursor",
'RPLYj': function (_0x1c7600, _0xe03586) {
return _0x1c7600 === _0xe03586;
},
'MGVKs': function (_0x4fe688, _0x467499) {
return _0x4fe688 !== _0x467499;
},
'ryaos': 'uKgvW',
'voPhc': "Cursor",
'lXGbz': "cursor-updater",
'xKriv': ".cursor",
'ZoVAa': 'CTJTi',
'MCBOh': "YZsoE",
'pGLVT': "jAgIw",
'OUBfk': "darwin",
'FYnvF': 'Caches',
'uIkRt': "Library",
'tQzIF': "Logs",
'HlGXa': "WKeGp",
'EtSsM': "rxZvP",
'FNyIR': "pLQpn",
'WPZrs': 'udDhy',
'jyFFs': '.cache',
'hMrGj': ".local",
'ISlsh': "share",
'yteSk': 'lkchx',
'Prgty': "SPIaC",
'WVkud': "FbJEH",
'okltc': "UEqoH"
};
try {
if (process["platform"] === _0x5d7007.PGlXD) {
await execAsync("taskkill /F /IM Cursor.exe")["catch"](() => {});
} else if (_0x5d7007["Psmij"] === _0x5d7007["gYxAu"]) {
this._postMessage({
'type': "showToast",
'message': "禁用自动更新失败: " + _0xaf40e5,
'icon': '❌'
});
} else {
await _0x5d7007["MuQDV"](execAsync, _0x5d7007["IKcBt"]).catch(() => {});
}
await new Promise(_0x30bca7 => setTimeout(_0x30bca7, 0x7d0));
const _0x27dda7 = process.env["APPDATA"] || '';
const _0x2dfaf0 = process["env"].LOCALAPPDATA || '';
const _0x2bcaef = process["env"].HOME || process.env["USERPROFILE"] || '';
let _0x1e982b = 0x0;
if (process.platform === _0x5d7007["PGlXD"]) {
if (_0x5d7007["MGVKs"]('OMLAe', _0x5d7007["ryaos"])) {
const _0x680500 = [path.join(_0x27dda7, _0x5d7007["voPhc"]), path["join"](_0x2dfaf0, _0x5d7007["voPhc"]), path["join"](_0x2dfaf0, _0x5d7007.lXGbz), path["join"](_0x2bcaef, _0x5d7007["xKriv"])];
for (const _0x395cca of _0x680500) {
if (_0x5d7007["ZoVAa"] !== "CTJTi") {
this._postMessage({
'type': 'userSwitchStatus',
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': '获取状态失败'
});
} else {
try {
if (fs["existsSync"](_0x395cca)) {
if (_0x5d7007["aPXBq"](_0x5d7007["MCBOh"], _0x5d7007["pGLVT"])) {
this["_postMessage"]({
'type': _0x5d7007["QgDaW"],
'online': _0x1e9bca
});
} else {
fs["rmSync"](_0x395cca, {
'recursive': true,
'force': true
});
_0x1e982b++;
console["log"]("[CursorPro] 已清理: " + _0x395cca);
}
}
} catch (_0x47ea0c) {
console["warn"]("[CursorPro] 清理失败: " + _0x395cca, _0x47ea0c);
}
}
}
} else {
_0x305e73["log"](_0x5d7007["rCPOJ"]);
}
} else {
if (process["platform"] === _0x5d7007["OUBfk"]) {
const _0x173109 = [path["join"](_0x2bcaef, "Library", "Application Support", _0x5d7007["voPhc"]), path["join"](_0x2bcaef, "Library", _0x5d7007["FYnvF"], _0x5d7007["voPhc"]), path["join"](_0x2bcaef, _0x5d7007.uIkRt, _0x5d7007["tQzIF"], _0x5d7007.voPhc), path.join(_0x2bcaef, 'Library', "Application Support", 'Caches', _0x5d7007.lXGbz), path["join"](_0x2bcaef, _0x5d7007["xKriv"])];
for (const _0x151011 of _0x173109) {
if ("ZwnwK" === "juOiE") {
const _0x4223b9 = _0x6afa13["readFileSync"](_0x263f1d, 'utf-8');
const _0x4ffeb2 = _0x2673e3["parse"](_0x4223b9);
if (_0x4ffeb2["version"]) {
_0x4e128b["log"](_0x5d7007["FZidX"], _0x4ffeb2["version"], _0x5d7007["nLBbF"], _0x3afc55);
return _0x4ffeb2["version"];
}
} else {
try {
if (fs["existsSync"](_0x151011)) {
if (_0x5d7007["HlGXa"] !== _0x5d7007["EtSsM"]) {
fs["rmSync"](_0x151011, {
'recursive': true,
'force': true
});
_0x1e982b++;
} else {
this["_postMessage"]({
'type': _0x5d7007["tRjSQ"],
'success': false,
'error': _0x1b6792.error || _0x5d7007["BlfQc"]
});
}
}
} catch (_0x52cb05) {
if (_0x5d7007.FNyIR !== _0x5d7007["WPZrs"]) {
console["warn"]("[CursorPro] 清理失败: " + _0x151011, _0x52cb05);
} else {
this["_postMessage"]({
'type': _0x5d7007["JlTFY"],
'success': false,
'error': _0xd37ccd["error"] || _0x5d7007["cqICS"]
});
}
}
}
}
} else {
const _0x305f11 = [path["join"](_0x2bcaef, ".config", _0x5d7007["voPhc"]), path.join(_0x2bcaef, _0x5d7007["jyFFs"], _0x5d7007["voPhc"]), path["join"](_0x2bcaef, _0x5d7007["hMrGj"], _0x5d7007.ISlsh, _0x5d7007.voPhc), path["join"](_0x2bcaef, _0x5d7007.xKriv)];
for (const _0x5bbdfa of _0x305f11) {
if ('lkchx' !== _0x5d7007["yteSk"]) {
_0x17a266["error"](_0x5d7007["JPunF"]);
_0xc8224e["error"](_0x5d7007["KMKzx"], _0x45b7c8);
_0x557053["error"](_0x5d7007["xFYQT"], _0x27fd6a.length);
_0x3c4a59["error"](_0x5d7007.hxRZC, _0x23fb79);
const _0x1c19d0 = _0x54cc25["includes"]('_showNotification');
const _0x605a0e = _0x4b5d6c["includes"]("getItems()");
_0x24e1b7.error("[CursorPro] 包含 _showNotification:", _0x1c19d0);
_0x16679d["error"]("[CursorPro] 包含 getItems():", _0x605a0e);
this["_postMessage"]({
'type': _0x5d7007["IjZFI"],
'success': false,
'error': _0x5d7007["JiWRI"],
'details': "路径: " + _0x8d33d3
});
return;
} else {
try {
if (fs.existsSync(_0x5bbdfa)) {
fs.rmSync(_0x5bbdfa, {
'recursive': true,
'force': true
});
_0x1e982b++;
}
} catch (_0x3fff64) {
if ('SPIaC' === _0x5d7007["Prgty"]) {
console["warn"]("[CursorPro] 清理失败: " + _0x5bbdfa, _0x3fff64);
} else {
if (_0x5a8ee0 === _0x67147f) {
_0x11f2b9 = _0x3ddb74;
}
var _0x5443a8 = _0x3e5510["getOwnPropertyDescriptor"](_0xf4f8d, _0x23f58b);
if (!_0x5443a8 || (_0x5d7007["pYIFs"]('get', _0x5443a8) ? !_0x30ad0e["__esModule"] : _0x5443a8["writable"] || _0x5443a8["configurable"])) {
_0x5443a8 = {
'enumerable': true,
'get': function () {
return _0x3769fc[_0x59f7bf];
}
};
}
_0xdc785.defineProperty(_0x25dfad, _0x4b142f, _0x5443a8);
}
}
}
}
}
}
vscode["window"]["showInformationMessage"]("✅ Cursor 环境清理完成!已清理 " + _0x1e982b + " 个目录。请重新启动 Cursor。");
} catch (_0x559de5) {
if (_0x5d7007["WVkud"] !== _0x5d7007["okltc"]) {
vscode["window"].showErrorMessage("清理失败: " + _0x559de5);
} else {
return;
}
}
}
._cleanProxySettings() {
const _0x476eaf = {
'rbZoX': "/etc/hosts",
'eHWqT': function (_0x4595b3, _0x51481f) {
return _0x4595b3 > _0x51481f;
},
'UIOhf': 'versionCheck',
'jYVrR': "app",
'vgDUh': "package.json",
'rqoZM': '连接服务器失败',
'PbRuC': 'uJNLm',
'ctBOw': function (_0x3ad726, _0x1a1bc9) {
return _0x3ad726 === _0x1a1bc9;
},
'YNRuA': function (_0x374e35, _0x5f2806) {
return _0x374e35 !== _0x5f2806;
},
'AcPSo': "Cursor",
'XeYdv': 'User',
'sRZng': "darwin",
'EYltU': 'Library',
'cngrf': "Application Support",
'bQVqg': "settings.json",
'lMMGf': "UAknb",
'eEioj': ".config",
'aTJcA': "TSToT",
'YGjhE': function (_0xb1f254, _0x285077) {
return _0xb1f254 in _0x285077;
},
'TTFqW': "tQfhG",
'dtgRq': 'xvUoy',
'KqxTd': "utf-8",
'ANrMY': "[CursorPro] 清理 settings.json 代理配置失败:"
};
try {
if (_0x476eaf["PbRuC"] === _0x476eaf["PbRuC"]) {
const _0x232e3c = process["platform"];
const _0x35e9f7 = process["env"]["HOME"] || process.env["USERPROFILE"] || '';
let _0x50dd63;
if (_0x476eaf["ctBOw"](_0x232e3c, "win32")) {
if (_0x476eaf["YNRuA"]("xHyzt", "xHyzt")) {
return _0x476eaf["rbZoX"];
} else {
const _0x3f558b = process.env["APPDATA"] || '';
_0x50dd63 = path.join(_0x3f558b, _0x476eaf["AcPSo"], _0x476eaf["XeYdv"], "settings.json");
}
} else {
if (_0x232e3c === _0x476eaf["sRZng"]) {
_0x50dd63 = path["join"](_0x35e9f7, _0x476eaf["EYltU"], _0x476eaf["cngrf"], _0x476eaf["AcPSo"], 'User', _0x476eaf["bQVqg"]);
} else {
if (_0x476eaf["ctBOw"](_0x476eaf["lMMGf"], 'UAknb')) {
_0x50dd63 = path["join"](_0x35e9f7, _0x476eaf["eEioj"], _0x476eaf["AcPSo"], _0x476eaf["XeYdv"], _0x476eaf["bQVqg"]);
} else {
const _0x13402f = _0xb498dc["version"];
const _0x50bf1b = _0x227cb4.CURRENT_VERSION;
const _0x310335 = _0x476eaf["eHWqT"](this["_compareVersions"](_0x13402f, _0x50bf1b), 0x0);
this["_postMessage"]({
'type': _0x476eaf["UIOhf"],
'success': true,
'currentVersion': _0x50bf1b,
'latestVersion': _0x13402f,
'hasUpdate': _0x310335
});
}
}
}
if (!fs.existsSync(_0x50dd63)) {
return;
}
const _0x3b1f5e = fs["readFileSync"](_0x50dd63, 'utf-8');
let _0x2d1395;
try {
_0x2d1395 = JSON.parse(_0x3b1f5e);
} catch {
if (_0x476eaf.aTJcA === _0x476eaf.aTJcA) {
return;
} else {
_0x374c70 = _0xf2eaf5.join(_0x313a74, "resources", _0x476eaf["jYVrR"], _0x476eaf.vgDUh);
}
}
const _0x312520 = ["http.proxy", "http.proxyStrictSSL", "http.proxySupport", "cursor.general.disableHttp2", "http.noProxy"];
let _0x163e93 = false;
for (const _0x2ee1a1 of _0x312520) {
if (_0x2ee1a1 in _0x2d1395) {
_0x163e93 = true;
delete _0x2d1395[_0x2ee1a1];
}
}
if (_0x163e93) {
if (_0x476eaf["TTFqW"] !== 'xvUoy') {
fs["writeFileSync"](_0x50dd63, JSON["stringify"](_0x2d1395, null, 0x4), _0x476eaf["KqxTd"]);
console["log"]("[CursorPro] 已清理 settings.json 中的旧代理配置");
} else {
_0x54658c = _0x115a6a[0x1]["trim"]();
}
}
} else {
const _0x75d65c = _0x5b4ad7?.["message"] || '连接服务器失败';
this["_postMessage"]({
'type': "manualSeamlessSwitched",
'success': false,
'error': _0x75d65c
});
}
} catch (_0xaf9b9c) {
console["warn"](_0x476eaf.ANrMY, _0xaf9b9c);
}
}
["_getHostsPath"]() {
const _0x1afd5f = {
'IIhaI': "win32",
'rhwiN': "C:\\Windows\\System32\\drivers\\etc\\hosts",
'WCHqe': '/etc/hosts'
};
return process.platform === _0x1afd5f["IIhaI"] ? _0x1afd5f["rhwiN"] : '/etc/hosts';
}
._readHostsFile() {
const _0x2eb328 = {
'wAevF': "[CursorPro] 写入本地失败:",
'sUhUV': function (_0x5ed9b2, _0x485978) {
return _0x5ed9b2 !== _0x485978;
},
'hsoXL': 'SLTdx',
'XvGHn': 'utf-8',
'LHIiR': "[CursorPro] Read hosts error:"
};
try {
if (_0x2eb328["sUhUV"]('SLTdx', _0x2eb328["hsoXL"])) {
_0x154660["error"](_0x2eb328["wAevF"], _0x1f3d21);
_0x12820c.window["showErrorMessage"]("写入失败: " + _0x430c52);
return false;
} else {
const _0x49f82f = this["_getHostsPath"]();
if (fs["existsSync"](_0x49f82f)) {
return fs.readFileSync(_0x49f82f, _0x2eb328["XvGHn"]);
}
}
} catch (_0x280006) {
console["error"](_0x2eb328["LHIiR"], _0x280006);
}
return '';
}
["_hasHostsConfig"]() {
const _0x18cd4d = this["_readHostsFile"]();
return _0x18cd4d["includes"](this["HOSTS_MARKER_START"]);
}
async ._grantHostsWritePermission() {
const _0x32c62b = {
'vkbEE': "seamlessStatus",
'seTZS': '检测状态失败',
'hKgsG': function (_0x4a5bc9, _0x2bfac2) {
return _0x4a5bc9 !== _0x2bfac2;
},
'ScmlY': "win32",
'HqZOI': "ffBKI",
'Qwoeu': function (_0x36c14a, _0x3b36cd) {
return _0x36c14a(_0x3b36cd);
},
'mzHlg': "[CursorPro] Hosts file permission granted to user:",
'wVYbp': "[CursorPro] Grant hosts permission error:"
};
if (_0x32c62b["hKgsG"](process["platform"], _0x32c62b["ScmlY"])) {
return false;
}
try {
if (_0x32c62b["HqZOI"] === _0x32c62b["HqZOI"]) {
const _0x4dd7b0 = this._getHostsPath();
const _0x52e208 = process["env"].USERNAME || '';
if (!_0x52e208) {
return false;
}
const _0xb2d318 = _0x4dd7b0["replace"](/\\/g, "\\\\");
const _0x1a66f9 = "powershell -WindowStyle Hidden -Command \"Start-Process powershell -ArgumentList '-WindowStyle Hidden -Command icacls \\\"" + _0xb2d318 + '\" /grant ' + _0x52e208 + ":M' -Verb RunAs -Wait\"";
await _0x32c62b["Qwoeu"](execAsync, _0x1a66f9);
this["_hostsPermissionGranted"] = true;
console["log"](_0x32c62b["mzHlg"], _0x52e208);
return true;
} else {
this["_postMessage"]({
'type': _0x32c62b.vkbEE,
'is_injected': false,
'error': _0x32c62b["seTZS"]
});
}
} catch (_0x32d96e) {
console["error"](_0x32c62b["wVYbp"], _0x32d96e);
return false;
}
}
async ["_writeHostsFile"](_0x5922a3) {
const _0x499688 = {
'xBPFl': "usageCheckResult",
'JhZQT': "未激活授权码",
'iNsae': 'cursorAuth/cachedSignUpType',
'AmHRk': "cursorAuth/stripeMembershipType",
'FOcWe': function (_0x5324f3, _0x2a612f) {
return _0x5324f3 === _0x2a612f;
},
'KudFK': "win32",
'Vogwl': "qQhXV",
'JcomX': 'utf-8',
'ERSCs': "[CursorPro] Direct write failed, trying to grant permission",
'oXrgE': 'gFBAJ',
'YmFQv': 'UnshK',
'CGqqu': "cursorpro_hosts_temp.txt",
'vkEWS': function (_0x12ee8c, _0x39fa65) {
return _0x12ee8c !== _0x39fa65;
},
'OaUGz': "XVhkW",
'ofVDg': "kizvY",
'NrWkg': function (_0x3a76ad, _0x4ab4f9) {
return _0x3a76ad(_0x4ab4f9);
},
'sPvNi': "ipconfig /flushdns",
'iDcQt': function (_0x54a20c, _0x2484fe) {
return _0x54a20c === _0x2484fe;
},
'HLfqb': "darwin",
'vgoUd': "/tmp/hosts_cursor_temp",
'HGnBv': function (_0x134b08, _0x2d8a5b) {
return _0x134b08(_0x2d8a5b);
},
'jDqga': 'BDewf',
'txnlf': "[CursorPro] Write hosts error:"
};
const _0x2983c4 = this["_getHostsPath"]();
try {
if (_0x499688["FOcWe"](process.platform, _0x499688.KudFK)) {
let _0x27620a = false;
try {
if (_0x499688["Vogwl"] !== _0x499688["Vogwl"]) {
_0x3ec235 = _0x26751d["dirname"](_0x1b0534["trim"]());
} else {
fs["writeFileSync"](_0x2983c4, _0x5922a3, _0x499688["JcomX"]);
_0x27620a = true;
}
} catch (_0x2a820d) {
console["log"](_0x499688["ERSCs"]);
}
if (!_0x27620a) {
if (!this._hostsPermissionGranted) {
const _0x1cf639 = await this["_grantHostsWritePermission"]();
if (_0x1cf639) {
if (_0x499688["oXrgE"] === _0x499688["YmFQv"]) {
this._postMessage({
'type': _0x499688.xBPFl,
'success': false,
'error': _0x499688["JhZQT"]
});
return;
} else {
try {
fs["writeFileSync"](_0x2983c4, _0x5922a3, _0x499688["JcomX"]);
_0x27620a = true;
} catch (_0x22fb5c) {
console["log"]("[CursorPro] Write still failed after permission grant");
}
}
}
}
}
if (!_0x27620a) {
const _0x1e3a86 = path["join"](process["env"]["TEMP"] || '', _0x499688.CGqqu);
fs["writeFileSync"](_0x1e3a86, _0x5922a3, _0x499688["JcomX"]);
const _0x2cf526 = _0x1e3a86["replace"](/\\/g, "\\\\");
const _0x456ea4 = _0x2983c4["replace"](/\\/g, "\\\\");
const _0x2a923f = "powershell -WindowStyle Hidden -Command \"Start-Process powershell -ArgumentList '-WindowStyle Hidden -Command Copy-Item -Path \\\"" + _0x2cf526 + '\" -Destination \"' + _0x456ea4 + "\\\" -Force' -Verb RunAs -Wait\"";
await execAsync(_0x2a923f);
try {
if (_0x499688["OaUGz"] !== _0x499688["ofVDg"]) {
fs["unlinkSync"](_0x1e3a86);
} else {
_0x23b2c1["push"]([_0x499688["iNsae"], _0x2e0cc7.sign_up_type]);
}
} catch {}
}
try {
await _0x499688["NrWkg"](execAsync, _0x499688["sPvNi"]);
console["log"]("[CursorPro] Windows DNS 缓存已刷新");
} catch (_0x460c7f) {
console.warn("[CursorPro] Windows DNS 刷新失败:", _0x460c7f);
}
} else {
if (_0x499688["iDcQt"](process["platform"], _0x499688.HLfqb)) {
const _0x24a472 = _0x499688["vgoUd"];
fs["writeFileSync"](_0x24a472, _0x5922a3, _0x499688["JcomX"]);
const _0x22f069 = "do shell script \"cp '" + _0x24a472 + "' '" + _0x2983c4 + "' && rm '" + _0x24a472 + "' && dscacheutil -flushcache && killall -HUP mDNSResponder\" with administrator privileges";
await _0x499688["HGnBv"](execAsync, 'osascript -e "' + _0x22f069.replace(/"/g, "\\\"") + "\"");
} else {
fs["writeFileSync"](_0x2983c4, _0x5922a3, _0x499688["JcomX"]);
}
}
return true;
} catch (_0x4e285f) {
console["error"](_0x499688["txnlf"], _0x4e285f);
return false;
}
}
async ["_handleToggleProxy"](_0x45fe86, _0x2bcba7) {
const _0x55a623 = {
'ejdVR': "[CursorPro] 检测无感换号状态失败:",
'PEste': function (_0x53a002, _0x4c22fe) {
return _0x53a002 === _0x4c22fe;
},
'hgedP': "win32",
'qGQVl': "[CursorPro] macOS 获取进程路径失败:",
'uJGtI': function (_0x48017f, _0x5c2c7c) {
return _0x48017f !== _0x5c2c7c;
},
'JOyUC': "owyly",
'abtRx': "JZnQC",
'bPNQC': "cursorpro.key",
'XKRmO': 'cursorpro.expireDate',
'lrUSI': "proxyUpdated",
'wngsU': '请先激活授权码',
'bNcBC': 'showToast',
'wbUaU': "nMubd",
'qvcRi': function (_0x6220c6, _0x46b6bf) {
return _0x6220c6 > _0x46b6bf;
},
'rBQDv': "授权码已过期,无法开启免魔法",
'RrtRU': function (_0x572eb6, _0x46c0a4) {
return _0x572eb6 !== _0x46c0a4;
},
'PoFgx': "BHFHl",
'xXref': function (_0x1b909c, _0x5c9bad) {
return _0x1b909c + _0x5c9bad;
},
'HwXSS': function (_0x576fb0, _0x41a4c1) {
return _0x576fb0 !== _0x41a4c1;
},
'LwgUG': "ejFIc",
'yTNgQ': "QrGmP",
'rATBP': "免魔法已关闭",
'jtzgG': "修改 hosts 文件失败,请确保有管理员权限",
'SfnWE': '更新配置失败'
};
try {
if ("JCMUi" === "JCMUi") {
if (_0x45fe86) {
if (_0x55a623["uJGtI"](_0x55a623.JOyUC, _0x55a623["abtRx"])) {
const _0x2e87c9 = this["_context"]["globalState"]["get"](_0x55a623["bPNQC"]);
const _0x4818f7 = this._context.globalState.get('cursorpro.expireDate');
if (!_0x2e87c9) {
this["_postMessage"]({
'type': _0x55a623["lrUSI"],
'success': false,
'error': _0x55a623["wngsU"]
});
this["_postMessage"]({
'type': _0x55a623["bNcBC"],
'message': '请先激活授权码',
'icon': '⚠️'
});
return;
}
if (_0x4818f7) {
if (_0x55a623["wbUaU"] === _0x55a623.wbUaU) {
const _0x13c1c7 = new Date(_0x4818f7)["getTime"]();
if (_0x55a623["qvcRi"](Date["now"](), _0x13c1c7)) {
this._postMessage({
'type': _0x55a623["lrUSI"],
'success': false,
'error': _0x55a623.rBQDv
});
this["_postMessage"]({
'type': _0x55a623["bNcBC"],
'message': _0x55a623["rBQDv"],
'icon': '⚠️'
});
return;
}
} else {
_0xdb849d["error"]("[CursorPro] 检测无感换号状态失败:", _0x27cca9);
return false;
}
}
} else {
return true;
}
}
this["_cleanProxySettings"]();
let _0x41dcbc = this["_readHostsFile"]();
const _0x8cbdf8 = _0x41dcbc["indexOf"](this["HOSTS_MARKER_START"]);
const _0x5529db = _0x41dcbc["indexOf"](this.HOSTS_MARKER_END);
if (_0x55a623["uJGtI"](_0x8cbdf8, -0x1) && _0x5529db !== -0x1) {
if (_0x55a623["PoFgx"] !== 'jcvMA') {
_0x41dcbc = _0x41dcbc.substring(0x0, _0x8cbdf8) + _0x41dcbc["substring"](_0x55a623["xXref"](_0x5529db, this.HOSTS_MARKER_END["length"]));
} else {
return _0x55a623["PEste"](_0x52d6bb["platform"], _0x55a623.hgedP) ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts";
}
}
_0x41dcbc = _0x41dcbc["replace"](/\n{3,}/g, "\n\n")["trim"]();
if (_0x45fe86) {
const _0x3c2da2 = this.CURSOR_DOMAINS.map(_0x2b32f6 => this.SNI_PROXY_IP + " " + _0x2b32f6)["join"]("\n");
const _0x12c61b = "\n\n" + this.HOSTS_MARKER_START + "\n" + _0x3c2da2 + "\n" + this["HOSTS_MARKER_END"] + "\n";
_0x41dcbc += _0x12c61b;
}
const _0x5b508c = await this._writeHostsFile(_0x41dcbc);
if (_0x5b508c) {
if (_0x55a623.LwgUG !== _0x55a623["yTNgQ"]) {
0x0;
await client_1["updateProxyConfig"](_0x45fe86, this["SNI_PROXY_IP"]);
this["_postMessage"]({
'type': _0x55a623["lrUSI"],
'success': true,
'enabled': _0x45fe86,
'url': this.SNI_PROXY_IP
});
this["_postMessage"]({
'type': _0x55a623["bNcBC"],
'message': _0x45fe86 ? "免魔法已开启" : _0x55a623["rATBP"],
'icon': '✅'
});
} else {
_0x5dcacb.log("[CursorPro] 快捷方式解析获取路径失败");
}
} else {
this["_postMessage"]({
'type': "proxyUpdated",
'success': false,
'error': _0x55a623["jtzgG"]
});
this._postMessage({
'type': "showToast",
'message': "需要管理员权限修改 hosts 文件",
'icon': '⚠️'
});
}
} else {
_0x2faaed["warn"](_0x55a623["qGQVl"], _0x591cf9);
}
} catch (_0x15bb87) {
console["error"]("[CursorPro] Toggle proxy error:", _0x15bb87);
this["_postMessage"]({
'type': _0x55a623["lrUSI"],
'success': false,
'error': _0x55a623["SfnWE"]
});
}
}
async ["_handleGetProxyStatus"]() {
const _0x2c5a98 = {
'fZAIy': "[CursorPro] Get proxy status error:",
'wipaS': "proxyStatus"
};
try {
const _0x45986e = this["_hasHostsConfig"]();
this._postMessage({
'type': "proxyStatus",
'enabled': _0x45986e,
'url': _0x45986e ? this.SNI_PROXY_IP : ''
});
} catch (_0x590417) {
console.error(_0x2c5a98["fZAIy"], _0x590417);
this._postMessage({
'type': _0x2c5a98["wipaS"],
'enabled': false,
'url': ''
});
}
}
async ["_handleGetSeamlessStatus"]() {
const _0x5ae0f5 = {
'KFUBS': 'seamlessStatus',
'rCNDh': '未找到'
};
try {
const _0x95ad53 = await this["_getWorkbenchPathAsync"]();
let _0x571ba2 = false;
if (_0x95ad53 && fs.existsSync(_0x95ad53)) {
const _0x16bc8d = fs["readFileSync"](_0x95ad53, 'utf-8');
_0x571ba2 = this["_checkInjected"](_0x16bc8d);
}
this["_postMessage"]({
'type': _0x5ae0f5["KFUBS"],
'is_injected': _0x571ba2,
'workbench_path': _0x95ad53 || '未找到'
});
} catch (_0x4253d3) {
this["_postMessage"]({
'type': "seamlessStatus",
'is_injected': false,
'error': "检测状态失败"
});
}
}
async ._getCursorInstallPath() {
const _0x56e2a7 = {
'Dikkd': "showToast",
'jsXpS': "请先激活授权码",
'YOVDn': "更新配置失败",
'iTlfT': "[CursorPro] 创建备份文件",
'yLNTm': 'resources',
'GeHhf': 'app',
'CXUfC': "package.json",
'UtnZu': "[CursorPro] 读取账号失败:",
'gnUSM': "[CursorPro] 写入文件失败:",
'bYxaW': function (_0x423a3a, _0x5db055) {
return _0x423a3a === _0x5db055;
},
'EgKGn': "EPERM",
'EAHLk': function (_0x337fa2, _0x2cea6d) {
return _0x337fa2 === _0x2cea6d;
},
'WjWcW': "EACCES",
'MQZgl': "EROFS",
'oengj': function (_0x277036, _0x403852) {
return _0x277036 === _0x403852;
},
'Aarxw': 'darwin',
'DJbBl': "没有写入权限,请在终端执行: sudo chmod -R 777 /Applications/Cursor.app",
'aREDm': "seamlessInjected",
'iIXMD': "usageCheckResult",
'BDJnl': function (_0x1e4a2f, _0x534c0a) {
return _0x1e4a2f(_0x534c0a);
},
'DtDgA': function (_0x29bc62, _0x322a2b) {
return _0x29bc62 < _0x322a2b;
},
'mmvWR': "[CursorPro] SQLite 更新失败:",
'oaRrk': "SQLite",
'CTVdA': function (_0x74a645, _0x1120bf) {
return _0x74a645 * _0x1120bf;
},
'Uuffn': 'userSwitchStatus',
'rBiqx': "未激活授权码",
'rQFft': "cursorPath",
'RnudW': "[CursorPro] 使用用户配置的 Cursor 路径:",
'PVaIE': "win32",
'XfqQZ': function (_0x9c7d0d, _0x5e3a66) {
return _0x9c7d0d(_0x5e3a66);
},
'DeasY': function (_0x4abb75, _0x582177) {
return _0x4abb75 !== _0x582177;
},
'AsIZj': "qoucU",
'nqiCC': 'DFFnS',
'QVuwP': "[CursorPro] WMIC 获取路径失败",
'dRsNK': 'YbsJH',
'jErMS': "KgPWK",
'NyxMG': 'powershell -Command "Get-Process Cursor -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Path"',
'wEuDv': function (_0x124977, _0x7c188e) {
return _0x124977 !== _0x7c188e;
},
'XOHNV': "PCmsj",
'TGItL': "[CursorPro] PowerShell Get-Process 获取路径失败",
'thwli': 'reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall" /s /f "Cursor" 2>nul | findstr "InstallLocation"',
'VMcWU': 'xkLFN',
'QxSsa': "VRqTq",
'dCyzn': "qGOpJ",
'fdUBf': "WEzFK",
'PIiyE': "[CursorPro] 注册表方法1获取路径失败",
'sbJjp': function (_0x20ef8a, _0x2ae693) {
return _0x20ef8a(_0x2ae693);
},
'ZzzNm': "reg query \"HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\" /s /f \"Cursor\" 2>nul | findstr \"InstallLocation\"",
'nbZaF': function (_0x1cbd3c, _0x4a6cb7) {
return _0x1cbd3c === _0x4a6cb7;
},
'wbtDv': "vnDbD",
'cNdLq': 'xFoOA',
'FZvwj': 'OHDPB',
'UneuY': 'Microsoft',
'qsIby': "Windows",
'EHZof': 'Cursor.lnk',
'jjkbK': "C:\\ProgramData",
'BtFbH': "Start Menu",
'JdBJc': function (_0x28f75d, _0x183780) {
return _0x28f75d(_0x183780);
},
'jsxnQ': function (_0x136514, _0x280034) {
return _0x136514 === _0x280034;
},
'qBUXV': "[CursorPro] 快捷方式解析获取路径失败",
'exySU': "vhjCP",
'TGkVo': function (_0x23968b, _0x7071) {
return _0x23968b !== _0x7071;
},
'suGMP': "BQAEU",
'UFTPT': "[CursorPro] where 命令获取路径失败",
'DmbzX': "C:\\Program Files",
'pezWM': "ProgramFiles(x86)",
'siiYr': "Programs",
'qYQbK': "Cursor",
'IrvuT': 'cursor',
'GSVlF': "AppData",
'MCVpB': "Local",
'PDSZm': "XrXcG",
'EgLjx': function (_0x28fb08, _0xcbe128) {
return _0x28fb08 !== _0xcbe128;
},
'HILVh': "iDOKM",
'smRnq': "EZQju",
'goLBO': function (_0x534585, _0x3cba48) {
return _0x534585(_0x3cba48);
},
'PfsJK': function (_0x1edda8, _0x24c322) {
return _0x1edda8 !== _0x24c322;
},
'SZhcT': "kFqGj",
'NkvWo': "AvPWh",
'fIoaQ': function (_0x241ec0, _0x2ed30c) {
return _0x241ec0 === _0x2ed30c;
},
'AEQys': "DLzJi",
'DMxiK': "fmKaB",
'KCchE': "ps -eo comm,args | grep -i \"[C]ursor\" | grep -v \"grep\" | head -1",
'oSNCM': "[CursorPro] macOS 获取进程路径失败:",
'vFKuA': function (_0x3f2aba, _0x3b57d7) {
return _0x3f2aba !== _0x3b57d7;
},
'BzqQS': "LPxcr",
'Iiavz': function (_0x518563, _0x266c3c) {
return _0x518563(_0x266c3c);
},
'DTxsT': "mdfind \"kMDItemCFBundleIdentifier == 'com.todesktop.*cursor*'\" 2>/dev/null | head -1",
'Duhra': '/Applications/Cursor.app',
'TWejg': function (_0x5bd29f, _0x55a6c4) {
return _0x5bd29f(_0x55a6c4);
},
'hHnTm': function (_0x24d237, _0x40656e) {
return _0x24d237(_0x40656e);
},
'ytsfa': '/bin',
'fYZrC': 'BDrEe',
'TLLsB': "which cursor 2>/dev/null",
'IGQIN': "RTVew",
'rbFqJ': "[CursorPro] Linux 获取进程路径失败:",
'WgRyf': "/opt/Cursor",
'XOLnJ': '/opt/cursor',
'fxGJt': "/usr/share/cursor",
'lzEMa': "/usr/lib/cursor",
'gQXjY': "Applications/cursor",
'EghBP': "[CursorPro] 获取 Cursor 安装路径失败:"
};
if (this["_cachedCursorPath"]) {
return this["_cachedCursorPath"];
}
const _0x39cd5d = vscode["workspace"]["getConfiguration"]("cursorpro");
const _0x3bf8b8 = _0x39cd5d["get"](_0x56e2a7.rQFft);
if (_0x3bf8b8 && fs["existsSync"](_0x3bf8b8)) {
console["log"](_0x56e2a7["RnudW"], _0x3bf8b8);
this._cachedCursorPath = _0x3bf8b8;
return _0x3bf8b8;
}
const _0x51335c = process["platform"];
let _0x36d8e8 = null;
try {
if (_0x51335c === _0x56e2a7.PVaIE) {
try {
const {
stdout: _0x446f65
} = await execAsync("wmic process where \"name='Cursor.exe'\" get ExecutablePath /format:list 2>nul");
if (_0x446f65) {
if (_0x56e2a7["DeasY"](_0x56e2a7["AsIZj"], _0x56e2a7["AsIZj"])) {
this["_postMessage"]({
'type': _0x56e2a7["Dikkd"],
'message': _0x56e2a7.jsXpS,
'icon': '⚠️'
});
return;
} else {
const _0x19ca83 = _0x446f65["match"](/ExecutablePath=(.+)/);
if (_0x19ca83 && _0x19ca83[0x1]) {
if (_0x56e2a7["nqiCC"] === "qzRkG") {
this._postMessage({
'type': "showToast",
'message': "重置机器码失败: " + _0x51bc1d,
'icon': '❌'
});
} else {
const _0x27a427 = _0x19ca83[0x1]["trim"]();
_0x36d8e8 = path["dirname"](_0x27a427);
}
}
}
}
} catch (_0x4c944d) {
console["log"](_0x56e2a7.QVuwP);
}
if (!_0x36d8e8) {
if ('YbsJH' !== _0x56e2a7["jErMS"]) {
try {
const {
stdout: _0x2ac2d3
} = await _0x56e2a7["BDJnl"](execAsync, _0x56e2a7.NyxMG);
if (_0x2ac2d3 && _0x2ac2d3["trim"]()) {
_0x36d8e8 = path["dirname"](_0x2ac2d3["trim"]());
}
} catch (_0x387539) {
if (_0x56e2a7["wEuDv"](_0x56e2a7.XOHNV, "idSrD")) {
console.log(_0x56e2a7["TGItL"]);
} else if (_0x36e365["includes"](_0x216fbb.scode)) {
_0x51a668 = _0x5d60b0["replace"](_0x562774["scode"], _0x1ac061["replacement"]);
_0x15853d["push"](_0x1d4997["name"]);
} else {
_0x41fc0e["push"](_0x551686["name"]);
}
}
} else {
_0x86b57c = _0xcd7e5a["dirname"](_0x337963);
}
}
if (!_0x36d8e8) {
try {
const {
stdout: _0x1bbadc
} = await execAsync(_0x56e2a7["thwli"]);
if (_0x1bbadc && _0x1bbadc.trim()) {
const _0x53b6fb = _0x1bbadc.match(/InstallLocation\s+REG_SZ\s+(.+)/);
if (_0x53b6fb && _0x53b6fb[0x1] && fs["existsSync"](_0x53b6fb[0x1]["trim"]())) {
if (_0x56e2a7["VMcWU"] !== _0x56e2a7.QxSsa) {
_0x36d8e8 = _0x53b6fb[0x1]["trim"]();
} else {
this["_postMessage"]({
'type': "proxyUpdated",
'success': false,
'error': _0x56e2a7["jsXpS"]
});
this["_postMessage"]({
'type': _0x56e2a7["Dikkd"],
'message': _0x56e2a7["jsXpS"],
'icon': '⚠️'
});
return;
}
}
}
} catch (_0x4253cf) {
if (_0x56e2a7["dCyzn"] !== _0x56e2a7["fdUBf"]) {
console.log(_0x56e2a7.PIiyE);
} else {
this["_postMessage"]({
'type': 'seamlessConfigUpdated',
'success': false,
'error': _0x56e2a7["YOVDn"]
});
}
}
}
if (!_0x36d8e8) {
try {
const {
stdout: _0xf5d246
} = await execAsync(_0x56e2a7["ZzzNm"]);
if (_0xf5d246 && _0xf5d246.trim()) {
const _0x3c2cd7 = _0xf5d246["match"](/InstallLocation\s+REG_SZ\s+(.+)/);
if (_0x3c2cd7 && _0x3c2cd7[0x1] && fs.existsSync(_0x3c2cd7[0x1].trim())) {
if (_0x56e2a7["nbZaF"](_0x56e2a7["wbtDv"], _0x56e2a7["cNdLq"])) {
_0x371f53 = _0x3146b2["replace"](_0x262100["scode"], _0x35b030["replacement"]);
_0x2f13c6.push(_0x495b54.name);
} else {
_0x36d8e8 = _0x3c2cd7[0x1]["trim"]();
}
}
}
} catch (_0x38448a) {
console["log"]("[CursorPro] 注册表方法2获取路径失败");
}
}
if (!_0x36d8e8) {
if (_0x56e2a7["FZvwj"] !== 'ASYNt') {
try {
const _0x4a36af = path["join"](process["env"]["APPDATA"] || '', _0x56e2a7["UneuY"], _0x56e2a7.qsIby, "Start Menu", 'Programs', _0x56e2a7["EHZof"]);
const _0x3876ac = path["join"](_0x56e2a7["jjkbK"], _0x56e2a7["UneuY"], 'Windows', _0x56e2a7["BtFbH"], "Programs", _0x56e2a7["EHZof"]);
for (const _0x20745d of [_0x4a36af, _0x3876ac]) {
if (fs["existsSync"](_0x20745d)) {
const {
stdout: _0x321537
} = await execAsync("powershell -Command \"(New-Object -ComObject WScript.Shell).CreateShortcut('" + _0x20745d["replace"](/'/g, "''") + "').TargetPath\"");
if (_0x321537 && _0x321537.trim() && fs.existsSync(_0x321537["trim"]())) {
if (_0x56e2a7["jsxnQ"]("EzvlI", "EzvlI")) {
_0x36d8e8 = path["dirname"](_0x321537["trim"]());
break;
} else {
_0x5839cf = ["/Applications/Cursor.app/Contents/Resources/app/out/vs/workbench/workbench.desktop.main.js"];
}
}
}
}
} catch (_0x628be0) {
console["log"](_0x56e2a7["qBUXV"]);
}
} else {
const _0x41d381 = _0x1d7b98.match(/ExecutablePath=(.+)/);
if (_0x41d381 && _0x41d381[0x1]) {
const _0x311d7f = _0x41d381[0x1]["trim"]();
_0x7495 = _0x387799["dirname"](_0x311d7f);
}
}
}
if (!_0x36d8e8) {
if (_0x56e2a7["exySU"] === _0x56e2a7["exySU"]) {
try {
const {
stdout: _0x4d3618
} = await _0x56e2a7["JdBJc"](execAsync, "where cursor 2>nul");
if (_0x4d3618 && _0x4d3618["trim"]()) {
const _0x1e390f = _0x4d3618.trim()["split"]("\n");
for (const _0x4be01a of _0x1e390f) {
const _0x2817ed = _0x4be01a.trim();
if (_0x2817ed && fs.existsSync(_0x2817ed)) {
_0x36d8e8 = path["dirname"](_0x2817ed);
break;
}
}
}
} catch (_0x2b8ad6) {
if ("BQAEU" !== _0x56e2a7["suGMP"]) {
_0x33db66["copyFileSync"](_0x51579c, _0x931655);
_0x261bd5["log"](_0x56e2a7["iTlfT"]);
} else {
console["log"](_0x56e2a7["UFTPT"]);
}
}
} else {
const _0x4c6948 = _0x4dafc4[0x1].trim();
_0x373919 = _0x57ec2c.dirname(_0x4c6948);
_0x543724 = _0x3fcb44["join"](_0x2ba35f, _0x56e2a7["yLNTm"], _0x56e2a7["GeHhf"], _0x56e2a7["CXUfC"]);
}
}
if (!_0x36d8e8) {
const _0x526dcd = process["env"].LOCALAPPDATA || '';
const _0x11abe2 = process["env"]["USERPROFILE"] || '';
const _0x5a2b8c = process["env"]["ProgramFiles"] || _0x56e2a7["DmbzX"];
const _0x53bae9 = process["env"][_0x56e2a7["pezWM"]] || "C:\\Program Files (x86)";
const _0x7ed789 = [path["join"](_0x526dcd, _0x56e2a7.siiYr, _0x56e2a7.qYQbK), path.join(_0x526dcd, _0x56e2a7["siiYr"], _0x56e2a7["IrvuT"]), path["join"](_0x11abe2, _0x56e2a7["GSVlF"], _0x56e2a7.MCVpB, _0x56e2a7.siiYr, _0x56e2a7.qYQbK), path.join(_0x5a2b8c, _0x56e2a7.qYQbK), path["join"](_0x53bae9, "Cursor"), path.join(_0x526dcd, _0x56e2a7["qYQbK"]), path["join"](_0x526dcd, _0x56e2a7["IrvuT"])];
for (const _0x5e748e of _0x7ed789) {
if (_0x56e2a7["EAHLk"]("mDWBe", _0x56e2a7["PDSZm"])) {
_0x4e428d.error(_0x56e2a7["UtnZu"], _0x4ee69e);
return [];
} else {
if (_0x5e748e && fs["existsSync"](_0x5e748e)) {
_0x36d8e8 = _0x5e748e;
break;
}
}
}
}
} else {
if (_0x51335c === _0x56e2a7["Aarxw"]) {
if (_0x56e2a7["EgLjx"](_0x56e2a7.HILVh, "mPbmb")) {
try {
if ("VYhDm" === _0x56e2a7["smRnq"]) {
_0x3f27c6.error(_0x56e2a7["gnUSM"], _0x16e0a9);
if (_0x56e2a7["bYxaW"](_0x3fa137["code"], _0x56e2a7["EgKGn"]) || _0x56e2a7["EAHLk"](_0x50c56a["code"], _0x56e2a7["WjWcW"]) || _0x2fdaaf.code === _0x56e2a7.MQZgl) {
const _0x2f5e07 = _0xf7d812["platform"];
let _0xee0d40 = "没有写入权限";
if (_0x56e2a7["oengj"](_0x2f5e07, 'darwin')) {
_0xee0d40 = _0x56e2a7["DJbBl"];
} else if (_0x2f5e07 === "linux") {
_0xee0d40 = "没有写入权限,请使用 sudo 权限运行或修改文件权限";
}
this["_postMessage"]({
'type': _0x56e2a7["aREDm"],
'success': false,
'error': _0xee0d40,
'needAdmin': true,
'path': _0x4f0e82
});
return;
}
throw _0x47d908;
} else {
const {
stdout: _0x369a56
} = await _0x56e2a7["goLBO"](execAsync, "lsof -c Cursor 2>/dev/null | grep \"txt\" | grep -i \"Cursor.app\" | head -1 | awk '{print $9}'");
if (_0x369a56 && _0x369a56.trim()) {
if (_0x56e2a7.SZhcT !== _0x56e2a7["SZhcT"]) {
this["_postMessage"]({
'type': "usageCheckResult",
'success': true,
'needConfirm': false
});
} else {
const _0x257e0d = _0x369a56.trim()["match"](/(.+\.app)/);
if (_0x257e0d) {
if (_0x56e2a7["bYxaW"](_0x56e2a7.NkvWo, 'hsffN')) {
this["_postMessage"]({
'type': _0x56e2a7["iIXMD"],
'success': true,
'needConfirm': false
});
return;
} else {
_0x36d8e8 = _0x257e0d[0x1];
}
}
}
}
}
} catch (_0x1b82a1) {}
if (!_0x36d8e8) {
try {
if (_0x56e2a7["fIoaQ"](_0x56e2a7.AEQys, _0x56e2a7["DMxiK"])) {
const _0x3b6ec9 = _0x4396d5.data["usage"] || {};
const _0x318ca7 = _0x56e2a7["BDJnl"](_0x5a3f82, _0x3b6ec9["totalCostUSD"] || 0x0);
if (_0x56e2a7["DtDgA"](_0x318ca7, 0xa)) {
this["_postMessage"]({
'type': _0x56e2a7.iIXMD,
'success': true,
'needConfirm': true,
'costUSD': _0x318ca7.toFixed(0x2),
'email': _0x430d08
});
} else {
this["_postMessage"]({
'type': _0x56e2a7["iIXMD"],
'success': true,
'needConfirm': false
});
}
} else {
const {
stdout: _0x58b89f
} = await execAsync(_0x56e2a7["KCchE"]);
if (_0x58b89f && _0x58b89f.trim()) {
const _0x488389 = _0x58b89f["match"](/(\/.+\.app)/);
if (_0x488389) {
_0x36d8e8 = _0x488389[0x1];
}
}
}
} catch (_0x58c36b) {
console.warn(_0x56e2a7["oSNCM"], _0x58c36b);
}
}
if (!_0x36d8e8) {
if (_0x56e2a7["vFKuA"]("LPxcr", _0x56e2a7["BzqQS"])) {
_0x178033.error("[CursorPro] Write hosts error:", _0x1a091f);
return false;
} else {
try {
const {
stdout: _0x45fa41
} = await execAsync(_0x56e2a7["DTxsT"]);
if (_0x45fa41 && _0x45fa41.trim() && fs.existsSync(_0x45fa41["trim"]())) {
_0x36d8e8 = _0x45fa41.trim();
}
} catch (_0x141dcf) {}
}
}
if (!_0x36d8e8 && fs["existsSync"]('/Applications/Cursor.app')) {
_0x36d8e8 = _0x56e2a7["Duhra"];
}
} else {
_0x221adf["warn"](_0x56e2a7["mmvWR"], _0x45ce1f.message);
_0x2ae3cb["push"](_0x56e2a7["oaRrk"]);
}
} else {
try {
const {
stdout: _0x11564d
} = await execAsync('pgrep -f "[c]ursor" | head -1');
const _0x5dd0f3 = _0x11564d && _0x11564d.trim();
if (_0x5dd0f3) {
const {
stdout: _0x447245
} = await _0x56e2a7["hHnTm"](execAsync, "readlink -f /proc/" + _0x5dd0f3 + "/exe 2>/dev/null");
if (_0x447245 && _0x447245["trim"]()) {
const _0x11b963 = _0x447245["trim"]();
_0x36d8e8 = path.dirname(_0x11b963);
if (_0x36d8e8["endsWith"](_0x56e2a7["ytsfa"])) {
_0x36d8e8 = path["dirname"](_0x36d8e8);
}
}
}
} catch (_0x27a28d) {}
if (!_0x36d8e8) {
if ("BDrEe" !== _0x56e2a7["fYZrC"]) {
let _0x34acf5 = '';
const _0x3634b6 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let _0x1963ff = 0x0; _0x1963ff < 0x20; _0x1963ff++) {
_0x34acf5 += _0x3634b6.charAt(_0x5a7f9b["floor"](_0x142a7a["random"]() * _0x3634b6["length"]));
}
return _0x34acf5;
} else {
try {
const {
stdout: _0x400a70
} = await _0x56e2a7["BDJnl"](execAsync, _0x56e2a7["TLLsB"]);
if (_0x400a70 && _0x400a70.trim()) {
const _0x44bb60 = await execAsync('readlink -f "' + _0x400a70.trim() + '" 2>/dev/null');
if (_0x44bb60.stdout && _0x44bb60["stdout"].trim()) {
_0x36d8e8 = path["dirname"](_0x44bb60["stdout"].trim());
if (_0x36d8e8["endsWith"]('/bin')) {
if (_0x56e2a7["oengj"](_0x56e2a7.IGQIN, "ZRSMl")) {
this["_postMessage"]({
'type': 'userSwitchStatus',
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': _0x56e2a7["rBiqx"]
});
return;
} else {
_0x36d8e8 = path["dirname"](_0x36d8e8);
}
}
}
}
} catch (_0x1d7835) {
console["warn"](_0x56e2a7["rbFqJ"], _0x1d7835);
}
}
}
if (!_0x36d8e8) {
const _0x38357a = [_0x56e2a7["WgRyf"], _0x56e2a7["XOLnJ"], _0x56e2a7["fxGJt"], _0x56e2a7["lzEMa"], path["join"](process["env"]["HOME"] || '', ".local/share/cursor"), path.join(process["env"]["HOME"] || '', _0x56e2a7["gQXjY"])];
for (const _0x3a8856 of _0x38357a) {
if (fs.existsSync(_0x3a8856)) {
_0x36d8e8 = _0x3a8856;
break;
}
}
}
}
}
} catch (_0x2440bb) {
console["error"](_0x56e2a7["EghBP"], _0x2440bb);
}
if (_0x36d8e8) {
this._cachedCursorPath = _0x36d8e8;
}
return _0x36d8e8;
}
._getWorkbenchPath() {
return this["_getWorkbenchPathSync"]();
}
._getWorkbenchPathSync() {
const _0x45dfd9 = {
'UfpAf': "storage.serviceMachineId",
'Anviz': "[CursorPro] machineid 更新失败:",
'VVCFs': "machineid",
'JyreV': function (_0x2669b9, _0x3af5b1) {
return _0x2669b9(_0x3af5b1);
},
'LuKVI': 'crypto',
'SWJRm': function (_0xc6cc6a, _0x1e79ba) {
return _0xc6cc6a & _0x1e79ba;
},
'FQssd': function (_0x36d4a3, _0x3f9411) {
return _0x36d4a3 !== _0x3f9411;
},
'eUATr': function (_0x5176f0, _0x2f72df) {
return _0x5176f0 === _0x2f72df;
},
'jTUqv': "darwin",
'VLslV': 'xuLZV',
'UWqNM': "app",
'sQFsh': "out",
'eRJjA': "workbench",
'gkqWe': "workbench.desktop.main.js",
'ZSOkm': function (_0x45c79f, _0x381d17) {
return _0x45c79f !== _0x381d17;
},
'SccyE': "kWVws",
'dVhNW': "resources",
'VfwmP': function (_0x239346, _0xe3f08f) {
return _0x239346 === _0xe3f08f;
},
'NyLwi': "/Applications/Cursor.app/Contents/Resources/app/out/vs/workbench/workbench.desktop.main.js",
'aJjyB': 'qRWfN',
'bWpPz': "/opt/Cursor/resources/app/out/vs/workbench/workbench.desktop.main.js"
};
const _0x476275 = process["platform"];
if (this._cachedCursorPath) {
if (_0x45dfd9["FQssd"]('zZyLK', "PQRiM")) {
let _0x3205e4;
if (_0x45dfd9["eUATr"](_0x476275, _0x45dfd9["jTUqv"])) {
if (_0x45dfd9["eUATr"]("xuLZV", 'xuLZV')) {
_0x3205e4 = path.join(this["_cachedCursorPath"], 'Contents', "Resources", _0x45dfd9["UWqNM"], _0x45dfd9["sQFsh"], 'vs', _0x45dfd9.eRJjA, _0x45dfd9["gkqWe"]);
} else {
_0x3e2976["push"]([_0x45dfd9["UfpAf"], _0x4568af["serviceMachineId"]]);
}
} else if (_0x45dfd9["ZSOkm"]("XbfIf", _0x45dfd9["SccyE"])) {
_0x3205e4 = path["join"](this["_cachedCursorPath"], _0x45dfd9.dVhNW, "app", _0x45dfd9["sQFsh"], 'vs', _0x45dfd9["eRJjA"], "workbench.desktop.main.js");
} else {
_0x575999["warn"](_0x45dfd9["Anviz"], _0x58392c.message);
_0x8af8ae["push"](_0x45dfd9["VVCFs"]);
}
if (fs.existsSync(_0x3205e4)) {
return _0x3205e4;
}
} else {
return [];
}
}
if (_0x45dfd9["eUATr"](_0x476275, 'win32')) {
return null;
}
let _0x5a8c19 = [];
if (_0x45dfd9["VfwmP"](_0x476275, _0x45dfd9.jTUqv)) {
_0x5a8c19 = [_0x45dfd9["NyLwi"]];
} else {
if ('DESET' !== _0x45dfd9["aJjyB"]) {
_0x5a8c19 = [_0x45dfd9["bWpPz"], '/usr/share/cursor/resources/app/out/vs/workbench/workbench.desktop.main.js'];
} else {
const _0x495a3b = _0x45dfd9["JyreV"](_0x32b48c, 'crypto');
const _0xfc487e = _0x495a3b["randomBytes"](0x6);
_0xfc487e[0x0] = _0x45dfd9["SWJRm"](_0xfc487e[0x0] | 0x2, 0xfe);
return _0x55363f["from"](_0xfc487e)["map"](_0x210fd8 => _0x210fd8.toString(0x10)["padStart"](0x2, '0'))["join"](':');
}
}
for (const _0x3c46cb of _0x5a8c19) {
if (fs["existsSync"](_0x3c46cb)) {
return _0x3c46cb;
}
}
return null;
}
async ["_getWorkbenchPathAsync"]() {
const _0x333f76 = {
'diJhY': "C:\\Program Files",
'BHmwx': "ProgramFiles(x86)",
'xDKiN': "C:\\Program Files (x86)",
'aIUry': "Programs",
'oemiO': "Cursor",
'wNjLv': "resources",
'BzPhh': "package.json",
'dNHJx': "cursor",
'JBwsK': "app",
'NoEGQ': "AppData",
'GOKzJ': "Local",
'okosv': 'versionCheck',
'ktVBs': function (_0x175f78, _0x5a924f) {
return _0x175f78 === _0x5a924f;
},
'fYTsi': "EUUHA",
'idevD': "eXeOK",
'SJHtk': function (_0x48c702, _0x410996) {
return _0x48c702 === _0x410996;
},
'AJPrD': "darwin",
'qcilt': function (_0x48c64d, _0x367af2) {
return _0x48c64d === _0x367af2;
},
'yQEWX': "vUlDT",
'Knhyl': "Contents",
'NPYXr': "Resources",
'xDNVo': "out",
'Lnhsa': "workbench",
'ejmIv': "workbench.desktop.main.js",
'yfprZ': "dtGAS"
};
const _0x4a5df6 = process.platform;
const _0x1a6628 = await this["_getCursorInstallPath"]();
if (_0x1a6628) {
if (_0x333f76["ktVBs"](_0x333f76["fYTsi"], _0x333f76["idevD"])) {
const _0x56cab4 = _0x12c65b[0x1]["trim"]();
_0x13e8cf = _0x13c1c8["dirname"](_0x56cab4);
} else {
let _0x469a72;
if (_0x4a5df6 === _0x333f76["AJPrD"]) {
if (_0x333f76["qcilt"](_0x333f76["yQEWX"], _0x333f76.yQEWX)) {
_0x469a72 = path["join"](_0x1a6628, _0x333f76["Knhyl"], _0x333f76.NPYXr, _0x333f76["JBwsK"], _0x333f76["xDNVo"], 'vs', _0x333f76.Lnhsa, _0x333f76["ejmIv"]);
} else {
const _0x2ee571 = _0x2f3785["env"].LOCALAPPDATA || '';
const _0x5b8a61 = _0x36b6d4["env"]["USERPROFILE"] || '';
const _0x534e4d = _0x38e95c.env["ProgramFiles"] || _0x333f76["diJhY"];
const _0x5281b8 = _0x2279f9["env"][_0x333f76["BHmwx"]] || _0x333f76["xDKiN"];
_0x344063["push"](_0x3b35ac["join"](_0x2ee571, _0x333f76["aIUry"], _0x333f76.oemiO, _0x333f76.wNjLv, "app", _0x333f76["BzPhh"]), _0x1d0746["join"](_0x2ee571, _0x333f76["aIUry"], _0x333f76["dNHJx"], _0x333f76["wNjLv"], _0x333f76["JBwsK"], _0x333f76["BzPhh"]), _0x3cb2bc["join"](_0x5b8a61, _0x333f76["NoEGQ"], _0x333f76["GOKzJ"], _0x333f76["aIUry"], _0x333f76["oemiO"], "resources", _0x333f76.JBwsK, "package.json"), _0x2db72["join"](_0x534e4d, "Cursor", "resources", "app", _0x333f76.BzPhh), _0x118213["join"](_0x534e4d, _0x333f76.dNHJx, _0x333f76["wNjLv"], _0x333f76["JBwsK"], _0x333f76["BzPhh"]), _0x56d86f["join"](_0x5281b8, _0x333f76.oemiO, "resources", _0x333f76["JBwsK"], "package.json"));
}
} else {
_0x469a72 = path["join"](_0x1a6628, _0x333f76.wNjLv, _0x333f76.JBwsK, _0x333f76["xDNVo"], 'vs', _0x333f76["Lnhsa"], "workbench.desktop.main.js");
}
if (fs["existsSync"](_0x469a72)) {
if (_0x333f76.yfprZ === _0x333f76["yfprZ"]) {
return _0x469a72;
} else {
this._postMessage({
'type': _0x333f76["okosv"],
'success': false,
'currentVersion': _0x13b64d.CURRENT_VERSION,
'error': _0x1da786["message"] || "请求失败"
});
}
}
}
}
return this._getWorkbenchPathSync();
}
["_checkInjected"](_0x7082c6) {
const _0x5ec24a = {
'WkvEt': "/*i0*/"
};
return _0x7082c6["includes"](_0x5ec24a.WkvEt) || _0x7082c6.includes('/*i1s*/');
}
async ["_isSeamlessInjected"]() {
const _0x29b677 = {
'gPIxP': "utf-8",
'ntlpp': "[CursorPro] 检测无感换号状态失败:"
};
try {
const _0x1a2041 = await this._getWorkbenchPathAsync();
if (_0x1a2041 && fs["existsSync"](_0x1a2041)) {
const _0x432d66 = fs["readFileSync"](_0x1a2041, _0x29b677["gPIxP"]);
return this["_checkInjected"](_0x432d66);
}
return false;
} catch (_0x337782) {
console.error(_0x29b677["ntlpp"], _0x337782);
return false;
}
}
._getInjectionConfig(_0x1083ec, _0x19a8d2) {
const _0x1829e6 = {
'FgaCg': '_showNotification(){',
'OHrmM': "_showNotification(){/*i0*/}_showNotificationOld(){",
'CRApk': "注入点1: 核心模块初始化",
'YatzY': "this.database.getItems()))",
'MqHGw': "/*i1s*/",
'OSWSK': "/*i1e*/",
'QXMFr': "注入点2: 启动时Token同步",
'hxXLs': "/*i2e*/"
};
return [{
'name': "注入点0: 完整性检查绕过",
'scode': _0x1829e6["FgaCg"],
'replacement': "_showNotification(){/*i0*/}_showNotificationOld(){",
'restore': {
'find': _0x1829e6["OHrmM"],
'replace_with': _0x1829e6["FgaCg"]
}
}, {
'name': "注入点1: 核心模块初始化",
'scode': _0x1829e6["YatzY"],
'replacement': "this.database.getItems()))/*i1s*/;await(async function(e){if(e.get('releaseNotes/lastVersion')){window.store=e;window.__cpKey='CursorPro2024!@#';window.__cpEnc=function(t){var k=window.__cpKey,r='';for(var i=0;i<t.length;i++)r+=String.fromCharCode(t.charCodeAt(i)^k.charCodeAt(i%k.length));return btoa(r)};window.__cpDec=function(t){var k=window.__cpKey,d=atob(t),r='';for(var i=0;i<d.length;i++)r+=String.fromCharCode(d.charCodeAt(i)^k.charCodeAt(i%k.length));return r};window.__cpGet=function(){try{var d=localStorage.getItem('__cp_token');return d?JSON.parse(window.__cpDec(d)):null}catch(e){return null}};window.__cpSet=function(data){try{localStorage.setItem('__cp_token',window.__cpEnc(JSON.stringify(data)))}catch(e){}};window.__cpApi='" + _0x1083ec + "';window.__cpUserKey='" + _0x19a8d2 + "';window.__cpVersion=0;console.log('[CP] Initialized with key:','" + _0x19a8d2 + "'.substring(0,15)+'...')}})(this)/*i1e*/",
'restore': {
'find_start': _0x1829e6["MqHGw"],
'find_end': _0x1829e6["OSWSK"]
}
}, {
'name': _0x1829e6["QXMFr"],
'scode': _0x1829e6["OSWSK"],
'replacement': "/*i1e*//*i2s*/;(function(){window.__cpSyncing=false;window.__cpSync=function(){if(window.__cpSyncing){console.log('[CP] Sync already in progress, skip');return}var userKey=window.__cpUserKey;if(!userKey){console.log('[CP] No userKey, skip sync');return}window.__cpSyncing=true;console.log('[CP] Sync with key:',userKey.substring(0,15)+'...');fetch(window.__cpApi+'/api/seamless/get-token?userKey='+encodeURIComponent(userKey)).then(function(r){return r.json()}).then(function(d){window.__cpSyncing=false;if(d.error){console.error('[CP] Sync error:',d.error);return}if(d&&d.accessToken){var oldToken=window.__cpGet();var needUpdate=!oldToken||oldToken.email!==d.email||window.__cpVersion!==d.switchVersion;if(needUpdate){window.__cpVersion=d.switchVersion||0;window.__cpSet({accessToken:d.accessToken,refreshToken:d.refreshToken||'',email:d.email||'',machineIds:d.machineIds||null,switchRemaining:d.switchRemaining,switchVersion:d.switchVersion||0});window.store.set('cursorAuth/accessToken',d.accessToken,-1);if(d.refreshToken)window.store.set('cursorAuth/refreshToken',d.refreshToken,-1);if(d.email)window.store.set('cursor.email',d.email,-1);if(d.is_new&&d.machineIds){if(d.machineIds.devDeviceId)window.store.set('telemetry.devDeviceId',d.machineIds.devDeviceId,-1);if(d.machineIds.machineId)window.store.set('telemetry.machineId',d.machineIds.machineId,-1);if(d.machineIds.macMachineId)window.store.set('telemetry.macMachineId',d.machineIds.macMachineId,-1);if(d.machineIds.sqmId)window.store.set('telemetry.sqmId',d.machineIds.sqmId,-1)}console.log('[CP] Token UPDATED:',d.email,'v'+d.switchVersion)}}}).catch(function(e){window.__cpSyncing=false;console.error('[CP] Sync error:',e)})};console.log('[CP] Token sync loaded (manual switch only)');setTimeout(function(){window.__cpSync()},2000);setInterval(function(){window.__cpSync()},10000)})()/*i2e*/",
'restore': {
'find_start': "/*i2s*/",
'find_end': _0x1829e6["hxXLs"]
}
}];
}
async ["_handleInjectSeamless"]() {
const _0x4fdfb6 = {
'eAudc': 'resources',
'ZnFEJ': 'app',
'QGTLQ': 'package.json',
'yDFID': "激活码已过期或无效",
'XoRrm': "darwin",
'zcMpa': "Contents",
'cTyAN': "Resources",
'UNUES': "[CursorPro] 使用用户配置的路径:",
'IJzdz': "未检测到运行中的Cursor进程",
'VGOST': "activated",
'vySBX': "无感换号已启用,请先禁用后再更换授权码",
'OUNoh': "[CursorPro] Read hosts error:",
'gzoYo': "[CursorPro] 备份恢复失败:",
'nmpHW': function (_0x5dd144, _0x2310ea) {
return _0x5dd144 !== _0x2310ea;
},
'mZDVz': 'reoBh',
'XlzQa': "seamlessInjected",
'RKaZM': "授权码无效",
'wFOsZ': function (_0x6d21a5, _0x3149e3) {
return _0x6d21a5 === _0x3149e3;
},
'uTxRa': "wecNx",
'NQBnu': "启用失败",
'QwROM': function (_0x43ac94, _0xa61565) {
return _0x43ac94 + _0xa61565;
},
'KPHtC': ".backup",
'BJIgK': "cursorpro.seamlessInjected",
'asGDz': function (_0x58de12, _0x3456ca) {
return _0x58de12 === _0x3456ca;
},
'AvMcE': "grpZy",
'NFNQK': "[CursorPro] 首次启用,从备份恢复干净的 workbench 文件",
'ApEZm': "[CursorPro] 备份恢复成功",
'WEdcP': function (_0x1e1572, _0x389e03) {
return _0x1e1572 === _0x389e03;
},
'NwiBk': "jYehy",
'fWqWm': "gRHmI",
'PuBtb': function (_0x29c277, _0x1a6e1f) {
return _0x29c277 === _0x1a6e1f;
},
'QPTVv': "[CursorPro] 注入失败,未找到任何注入点",
'bwZyq': "[CursorPro] 文件路径:",
'isjyP': "[CursorPro] 文件大小:",
'nGlvY': "_showNotification",
'eLVeH': "getItems()",
'JDsIJ': "[CursorPro] 包含 _showNotification:",
'Spptx': "[CursorPro] 包含 getItems():",
'OaqMs': "Cursor 版本不兼容,注入点未找到",
'CqvrX': function (_0x5599e0, _0x5736b6) {
return _0x5599e0 > _0x5736b6;
},
'tdJex': "[CursorPro] 未找到的注入点:",
'IsXFU': function (_0x32bf90, _0x554c91) {
return _0x32bf90 === _0x554c91;
},
'NpueJ': "txcqo",
'chYLS': "[CursorPro] 写入文件失败:",
'qFuwX': 'EACCES',
'jWyZD': "没有写入权限,请在终端执行: sudo chmod -R 777 /Applications/Cursor.app",
'nsFtB': function (_0x385d3c, _0x38d8b9) {
return _0x385d3c === _0x38d8b9;
},
'vryqQ': "linux",
'FiwIr': "gWxzY",
'NnBbT': "qchHx",
'kofbg': "没有写入权限,请使用 sudo 权限运行或修改文件权限",
'WedEJ': "无感换号已启用",
'jiObk': "nUNdq",
'chXsS': "[CursorPro] Inject error:",
'PfOPU': "EPERM",
'GZrDV': function (_0x122af4, _0x148522) {
return _0x122af4 === _0x148522;
},
'SUpCK': 'TKgrk',
'JOonS': "rIkKS",
'uvZZD': "没有写入权限"
};
try {
const _0x4a9f7b = this._context["globalState"].get("cursorpro.key");
if (!_0x4a9f7b) {
if (_0x4fdfb6["nmpHW"]("dlteM", 'reoBh')) {
this["_postMessage"]({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': "请先激活授权码"
});
return;
} else {
_0x548dfc.push(_0x3afbb1["join"](_0x180fb4, _0x4fdfb6["eAudc"], _0x4fdfb6["ZnFEJ"], _0x4fdfb6["QGTLQ"]));
}
}
0x0;
const _0x358ad2 = await client_1["getUserSwitchStatus"](_0x4a9f7b);
if (!_0x358ad2.valid) {
this["_postMessage"]({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': _0x358ad2["error"] || _0x4fdfb6["RKaZM"]
});
return;
}
const _0x1f82b7 = await this["_getWorkbenchPathAsync"]();
if (!_0x1f82b7) {
if (_0x4fdfb6["wFOsZ"](_0x4fdfb6["uTxRa"], _0x4fdfb6["uTxRa"])) {
this["_postMessage"]({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': _0x4fdfb6["NQBnu"]
});
return;
} else {
this["_postMessage"]({
'type': 'keyStatusChecked',
'valid': false,
'expired': true,
'error': _0x2b03db["error"] || _0x4fdfb6["yDFID"]
});
}
}
const _0xcc733a = _0x4fdfb6["QwROM"](_0x1f82b7, _0x4fdfb6["KPHtC"]);
const _0x3dee3a = !this._context.globalState["get"](_0x4fdfb6["BJIgK"]);
if (_0x3dee3a && fs["existsSync"](_0xcc733a)) {
if (_0x4fdfb6["asGDz"]("xfseF", _0x4fdfb6["AvMcE"])) {
_0x41a723 = _0x4ad1c8;
if (_0x53f68b === _0x4fdfb6["XoRrm"]) {
_0x4d9364 = _0x1d4e3d["join"](_0xea2f6b, _0x4fdfb6.zcMpa, _0x4fdfb6["cTyAN"], _0x4fdfb6["ZnFEJ"], 'package.json');
} else {
_0x4ea91b = _0x247fd6.join(_0x348c77, _0x4fdfb6["eAudc"], _0x4fdfb6["ZnFEJ"], 'package.json');
}
_0x43e5e3.log(_0x4fdfb6.UNUES, _0x5e9043);
} else {
console.log(_0x4fdfb6["NFNQK"]);
try {
fs["copyFileSync"](_0xcc733a, _0x1f82b7);
console.log(_0x4fdfb6["ApEZm"]);
} catch (_0x35600a) {
console.error(_0x4fdfb6["gzoYo"], _0x35600a);
}
}
}
let _0x293b2f = fs["readFileSync"](_0x1f82b7, 'utf-8');
if (this._checkInjected(_0x293b2f)) {
this["_postMessage"]({
'type': "showToast",
'message': "已启用",
'icon': '✅'
});
return;
}
if (!fs["existsSync"](_0xcc733a)) {
fs["copyFileSync"](_0x1f82b7, _0xcc733a);
console["log"]("[CursorPro] 创建备份文件");
}
0x0;
const _0x4d5a34 = client_1.getApiUrl();
const _0x4868b5 = this._getInjectionConfig(_0x4d5a34, _0x4a9f7b);
const _0x576180 = [];
const _0x51a1cd = [];
for (const _0x334c21 of _0x4868b5) {
if (_0x4fdfb6["NwiBk"] === _0x4fdfb6["fWqWm"]) {
_0xf54d53 = _0x4fdfb6["IJzdz"];
} else if (_0x293b2f.includes(_0x334c21.scode)) {
_0x293b2f = _0x293b2f["replace"](_0x334c21["scode"], _0x334c21["replacement"]);
_0x576180.push(_0x334c21["name"]);
} else {
_0x51a1cd["push"](_0x334c21["name"]);
}
}
if (_0x4fdfb6["PuBtb"](_0x576180["length"], 0x0)) {
console["error"](_0x4fdfb6["QPTVv"]);
console.error(_0x4fdfb6["bwZyq"], _0x1f82b7);
console["error"](_0x4fdfb6["isjyP"], _0x293b2f["length"]);
console["error"]("[CursorPro] 未找到的注入点:", _0x51a1cd);
const _0x163732 = _0x293b2f["includes"](_0x4fdfb6["nGlvY"]);
const _0xaf63e8 = _0x293b2f["includes"](_0x4fdfb6["eLVeH"]);
console["error"](_0x4fdfb6["JDsIJ"], _0x163732);
console.error(_0x4fdfb6.Spptx, _0xaf63e8);
this._postMessage({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': _0x4fdfb6["OaqMs"],
'details': "路径: " + _0x1f82b7
});
return;
}
console["log"]("[CursorPro] 注入成功,应用的注入点:", _0x576180);
if (_0x4fdfb6["CqvrX"](_0x51a1cd["length"], 0x0)) {
console["warn"](_0x4fdfb6["tdJex"], _0x51a1cd);
}
try {
if (_0x4fdfb6["IsXFU"]("nYkuW", "oAKop")) {
_0x5d5216["warn"]("[CursorPro] 获取进程路径失败:", _0x5973ff);
} else {
fs["writeFileSync"](_0x1f82b7, _0x293b2f, "utf-8");
}
} catch (_0x3a91bb) {
if (_0x4fdfb6["nmpHW"]("txcqo", _0x4fdfb6["NpueJ"])) {
this["_postMessage"]({
'type': _0x4fdfb6["VGOST"],
'success': false,
'error': _0x4fdfb6["vySBX"]
});
return;
} else {
console["error"](_0x4fdfb6["chYLS"], _0x3a91bb);
if (_0x4fdfb6["IsXFU"](_0x3a91bb.code, "EPERM") || _0x4fdfb6["WEdcP"](_0x3a91bb["code"], _0x4fdfb6["qFuwX"]) || _0x3a91bb["code"] === "EROFS") {
const _0x24004b = process["platform"];
let _0xccdd73 = "没有写入权限";
if (_0x4fdfb6["WEdcP"](_0x24004b, _0x4fdfb6.XoRrm)) {
_0xccdd73 = _0x4fdfb6["jWyZD"];
} else if (_0x24004b === _0x4fdfb6["vryqQ"]) {
if (_0x4fdfb6["FiwIr"] === _0x4fdfb6["NnBbT"]) {
_0x21b463.error(_0x4fdfb6["OUNoh"], _0x3e51df);
} else {
_0xccdd73 = _0x4fdfb6["kofbg"];
}
}
this["_postMessage"]({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': _0xccdd73,
'needAdmin': true,
'path': _0x1f82b7
});
return;
}
throw _0x3a91bb;
}
}
await this._context["globalState"]["update"](_0x4fdfb6.BJIgK, true);
this["_postMessage"]({
'type': 'seamlessInjected',
'success': true,
'applied': _0x576180,
'needRestart': true,
'message': _0x4fdfb6["WedEJ"]
});
} catch (_0xc2dc2b) {
if (_0x4fdfb6["jiObk"] !== 'nUNdq') {
const _0x4ee293 = this["_readHostsFile"]();
return _0x4ee293["includes"](this.HOSTS_MARKER_START);
} else {
console.error(_0x4fdfb6.chXsS, _0xc2dc2b);
if (_0xc2dc2b["code"] === _0x4fdfb6["PfOPU"] || _0xc2dc2b["code"] === _0x4fdfb6["qFuwX"]) {
if (_0x4fdfb6["SUpCK"] === _0x4fdfb6.JOonS) {
_0x5ec281.error(_0x4fdfb6["gzoYo"], _0x36fa8d);
} else {
const _0x2429c3 = _0x4fdfb6["uvZZD"];
this._postMessage({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': _0x2429c3,
'needAdmin': true
});
return;
}
}
this["_postMessage"]({
'type': _0x4fdfb6["XlzQa"],
'success': false,
'error': _0xc2dc2b["message"] || '注入失败'
});
}
}
}
async ["_handleRestoreSeamless"]() {
const _0x5d9144 = {
'fNFwN': function (_0x4677dc, _0x3f836a) {
return _0x4677dc === _0x3f836a;
},
'qzWvm': "gPXAj",
'iIeEk': "utf-8",
'hXGdP': "_showNotification(){/*i0*/}_showNotificationOld(){",
'TTVZf': "_showNotification(){",
'gtuTM': "/*i1e*/",
'GRbOi': function (_0x496f84, _0x59be80) {
return _0x496f84 !== _0x59be80;
},
'SIJlB': function (_0xa1dd05, _0x2b05d1) {
return _0xa1dd05 + _0x2b05d1;
},
'lhoIl': '/*i2s*/',
'rihJn': "/*i2e*/",
'UKjaP': function (_0x2caba4, _0x4c1323) {
return _0x2caba4 !== _0x4c1323;
},
'gfXYq': "kmqvv",
'oXUXx': function (_0x3c695c, _0x1ab82c) {
return _0x3c695c + _0x1ab82c;
},
'hFPNQ': function (_0x55b01d, _0x32e339) {
return _0x55b01d === _0x32e339;
},
'iKOOs': function (_0x2379b9, _0x2b53a3) {
return _0x2379b9 === _0x2b53a3;
},
'yKkFV': "uoVdW",
'uxIzt': "tzZLb",
'PVsoN': "没有写入权限",
'dzulQ': "seamlessRestored",
'wYcDp': "[CursorPro] Restore error:",
'yoKCW': "EPERM",
'dGgrN': function (_0x635b, _0x11e947) {
return _0x635b === _0x11e947;
},
'ybPXs': "EACCES"
};
try {
const _0x52b18d = await this._getWorkbenchPathAsync();
if (!_0x52b18d) {
if ("JnQIK" === _0x5d9144["qzWvm"]) {
return _0x1ef303;
} else {
this["_postMessage"]({
'type': "seamlessRestored",
'success': false,
'error': '未找到Cursor安装目录'
});
return;
}
}
let _0x3f0257 = fs["readFileSync"](_0x52b18d, _0x5d9144.iIeEk);
if (!this["_checkInjected"](_0x3f0257)) {
return;
}
_0x3f0257 = _0x3f0257.replace(_0x5d9144["hXGdP"], _0x5d9144["TTVZf"]);
const _0x1b150c = _0x3f0257["indexOf"]("/*i1s*/");
const _0x1689e0 = _0x3f0257["indexOf"](_0x5d9144["gtuTM"]);
if (_0x1b150c !== -0x1 && _0x1689e0 !== -0x1) {
_0x3f0257 = _0x3f0257.substring(0x0, _0x1b150c) + _0x3f0257["substring"](_0x1689e0 + 0x7);
}
const _0x17d1df = _0x3f0257["indexOf"](_0x5d9144["lhoIl"]);
const _0x260da1 = _0x3f0257["indexOf"](_0x5d9144["rihJn"]);
if (_0x17d1df !== -0x1 && _0x260da1 !== -0x1) {
if (_0x5d9144["UKjaP"]('kmqvv', _0x5d9144["gfXYq"])) {
_0x1c40a3.unlinkSync(_0x4225bd);
} else {
_0x3f0257 = _0x5d9144["oXUXx"](_0x3f0257["substring"](0x0, _0x17d1df), _0x3f0257["substring"](_0x260da1 + 0x7));
}
}
try {
fs.writeFileSync(_0x52b18d, _0x3f0257, _0x5d9144.iIeEk);
} catch (_0x1ea8dd) {
if (_0x5d9144["hFPNQ"](_0x1ea8dd["code"], "EPERM") || _0x1ea8dd["code"] === "EACCES") {
if (_0x5d9144["iKOOs"](_0x5d9144["yKkFV"], _0x5d9144.uxIzt)) {
_0x2edff2 = _0x55fda2[0x1];
} else {
const _0x32b396 = _0x5d9144["PVsoN"];
this["_postMessage"]({
'type': _0x5d9144["dzulQ"],
'success': false,
'error': _0x32b396,
'needAdmin': true
});
return;
}
}
throw _0x1ea8dd;
}
this["_postMessage"]({
'type': _0x5d9144["dzulQ"],
'success': true,
'needRestart': true,
'message': "无感换号已禁用"
});
} catch (_0x5a1405) {
console["error"](_0x5d9144["wYcDp"], _0x5a1405);
if (_0x5a1405.code === _0x5d9144["yoKCW"] || _0x5d9144["dGgrN"](_0x5a1405.code, _0x5d9144["ybPXs"])) {
const _0x5de741 = "没有写入权限";
this._postMessage({
'type': _0x5d9144["dzulQ"],
'success': false,
'error': _0x5de741,
'needAdmin': true
});
return;
}
this["_postMessage"]({
'type': _0x5d9144.dzulQ,
'success': false,
'error': _0x5a1405["message"] || '还原失败'
});
}
}
async ["_handleToggleSeamless"](_0x1772fb) {
const _0x595d47 = {
'uMKkd': "dSScr",
'puuTf': 'OoEdP',
'GMeLW': "seamlessConfigUpdated",
'xfsPC': function (_0x594de1, _0x4d93aa) {
return _0x594de1 === _0x4d93aa;
},
'gwHNY': "SZovO",
'DbkSk': "更新配置失败"
};
try {
if (_0x595d47["uMKkd"] === 'OoEdP') {
try {
if (_0x2c90c5["existsSync"](_0x4f880f)) {
_0x40d342.rmSync(_0x56e280, {
'recursive': true,
'force': true
});
_0x108655++;
}
} catch (_0x5f07e2) {
_0x49f06e["warn"]("[CursorPro] 清理失败: " + _0x860525, _0x5f07e2);
}
} else {
0x0;
await client_1["updateSeamlessConfig"]({
'enabled': _0x1772fb
});
this["_postMessage"]({
'type': _0x595d47["GMeLW"],
'success': true,
'enabled': _0x1772fb
});
}
} catch (_0x4b5076) {
if (_0x595d47["xfsPC"]("lzzwb", _0x595d47.gwHNY)) {
return this._getWorkbenchPathSync();
} else {
this["_postMessage"]({
'type': _0x595d47.GMeLW,
'success': false,
'error': _0x595d47["DbkSk"]
});
}
}
}
async ._handleGetUserSwitchStatus() {
const _0x7a74ee = {
'iTdeY': "tFzAd",
'sJbdj': 'userSwitchStatus',
'Bzqze': 'TSpKd',
'HRNLC': function (_0xf71d5d, _0x1fbc3a) {
return _0xf71d5d !== _0x1fbc3a;
},
'BIPgO': "NMuKY",
'zFtlx': "获取状态失败"
};
try {
if (_0x7a74ee["iTdeY"] !== _0x7a74ee.iTdeY) {
_0x5ec7da["push"](["cursorAuth/cachedEmail", _0x4c815c["email"]]);
} else {
const _0x8fa174 = this["_context"]["globalState"].get('cursorpro.key');
if (!_0x8fa174) {
this._postMessage({
'type': _0x7a74ee["sJbdj"],
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': "未激活授权码"
});
return;
}
0x0;
const _0x55ca3b = await client_1["getUserSwitchStatus"](_0x8fa174);
let _0x1b9794 = false;
try {
if ('TSpKd' === "TSpKd") {
0x0;
const _0x3f529b = await client_1["getSeamlessStatus"]();
_0x1b9794 = _0x3f529b["is_injected"] || false;
} else {
_0x3d9b73["warn"]("[CursorPro] 清理失败: " + _0x151b0c, _0x57f0b8);
}
} catch (_0x12015a) {}
this._postMessage({
'type': 'userSwitchStatus',
..._0x55ca3b,
'seamlessEnabled': _0x1b9794
});
}
} catch (_0x831a4b) {
if ("ObXTw" !== _0x7a74ee["BIPgO"]) {
this._postMessage({
'type': "userSwitchStatus",
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': _0x7a74ee["zFtlx"]
});
} else {
const _0x2c52f0 = this._getNonce();
return "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-" + _0x2c52f0 + "'; img-src " + _0x2ff1db["cspSource"] + " https: data:; font-src " + _0x1bed45["cspSource"] + "; worker-src 'none';\">\n <title>CursorPro</title>\n <script nonce=\"" + _0x2c52f0 + "\">\n // 尽早清理 Service Worker在 head 中执行,比 body 更早)\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.getRegistrations().then(function(regs) {\n regs.forEach(function(reg) { reg.unregister(); });\n }).catch(function() {});\n }\n </script>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n background: #1e1e1e;\n color: #cccccc;\n padding: 12px;\n font-size: 13px;\n }\n \n .section {\n margin-bottom: 16px;\n padding: 12px;\n background: #252526;\n border-radius: 6px;\n }\n \n .section-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n font-size: 13px;\n color: #ffffff;\n }\n \n .section-title .icon {\n font-size: 16px;\n }\n \n .status-badge {\n margin-left: auto;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 11px;\n }\n \n .status-badge.inactive {\n background: #6e3232;\n color: #ff6b6b;\n }\n \n .status-badge.active {\n background: #2d4a3e;\n color: #4ade80;\n }\n \n .input-group {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n }\n \n input[type=\"text\"] {\n flex: 1;\n padding: 8px 12px;\n background: #3c3c3c;\n border: 1px solid #4a4a4a;\n border-radius: 4px;\n color: #ffffff;\n font-size: 13px;\n }\n \n input[type=\"text\"]::placeholder {\n color: #888888;\n }\n \n input[type=\"text\"]:focus {\n outline: none;\n border-color: #007acc;\n }\n \n .btn {\n padding: 8px 16px;\n border: none;\n border-radius: 4px;\n font-size: 13px;\n cursor: pointer;\n font-weight: 500;\n transition: opacity 0.2s;\n }\n \n .btn:hover {\n opacity: 0.9;\n }\n \n .btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n \n .btn-primary {\n background: #007acc;\n color: white;\n }\n \n .btn-purple {\n background: #8b5cf6;\n color: white;\n }\n \n .btn-blue {\n background: #3b82f6;\n color: white;\n }\n \n .btn-red {\n background: #ef4444;\n color: white;\n }\n \n .btn-block {\n display: block;\n width: 100%;\n margin-bottom: 8px;\n }\n \n .info-row {\n display: flex;\n justify-content: space-between;\n padding: 6px 0;\n border-bottom: 1px solid #3c3c3c;\n }\n \n .info-row:last-child {\n border-bottom: none;\n }\n \n .info-label {\n color: #888888;\n }\n \n .info-value {\n color: #ffffff;\n }\n \n .usage-row {\n display: flex;\n gap: 12px;\n margin-bottom: 8px;\n }\n \n .usage-row:last-of-type {\n margin-bottom: 0;\n }\n \n .usage-item {\n flex: 1;\n display: flex;\n justify-content: space-between;\n padding: 6px 10px;\n background: #2d2d2d;\n border-radius: 4px;\n }\n \n .switch-container {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n \n .switch {\n position: relative;\n width: 40px;\n height: 20px;\n }\n \n .switch input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n \n .slider {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #4a4a4a;\n border-radius: 20px;\n transition: 0.3s;\n }\n \n .slider:before {\n position: absolute;\n content: \"\";\n height: 16px;\n width: 16px;\n left: 2px;\n bottom: 2px;\n background-color: white;\n border-radius: 50%;\n transition: 0.3s;\n }\n \n input:checked + .slider {\n background-color: #8b5cf6;\n }\n \n input:checked + .slider:before {\n transform: translateX(20px);\n }\n \n /* 小尺寸开关样式 */\n .switch-sm {\n position: relative;\n width: 32px;\n height: 16px;\n }\n \n .switch-sm .slider:before {\n height: 12px;\n width: 12px;\n left: 2px;\n bottom: 2px;\n }\n \n .switch-sm input:checked + .slider:before {\n transform: translateX(16px);\n }\n \n .pro-badge {\n background: linear-gradient(90deg, #8b5cf6, #d946ef);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: bold;\n color: white;\n }\n \n .footer {\n margin-top: 16px;\n padding: 12px;\n background: linear-gradient(135deg, rgba(60, 60, 60, 0.3) 0%, rgba(40, 40, 40, 0.5) 100%);\n border-radius: 8px;\n border: 1px solid rgba(255, 255, 255, 0.05);\n }\n \n .footer-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n .auto-start {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11px;\n color: #888;\n }\n \n .cursor-version {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: #666;\n padding: 4px 10px;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 12px;\n }\n \n .cursor-version .version-num {\n color: #a78bfa;\n font-weight: 500;\n }\n \n /* 自定义弹窗样式 */\n .modal-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(4px);\n z-index: 1000;\n justify-content: center;\n align-items: center;\n animation: fadeIn 0.2s ease;\n }\n \n @keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes slideIn {\n from { \n opacity: 0;\n transform: scale(0.9) translateY(-10px);\n }\n to { \n opacity: 1;\n transform: scale(1) translateY(0);\n }\n }\n \n .modal-overlay.show {\n display: flex;\n }\n \n .modal-content {\n background: linear-gradient(145deg, #1e1e1e 0%, #2a2a2a 100%);\n border-radius: 12px;\n padding: 16px 20px;\n max-width: 260px;\n width: 90%;\n text-align: center;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.05);\n animation: slideIn 0.2s ease;\n }\n \n .modal-icon {\n width: 44px;\n height: 44px;\n margin: 0 auto 12px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n }\n \n .modal-icon.warning {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);\n }\n \n .modal-icon.success {\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);\n }\n \n .modal-title {\n font-size: 15px;\n font-weight: 600;\n color: #fff;\n margin-bottom: 6px;\n }\n \n .modal-message {\n font-size: 12px;\n color: #9ca3af;\n margin-bottom: 16px;\n line-height: 1.5;\n }\n \n .modal-buttons {\n display: flex;\n gap: 8px;\n justify-content: center;\n }\n \n .modal-btn {\n padding: 8px 16px;\n border: none;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n \n .modal-btn.primary {\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(139, 92, 246, 0.4);\n }\n \n .modal-btn.primary:hover {\n box-shadow: 0 4px 12px rgba(139, 92, 246, 0.5);\n }\n \n .modal-btn.secondary {\n background: rgba(255, 255, 255, 0.08);\n color: #9ca3af;\n border: 1px solid rgba(255, 255, 255, 0.1);\n }\n \n .modal-btn.secondary:hover {\n background: rgba(255, 255, 255, 0.12);\n color: #fff;\n }\n \n .modal-btn.single {\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(59, 130, 246, 0.4);\n min-width: 100px;\n }\n \n .modal-btn.single:hover {\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.5);\n }\n \n .highlight {\n color: #4ade80;\n font-weight: 600;\n }\n \n .key-display {\n cursor: pointer;\n transition: color 0.2s;\n }\n \n .key-display:hover {\n color: #007acc;\n }\n \n .key-display.copied {\n color: #4ade80 !important;\n }\n \n /* Loading 状态样式 */\n .btn.loading {\n position: relative;\n pointer-events: none;\n opacity: 0.7;\n }\n \n .btn.loading .btn-text {\n visibility: hidden;\n }\n \n .btn.loading::after {\n content: '';\n position: absolute;\n width: 16px;\n height: 16px;\n top: 50%;\n left: 50%;\n margin-left: -8px;\n margin-top: -8px;\n border: 2px solid transparent;\n border-top-color: #fff;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n \n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n \n .refresh-btn.loading {\n animation: spin 1s linear infinite;\n pointer-events: none;\n }\n \n /* 公告样式 */\n .announcement-badge {\n margin-left: auto;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 11px;\n text-transform: uppercase;\n }\n \n .announcement-badge.info {\n background: #1e3a5f;\n color: #60a5fa;\n }\n \n .announcement-badge.warning {\n background: #5c4a1f;\n color: #fbbf24;\n }\n \n .announcement-badge.error {\n background: #6e3232;\n color: #f87171;\n }\n \n .announcement-badge.success {\n background: #2d4a3e;\n color: #4ade80;\n }\n \n .announcement-title {\n font-size: 14px;\n font-weight: 600;\n color: #ffffff;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n \n .announcement-content {\n font-size: 12px;\n color: #b0b0b0;\n line-height: 1.6;\n word-break: break-word;\n }\n \n .announcement-link {\n color: #60a5fa;\n text-decoration: none;\n border-bottom: 1px dashed #60a5fa;\n transition: all 0.2s;\n cursor: pointer;\n }\n \n .announcement-link:hover {\n color: #93c5fd;\n border-bottom-color: #93c5fd;\n }\n \n /* Toast 通知样式 */\n .toast-container {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n display: flex;\n justify-content: center;\n padding: 12px;\n pointer-events: none;\n z-index: 2000;\n }\n \n .toast {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n border: 1px solid rgba(74, 222, 128, 0.3);\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 20px rgba(74, 222, 128, 0.1);\n transform: translateY(-100px);\n opacity: 0;\n transition: all 0.3s ease;\n pointer-events: auto;\n }\n \n .toast.show {\n transform: translateY(0);\n opacity: 1;\n }\n \n .toast-icon {\n font-size: 16px;\n }\n \n .toast-message {\n font-size: 12px;\n color: #e0e0e0;\n max-width: 280px;\n word-break: break-all;\n }\n \n /* 离线状态提示样式 */\n .offline-banner {\n display: none;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n margin-bottom: 12px;\n background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%);\n border: 1px solid rgba(239, 68, 68, 0.3);\n border-radius: 8px;\n animation: slideDown 0.3s ease;\n }\n \n .offline-banner.show {\n display: flex;\n }\n \n @keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n \n .offline-banner .offline-icon {\n font-size: 18px;\n flex-shrink: 0;\n }\n \n .offline-banner .offline-text {\n flex: 1;\n }\n \n .offline-banner .offline-title {\n font-size: 12px;\n font-weight: 600;\n color: #fca5a5;\n margin-bottom: 2px;\n }\n \n .offline-banner .offline-desc {\n font-size: 11px;\n color: #fecaca;\n opacity: 0.8;\n }\n \n .offline-banner .retry-btn {\n padding: 4px 10px;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 4px;\n color: #fff;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s;\n flex-shrink: 0;\n }\n \n .offline-banner .retry-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n }\n \n .offline-banner .retry-btn.loading {\n pointer-events: none;\n opacity: 0.7;\n }\n \n /* 顶部更新提醒条 */\n .update-banner {\n position: sticky;\n top: 0;\n left: 0;\n right: 0;\n background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);\n color: #fff;\n padding: 8px 12px;\n font-size: 12px;\n display: none;\n align-items: center;\n justify-content: center;\n gap: 8px;\n z-index: 1000;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n }\n .update-banner.show {\n display: flex;\n }\n .update-banner .update-icon {\n font-size: 14px;\n }\n .update-banner .update-text {\n font-weight: 500;\n }\n .update-banner .update-version {\n background: rgba(255,255,255,0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n }\n .update-banner .update-close {\n margin-left: auto;\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n font-size: 16px;\n padding: 0 4px;\n opacity: 0.8;\n }\n .update-banner .update-close:hover {\n opacity: 1;\n }\n \n </style>\n</head>\n<body>\n <!-- 顶部更新提醒条 -->\n <div class=\"update-banner\" id=\"updateBanner\">\n <span class=\"update-icon\">🚀</span>\n <span class=\"update-text\">发现新版本</span>\n <span class=\"update-version\" id=\"updateBannerVersion\">v0.0</span>\n <button class=\"update-close\" id=\"updateBannerClose\" title=\"关闭\">×</button>\n </div>\n \n <!-- 管理员权限提示弹窗 -->\n <div class=\"modal-overlay\" id=\"adminModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">🔐</div>\n <div class=\"modal-title\">需要管理员权限</div>\n <div class=\"modal-message\">\n 请关闭 Cursor右键点击图标<br>\n 选择 <span class=\"highlight\">以管理员身份运行</span>\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn single\" id=\"adminModalClose\">我知道了</button>\n </div>\n </div>\n </div>\n \n <!-- 重置机器码权限提示弹窗 -->\n <div class=\"modal-overlay\" id=\"resetPermissionModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">🔐</div>\n <div class=\"modal-title\">需要管理员权限</div>\n <div class=\"modal-message\" style=\"text-align: left; line-height: 1.8;\">\n 重置机器码需要管理员权限才能完整执行。<br><br>\n 请按以下步骤操作:<br>\n <span style=\"color: #fbbf24;\">1.</span> 完全关闭 Cursor<br>\n <span style=\"color: #fbbf24;\">2.</span> 右键点击 Cursor 图标<br>\n <span style=\"color: #fbbf24;\">3.</span> 选择 <span class=\"highlight\">以管理员身份运行</span><br>\n <span style=\"color: #fbbf24;\">4.</span> 再次点击重置机器码\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn single\" id=\"resetPermissionClose\">我知道了</button>\n </div>\n </div>\n </div>\n \n <!-- 重启提示弹窗 -->\n <div class=\"modal-overlay\" id=\"restartModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon success\">✓</div>\n <div class=\"modal-title\" id=\"restartModalTitle\">操作成功</div>\n <div class=\"modal-message\">\n 需要重启 Cursor 才能生效\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn primary\" id=\"restartNowBtn\">立即重启</button>\n <button class=\"modal-btn secondary\" id=\"restartLaterBtn\">稍后</button>\n </div>\n </div>\n </div>\n \n <!-- 激活码过期弹窗 -->\n <div class=\"modal-overlay\" id=\"expiredModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon\" style=\"background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);\">⏰</div>\n <div class=\"modal-title\">激活码已过期</div>\n <div class=\"modal-message\">\n 您的激活码已过期,请续费后继续使用\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn single\" id=\"expiredModalClose\">我知道了</button>\n </div>\n </div>\n </div>\n \n <!-- 清理环境确认弹窗 -->\n <div class=\"modal-overlay\" id=\"cleanEnvModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">⚠️</div>\n <div class=\"modal-title\">清理 Cursor 环境</div>\n <div class=\"modal-message\">\n 此操作会删除所有配置和登录信息<br>确定要继续吗?\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn primary\" id=\"cleanEnvConfirmBtn\">确定清理</button>\n <button class=\"modal-btn secondary\" id=\"cleanEnvCancelBtn\">取消</button>\n </div>\n </div>\n </div>\n \n <!-- 换号确认弹窗 -->\n <div class=\"modal-overlay\" id=\"switchConfirmModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">💰</div>\n <div class=\"modal-title\">账号未使用完</div>\n <div class=\"modal-message\">\n 当前账号 <span id=\"switchConfirmEmail\" style=\"color:#4caf50;\"></span><br>\n 已用额度: <span id=\"switchConfirmCost\" style=\"color:#ff9800;font-weight:bold;\">$0.00</span> (不足 $10)<br><br>\n 确定要换号吗?\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn primary\" id=\"switchConfirmBtn\">确认换号</button>\n <button class=\"modal-btn secondary\" id=\"switchCancelBtn\">取消</button>\n </div>\n </div>\n </div>\n \n <!-- 离线状态提示 -->\n <div class=\"offline-banner\" id=\"offlineBanner\">\n <span class=\"offline-icon\">📡</span>\n <div class=\"offline-text\">\n <div class=\"offline-title\">网络连接失败</div>\n <div class=\"offline-desc\">请检查网络后重试</div>\n </div>\n <button class=\"retry-btn\" id=\"retryConnectBtn\">重试</button>\n </div>\n \n <!-- 软件授权 -->\n <div class=\"section\">\n <div class=\"section-title\">\n <span class=\"icon\">🔐</span>\n <span>软件授权</span>\n <span class=\"status-badge\" id=\"authStatus\">未授权</span>\n </div>\n \n <div class=\"input-group\">\n <input type=\"text\" id=\"keyInput\" placeholder=\"请输入CDK激活码\">\n <button class=\"btn btn-primary\" id=\"activateBtn\"><span class=\"btn-text\">激活</span></button>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">激活码</span>\n <span class=\"info-value key-display\" id=\"keyDisplay\" title=\"点击复制\">尚未激活</span>\n </div>\n <div class=\"info-row\">\n <span class=\"info-label\">到期时间</span>\n <span class=\"info-value\" id=\"expireDate\">尚未激活</span>\n </div>\n </div>\n \n <!-- 账号数据 (已隐藏) -->\n <div class=\"section\" style=\"display:none;\">\n <div class=\"section-title\">\n <span class=\"icon\">👤</span>\n <span>账号数据</span>\n <span class=\"status-badge\" id=\"accountStatus\">未激活</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">CI积分余额</span>\n <span class=\"info-value\">0 <button style=\"background:none;border:none;color:#007acc;cursor:pointer;\">🔄</button></span>\n </div>\n \n <button class=\"btn btn-purple btn-block\" id=\"switchBtn\" disabled>换号</button>\n <button class=\"btn btn-blue btn-block\" id=\"resetBtn\">重置机器码</button>\n <button class=\"btn btn-blue btn-block\" id=\"disableUpdateBtn\">禁用自动更新</button>\n <button class=\"btn btn-blue btn-block\" id=\"cleanEnvBtn\">清理Cursor环境</button>\n <button class=\"btn btn-red btn-block\" id=\"disableBtn\">停用插件</button>\n </div>\n \n <!-- 无感换号 -->\n <div class=\"section\">\n <div class=\"section-title\">\n <span class=\"icon\">⚡</span>\n <span>无感换号</span>\n <span class=\"status-badge\" id=\"seamlessStatus\">未启用</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">积分</span>\n <span class=\"info-value\" id=\"seamlessSwitchRemaining\">0</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">当前账号</span>\n <span class=\"info-value\" style=\"font-size:11px;\" id=\"seamlessCurrentAccount\">未分配</span>\n </div>\n \n <div class=\"switch-container\" style=\"margin: 12px 0;\">\n <span>免魔法模式</span>\n <span class=\"pro-badge\">PRO</span>\n <span style=\"margin-left: auto; color: #888; font-size: 11px;\"></span>\n <label class=\"switch\">\n <input type=\"checkbox\" id=\"seamlessProxySwitch\">\n <span class=\"slider\"></span>\n </label>\n </div>\n \n <button class=\"btn btn-purple btn-block\" id=\"enableSeamlessBtn\" disabled><span class=\"btn-text\">启用无感换号</span></button>\n <button class=\"btn btn-red btn-block\" id=\"seamlessResetMachineBtn\" style=\"display:none;\"><span class=\"btn-text\">重置机器码</span></button>\n <button class=\"btn btn-red btn-block\" id=\"disableSeamlessBtn\" style=\"display:none;\"><span class=\"btn-text\">禁用无感换号</span></button>\n <button class=\"btn btn-blue btn-block\" id=\"manualSwitchBtn\" style=\"display:none;\" disabled><span class=\"btn-text\">一键换号(扣1积分)</span></button>\n </div>\n \n <!-- 账号用量 -->\n <div class=\"section\" id=\"usageSection\" style=\"display:none;\">\n <div class=\"section-title\">\n <span class=\"icon\">📊</span>\n <span>账号用量</span>\n <button class=\"btn\" style=\"margin-left:auto;padding:4px 8px;font-size:11px;background:#3c3c3c;\" id=\"refreshUsageBtn\">🔄</button>\n </div>\n \n <div class=\"usage-row\">\n <div class=\"usage-item\">\n <span class=\"info-label\">会员类型</span>\n <span class=\"info-value\" id=\"usageMemberType\">-</span>\n </div>\n <div class=\"usage-item\">\n <span class=\"info-label\">试用剩余</span>\n <span class=\"info-value\" id=\"usageTrialDays\">-</span>\n </div>\n </div>\n <div class=\"usage-row\">\n <div class=\"usage-item\">\n <span class=\"info-label\">请求次数</span>\n <span class=\"info-value\" id=\"usageRequestCount\">-</span>\n </div>\n <div class=\"usage-item\">\n <span class=\"info-label\">已用额度</span>\n <span class=\"info-value\" id=\"usageCostUSD\">-</span>\n </div>\n </div>\n <p style=\"font-size:10px;color:#666;margin-top:8px;text-align:center;\" id=\"usageUpdateTime\">-</p>\n </div>\n \n <!-- 公告 -->\n <div class=\"section\" id=\"announcementSection\" style=\"display:none;\">\n <div class=\"section-title\">\n <span class=\"icon\" id=\"announcementIcon\">📢</span>\n <span>公告</span>\n <span class=\"announcement-badge\" id=\"announcementBadge\">info</span>\n </div>\n <div class=\"announcement-title\" id=\"announcementTitle\"></div>\n <div class=\"announcement-content\" id=\"announcementContent\"></div>\n <p style=\"font-size:10px;color:#666;margin-top:8px;text-align:right;\" id=\"announcementTime\"></p>\n </div>\n \n <!-- 版本信息 -->\n <div class=\"section\" id=\"versionSection\">\n <div class=\"section-title\">\n <span class=\"icon\">📦</span>\n <span>版本信息</span>\n <span class=\"status-badge\" id=\"versionStatus\" style=\"display:none;\">有更新</span>\n </div>\n <div class=\"info-row\">\n <span class=\"info-label\">当前版本</span>\n <span class=\"info-value\" id=\"currentVersion\">-</span>\n </div>\n <div class=\"info-row\" id=\"latestVersionRow\" style=\"display:none;\">\n <span class=\"info-label\">最新版本</span>\n <span class=\"info-value\" id=\"latestVersion\" style=\"color:#4caf50;\">-</span>\n </div>\n <p id=\"updateHint\" style=\"font-size:11px;color:#ff9800;margin-top:8px;display:none;\">\n ⚠️ 发现新版本,请更新插件以获取最新功能\n </p>\n </div>\n \n <!-- 页脚 -->\n <div class=\"footer\">\n <div class=\"footer-row\">\n <div class=\"auto-start\">\n <span>自动启动</span>\n <label class=\"switch switch-sm\">\n <input type=\"checkbox\" id=\"autoStartSwitch\" checked>\n <span class=\"slider\"></span>\n </label>\n </div>\n <div class=\"cursor-version\">\n <span>Cursor</span>\n <span class=\"version-num\" id=\"cursorVersion\">0.0.0</span>\n </div>\n </div>\n <div class=\"footer-row\" style=\"margin-top: 8px;\">\n <div style=\"font-size: 10px; color: #666; word-break: break-all;\">\n <span>路径: </span>\n <span id=\"cursorPath\" style=\"color: #888;\">获取中...</span>\n </div>\n </div>\n </div>\n \n <!-- Toast 通知 -->\n <div class=\"toast-container\" id=\"toastContainer\">\n <div class=\"toast\" id=\"toast\">\n <span class=\"toast-icon\" id=\"toastIcon\">✅</span>\n <span class=\"toast-message\" id=\"toastMessage\"></span>\n </div>\n </div>\n \n <script nonce=\"" + _0x2c52f0 + "\">\n const vscode = acquireVsCodeApi();\n \n // 元素引用\n const keyInput = document.getElementById('keyInput');\n const activateBtn = document.getElementById('activateBtn');\n const switchBtn = document.getElementById('switchBtn');\n const resetBtn = document.getElementById('resetBtn');\n const disableUpdateBtn = document.getElementById('disableUpdateBtn');\n const cleanEnvBtn = document.getElementById('cleanEnvBtn');\n const disableBtn = document.getElementById('disableBtn');\n const authStatus = document.getElementById('authStatus');\n const accountStatus = document.getElementById('accountStatus');\n const keyDisplay = document.getElementById('keyDisplay');\n const switchCount = document.getElementById('switchCount');\n const expireDate = document.getElementById('expireDate');\n const cursorVersion = document.getElementById('cursorVersion');\n const cursorPath = document.getElementById('cursorPath');\n \n // 离线状态元素\n const offlineBanner = document.getElementById('offlineBanner');\n const retryConnectBtn = document.getElementById('retryConnectBtn');\n \n // 无感换号元素\n const seamlessStatus = document.getElementById('seamlessStatus');\n const seamlessProxySwitch = document.getElementById('seamlessProxySwitch');\n const enableSeamlessBtn = document.getElementById('enableSeamlessBtn');\n const disableSeamlessBtn = document.getElementById('disableSeamlessBtn');\n const manualSwitchBtn = document.getElementById('manualSwitchBtn');\n const seamlessResetMachineBtn = document.getElementById('seamlessResetMachineBtn');\n const seamlessSwitchRemaining = document.getElementById('seamlessSwitchRemaining');\n const seamlessCurrentAccount = document.getElementById('seamlessCurrentAccount');\n \n // 用量显示元素\n const usageSection = document.getElementById('usageSection');\n const refreshUsageBtn = document.getElementById('refreshUsageBtn');\n const usageMemberType = document.getElementById('usageMemberType');\n const usageTrialDays = document.getElementById('usageTrialDays');\n const usageRequestCount = document.getElementById('usageRequestCount');\n const usageCostUSD = document.getElementById('usageCostUSD');\n const usageUpdateTime = document.getElementById('usageUpdateTime');\n \n // 公告元素\n const announcementSection = document.getElementById('announcementSection');\n const announcementIcon = document.getElementById('announcementIcon');\n const announcementBadge = document.getElementById('announcementBadge');\n const announcementTitle = document.getElementById('announcementTitle');\n const announcementContent = document.getElementById('announcementContent');\n const announcementTime = document.getElementById('announcementTime');\n \n // 版本元素\n const versionSection = document.getElementById('versionSection');\n const versionStatus = document.getElementById('versionStatus');\n const currentVersionEl = document.getElementById('currentVersion');\n const latestVersionEl = document.getElementById('latestVersion');\n const latestVersionRow = document.getElementById('latestVersionRow');\n const updateHint = document.getElementById('updateHint');\n \n // 顶部更新提醒条\n const updateBanner = document.getElementById('updateBanner');\n const updateBannerVersion = document.getElementById('updateBannerVersion');\n const updateBannerClose = document.getElementById('updateBannerClose');\n \n // Toast 元素\n const toast = document.getElementById('toast');\n const toastIcon = document.getElementById('toastIcon');\n const toastMessage = document.getElementById('toastMessage');\n let toastTimer = null;\n \n // 显示 Toast 通知\n function showToast(message, icon = '✅', duration = 10000) {\n // 清除之前的定时器\n if (toastTimer) {\n clearTimeout(toastTimer);\n }\n \n toastIcon.textContent = icon;\n toastMessage.textContent = message;\n toast.classList.add('show');\n \n // 设置自动隐藏\n toastTimer = setTimeout(() => {\n toast.classList.remove('show');\n }, duration);\n }\n \n // 禁用换号按钮并显示倒计时\n let switchBtnCountdownTimer = null;\n const originalSwitchBtnText = '一键换号(扣1积分)';\n \n function disableSwitchBtnWithCountdown(seconds) {\n // 清除之前的定时器\n if (switchBtnCountdownTimer) {\n clearInterval(switchBtnCountdownTimer);\n }\n \n let remaining = seconds;\n manualSwitchBtn.disabled = true;\n manualSwitchBtn.querySelector('.btn-text').textContent = remaining + '秒后可用';\n \n switchBtnCountdownTimer = setInterval(() => {\n remaining--;\n if (remaining <= 0) {\n clearInterval(switchBtnCountdownTimer);\n switchBtnCountdownTimer = null;\n manualSwitchBtn.disabled = false;\n manualSwitchBtn.querySelector('.btn-text').textContent = originalSwitchBtnText;\n } else {\n manualSwitchBtn.querySelector('.btn-text').textContent = remaining + '秒后可用';\n }\n }, 1000);\n }\n \n // 弹窗元素\n const adminModal = document.getElementById('adminModal');\n const adminModalClose = document.getElementById('adminModalClose');\n const resetPermissionModal = document.getElementById('resetPermissionModal');\n const resetPermissionClose = document.getElementById('resetPermissionClose');\n const restartModal = document.getElementById('restartModal');\n const restartModalTitle = document.getElementById('restartModalTitle');\n const restartNowBtn = document.getElementById('restartNowBtn');\n const restartLaterBtn = document.getElementById('restartLaterBtn');\n const expiredModal = document.getElementById('expiredModal');\n const expiredModalClose = document.getElementById('expiredModalClose');\n const cleanEnvModal = document.getElementById('cleanEnvModal');\n const cleanEnvConfirmBtn = document.getElementById('cleanEnvConfirmBtn');\n const cleanEnvCancelBtn = document.getElementById('cleanEnvCancelBtn');\n \n // 换号确认弹窗元素\n const switchConfirmModal = document.getElementById('switchConfirmModal');\n const switchConfirmEmail = document.getElementById('switchConfirmEmail');\n const switchConfirmCost = document.getElementById('switchConfirmCost');\n const switchConfirmBtn = document.getElementById('switchConfirmBtn');\n const switchCancelBtn = document.getElementById('switchCancelBtn');\n \n // 显示管理员权限弹窗\n function showAdminModal() {\n adminModal.classList.add('show');\n }\n \n // 显示重置机器码权限提示弹窗\n function showAdminPermissionModal() {\n resetPermissionModal.classList.add('show');\n }\n \n // 重置机器码权限弹窗 - 关闭按钮\n resetPermissionClose.addEventListener('click', () => {\n resetPermissionModal.classList.remove('show');\n });\n \n // 点击遮罩关闭权限提示弹窗\n resetPermissionModal.addEventListener('click', (e) => {\n if (e.target === resetPermissionModal) {\n resetPermissionModal.classList.remove('show');\n }\n });\n \n // 显示重启提示弹窗\n let restartModalAction = 'reload'; // 'reload' 或 'close'\n \n function showRestartModal(title, action = 'reload') {\n restartModalTitle.textContent = title || '操作成功';\n restartModalAction = action;\n // 根据操作类型更新按钮文字\n restartNowBtn.textContent = action === 'close' ? '立即关闭 Cursor' : '立即重启';\n restartModal.classList.add('show');\n }\n \n // 显示过期弹窗\n function showExpiredModal() {\n expiredModal.classList.add('show');\n }\n \n // 关闭管理员弹窗\n adminModalClose.addEventListener('click', () => {\n adminModal.classList.remove('show');\n });\n \n // 点击遮罩关闭管理员弹窗\n adminModal.addEventListener('click', (e) => {\n if (e.target === adminModal) {\n adminModal.classList.remove('show');\n }\n });\n \n // 立即重启/关闭按钮\n restartNowBtn.addEventListener('click', () => {\n restartModal.classList.remove('show');\n if (restartModalAction === 'close') {\n // 完全关闭 Cursor\n vscode.postMessage({ type: 'closeCursor' });\n } else {\n // 重新加载窗口\n vscode.postMessage({ type: 'reloadWindow' });\n }\n });\n \n // 稍后手动按钮\n restartLaterBtn.addEventListener('click', () => {\n restartModal.classList.remove('show');\n });\n \n // 点击遮罩关闭重启弹窗\n restartModal.addEventListener('click', (e) => {\n if (e.target === restartModal) {\n restartModal.classList.remove('show');\n }\n });\n \n // 关闭过期弹窗\n expiredModalClose.addEventListener('click', () => {\n expiredModal.classList.remove('show');\n });\n \n // 点击遮罩关闭过期弹窗\n expiredModal.addEventListener('click', (e) => {\n if (e.target === expiredModal) {\n expiredModal.classList.remove('show');\n }\n });\n \n // 当前账号邮箱(用于查询用量)\n let currentAccountEmail = '';\n let usageRefreshInterval = null;\n // 存储完整激活码(用于复制)\n let fullActivationKey = '';\n // 当前剩余换号次数\n let currentSwitchRemaining = 0;\n // 当前到期时间\n let currentExpireDate = '';\n \n // 检查卡密是否已过期\n function isKeyExpired() {\n if (!currentExpireDate) return true;\n try {\n const expireTime = new Date(currentExpireDate).getTime();\n return Date.now() > expireTime;\n } catch {\n return true;\n }\n }\n \n // 格式化到期时间为北京时间\n function formatExpireDate(dateStr) {\n if (!dateStr) return '';\n try {\n // 后端返回的时间没有时区标识,假设是 UTC 时间\n // 将空格替换为T并添加Z表示UTC\n let utcStr = dateStr;\n if (!dateStr.includes('T') && !dateStr.includes('Z') && !dateStr.includes('+')) {\n utcStr = dateStr.replace(' ', 'T') + 'Z';\n }\n const date = new Date(utcStr);\n \n // 使用中国时区格式化UTC+8\n return date.toLocaleString('zh-CN', {\n timeZone: 'Asia/Shanghai',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n });\n } catch {\n return dateStr; // 格式化失败返回原始值\n }\n }\n \n // 隐藏激活码后几位\n function maskKey(key) {\n if (!key || key.length <= 8) return key;\n return key.substring(0, key.length - 4) + '****';\n }\n \n // 点击激活码复制\n keyDisplay.addEventListener('click', () => {\n if (!fullActivationKey) return;\n navigator.clipboard.writeText(fullActivationKey).then(() => {\n keyDisplay.classList.add('copied');\n const originalText = keyDisplay.textContent;\n keyDisplay.textContent = '已复制!';\n setTimeout(() => {\n keyDisplay.textContent = maskKey(fullActivationKey);\n keyDisplay.classList.remove('copied');\n }, 1000);\n }).catch(() => {\n // 降级方案\n const textarea = document.createElement('textarea');\n textarea.value = fullActivationKey;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n keyDisplay.classList.add('copied');\n keyDisplay.textContent = '已复制!';\n setTimeout(() => {\n keyDisplay.textContent = maskKey(fullActivationKey);\n keyDisplay.classList.remove('copied');\n }, 1000);\n });\n });\n \n // Loading 状态控制\n function setButtonLoading(btn, loading) {\n if (loading) {\n btn.classList.add('loading');\n btn.disabled = true;\n } else {\n btn.classList.remove('loading');\n // 注意:某些按钮可能需要保持禁用状态,由调用方控制\n }\n }\n \n function setRefreshLoading(btn, loading) {\n if (loading) {\n btn.classList.add('loading');\n } else {\n btn.classList.remove('loading');\n }\n }\n \n // 获取初始状态\n vscode.postMessage({ type: 'getState' });\n vscode.postMessage({ type: 'getSeamlessStatus' });\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n vscode.postMessage({ type: 'getProxyStatus' });\n vscode.postMessage({ type: 'getAnnouncement' });\n vscode.postMessage({ type: 'checkVersion' });\n vscode.postMessage({ type: 'getCursorRunningPath' });\n \n // 激活按钮\n activateBtn.addEventListener('click', () => {\n const key = keyInput.value.trim();\n if (!key) {\n return;\n }\n setButtonLoading(activateBtn, true);\n vscode.postMessage({ type: 'activate', key });\n });\n \n // 换号按钮\n switchBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'switch' });\n });\n \n // 重置机器码按钮\n resetBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'resetMachineId' });\n });\n \n // 禁用自动更新按钮\n disableUpdateBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'disableUpdate' });\n });\n \n // 清理Cursor环境按钮 - 显示确认弹窗\n cleanEnvBtn.addEventListener('click', () => {\n cleanEnvModal.classList.add('show');\n });\n \n // 确认清理\n cleanEnvConfirmBtn.addEventListener('click', () => {\n cleanEnvModal.classList.remove('show');\n vscode.postMessage({ type: 'cleanEnv' });\n });\n \n // 取消清理\n cleanEnvCancelBtn.addEventListener('click', () => {\n cleanEnvModal.classList.remove('show');\n });\n \n // 点击遮罩关闭清理弹窗\n cleanEnvModal.addEventListener('click', (e) => {\n if (e.target === cleanEnvModal) {\n cleanEnvModal.classList.remove('show');\n }\n });\n \n // 停用按钮\n disableBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'disable' });\n });\n \n // 关闭更新提醒条\n updateBannerClose.addEventListener('click', () => {\n updateBanner.classList.remove('show');\n });\n \n // 免魔法开关\n seamlessProxySwitch.addEventListener('change', (e) => {\n const wantEnabled = e.target.checked;\n \n // 如果要开启免魔法,检查卡密是否过期(只要没过期就可以用,不管换号次数)\n if (wantEnabled && isKeyExpired()) {\n e.target.checked = false;\n showToast('授权码已过期,无法开启免魔法', '⚠️', 3000);\n return;\n }\n \n vscode.postMessage({ \n type: 'toggleProxy', \n enabled: wantEnabled,\n url: ''\n });\n });\n \n // 无感换号 - 启用按钮\n enableSeamlessBtn.addEventListener('click', () => {\n setButtonLoading(enableSeamlessBtn, true);\n vscode.postMessage({ type: 'injectSeamless' });\n });\n \n // 无感换号 - 禁用按钮\n disableSeamlessBtn.addEventListener('click', () => {\n setButtonLoading(disableSeamlessBtn, true);\n vscode.postMessage({ type: 'restoreSeamless' });\n });\n \n // 无感换号 - 手动换号按钮(先检查用量)\n manualSwitchBtn.addEventListener('click', () => {\n setButtonLoading(manualSwitchBtn, true);\n // 传递当前显示的账号邮箱\n vscode.postMessage({ type: 'checkUsageBeforeSwitch', email: currentAccountEmail });\n });\n \n // 换号确认弹窗 - 确认按钮\n switchConfirmBtn.addEventListener('click', () => {\n switchConfirmModal.classList.remove('show');\n setButtonLoading(manualSwitchBtn, true);\n vscode.postMessage({ type: 'confirmSwitch' });\n });\n \n // 换号确认弹窗 - 取消按钮\n switchCancelBtn.addEventListener('click', () => {\n switchConfirmModal.classList.remove('show');\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n });\n \n // 换号确认弹窗 - 点击遮罩关闭\n switchConfirmModal.addEventListener('click', (e) => {\n if (e.target === switchConfirmModal) {\n switchConfirmModal.classList.remove('show');\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n }\n });\n \n // 无感换号区域 - 重置机器码按钮\n seamlessResetMachineBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'resetMachineId' });\n });\n \n // 刷新用量按钮\n refreshUsageBtn.addEventListener('click', () => {\n if (currentAccountEmail) {\n setRefreshLoading(refreshUsageBtn, true);\n vscode.postMessage({ type: 'getAccountUsage', email: currentAccountEmail });\n }\n });\n \n // 刷新用量函数\n function refreshUsage() {\n if (currentAccountEmail) {\n vscode.postMessage({ type: 'getAccountUsage', email: currentAccountEmail });\n }\n }\n \n // 启动用量定时刷新 (每分钟一次)\n function startUsageRefresh() {\n if (usageRefreshInterval) {\n clearInterval(usageRefreshInterval);\n }\n // 立即刷新一次\n refreshUsage();\n // 每60秒刷新一次\n usageRefreshInterval = setInterval(refreshUsage, 60000);\n }\n \n // 停止用量刷新\n function stopUsageRefresh() {\n if (usageRefreshInterval) {\n clearInterval(usageRefreshInterval);\n usageRefreshInterval = null;\n }\n }\n \n // 更新用量显示\n function updateUsageDisplay(data) {\n if (!data) return;\n \n const subscription = data.subscription || {};\n const usage = data.usage || {};\n \n // 会员类型\n const memberTypeMap = {\n 'free_trial': '免费试用',\n 'pro': 'Pro会员',\n 'free': '免费版',\n 'business': '商业版'\n };\n usageMemberType.textContent = memberTypeMap[subscription.membershipType] || subscription.membershipType || '-';\n \n // 试用剩余天数\n if (subscription.daysRemainingOnTrial !== undefined && subscription.daysRemainingOnTrial !== null) {\n usageTrialDays.textContent = subscription.daysRemainingOnTrial + ' 天';\n usageTrialDays.style.color = subscription.daysRemainingOnTrial <= 3 ? '#f87171' : '#4ade80';\n } else {\n usageTrialDays.textContent = '-';\n usageTrialDays.style.color = '#fff';\n }\n \n // 请求次数\n usageRequestCount.textContent = (usage.totalUsageCount || 0) + ' 次';\n \n // 已用额度\n const costUSD = usage.totalCostUSD || 0;\n usageCostUSD.textContent = '$' + costUSD.toFixed(2);\n usageCostUSD.style.color = costUSD > 5 ? '#f87171' : (costUSD > 2 ? '#fbbf24' : '#4ade80');\n \n // 更新时间\n usageUpdateTime.textContent = '更新于 ' + new Date().toLocaleTimeString();\n }\n \n // 解析公告内容中的链接 {文字URL}\n function parseAnnouncementContent(content) {\n if (!content) return '';\n \n // 转义 HTML 特殊字符\n let escaped = content\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n \n // 匹配 {文字https://...} 或 {文字http://...} 格式\n const linkRegex = /\\{([^}]+?)(https?:\\/\\/[^}]+)\\}/g;\n \n escaped = escaped.replace(linkRegex, function(match, text, url) {\n return '<a href=\"' + url + '\" class=\"announcement-link\" target=\"_blank\">' + text + '</a>';\n });\n \n // 将换行符转换为 <br>\n escaped = escaped.replace(/\\n/g, '<br>');\n \n return escaped;\n }\n \n // 更新公告显示\n function updateAnnouncementDisplay(data) {\n if (!data || !data.is_active) {\n announcementSection.style.display = 'none';\n return;\n }\n \n // 显示公告区域\n announcementSection.style.display = 'block';\n \n // 设置图标和类型徽章\n const typeConfig = {\n 'info': { icon: '📢', text: '通知', class: 'info' },\n 'warning': { icon: '⚠️', text: '警告', class: 'warning' },\n 'error': { icon: '🚨', text: '重要', class: 'error' },\n 'success': { icon: '✅', text: '好消息', class: 'success' }\n };\n \n const config = typeConfig[data.type] || typeConfig.info;\n announcementIcon.textContent = config.icon;\n announcementBadge.textContent = config.text;\n announcementBadge.className = 'announcement-badge ' + config.class;\n \n // 设置标题和内容(解析链接)\n announcementTitle.textContent = data.title || '';\n announcementContent.innerHTML = parseAnnouncementContent(data.content || '');\n \n // 设置时间\n if (data.created_at) {\n const date = new Date(data.created_at);\n announcementTime.textContent = date.toLocaleDateString('zh-CN', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit'\n });\n } else {\n announcementTime.textContent = '';\n }\n }\n \n // 处理来自扩展的消息\n window.addEventListener('message', event => {\n const message = event.data;\n \n switch (message.type) {\n case 'state':\n updateUI(message);\n break;\n case 'activated':\n setButtonLoading(activateBtn, false);\n activateBtn.disabled = false;\n if (message.success) {\n // 调试日志\n console.log('[CursorPro] 前端收到激活成功消息:', message);\n \n authStatus.textContent = '已授权';\n authStatus.className = 'status-badge active';\n accountStatus.textContent = '已激活';\n accountStatus.className = 'status-badge active';\n switchBtn.disabled = false;\n // 更新激活码显示(使用后端返回的 key\n fullActivationKey = message.key || keyInput.value;\n keyDisplay.textContent = maskKey(fullActivationKey);\n // 更新到期时间\n console.log('[CursorPro] 更新到期时间:', message.expireDate);\n currentExpireDate = message.expireDate || '';\n expireDate.textContent = formatExpireDate(currentExpireDate) || '未知';\n // 更新换号次数\n if (message.switchRemaining !== undefined) {\n currentSwitchRemaining = message.switchRemaining;\n switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);\n }\n // 清空输入框\n keyInput.value = '';\n showToast('授权码激活成功!', '✅', 10000);\n } else {\n showToast(message.error || '激活失败', '❌', 10000);\n }\n break;\n case 'switched':\n if (message.success) {\n switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);\n showToast('换号成功: ' + (message.email || ''), '✅', 10000);\n } else {\n showToast(message.error || '换号失败', '❌', 10000);\n }\n break;\n case 'reset':\n authStatus.textContent = '未授权';\n authStatus.className = 'status-badge inactive';\n accountStatus.textContent = '未激活';\n accountStatus.className = 'status-badge inactive';\n switchBtn.disabled = true;\n keyInput.value = '';\n fullActivationKey = '';\n keyDisplay.textContent = '尚未激活';\n expireDate.textContent = '尚未激活';\n break;\n \n // 激活码状态检查结果\n case 'keyStatusChecked':\n if (message.valid) {\n // 激活码有效,更新显示\n currentExpireDate = message.expireDate || '';\n currentSwitchRemaining = message.switchRemaining || 0;\n expireDate.textContent = formatExpireDate(currentExpireDate);\n switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);\n } else if (message.expired) {\n // 激活码已过期,显示提示并重置状态\n currentExpireDate = '';\n currentSwitchRemaining = 0;\n authStatus.textContent = '已过期';\n authStatus.className = 'status-badge inactive';\n authStatus.style.background = '#6e3232';\n authStatus.style.color = '#ff6b6b';\n expireDate.textContent = '已过期';\n expireDate.style.color = '#f87171';\n switchBtn.disabled = true;\n enableSeamlessBtn.disabled = true;\n // 如果免魔法已开启,自动关闭\n if (seamlessProxySwitch.checked) {\n seamlessProxySwitch.checked = false;\n vscode.postMessage({ type: 'toggleProxy', enabled: false, url: '' });\n }\n // 显示过期弹窗\n showExpiredModal();\n }\n break;\n \n // 用户换号状态\n case 'userSwitchStatus':\n const remaining = message.switchRemaining || 0;\n const canSwitch = remaining > 0;\n \n // 更新全局变量\n currentSwitchRemaining = remaining;\n \n seamlessSwitchRemaining.textContent = remaining.toString();\n seamlessSwitchRemaining.style.color = canSwitch ? '#4ade80' : '#f87171';\n \n if (message.lockedAccount) {\n seamlessCurrentAccount.textContent = message.lockedAccount.email;\n \n // 设置当前账号邮箱并启动用量刷新\n if (message.lockedAccount.email && message.lockedAccount.email !== currentAccountEmail) {\n currentAccountEmail = message.lockedAccount.email;\n usageSection.style.display = 'block';\n startUsageRefresh();\n }\n } else {\n seamlessCurrentAccount.textContent = '未分配';\n \n // 没有锁定账号时隐藏用量区域\n currentAccountEmail = '';\n usageSection.style.display = 'none';\n stopUsageRefresh();\n }\n \n // 根据剩余次数控制手动换号按钮状态\n if (!canSwitch) {\n manualSwitchBtn.disabled = true;\n }\n // 启用无感换号按钮不受积分限制,只有过期才禁用\n enableSeamlessBtn.disabled = isKeyExpired();\n \n // 如果无感换号已启用,显示手动换号按钮和重置机器码按钮\n if (message.seamlessEnabled && canSwitch) {\n manualSwitchBtn.style.display = 'block';\n manualSwitchBtn.disabled = false;\n setButtonLoading(manualSwitchBtn, false);\n seamlessResetMachineBtn.style.display = 'block';\n }\n break;\n \n // 账号用量\n case 'accountUsage':\n setRefreshLoading(refreshUsageBtn, false);\n if (message.success && message.data) {\n updateUsageDisplay(message.data);\n } else {\n usageUpdateTime.textContent = '获取失败: ' + (message.error || '未知错误');\n usageUpdateTime.style.color = '#f87171';\n }\n break;\n \n // 无感换号状态\n case 'seamlessStatus':\n if (message.is_injected) {\n seamlessStatus.textContent = '已启用';\n seamlessStatus.className = 'status-badge active';\n enableSeamlessBtn.style.display = 'none';\n disableSeamlessBtn.style.display = 'block';\n disableSeamlessBtn.disabled = false;\n setButtonLoading(disableSeamlessBtn, false);\n manualSwitchBtn.style.display = 'block';\n manualSwitchBtn.disabled = false;\n setButtonLoading(manualSwitchBtn, false);\n seamlessResetMachineBtn.style.display = 'block';\n } else {\n seamlessStatus.textContent = '未启用';\n seamlessStatus.className = 'status-badge inactive';\n enableSeamlessBtn.style.display = 'block';\n setButtonLoading(enableSeamlessBtn, false);\n // 启用按钮不受积分限制,只有过期才禁用\n enableSeamlessBtn.disabled = isKeyExpired();\n disableSeamlessBtn.style.display = 'none';\n manualSwitchBtn.style.display = 'none';\n seamlessResetMachineBtn.style.display = 'none';\n }\n break;\n \n case 'seamlessInjected':\n setButtonLoading(enableSeamlessBtn, false);\n enableSeamlessBtn.disabled = false;\n if (message.success) {\n seamlessStatus.textContent = '已启用';\n seamlessStatus.className = 'status-badge active';\n enableSeamlessBtn.style.display = 'none';\n disableSeamlessBtn.style.display = 'block';\n manualSwitchBtn.style.display = 'block';\n seamlessResetMachineBtn.style.display = 'block';\n // 刷新用户状态\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n // 显示重启提示弹窗\n if (message.needRestart) {\n showRestartModal(message.message || '无感换号已启用');\n }\n } else {\n // 如果是权限错误,显示自定义弹窗\n if (message.needAdmin) {\n // Mac/Linux 权限问题,显示详细提示\n var errorMsg = message.error || '没有写入权限';\n if (message.path) {\n errorMsg += '\\n路径: ' + message.path;\n }\n showToast(errorMsg, '🔐', 15000);\n } else {\n // 显示详细错误\n var detailMsg = message.error || '启用失败';\n if (message.details) {\n detailMsg += '\\n' + message.details;\n }\n showToast(detailMsg, '❌', 15000);\n }\n }\n break;\n \n case 'seamlessRestored':\n setButtonLoading(disableSeamlessBtn, false);\n disableSeamlessBtn.disabled = false;\n if (message.success) {\n seamlessStatus.textContent = '未启用';\n seamlessStatus.className = 'status-badge inactive';\n enableSeamlessBtn.style.display = 'block';\n disableSeamlessBtn.style.display = 'none';\n manualSwitchBtn.style.display = 'none';\n seamlessResetMachineBtn.style.display = 'none';\n // 显示重启提示弹窗\n if (message.needRestart) {\n showRestartModal(message.message || '无感换号已禁用');\n }\n } else {\n // 如果是权限错误,显示自定义弹窗\n if (message.needAdmin) {\n showAdminModal();\n } else {\n showToast(message.error || '禁用失败', '❌', 10000);\n }\n }\n break;\n \n // 用量检查结果\n case 'usageCheckResult':\n if (message.success) {\n if (message.needConfirm) {\n // 需要确认,显示弹窗(按钮保持可用状态,等用户选择)\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n switchConfirmEmail.textContent = message.email || '';\n switchConfirmCost.textContent = '$' + (message.costUSD || '0.00');\n switchConfirmModal.classList.add('show');\n } else {\n // 不需要确认,直接换号\n vscode.postMessage({ type: 'confirmSwitch' });\n }\n } else {\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n showToast(message.error || '检查失败', '❌', 5000);\n }\n break;\n \n case 'manualSeamlessSwitched':\n setButtonLoading(manualSwitchBtn, false);\n if (message.success) {\n seamlessSwitchRemaining.textContent = (message.switchRemaining || 0).toString();\n seamlessCurrentAccount.textContent = message.email || '未知';\n // 显示 Toast 通知10秒后消失\n showToast('已切换到: ' + (message.email || '新账号') + '约10秒内自动生效', '✅', 10000);\n // 刷新状态\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n // 禁用按钮10秒显示倒计时\n disableSwitchBtnWithCountdown(10);\n } else {\n manualSwitchBtn.disabled = false;\n showToast(message.error || '换号失败', '❌', 5000);\n }\n break;\n \n case 'proxyStatus':\n // 设置免魔法开关状态\n seamlessProxySwitch.checked = message.enabled;\n break;\n \n // 公告\n case 'announcement':\n if (message.success && message.data) {\n updateAnnouncementDisplay(message.data);\n } else {\n announcementSection.style.display = 'none';\n }\n break;\n \n // 版本检查\n case 'versionCheck':\n currentVersionEl.textContent = message.currentVersion || '-';\n if (message.success && message.hasUpdate) {\n // 有更新\n latestVersionEl.textContent = message.latestVersion;\n latestVersionRow.style.display = 'flex';\n versionStatus.style.display = 'inline-block';\n versionStatus.style.background = '#ff9800';\n updateHint.style.display = 'block';\n \n // 显示顶部更新提醒条\n updateBannerVersion.textContent = 'v' + message.latestVersion;\n updateBanner.classList.add('show');\n } else if (message.success) {\n // 已是最新版\n versionStatus.textContent = '最新';\n versionStatus.style.display = 'inline-block';\n versionStatus.style.background = '#4caf50';\n latestVersionRow.style.display = 'none';\n updateHint.style.display = 'none';\n updateBanner.classList.remove('show');\n }\n break;\n \n // Cursor 运行路径\n case 'cursorRunningPath':\n if (message.path) {\n const pathText = message.path + (message.packageExists ? ' ✓' : ' ✗');\n cursorPath.textContent = pathText;\n cursorPath.style.color = message.packageExists ? '#4ade80' : '#f87171';\n // 同时更新版本号\n if (message.cursorVersion) {\n cursorVersion.textContent = message.cursorVersion;\n }\n } else {\n cursorPath.textContent = '未找到';\n cursorPath.style.color = '#f87171';\n }\n break;\n \n // 管理员权限不足提示\n case 'adminPermissionRequired':\n showAdminPermissionModal();\n break;\n \n // 机器码重置\n case 'machineIdReset':\n if (message.success && message.needRestart) {\n // 机器码重置需要完全关闭 Cursor不是 reload\n showRestartModal(message.message || '机器码重置成功', 'close');\n }\n break;\n \n // 通用 Toast 消息\n case 'showToast':\n showToast(message.message || '', message.icon || '📢', 10000);\n break;\n \n // 网络状态\n case 'networkStatus':\n updateOfflineStatus(!message.online);\n break;\n }\n });\n \n // 离线状态显示/隐藏\n let wasOffline = false; // 跟踪之前是否离线\n function updateOfflineStatus(isOffline) {\n if (isOffline) {\n offlineBanner.classList.add('show');\n wasOffline = true;\n } else {\n offlineBanner.classList.remove('show');\n // 只有从离线恢复到在线时才刷新状态\n if (wasOffline) {\n wasOffline = false;\n vscode.postMessage({ type: 'getState' });\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n }\n }\n }\n \n // 重试连接按钮\n retryConnectBtn.addEventListener('click', async () => {\n retryConnectBtn.classList.add('loading');\n retryConnectBtn.textContent = '连接中...';\n \n // 发起真正的网络请求来测试网络\n vscode.postMessage({ type: 'retryConnect' });\n \n // 5秒后恢复按钮状态给网络请求足够时间\n setTimeout(() => {\n retryConnectBtn.classList.remove('loading');\n retryConnectBtn.textContent = '重试';\n }, 5000);\n });\n \n function updateUI(state) {\n if (state.isActivated) {\n authStatus.textContent = '已授权';\n authStatus.className = 'status-badge active';\n accountStatus.textContent = '已激活';\n accountStatus.className = 'status-badge active';\n switchBtn.disabled = false;\n fullActivationKey = state.key;\n keyDisplay.textContent = maskKey(fullActivationKey);\n // 更新到期时间\n currentExpireDate = state.expireDate || '';\n expireDate.textContent = formatExpireDate(currentExpireDate);\n // 更新换号次数\n if (state.switchRemaining !== undefined) {\n currentSwitchRemaining = state.switchRemaining;\n switchCount.textContent = state.switchRemaining + '/' + (state.switchLimit || 100);\n }\n // 启用无感换号按钮(只有过期才禁用)\n enableSeamlessBtn.disabled = isKeyExpired();\n }\n cursorVersion.textContent = state.cursorVersion || '0.0.0';\n \n // 根据网络状态显示/隐藏离线提示\n if (state.isOnline === false) {\n offlineBanner.classList.add('show');\n wasOffline = true;\n } else if (state.isOnline === true) {\n // 网络恢复,隐藏离线提示\n offlineBanner.classList.remove('show');\n wasOffline = false;\n }\n }\n </script>\n</body>\n</html>";
}
}
}
async ["_handleGetAccountUsage"](_0x1b796a) {
const _0x312bb1 = {
'kwSDs': "[CursorPro] Toggle proxy error:",
'cuNHx': "proxyUpdated",
'AlVbI': '更新配置失败',
'cBprM': "accountUsage",
'pLAQo': "未提供账号邮箱",
'XCtgT': function (_0x51bb3f, _0x5ae513) {
return _0x51bb3f(_0x5ae513);
},
'LcuLD': "获取用量失败",
'JvSqa': "NYkng",
'rptjh': "请求失败"
};
try {
if (!_0x1b796a) {
this._postMessage({
'type': _0x312bb1.cBprM,
'success': false,
'error': _0x312bb1["pLAQo"]
});
return;
}
0x0;
const _0x58b290 = client_1["getApiUrl"]() + "/api/cursor-accounts/query?email=" + _0x312bb1["XCtgT"](encodeURIComponent, _0x1b796a) + '&refresh=true';
const _0x507bbc = await _0x312bb1["XCtgT"](fetch, _0x58b290);
const _0x46ba2b = await _0x507bbc.json();
if (_0x46ba2b["success"] && _0x46ba2b["data"]) {
this["_postMessage"]({
'type': _0x312bb1["cBprM"],
'success': true,
'data': _0x46ba2b["data"]
});
const _0x4cf6e5 = _0x46ba2b["data"]["usage"] || {};
const _0x3d3ce3 = _0x4cf6e5["totalUsageCount"] || 0x0;
const _0x1f779f = _0x312bb1["XCtgT"](parseFloat, _0x4cf6e5["totalCostUSD"] || 0x0);
0x0;
extension_1["updateUsageStatusBar"](_0x3d3ce3, _0x1f779f);
} else {
this["_postMessage"]({
'type': _0x312bb1.cBprM,
'success': false,
'error': _0x46ba2b["error"] || _0x312bb1["LcuLD"]
});
}
} catch (_0x3c8684) {
if (_0x312bb1["JvSqa"] !== 'NYkng') {
_0x496ef8["error"](_0x312bb1["kwSDs"], _0x4d4142);
this["_postMessage"]({
'type': _0x312bb1["cuNHx"],
'success': false,
'error': _0x312bb1["AlVbI"]
});
} else {
this["_postMessage"]({
'type': _0x312bb1["cBprM"],
'success': false,
'error': _0x3c8684.message || _0x312bb1["rptjh"]
});
}
}
}
async ["_handleGetAnnouncement"]() {
const _0x507cc2 = {
'eXcSu': "cursorpro.key",
'wCuhU': "cursorpro.expireDate",
'tQyYP': '请先激活授权码',
'fEjcy': function (_0x14a329, _0x3ca24d) {
return _0x14a329 > _0x3ca24d;
},
'GLUmw': "proxyUpdated",
'Bjkrw': '授权码已过期,无法开启免魔法',
'trGXG': 'showToast',
'aCZjy': function (_0x85327, _0x557946) {
return _0x85327(_0x557946);
},
'aHNrz': 'announcement',
'PynOc': function (_0x4e3da2, _0x27c602) {
return _0x4e3da2 === _0x27c602;
},
'LjnPR': 'ysOwe',
'RdeWm': "获取公告失败",
'XcVTX': "请求失败"
};
try {
0x0;
const _0x2127d9 = client_1["getApiUrl"]() + "/api/announcements/latest";
const _0x59851a = await _0x507cc2["aCZjy"](fetch, _0x2127d9);
const _0x1529e0 = await _0x59851a.json();
if (_0x1529e0["success"] && _0x1529e0["data"]) {
this._postMessage({
'type': _0x507cc2["aHNrz"],
'success': true,
'data': _0x1529e0["data"]
});
} else {
if ('ysOwe' === _0x507cc2["LjnPR"]) {
this._postMessage({
'type': "announcement",
'success': false,
'error': _0x1529e0["error"] || _0x507cc2["RdeWm"]
});
} else {
const _0x2213b8 = this["_context"].globalState.get(_0x507cc2["eXcSu"]);
const _0x3fde55 = this["_context"]["globalState"]["get"](_0x507cc2["wCuhU"]);
if (!_0x2213b8) {
this["_postMessage"]({
'type': 'proxyUpdated',
'success': false,
'error': '请先激活授权码'
});
this["_postMessage"]({
'type': "showToast",
'message': _0x507cc2["tQyYP"],
'icon': '⚠️'
});
return;
}
if (_0x3fde55) {
const _0x88cb25 = new _0x3cd6be(_0x3fde55)["getTime"]();
if (_0x507cc2["fEjcy"](_0x4cae44["now"](), _0x88cb25)) {
this._postMessage({
'type': _0x507cc2.GLUmw,
'success': false,
'error': _0x507cc2["Bjkrw"]
});
this._postMessage({
'type': _0x507cc2["trGXG"],
'message': "授权码已过期,无法开启免魔法",
'icon': '⚠️'
});
return;
}
}
}
}
} catch (_0x2ebc04) {
this["_postMessage"]({
'type': _0x507cc2["aHNrz"],
'success': false,
'error': _0x2ebc04.message || _0x507cc2["XcVTX"]
});
}
}
async ["_handleCheckVersion"]() {
const _0x250fa3 = {
'HgWOc': "[CursorPro] 使用用户配置的 Cursor 路径:",
'QXFeq': function (_0x28c00c, _0x55597c) {
return _0x28c00c > _0x55597c;
},
'lYCxA': "versionCheck",
'QtoxZ': function (_0x5cd3f7, _0x1bb416) {
return _0x5cd3f7 === _0x1bb416;
},
'xqknY': "vUHCr",
'GbNrd': "请求失败"
};
try {
0x0;
const _0xcbd93e = await client_1["getLatestVersion"]();
if (_0xcbd93e.success && _0xcbd93e.version) {
const _0x59dc2f = _0xcbd93e["version"];
const _0x1a5d58 = CursorProViewProvider["CURRENT_VERSION"];
const _0x4acb32 = _0x250fa3["QXFeq"](this["_compareVersions"](_0x59dc2f, _0x1a5d58), 0x0);
this["_postMessage"]({
'type': _0x250fa3["lYCxA"],
'success': true,
'currentVersion': _0x1a5d58,
'latestVersion': _0x59dc2f,
'hasUpdate': _0x4acb32
});
} else {
this["_postMessage"]({
'type': _0x250fa3["lYCxA"],
'success': false,
'currentVersion': CursorProViewProvider.CURRENT_VERSION,
'error': _0xcbd93e["error"] || "获取版本失败"
});
}
} catch (_0x5d97b6) {
if (_0x250fa3["QtoxZ"](_0x250fa3["xqknY"], "LOWQh")) {
_0x21c480["log"](_0x250fa3["HgWOc"], _0x41f567);
this["_cachedCursorPath"] = _0x3c3681;
return _0xb7920c;
} else {
this._postMessage({
'type': "versionCheck",
'success': false,
'currentVersion': CursorProViewProvider.CURRENT_VERSION,
'error': _0x5d97b6["message"] || _0x250fa3["GbNrd"]
});
}
}
}
["_compareVersions"](_0x2c35a0, _0x3e2c58) {
const _0x576d14 = {
'PMKNW': function (_0x2cee68, _0x17cabb) {
return _0x2cee68 < _0x17cabb;
},
'qyNxu': function (_0xbd034d, _0x5b41) {
return _0xbd034d > _0x5b41;
},
'HZvmu': function (_0x1f686e, _0x307d8c) {
return _0x1f686e < _0x307d8c;
}
};
const _0xbaec2f = _0x2c35a0["split"]('.')["map"](Number);
const _0x52cf6d = _0x3e2c58["split"]('.')["map"](Number);
const _0x23e911 = Math["max"](_0xbaec2f["length"], _0x52cf6d["length"]);
for (let _0x2d8ca5 = 0x0; _0x2d8ca5 < _0x23e911; _0x2d8ca5++) {
const _0x237a97 = _0xbaec2f[_0x2d8ca5] || 0x0;
const _0x266b01 = _0x52cf6d[_0x2d8ca5] || 0x0;
if (_0x576d14["qyNxu"](_0x237a97, _0x266b01)) {
return 0x1;
}
if (_0x237a97 < _0x266b01) {
return -0x1;
}
}
return 0x0;
}
async ["_handleGetCursorRunningPath"]() {
const _0x46ebbb = {
'SsULC': "[CursorPro] 使用 VS Code API 获取版本:",
'AwKfF': 'utf-8',
'zAvXx': "UBmxB",
'QhWXL': "未找到",
'bZBTW': 'cursorpro',
'vlHDb': 'cursorPath',
'ONVXL': function (_0x45b9b2, _0x3d0419) {
return _0x45b9b2 === _0x3d0419;
},
'JPYoo': "darwin",
'nEYhA': 'Contents',
'EbBLW': "Resources",
'lMfdt': "app",
'MFjtx': "package.json",
'NjVqB': "[CursorPro] 使用用户配置的路径:",
'Wxyfp': "win32",
'JSWuW': "BbiYe",
'ACRef': "wmic process where \"name='Cursor.exe'\" get ExecutablePath /format:list 2>nul",
'ydRHF': "resources",
'ANYDK': function (_0x3ac49f, _0x3550a9) {
return _0x3ac49f === _0x3550a9;
},
'rEwYQ': "snkgX",
'YxYZp': "BoVlO",
'Qvzam': function (_0x5c6915, _0xdddb6e) {
return _0x5c6915 === _0xdddb6e;
},
'FyfZA': function (_0x35b4f7, _0x394159) {
return _0x35b4f7 !== _0x394159;
},
'eCMQp': 'DZGqD',
'QKwAH': 'Programs',
'eEobw': "cursor",
'aouCU': "ZhNbs",
'XXRrw': "WrYgR",
'biXGl': "/Applications/Cursor.app",
'ErbAO': "/usr/share/cursor",
'vvvXG': ".local",
'kVBXU': "share",
'sxYuF': "mnjXn",
'sYfMC': "WRpnS",
'UFfHe': "[CursorPro] 从路径获取 Cursor 版本:",
'HLsOj': 'cursorRunningPath',
'stZTh': "获取失败: "
};
try {
if ("UBmxB" !== _0x46ebbb.zAvXx) {
return [{
'email': _0x7e9b73,
'access_token': _0x4f7a33,
'refresh_token': _0x32c653 || _0x23d4b2
}];
} else {
const _0x1b946c = process["platform"];
let _0x306e39 = _0x46ebbb.QhWXL;
let _0x260237 = '';
const _0x36a669 = vscode["workspace"]["getConfiguration"](_0x46ebbb["bZBTW"]);
const _0x49eda3 = _0x36a669["get"](_0x46ebbb["vlHDb"]);
if (_0x49eda3 && fs.existsSync(_0x49eda3)) {
_0x306e39 = _0x49eda3;
if (_0x1b946c === _0x46ebbb.JPYoo) {
_0x260237 = path["join"](_0x49eda3, _0x46ebbb["nEYhA"], _0x46ebbb["EbBLW"], _0x46ebbb["lMfdt"], _0x46ebbb["MFjtx"]);
} else {
_0x260237 = path["join"](_0x49eda3, "resources", _0x46ebbb.lMfdt, _0x46ebbb["MFjtx"]);
}
console.log(_0x46ebbb["NjVqB"], _0x49eda3);
} else {
if (_0x1b946c === _0x46ebbb.Wxyfp) {
try {
if (_0x46ebbb["JSWuW"] === "eKgQY") {
_0x2258e6 = true;
delete _0x2dff6a[_0x1d391b];
} else {
const {
stdout: _0x1a7f66
} = await execAsync(_0x46ebbb["ACRef"]);
const _0xa3209b = _0x1a7f66["match"](/ExecutablePath=(.+)/);
if (_0xa3209b && _0xa3209b[0x1]) {
const _0x5d0249 = _0xa3209b[0x1]["trim"]();
_0x306e39 = path.dirname(_0x5d0249);
_0x260237 = path["join"](_0x306e39, _0x46ebbb.ydRHF, _0x46ebbb.lMfdt, _0x46ebbb.MFjtx);
}
}
} catch (_0x48a57c) {
if (_0x46ebbb["rEwYQ"] === _0x46ebbb["YxYZp"]) {
_0x15013a["log"](_0x46ebbb["SsULC"], _0x3e70a4.version);
return _0x1800fc.version;
} else {
console.log("[CursorPro] WMIC 获取路径失败:", _0x48a57c);
}
}
if (_0x306e39 === _0x46ebbb["QhWXL"]) {
if (_0x46ebbb["FyfZA"]("DZGqD", _0x46ebbb["eCMQp"])) {
try {
const _0x378439 = this["_getHostsPath"]();
if (_0x1530ba["existsSync"](_0x378439)) {
return _0x4386be["readFileSync"](_0x378439, _0x46ebbb["AwKfF"]);
}
} catch (_0xba9c07) {
_0x79d384["error"]("[CursorPro] Read hosts error:", _0xba9c07);
}
return '';
} else {
const _0x17a391 = process["env"]["LOCALAPPDATA"] || '';
const _0x6b3334 = [path["join"](_0x17a391, _0x46ebbb["QKwAH"], 'cursor'), path["join"](_0x17a391, _0x46ebbb["eEobw"])];
for (const _0x516d23 of _0x6b3334) {
const _0x495418 = path["join"](_0x516d23, _0x46ebbb["ydRHF"], "app", _0x46ebbb["MFjtx"]);
if (fs.existsSync(_0x495418)) {
_0x306e39 = _0x516d23;
_0x260237 = _0x495418;
break;
}
}
}
}
} else {
if (_0x1b946c === "darwin") {
if (_0x46ebbb["Qvzam"](_0x46ebbb["aouCU"], _0x46ebbb["XXRrw"])) {
return null;
} else {
_0x306e39 = (await this["_getCursorInstallPath"]()) || _0x46ebbb["biXGl"];
_0x260237 = path["join"](_0x306e39, _0x46ebbb["nEYhA"], _0x46ebbb.EbBLW, 'app', _0x46ebbb.MFjtx);
}
} else {
const _0x1071f5 = process.env["HOME"] || '';
const _0x34c761 = [_0x46ebbb["ErbAO"], path.join(_0x1071f5, _0x46ebbb["vvvXG"], _0x46ebbb["kVBXU"], _0x46ebbb.eEobw)];
for (const _0x1aac5b of _0x34c761) {
if (fs.existsSync(_0x1aac5b)) {
_0x306e39 = _0x1aac5b;
_0x260237 = path["join"](_0x1aac5b, _0x46ebbb["ydRHF"], 'app', "package.json");
break;
}
}
}
}
}
const _0x3c9745 = _0x260237 && fs["existsSync"](_0x260237);
let _0xd636a6 = '';
if (_0x3c9745) {
try {
if (_0x46ebbb["sxYuF"] === _0x46ebbb["sYfMC"]) {
if (_0x343ee2["existsSync"](_0x44179b)) {
return _0x52b912;
}
} else {
const _0x4c9fc9 = fs.readFileSync(_0x260237, _0x46ebbb["AwKfF"]);
const _0x4056ed = JSON["parse"](_0x4c9fc9);
_0xd636a6 = _0x4056ed.version || '';
console["log"](_0x46ebbb["UFfHe"], _0xd636a6);
}
} catch (_0x15526b) {
console.log("[CursorPro] 读取 package.json 失败:", _0x15526b);
}
}
this._postMessage({
'type': 'cursorRunningPath',
'path': _0x306e39,
'packageJsonPath': _0x260237,
'packageExists': _0x3c9745,
'cursorVersion': _0xd636a6
});
}
} catch (_0x1da737) {
this._postMessage({
'type': _0x46ebbb["HLsOj"],
'path': "获取失败: " + (_0x1da737["message"] || _0x1da737),
'packageJsonPath': '',
'packageExists': false,
'cursorVersion': ''
});
}
}
async ["_handleCheckUsageBeforeSwitch"](_0x423ed0) {
const _0x46be7a = {
'sEVKj': "[CursorPro] PowerShell Get-Process 获取路径失败",
'kcIfn': "[CursorPro] Direct write failed, trying to grant permission",
'qVzhF': function (_0x1030be, _0x3ef0ad) {
return _0x1030be === _0x3ef0ad;
},
'NTZfw': "klkmy",
'LnwIK': 'usageCheckResult',
'yCHku': "未激活授权码",
'wnjiM': function (_0x5ba0af, _0x167687) {
return _0x5ba0af === _0x167687;
},
'FHkCa': "taehn",
'Elfrz': function (_0x4cea4c, _0x4a5432) {
return _0x4cea4c(_0x4a5432);
},
'uXXMl': function (_0x4a7089, _0x1a8977) {
return _0x4a7089(_0x1a8977);
},
'rMdug': "Drfmf",
'KaGPw': "lZGGL",
'DqgLz': function (_0x3614c7, _0x5a56ba) {
return _0x3614c7 < _0x5a56ba;
},
'nMItX': "aCFwf",
'YHdCp': 'MhURV',
'zYseP': function (_0x315829, _0x209dfd) {
return _0x315829 !== _0x209dfd;
},
'XaQBc': "PgKQl",
'PYWHP': 'hlMgj',
'EKVNJ': "zdYFk"
};
try {
if ('pydTE' !== _0x46be7a["NTZfw"]) {
const _0x265715 = this["_context"]["globalState"]["get"]("cursorpro.key");
if (!_0x265715) {
this["_postMessage"]({
'type': _0x46be7a["LnwIK"],
'success': false,
'error': _0x46be7a.yCHku
});
return;
}
if (!_0x423ed0) {
if (_0x46be7a["FHkCa"] === _0x46be7a["FHkCa"]) {
this["_postMessage"]({
'type': "usageCheckResult",
'success': true,
'needConfirm': false
});
return;
} else {
_0x4ade37["window"].showErrorMessage("清理失败: " + _0x39dd6b);
}
}
0x0;
const _0xe4de04 = client_1["getApiUrl"]() + '/api/cursor-accounts/query?email=' + encodeURIComponent(_0x423ed0) + "&refresh=false";
const _0x4e6615 = await fetch(_0xe4de04);
const _0xa38d3b = await _0x4e6615.json();
if (_0xa38d3b["success"] && _0xa38d3b.data) {
if (_0x46be7a.rMdug !== _0x46be7a["KaGPw"]) {
const _0x1a9459 = _0xa38d3b["data"]["usage"] || {};
const _0x54f98 = parseFloat(_0x1a9459["totalCostUSD"] || 0x0);
if (_0x46be7a["DqgLz"](_0x54f98, 0xa)) {
if (_0x46be7a["wnjiM"](_0x46be7a["nMItX"], _0x46be7a["YHdCp"])) {
_0x36aa30["log"](_0x46be7a["sEVKj"]);
} else {
this["_postMessage"]({
'type': _0x46be7a["LnwIK"],
'success': true,
'needConfirm': true,
'costUSD': _0x54f98.toFixed(0x2),
'email': _0x423ed0
});
}
} else {
this._postMessage({
'type': _0x46be7a["LnwIK"],
'success': true,
'needConfirm': false
});
}
} else {
_0x11939f["rmSync"](_0x5a5124, {
'recursive': true,
'force': true
});
_0x5829eb++;
}
} else if (_0x46be7a["zYseP"]('GbpRm', _0x46be7a.XaQBc)) {
this["_postMessage"]({
'type': _0x46be7a["LnwIK"],
'success': true,
'needConfirm': false
});
} else {
_0x34b65e["log"](_0x46be7a["kcIfn"]);
}
} else {
if (_0x46be7a["qVzhF"](_0x12d7bd, _0x4c400f)) {
_0x2cc937 = _0x34b272;
}
_0x370969[_0x2f7e57] = _0x496a29[_0x21aa14];
}
} catch (_0xc3e637) {
if (_0x46be7a["zYseP"](_0x46be7a["PYWHP"], _0x46be7a["EKVNJ"])) {
this["_postMessage"]({
'type': 'usageCheckResult',
'success': true,
'needConfirm': false
});
} else {
_0xd7775["push"](_0x5f24a2.name);
}
}
}
async ._handleManualSeamlessSwitch() {
const _0x239b7a = {
'BIFqO': "utf-8",
'BfPph': "[CursorPro] Linux 获取进程路径失败:",
'loKNV': 'cursorRunningPath',
'HrshN': function (_0x5b042b, _0x3fb2de) {
return _0x5b042b + _0x3fb2de;
},
'ByJnO': "获取失败: ",
'yJBIQ': 'exYVj',
'KvCvh': 'manualSeamlessSwitched',
'VLaZZ': "未激活授权码",
'tbDpF': function (_0x5a9370, _0x36f88c) {
return _0x5a9370 !== _0x36f88c;
},
'yPImL': 'ingEM',
'mlftM': function (_0x148013, _0x58777f) {
return _0x148013 !== _0x58777f;
},
'jnyry': "FYJZv",
'HxZxj': "换号失败",
'sLjSr': "连接服务器失败"
};
try {
if (_0x239b7a["yJBIQ"] === 'exYVj') {
const _0x204f37 = this["_context"]["globalState"]["get"]("cursorpro.key");
if (!_0x204f37) {
this["_postMessage"]({
'type': _0x239b7a["KvCvh"],
'success': false,
'error': _0x239b7a["VLaZZ"]
});
return;
}
0x0;
const _0x4d82f2 = await client_1["switchSeamlessToken"](_0x204f37);
if (_0x4d82f2["switched"]) {
if (_0x4d82f2["email"]) {
await this["_context"].globalState["update"]("cursorpro.seamlessCurrentAccount", _0x4d82f2["email"]);
}
this["_postMessage"]({
'type': _0x239b7a["KvCvh"],
'success': true,
'email': _0x4d82f2["email"],
'switchRemaining': _0x4d82f2.switchRemaining
});
} else {
if (_0x239b7a["mlftM"]("JYbEY", _0x239b7a["jnyry"])) {
const _0x1d8cc3 = _0x4d82f2["message"] || _0x4d82f2["error"] || _0x239b7a["HxZxj"];
this._postMessage({
'type': _0x239b7a["KvCvh"],
'success': false,
'error': _0x1d8cc3
});
} else {
_0x48d9fc.warn(_0x239b7a["BfPph"], _0x2600b5);
}
}
} else {
this["_postMessage"]({
'type': 'cursorRunningPath',
'path': _0x239b7a["HrshN"](_0x239b7a["ByJnO"], _0x2ae8a1["message"] || _0x13ffd1),
'packageJsonPath': '',
'packageExists': false,
'cursorVersion': ''
});
}
} catch (_0x56a0cb) {
const _0x38f43a = _0x56a0cb?..message || _0x239b7a["sLjSr"];
this._postMessage({
'type': _0x239b7a["KvCvh"],
'success': false,
'error': _0x38f43a
});
}
}
async ["_handleGetCursorPath"]() {
const _0x38acb3 = {
'tbZpe': function (_0x46700e, _0x216ec6) {
return _0x46700e === _0x216ec6;
},
'pcUwb': "EPERM",
'WPzlq': "没有写入权限",
'drojl': 'seamlessRestored',
'fTNeN': "activated",
'TbbUg': "没有写入权限,请在终端执行: sudo chmod -R 777 /Applications/Cursor.app",
'NwHIv': "seamlessInjected",
'jmXuW': "请先激活授权码",
'rEDBm': 'utf-8',
'bpeCI': "启用失败",
'TFAWN': "win32",
'VsfTO': function (_0x5469b9, _0x18421f) {
return _0x5469b9(_0x18421f);
},
'LurDi': "wmic process where \"name='Cursor.exe'\" get ExecutablePath /format:list 2>nul",
'VtoJO': 'hKLIf',
'KDsFj': function (_0x211f3c, _0x10fb3d) {
return _0x211f3c === _0x10fb3d;
},
'rLwGW': "BKPzM",
'ePJAJ': 'ATCVo',
'WxyNi': "lshQE",
'lqoLD': "[CursorPro] 获取进程路径失败:",
'oVgdC': "Cursor",
'USGWH': "ps aux | grep -i \"[C]ursor\" | head -1 | awk '{print $11}'",
'gDuYC': "ps aux | grep -i \"[c]ursor\" | head -1 | awk '{print $11}'",
'bwLpU': "TJpGd",
'sWGNb': '.config',
'KbfNq': "rnnax",
'dALzw': '未检测到运行中的Cursor进程',
'mOngd': "未检测",
'GdGfE': function (_0x3b944e, _0x2c32f1) {
return _0x3b944e !== _0x2c32f1;
},
'vdFYP': "app",
'UmBJK': 'out',
'NSGgG': 'workbench',
'dEWjF': "workbench.desktop.main.js",
'AVeQH': "RgvPD",
'lEdrt': "Contents",
'mlBaX': "fFSTL",
'xjVUo': "resources",
'NFQWc': "LwcoD",
'IvxYw': "bwKxQ",
'UFtEi': "未找到",
'lWQvv': function (_0x273ac0, _0x5f39b) {
return _0x273ac0 !== _0x5f39b;
},
'EYQCn': "EvRNl",
'MiEkS': "cursorPath",
'HiXkV': function (_0xd0ebf9, _0x4cfcad) {
return _0xd0ebf9 || _0x4cfcad;
},
'hlIYy': 'ZzJmG',
'GONGu': '获取失败'
};
try {
const _0x2f8924 = process.platform;
let _0x46d162 = '';
let _0x3fe4eb = '';
if (_0x38acb3["tbZpe"](_0x2f8924, _0x38acb3.TFAWN)) {
try {
const {
stdout: _0x19a5fc
} = await _0x38acb3["VsfTO"](execAsync, _0x38acb3["LurDi"]);
const _0x1f42c2 = _0x19a5fc["match"](/ExecutablePath=(.+)/);
if (_0x1f42c2 && _0x1f42c2[0x1]) {
const _0x4dbd9f = _0x1f42c2[0x1]["trim"]();
_0x46d162 = path.dirname(_0x4dbd9f);
}
} catch (_0x1aba5f) {
if (_0x38acb3["VtoJO"] !== "hKLIf") {
if (_0x38acb3["tbZpe"](_0x763182["code"], _0x38acb3["pcUwb"]) || _0x38acb3["tbZpe"](_0x1d6dfe["code"], "EACCES")) {
const _0x5910ed = _0x38acb3["WPzlq"];
this["_postMessage"]({
'type': _0x38acb3["drojl"],
'success': false,
'error': _0x5910ed,
'needAdmin': true
});
return;
}
throw _0x25718f;
} else {
try {
if (_0x38acb3["KDsFj"](_0x38acb3["rLwGW"], _0x38acb3["rLwGW"])) {
const {
stdout: _0x54d048
} = await execAsync('powershell -Command "Get-Process Cursor -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Path"');
if (_0x54d048["trim"]()) {
if (_0x38acb3["ePJAJ"] !== _0x38acb3.WxyNi) {
_0x46d162 = path["dirname"](_0x54d048["trim"]());
} else {
this._postMessage({
'type': _0x38acb3["fTNeN"],
'success': false,
'error': '连接服务器失败'
});
}
}
} else {
_0x4bf468 = _0x1e8026["substring"](0x0, _0x40d01d) + _0x57a9ae["substring"](_0x17b950 + this.HOSTS_MARKER_END["length"]);
}
} catch (_0x215316) {
console.warn(_0x38acb3["lqoLD"], _0x215316);
}
}
}
const _0x268111 = process["env"]["APPDATA"] || '';
_0x3fe4eb = path["join"](_0x268111, _0x38acb3.oVgdC);
} else {
if (_0x2f8924 === "darwin") {
try {
const {
stdout: _0x4f065d
} = await _0x38acb3["VsfTO"](execAsync, _0x38acb3["USGWH"]);
if (_0x4f065d.trim()) {
const _0x5ebf8f = _0x4f065d["trim"]();
const _0x228acb = _0x5ebf8f.match(/(.+\.app)/);
if (_0x228acb) {
_0x46d162 = _0x228acb[0x1];
} else {
_0x46d162 = path.dirname(_0x5ebf8f);
}
}
} catch (_0x2b309c) {
console["warn"]("[CursorPro] 获取进程路径失败:", _0x2b309c);
}
const _0x6ea467 = process["env"].HOME || '';
_0x3fe4eb = path.join(_0x6ea467, 'Library', "Application Support", _0x38acb3.oVgdC);
} else {
try {
const {
stdout: _0x522bb9
} = await execAsync(_0x38acb3["gDuYC"]);
if (_0x522bb9["trim"]()) {
if (_0x38acb3["tbZpe"](_0x38acb3["bwLpU"], _0x38acb3["bwLpU"])) {
_0x46d162 = path.dirname(_0x522bb9["trim"]());
} else {
_0x3596e8 = _0x38acb3["TbbUg"];
}
}
} catch (_0x22983f) {
console["warn"](_0x38acb3["lqoLD"], _0x22983f);
}
const _0x456726 = process["env"].HOME || '';
_0x3fe4eb = path["join"](_0x456726, _0x38acb3["sWGNb"], _0x38acb3["oVgdC"]);
}
}
if (!_0x46d162) {
if ("dWdoR" === _0x38acb3["KbfNq"]) {
this["_postMessage"]({
'type': _0x38acb3["NwHIv"],
'success': false,
'error': _0x38acb3.jmXuW
});
return;
} else {
_0x46d162 = _0x38acb3["dALzw"];
}
}
let _0x121b7c = '';
if (_0x46d162 && !_0x46d162.includes(_0x38acb3["mOngd"])) {
if (_0x2f8924 === _0x38acb3["TFAWN"]) {
if (_0x38acb3["GdGfE"]('lPhmJ', "lPhmJ")) {
_0x1588d9["telemetry.devDeviceId"] = _0x11e099["devDeviceId"];
} else {
_0x121b7c = path["join"](_0x46d162, 'resources', _0x38acb3.vdFYP, 'out', 'vs', 'workbench', _0x38acb3["dEWjF"]);
}
} else {
if (_0x2f8924 === "darwin") {
if (_0x38acb3["KDsFj"]("RgvPD", _0x38acb3.AVeQH)) {
_0x121b7c = path["join"](_0x46d162, _0x38acb3.lEdrt, "Resources", _0x38acb3.vdFYP, _0x38acb3["UmBJK"], 'vs', _0x38acb3["NSGgG"], 'workbench.desktop.main.js');
} else {
_0x37d2a5["writeFileSync"](_0x3c282c, _0x4bc83c, 'utf-8');
_0x3e6238 = true;
}
} else {
if ("PYNDj" === _0x38acb3["mlBaX"]) {
this["_postMessage"]({
'type': "seamlessInjected",
'success': false,
'error': _0x38acb3["bpeCI"]
});
return;
} else {
_0x121b7c = path["join"](_0x46d162, _0x38acb3["xjVUo"], _0x38acb3["vdFYP"], _0x38acb3["UmBJK"], 'vs', "workbench", _0x38acb3["dEWjF"]);
}
}
}
if (!fs["existsSync"](_0x121b7c)) {
if (_0x38acb3["NFQWc"] !== _0x38acb3["IvxYw"]) {
_0x121b7c = (await this["_getWorkbenchPathAsync"]()) || _0x38acb3["UFtEi"];
} else {
const _0x984d92 = _0x84f583["match"](/InstallLocation\s+REG_SZ\s+(.+)/);
if (_0x984d92 && _0x984d92[0x1] && _0x529792["existsSync"](_0x984d92[0x1]["trim"]())) {
_0x36e7db = _0x984d92[0x1]["trim"]();
}
}
}
} else {
if (_0x38acb3["lWQvv"](_0x38acb3["EYQCn"], "npeOU")) {
_0x121b7c = (await this["_getWorkbenchPathAsync"]()) || "未找到";
} else {
return;
}
}
const _0xbd859c = _0x46d162 && !_0x46d162["includes"](_0x38acb3["mOngd"]) ? fs.existsSync(_0x46d162) : false;
const _0x354cf1 = _0x3fe4eb ? fs["existsSync"](_0x3fe4eb) : false;
this["_postMessage"]({
'type': _0x38acb3["MiEkS"],
'cursorPath': _0xbd859c ? _0x46d162 : _0x38acb3["HiXkV"](_0x46d162, "未找到"),
'dataPath': _0x354cf1 ? _0x3fe4eb : _0x38acb3["UFtEi"],
'workbenchPath': _0x121b7c,
'platform': _0x2f8924
});
} catch (_0x5c0ff6) {
if (_0x38acb3["GdGfE"](_0x38acb3["hlIYy"], "GnlEK")) {
this["_postMessage"]({
'type': _0x38acb3.MiEkS,
'cursorPath': _0x38acb3["GONGu"],
'dataPath': '获取失败',
'workbenchPath': _0x38acb3["GONGu"],
'error': _0x5c0ff6["message"]
});
} else {
this["_view"]?..webview["postMessage"](_0x1b6a0f);
}
}
}
async ._loadAccountsFromDB() {
const _0xefdab9 = {
'oRodx': "[CursorPro] 找到 Cursor 版本:",
'pvPNp': "路径:",
'wjbSZ': "cursorAuth/accessToken",
'YZqNp': "cursorAuth/refreshToken",
'dbFLV': "cursorAuth/cachedEmail",
'zHYNu': function (_0x3aff44, _0x103caf) {
return _0x3aff44 && _0x103caf;
},
'rTrKG': function (_0x26321b, _0x5690c1) {
return _0x26321b || _0x5690c1;
}
};
try {
0x0;
const _0x3d6d98 = account_1["getCursorPaths"]();
const {
dbPath: _0x22a865
} = _0x3d6d98;
if (!fs["existsSync"](_0x22a865)) {
return 'OIoiO' === "YEFIo" ? (_0x4484c3.log(_0xefdab9["oRodx"], _0xa4ee3f["version"], _0xefdab9["pvPNp"], _0x4c184d), _0x4e0899["version"]) : [];
}
0x0;
const _0x483399 = await sqlite_1.sqliteGet(_0x22a865, _0xefdab9["wjbSZ"]);
0x0;
const _0x207002 = await sqlite_1["sqliteGet"](_0x22a865, _0xefdab9["YZqNp"]);
0x0;
const _0x1c5151 = await sqlite_1["sqliteGet"](_0x22a865, _0xefdab9["dbFLV"]);
if (_0xefdab9["zHYNu"](_0x483399, _0x1c5151)) {
return [{
'email': _0x1c5151,
'access_token': _0x483399,
'refresh_token': _0xefdab9["rTrKG"](_0x207002, _0x483399)
}];
}
return [];
} catch (_0x7a83d1) {
console.error("[CursorPro] 读取账号失败:", _0x7a83d1);
return [];
}
}
async ["_sendState"]() {
const _0xd6358c = {
'vIjoy': 'cursorpro.expireDate',
'PnvAx': 'cursorpro.switchRemaining',
'WEZcg': "cursorpro.switchLimit",
'MBSJn': "state",
'CNAgf': function (_0x34bf6b, _0x520b84) {
return _0x34bf6b || _0x520b84;
},
'dNuxR': function (_0x289948, _0x9f1b8e) {
return _0x289948 || _0x9f1b8e;
},
'tZHta': function (_0x216c5e, _0x1ac055) {
return _0x216c5e ?? _0x1ac055;
}
};
const _0x32793c = this["_context"]["globalState"]["get"]("cursorpro.key");
const _0x59a0ae = this["_context"].globalState["get"]('cursorpro.expireDate');
const _0x769674 = this["_context"]["globalState"]["get"](_0xd6358c["PnvAx"]);
const _0x340d3f = this["_context"]["globalState"]["get"](_0xd6358c["WEZcg"]);
const _0x440ba5 = await this["_getCursorVersion"]();
0x0;
const _0x5026a1 = client_1["getOnlineStatus"]();
this["_postMessage"]({
'type': _0xd6358c["MBSJn"],
'isActivated': !!_0x32793c,
'key': _0xd6358c["CNAgf"](_0x32793c, ''),
'expireDate': _0xd6358c["dNuxR"](_0x59a0ae, ''),
'switchRemaining': _0x769674 ?? 0x0,
'switchLimit': _0xd6358c["tZHta"](_0x340d3f, 0x64),
'cursorVersion': _0x440ba5,
'isOnline': _0x5026a1
});
}
async ["_handleRetryConnect"]() {
const _0x229eab = {
'rRAOR': function (_0x37df60, _0x561596) {
return _0x37df60 < _0x561596;
},
'dLQJl': function (_0x4e9578, _0x5e18f6) {
return _0x4e9578 < _0x5e18f6;
},
'vBOsW': 'cursorpro.key',
'NhGlq': function (_0x10685c, _0x39a256) {
return _0x10685c === _0x39a256;
},
'uUjDH': "NZAQL",
'PglaH': function (_0x2bd5d8, _0x594963) {
return _0x2bd5d8 !== _0x594963;
},
'zwtrx': "ANSiR",
'vNOCd': "PPUYG",
'vKktT': function (_0x1fc5b2, _0x4589aa, _0x33e731) {
return _0x1fc5b2(_0x4589aa, _0x33e731);
},
'ZQDbk': "networkStatus",
'FbRju': "[CursorPro] Retry connect failed:"
};
try {
const _0x38b05a = this["_context"]["globalState"]["get"](_0x229eab["vBOsW"]);
if (_0x38b05a) {
if (_0x229eab["NhGlq"](_0x229eab["uUjDH"], _0x229eab["uUjDH"])) {
0x0;
await client_1.verifyKey(_0x38b05a);
} else {
const _0x32a796 = _0x54cc32.split('.')["map"](_0x4b9729);
const _0x2142ee = _0x996c39["split"]('.')["map"](_0x1e92ec);
const _0xa1e4e2 = _0x523189["max"](_0x32a796["length"], _0x2142ee["length"]);
for (let _0x509f14 = 0x0; _0x229eab["rRAOR"](_0x509f14, _0xa1e4e2); _0x509f14++) {
const _0x563ae1 = _0x32a796[_0x509f14] || 0x0;
const _0x3a3596 = _0x2142ee[_0x509f14] || 0x0;
if (_0x563ae1 > _0x3a3596) {
return 0x1;
}
if (_0x229eab["dLQJl"](_0x563ae1, _0x3a3596)) {
return -0x1;
}
}
return 0x0;
}
} else {
if (_0x229eab["PglaH"](_0x229eab.zwtrx, _0x229eab["vNOCd"])) {
0x0;
const _0x4f7f5e = client_1["getApiUrl"]() + '/api/announcements/latest';
await _0x229eab["vKktT"](fetch, _0x4f7f5e, {
'method': 'GET'
});
} else {
_0x1df13e = _0x281b54[0x1].trim();
}
}
await this["_sendState"]();
this._postMessage({
'type': _0x229eab.ZQDbk,
'online': true
});
} catch (_0x46319e) {
console["error"](_0x229eab["FbRju"], _0x46319e);
this["_postMessage"]({
'type': "networkStatus",
'online': false
});
}
}
async ["_getCursorVersion"]() {
const _0x4f58a2 = {
'PTNWv': "[CursorPro] 首次启用,从备份恢复干净的 workbench 文件",
'wswmm': "[CursorPro] 备份恢复成功",
'QtJiM': "[CursorPro] 备份恢复失败:",
'Xqkdy': "cursorPath",
'ItKog': "获取失败",
'YSmFZ': function (_0x4ecad8, _0x2cb4f2) {
return _0x4ecad8 !== _0x2cb4f2;
},
'bglvq': 'LtYMm',
'YXUju': "FXgaA",
'vhvSM': function (_0xf9bd4a, _0x1405ae) {
return _0xf9bd4a === _0x1405ae;
},
'bBFPC': "Contents",
'gBPlE': "Resources",
'bUMcY': 'app',
'CaEkI': "package.json",
'CfoeP': "Programs",
'pwRyy': "Cursor",
'TosHP': "resources",
'LPmpS': "cursor",
'RYOAX': "AppData",
'qCStx': "Local",
'DEXlW': "darwin",
'VNwrn': '/Applications/Cursor.app/Contents/Resources/app/package.json',
'fjFtX': "/usr/share/cursor/resources/app/package.json",
'jHXyq': "/opt/Cursor/resources/app/package.json",
'WWWWp': ".local",
'dUUUB': "olTfK",
'JVRzx': 'gPJxP',
'uGyrr': "dqmkC",
'RwEEN': "utf-8",
'PKTCU': "Eoizq",
'CRnub': "YcIFS",
'ZQMXp': "路径:",
'dEEFY': "[CursorPro] 尝试路径失败:",
'opjtq': function (_0xd9c47c, _0x4fb652) {
return _0xd9c47c(_0x4fb652);
},
'zEiiQ': "vscode",
'GjUNd': "[CursorPro] 使用 VS Code API 获取版本:",
'qlNII': "[CursorPro] 未找到 Cursor 版本,尝试的路径:",
'GOgfB': "[CursorPro] 获取 Cursor 版本失败:"
};
try {
const _0x574db7 = process["platform"];
const _0x369839 = [];
const _0x4065be = await this._getCursorInstallPath();
if (_0x4065be) {
if (_0x4f58a2["YSmFZ"](_0x4f58a2["bglvq"], _0x4f58a2.YXUju)) {
if (_0x4f58a2["vhvSM"](_0x574db7, "darwin")) {
_0x369839["push"](path.join(_0x4065be, _0x4f58a2.bBFPC, _0x4f58a2["gBPlE"], _0x4f58a2["bUMcY"], 'package.json'));
} else {
_0x369839["push"](path["join"](_0x4065be, "resources", 'app', _0x4f58a2.CaEkI));
}
} else {
_0x219157["rmSync"](_0x1a5f35, {
'recursive': true,
'force': true
});
}
}
if (_0x4f58a2["vhvSM"](_0x574db7, "win32")) {
const _0x2ff2ee = process["env"].LOCALAPPDATA || '';
const _0x55e816 = process["env"]["USERPROFILE"] || '';
const _0x1f7bd3 = process["env"].ProgramFiles || "C:\\Program Files";
const _0x1defa4 = process["env"]['ProgramFiles(x86)'] || "C:\\Program Files (x86)";
_0x369839["push"](path["join"](_0x2ff2ee, _0x4f58a2["CfoeP"], _0x4f58a2["pwRyy"], _0x4f58a2.TosHP, "app", "package.json"), path["join"](_0x2ff2ee, _0x4f58a2.CfoeP, _0x4f58a2["LPmpS"], _0x4f58a2.TosHP, 'app', _0x4f58a2.CaEkI), path["join"](_0x55e816, _0x4f58a2["RYOAX"], _0x4f58a2["qCStx"], _0x4f58a2["CfoeP"], _0x4f58a2["pwRyy"], _0x4f58a2["TosHP"], _0x4f58a2["bUMcY"], _0x4f58a2["CaEkI"]), path["join"](_0x1f7bd3, _0x4f58a2.pwRyy, _0x4f58a2.TosHP, 'app', "package.json"), path["join"](_0x1f7bd3, _0x4f58a2["LPmpS"], "resources", _0x4f58a2["bUMcY"], _0x4f58a2["CaEkI"]), path["join"](_0x1defa4, "Cursor", _0x4f58a2.TosHP, _0x4f58a2["bUMcY"], _0x4f58a2["CaEkI"]));
} else {
if (_0x574db7 === _0x4f58a2["DEXlW"]) {
_0x369839.push(_0x4f58a2["VNwrn"]);
} else {
const _0x221758 = process.env.HOME || '';
_0x369839["push"](_0x4f58a2["fjFtX"], _0x4f58a2["jHXyq"], "/opt/cursor/resources/app/package.json", path["join"](_0x221758, _0x4f58a2.WWWWp, 'share', "cursor", _0x4f58a2["TosHP"], 'app', _0x4f58a2.CaEkI));
}
}
for (const _0x339dc7 of _0x369839) {
if (_0x4f58a2["YSmFZ"]("olTfK", _0x4f58a2["dUUUB"])) {
return;
} else {
try {
if (_0x4f58a2["JVRzx"] !== "eTsxR") {
if (fs.existsSync(_0x339dc7)) {
if (_0x4f58a2["YSmFZ"](_0x4f58a2["uGyrr"], _0x4f58a2.uGyrr)) {
_0x14c38f["log"](_0x4f58a2.PTNWv);
try {
_0x4ace07["copyFileSync"](_0x1facd8, _0xbb494e);
_0x2425e0["log"](_0x4f58a2["wswmm"]);
} catch (_0x5ee7d8) {
_0x18ad92["error"](_0x4f58a2["QtJiM"], _0x5ee7d8);
}
} else {
const _0x3621b8 = fs["readFileSync"](_0x339dc7, _0x4f58a2["RwEEN"]);
const _0x1f565f = JSON["parse"](_0x3621b8);
if (_0x1f565f["version"]) {
if (_0x4f58a2["YSmFZ"](_0x4f58a2["PKTCU"], _0x4f58a2["CRnub"])) {
console["log"]("[CursorPro] 找到 Cursor 版本:", _0x1f565f["version"], _0x4f58a2["ZQMXp"], _0x339dc7);
return _0x1f565f["version"];
} else {
this["_postMessage"]({
'type': _0x4f58a2["Xqkdy"],
'cursorPath': "获取失败",
'dataPath': _0x4f58a2["ItKog"],
'workbenchPath': _0x4f58a2["ItKog"],
'error': _0x130c99["message"]
});
}
}
}
}
} else if (_0x1bada8.statSync(_0x1e9bf4)["isDirectory"]()) {
_0x56260a["rmSync"](_0x74e730, {
'recursive': true,
'force': true
});
} else {
_0x309108["unlinkSync"](_0x19d74d);
}
} catch (_0x2af808) {
console["log"](_0x4f58a2["dEEFY"], _0x339dc7, _0x2af808);
}
}
}
try {
const _0xe1f1d3 = _0x4f58a2["opjtq"](require, _0x4f58a2["zEiiQ"]);
if (_0xe1f1d3.version) {
console["log"]("[CursorPro] 使用 VS Code API 获取版本:", _0xe1f1d3["version"]);
return _0xe1f1d3.version;
}
} catch (_0x35ddef) {}
console["log"](_0x4f58a2["qlNII"], _0x369839);
return '未知';
} catch (_0x311666) {
console.error(_0x4f58a2["GOgfB"], _0x311666);
return '未知';
}
}
._postMessage(_0x571950) {
this["_view"]?.["webview"]["postMessage"](_0x571950);
}
["_getNonce"]() {
const _0x323fa5 = {
'YiwNs': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
'FVmpm': function (_0x262e06, _0x566f52) {
return _0x262e06 < _0x566f52;
},
'XVmEg': function (_0x892c66, _0x1cd020) {
return _0x892c66 === _0x1cd020;
},
'gFjzo': 'UMZcN',
'RjXnp': function (_0xd635ba, _0x484045) {
return _0xd635ba * _0x484045;
}
};
let _0x14dd44 = '';
const _0x44199d = _0x323fa5["YiwNs"];
for (let _0x5ece7c = 0x0; _0x323fa5["FVmpm"](_0x5ece7c, 0x20); _0x5ece7c++) {
if (_0x323fa5["XVmEg"](_0x323fa5["gFjzo"], "UMZcN")) {
_0x14dd44 += _0x44199d["charAt"](Math["floor"](Math["random"]() * _0x44199d["length"]));
} else if (_0x56e4a8["existsSync"](_0x2ed688)) {
_0x2ab3fb["rmSync"](_0x258880, {
'recursive': true,
'force': true
});
_0x3de72a++;
_0x1d3455["log"]("[CursorPro] 已清理: " + _0x202472);
}
}
return _0x14dd44;
}
["_getHtmlContent"](_0x504c5f) {
const _0x1d6267 = this["_getNonce"]();
return "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-" + _0x1d6267 + "'; img-src " + _0x504c5f["cspSource"] + " https: data:; font-src " + _0x504c5f["cspSource"] + "; worker-src 'none';\">\n <title>CursorPro</title>\n <script nonce=\"" + _0x1d6267 + "\">\n // 尽早清理 Service Worker在 head 中执行,比 body 更早)\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.getRegistrations().then(function(regs) {\n regs.forEach(function(reg) { reg.unregister(); });\n }).catch(function() {});\n }\n </script>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n background: #1e1e1e;\n color: #cccccc;\n padding: 12px;\n font-size: 13px;\n }\n \n .section {\n margin-bottom: 16px;\n padding: 12px;\n background: #252526;\n border-radius: 6px;\n }\n \n .section-title {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n font-size: 13px;\n color: #ffffff;\n }\n \n .section-title .icon {\n font-size: 16px;\n }\n \n .status-badge {\n margin-left: auto;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 11px;\n }\n \n .status-badge.inactive {\n background: #6e3232;\n color: #ff6b6b;\n }\n \n .status-badge.active {\n background: #2d4a3e;\n color: #4ade80;\n }\n \n .input-group {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n }\n \n input[type=\"text\"] {\n flex: 1;\n padding: 8px 12px;\n background: #3c3c3c;\n border: 1px solid #4a4a4a;\n border-radius: 4px;\n color: #ffffff;\n font-size: 13px;\n }\n \n input[type=\"text\"]::placeholder {\n color: #888888;\n }\n \n input[type=\"text\"]:focus {\n outline: none;\n border-color: #007acc;\n }\n \n .btn {\n padding: 8px 16px;\n border: none;\n border-radius: 4px;\n font-size: 13px;\n cursor: pointer;\n font-weight: 500;\n transition: opacity 0.2s;\n }\n \n .btn:hover {\n opacity: 0.9;\n }\n \n .btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n \n .btn-primary {\n background: #007acc;\n color: white;\n }\n \n .btn-purple {\n background: #8b5cf6;\n color: white;\n }\n \n .btn-blue {\n background: #3b82f6;\n color: white;\n }\n \n .btn-red {\n background: #ef4444;\n color: white;\n }\n \n .btn-block {\n display: block;\n width: 100%;\n margin-bottom: 8px;\n }\n \n .info-row {\n display: flex;\n justify-content: space-between;\n padding: 6px 0;\n border-bottom: 1px solid #3c3c3c;\n }\n \n .info-row:last-child {\n border-bottom: none;\n }\n \n .info-label {\n color: #888888;\n }\n \n .info-value {\n color: #ffffff;\n }\n \n .usage-row {\n display: flex;\n gap: 12px;\n margin-bottom: 8px;\n }\n \n .usage-row:last-of-type {\n margin-bottom: 0;\n }\n \n .usage-item {\n flex: 1;\n display: flex;\n justify-content: space-between;\n padding: 6px 10px;\n background: #2d2d2d;\n border-radius: 4px;\n }\n \n .switch-container {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n \n .switch {\n position: relative;\n width: 40px;\n height: 20px;\n }\n \n .switch input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n \n .slider {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #4a4a4a;\n border-radius: 20px;\n transition: 0.3s;\n }\n \n .slider:before {\n position: absolute;\n content: \"\";\n height: 16px;\n width: 16px;\n left: 2px;\n bottom: 2px;\n background-color: white;\n border-radius: 50%;\n transition: 0.3s;\n }\n \n input:checked + .slider {\n background-color: #8b5cf6;\n }\n \n input:checked + .slider:before {\n transform: translateX(20px);\n }\n \n /* 小尺寸开关样式 */\n .switch-sm {\n position: relative;\n width: 32px;\n height: 16px;\n }\n \n .switch-sm .slider:before {\n height: 12px;\n width: 12px;\n left: 2px;\n bottom: 2px;\n }\n \n .switch-sm input:checked + .slider:before {\n transform: translateX(16px);\n }\n \n .pro-badge {\n background: linear-gradient(90deg, #8b5cf6, #d946ef);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n font-weight: bold;\n color: white;\n }\n \n .footer {\n margin-top: 16px;\n padding: 12px;\n background: linear-gradient(135deg, rgba(60, 60, 60, 0.3) 0%, rgba(40, 40, 40, 0.5) 100%);\n border-radius: 8px;\n border: 1px solid rgba(255, 255, 255, 0.05);\n }\n \n .footer-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n .auto-start {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11px;\n color: #888;\n }\n \n .cursor-version {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: #666;\n padding: 4px 10px;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 12px;\n }\n \n .cursor-version .version-num {\n color: #a78bfa;\n font-weight: 500;\n }\n \n /* 自定义弹窗样式 */\n .modal-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(4px);\n z-index: 1000;\n justify-content: center;\n align-items: center;\n animation: fadeIn 0.2s ease;\n }\n \n @keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes slideIn {\n from { \n opacity: 0;\n transform: scale(0.9) translateY(-10px);\n }\n to { \n opacity: 1;\n transform: scale(1) translateY(0);\n }\n }\n \n .modal-overlay.show {\n display: flex;\n }\n \n .modal-content {\n background: linear-gradient(145deg, #1e1e1e 0%, #2a2a2a 100%);\n border-radius: 12px;\n padding: 16px 20px;\n max-width: 260px;\n width: 90%;\n text-align: center;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.05);\n animation: slideIn 0.2s ease;\n }\n \n .modal-icon {\n width: 44px;\n height: 44px;\n margin: 0 auto 12px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n }\n \n .modal-icon.warning {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);\n }\n \n .modal-icon.success {\n background: linear-gradient(135deg, #10b981 0%, #059669 100%);\n box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);\n }\n \n .modal-title {\n font-size: 15px;\n font-weight: 600;\n color: #fff;\n margin-bottom: 6px;\n }\n \n .modal-message {\n font-size: 12px;\n color: #9ca3af;\n margin-bottom: 16px;\n line-height: 1.5;\n }\n \n .modal-buttons {\n display: flex;\n gap: 8px;\n justify-content: center;\n }\n \n .modal-btn {\n padding: 8px 16px;\n border: none;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n \n .modal-btn.primary {\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(139, 92, 246, 0.4);\n }\n \n .modal-btn.primary:hover {\n box-shadow: 0 4px 12px rgba(139, 92, 246, 0.5);\n }\n \n .modal-btn.secondary {\n background: rgba(255, 255, 255, 0.08);\n color: #9ca3af;\n border: 1px solid rgba(255, 255, 255, 0.1);\n }\n \n .modal-btn.secondary:hover {\n background: rgba(255, 255, 255, 0.12);\n color: #fff;\n }\n \n .modal-btn.single {\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n color: white;\n box-shadow: 0 2px 8px rgba(59, 130, 246, 0.4);\n min-width: 100px;\n }\n \n .modal-btn.single:hover {\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.5);\n }\n \n .highlight {\n color: #4ade80;\n font-weight: 600;\n }\n \n .key-display {\n cursor: pointer;\n transition: color 0.2s;\n }\n \n .key-display:hover {\n color: #007acc;\n }\n \n .key-display.copied {\n color: #4ade80 !important;\n }\n \n /* Loading 状态样式 */\n .btn.loading {\n position: relative;\n pointer-events: none;\n opacity: 0.7;\n }\n \n .btn.loading .btn-text {\n visibility: hidden;\n }\n \n .btn.loading::after {\n content: '';\n position: absolute;\n width: 16px;\n height: 16px;\n top: 50%;\n left: 50%;\n margin-left: -8px;\n margin-top: -8px;\n border: 2px solid transparent;\n border-top-color: #fff;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n \n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n \n .refresh-btn.loading {\n animation: spin 1s linear infinite;\n pointer-events: none;\n }\n \n /* 公告样式 */\n .announcement-badge {\n margin-left: auto;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 11px;\n text-transform: uppercase;\n }\n \n .announcement-badge.info {\n background: #1e3a5f;\n color: #60a5fa;\n }\n \n .announcement-badge.warning {\n background: #5c4a1f;\n color: #fbbf24;\n }\n \n .announcement-badge.error {\n background: #6e3232;\n color: #f87171;\n }\n \n .announcement-badge.success {\n background: #2d4a3e;\n color: #4ade80;\n }\n \n .announcement-title {\n font-size: 14px;\n font-weight: 600;\n color: #ffffff;\n margin-bottom: 8px;\n line-height: 1.4;\n }\n \n .announcement-content {\n font-size: 12px;\n color: #b0b0b0;\n line-height: 1.6;\n word-break: break-word;\n }\n \n .announcement-link {\n color: #60a5fa;\n text-decoration: none;\n border-bottom: 1px dashed #60a5fa;\n transition: all 0.2s;\n cursor: pointer;\n }\n \n .announcement-link:hover {\n color: #93c5fd;\n border-bottom-color: #93c5fd;\n }\n \n /* Toast 通知样式 */\n .toast-container {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n display: flex;\n justify-content: center;\n padding: 12px;\n pointer-events: none;\n z-index: 2000;\n }\n \n .toast {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n border: 1px solid rgba(74, 222, 128, 0.3);\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 20px rgba(74, 222, 128, 0.1);\n transform: translateY(-100px);\n opacity: 0;\n transition: all 0.3s ease;\n pointer-events: auto;\n }\n \n .toast.show {\n transform: translateY(0);\n opacity: 1;\n }\n \n .toast-icon {\n font-size: 16px;\n }\n \n .toast-message {\n font-size: 12px;\n color: #e0e0e0;\n max-width: 280px;\n word-break: break-all;\n }\n \n /* 离线状态提示样式 */\n .offline-banner {\n display: none;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n margin-bottom: 12px;\n background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%);\n border: 1px solid rgba(239, 68, 68, 0.3);\n border-radius: 8px;\n animation: slideDown 0.3s ease;\n }\n \n .offline-banner.show {\n display: flex;\n }\n \n @keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n \n .offline-banner .offline-icon {\n font-size: 18px;\n flex-shrink: 0;\n }\n \n .offline-banner .offline-text {\n flex: 1;\n }\n \n .offline-banner .offline-title {\n font-size: 12px;\n font-weight: 600;\n color: #fca5a5;\n margin-bottom: 2px;\n }\n \n .offline-banner .offline-desc {\n font-size: 11px;\n color: #fecaca;\n opacity: 0.8;\n }\n \n .offline-banner .retry-btn {\n padding: 4px 10px;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 4px;\n color: #fff;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s;\n flex-shrink: 0;\n }\n \n .offline-banner .retry-btn:hover {\n background: rgba(255, 255, 255, 0.25);\n }\n \n .offline-banner .retry-btn.loading {\n pointer-events: none;\n opacity: 0.7;\n }\n \n /* 顶部更新提醒条 */\n .update-banner {\n position: sticky;\n top: 0;\n left: 0;\n right: 0;\n background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);\n color: #fff;\n padding: 8px 12px;\n font-size: 12px;\n display: none;\n align-items: center;\n justify-content: center;\n gap: 8px;\n z-index: 1000;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n }\n .update-banner.show {\n display: flex;\n }\n .update-banner .update-icon {\n font-size: 14px;\n }\n .update-banner .update-text {\n font-weight: 500;\n }\n .update-banner .update-version {\n background: rgba(255,255,255,0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 11px;\n }\n .update-banner .update-close {\n margin-left: auto;\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n font-size: 16px;\n padding: 0 4px;\n opacity: 0.8;\n }\n .update-banner .update-close:hover {\n opacity: 1;\n }\n \n </style>\n</head>\n<body>\n <!-- 顶部更新提醒条 -->\n <div class=\"update-banner\" id=\"updateBanner\">\n <span class=\"update-icon\">🚀</span>\n <span class=\"update-text\">发现新版本</span>\n <span class=\"update-version\" id=\"updateBannerVersion\">v0.0</span>\n <button class=\"update-close\" id=\"updateBannerClose\" title=\"关闭\">×</button>\n </div>\n \n <!-- 管理员权限提示弹窗 -->\n <div class=\"modal-overlay\" id=\"adminModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">🔐</div>\n <div class=\"modal-title\">需要管理员权限</div>\n <div class=\"modal-message\">\n 请关闭 Cursor右键点击图标<br>\n 选择 <span class=\"highlight\">以管理员身份运行</span>\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn single\" id=\"adminModalClose\">我知道了</button>\n </div>\n </div>\n </div>\n \n <!-- 重置机器码权限提示弹窗 -->\n <div class=\"modal-overlay\" id=\"resetPermissionModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">🔐</div>\n <div class=\"modal-title\">需要管理员权限</div>\n <div class=\"modal-message\" style=\"text-align: left; line-height: 1.8;\">\n 重置机器码需要管理员权限才能完整执行。<br><br>\n 请按以下步骤操作:<br>\n <span style=\"color: #fbbf24;\">1.</span> 完全关闭 Cursor<br>\n <span style=\"color: #fbbf24;\">2.</span> 右键点击 Cursor 图标<br>\n <span style=\"color: #fbbf24;\">3.</span> 选择 <span class=\"highlight\">以管理员身份运行</span><br>\n <span style=\"color: #fbbf24;\">4.</span> 再次点击重置机器码\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn single\" id=\"resetPermissionClose\">我知道了</button>\n </div>\n </div>\n </div>\n \n <!-- 重启提示弹窗 -->\n <div class=\"modal-overlay\" id=\"restartModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon success\">✓</div>\n <div class=\"modal-title\" id=\"restartModalTitle\">操作成功</div>\n <div class=\"modal-message\">\n 需要重启 Cursor 才能生效\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn primary\" id=\"restartNowBtn\">立即重启</button>\n <button class=\"modal-btn secondary\" id=\"restartLaterBtn\">稍后</button>\n </div>\n </div>\n </div>\n \n <!-- 激活码过期弹窗 -->\n <div class=\"modal-overlay\" id=\"expiredModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon\" style=\"background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);\">⏰</div>\n <div class=\"modal-title\">激活码已过期</div>\n <div class=\"modal-message\">\n 您的激活码已过期,请续费后继续使用\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn single\" id=\"expiredModalClose\">我知道了</button>\n </div>\n </div>\n </div>\n \n <!-- 清理环境确认弹窗 -->\n <div class=\"modal-overlay\" id=\"cleanEnvModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">⚠️</div>\n <div class=\"modal-title\">清理 Cursor 环境</div>\n <div class=\"modal-message\">\n 此操作会删除所有配置和登录信息<br>确定要继续吗?\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn primary\" id=\"cleanEnvConfirmBtn\">确定清理</button>\n <button class=\"modal-btn secondary\" id=\"cleanEnvCancelBtn\">取消</button>\n </div>\n </div>\n </div>\n \n <!-- 换号确认弹窗 -->\n <div class=\"modal-overlay\" id=\"switchConfirmModal\">\n <div class=\"modal-content\">\n <div class=\"modal-icon warning\">💰</div>\n <div class=\"modal-title\">账号未使用完</div>\n <div class=\"modal-message\">\n 当前账号 <span id=\"switchConfirmEmail\" style=\"color:#4caf50;\"></span><br>\n 已用额度: <span id=\"switchConfirmCost\" style=\"color:#ff9800;font-weight:bold;\">$0.00</span> (不足 $10)<br><br>\n 确定要换号吗?\n </div>\n <div class=\"modal-buttons\">\n <button class=\"modal-btn primary\" id=\"switchConfirmBtn\">确认换号</button>\n <button class=\"modal-btn secondary\" id=\"switchCancelBtn\">取消</button>\n </div>\n </div>\n </div>\n \n <!-- 离线状态提示 -->\n <div class=\"offline-banner\" id=\"offlineBanner\">\n <span class=\"offline-icon\">📡</span>\n <div class=\"offline-text\">\n <div class=\"offline-title\">网络连接失败</div>\n <div class=\"offline-desc\">请检查网络后重试</div>\n </div>\n <button class=\"retry-btn\" id=\"retryConnectBtn\">重试</button>\n </div>\n \n <!-- 软件授权 -->\n <div class=\"section\">\n <div class=\"section-title\">\n <span class=\"icon\">🔐</span>\n <span>软件授权</span>\n <span class=\"status-badge\" id=\"authStatus\">未授权</span>\n </div>\n \n <div class=\"input-group\">\n <input type=\"text\" id=\"keyInput\" placeholder=\"请输入CDK激活码\">\n <button class=\"btn btn-primary\" id=\"activateBtn\"><span class=\"btn-text\">激活</span></button>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">激活码</span>\n <span class=\"info-value key-display\" id=\"keyDisplay\" title=\"点击复制\">尚未激活</span>\n </div>\n <div class=\"info-row\">\n <span class=\"info-label\">到期时间</span>\n <span class=\"info-value\" id=\"expireDate\">尚未激活</span>\n </div>\n </div>\n \n <!-- 账号数据 (已隐藏) -->\n <div class=\"section\" style=\"display:none;\">\n <div class=\"section-title\">\n <span class=\"icon\">👤</span>\n <span>账号数据</span>\n <span class=\"status-badge\" id=\"accountStatus\">未激活</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">CI积分余额</span>\n <span class=\"info-value\">0 <button style=\"background:none;border:none;color:#007acc;cursor:pointer;\">🔄</button></span>\n </div>\n \n <button class=\"btn btn-purple btn-block\" id=\"switchBtn\" disabled>换号</button>\n <button class=\"btn btn-blue btn-block\" id=\"resetBtn\">重置机器码</button>\n <button class=\"btn btn-blue btn-block\" id=\"disableUpdateBtn\">禁用自动更新</button>\n <button class=\"btn btn-blue btn-block\" id=\"cleanEnvBtn\">清理Cursor环境</button>\n <button class=\"btn btn-red btn-block\" id=\"disableBtn\">停用插件</button>\n </div>\n \n <!-- 无感换号 -->\n <div class=\"section\">\n <div class=\"section-title\">\n <span class=\"icon\">⚡</span>\n <span>无感换号</span>\n <span class=\"status-badge\" id=\"seamlessStatus\">未启用</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">积分</span>\n <span class=\"info-value\" id=\"seamlessSwitchRemaining\">0</span>\n </div>\n \n <div class=\"info-row\">\n <span class=\"info-label\">当前账号</span>\n <span class=\"info-value\" style=\"font-size:11px;\" id=\"seamlessCurrentAccount\">未分配</span>\n </div>\n \n <div class=\"switch-container\" style=\"margin: 12px 0;\">\n <span>免魔法模式</span>\n <span class=\"pro-badge\">PRO</span>\n <span style=\"margin-left: auto; color: #888; font-size: 11px;\"></span>\n <label class=\"switch\">\n <input type=\"checkbox\" id=\"seamlessProxySwitch\">\n <span class=\"slider\"></span>\n </label>\n </div>\n \n <button class=\"btn btn-purple btn-block\" id=\"enableSeamlessBtn\" disabled><span class=\"btn-text\">启用无感换号</span></button>\n <button class=\"btn btn-red btn-block\" id=\"seamlessResetMachineBtn\" style=\"display:none;\"><span class=\"btn-text\">重置机器码</span></button>\n <button class=\"btn btn-red btn-block\" id=\"disableSeamlessBtn\" style=\"display:none;\"><span class=\"btn-text\">禁用无感换号</span></button>\n <button class=\"btn btn-blue btn-block\" id=\"manualSwitchBtn\" style=\"display:none;\" disabled><span class=\"btn-text\">一键换号(扣1积分)</span></button>\n </div>\n \n <!-- 账号用量 -->\n <div class=\"section\" id=\"usageSection\" style=\"display:none;\">\n <div class=\"section-title\">\n <span class=\"icon\">📊</span>\n <span>账号用量</span>\n <button class=\"btn\" style=\"margin-left:auto;padding:4px 8px;font-size:11px;background:#3c3c3c;\" id=\"refreshUsageBtn\">🔄</button>\n </div>\n \n <div class=\"usage-row\">\n <div class=\"usage-item\">\n <span class=\"info-label\">会员类型</span>\n <span class=\"info-value\" id=\"usageMemberType\">-</span>\n </div>\n <div class=\"usage-item\">\n <span class=\"info-label\">试用剩余</span>\n <span class=\"info-value\" id=\"usageTrialDays\">-</span>\n </div>\n </div>\n <div class=\"usage-row\">\n <div class=\"usage-item\">\n <span class=\"info-label\">请求次数</span>\n <span class=\"info-value\" id=\"usageRequestCount\">-</span>\n </div>\n <div class=\"usage-item\">\n <span class=\"info-label\">已用额度</span>\n <span class=\"info-value\" id=\"usageCostUSD\">-</span>\n </div>\n </div>\n <p style=\"font-size:10px;color:#666;margin-top:8px;text-align:center;\" id=\"usageUpdateTime\">-</p>\n </div>\n \n <!-- 公告 -->\n <div class=\"section\" id=\"announcementSection\" style=\"display:none;\">\n <div class=\"section-title\">\n <span class=\"icon\" id=\"announcementIcon\">📢</span>\n <span>公告</span>\n <span class=\"announcement-badge\" id=\"announcementBadge\">info</span>\n </div>\n <div class=\"announcement-title\" id=\"announcementTitle\"></div>\n <div class=\"announcement-content\" id=\"announcementContent\"></div>\n <p style=\"font-size:10px;color:#666;margin-top:8px;text-align:right;\" id=\"announcementTime\"></p>\n </div>\n \n <!-- 版本信息 -->\n <div class=\"section\" id=\"versionSection\">\n <div class=\"section-title\">\n <span class=\"icon\">📦</span>\n <span>版本信息</span>\n <span class=\"status-badge\" id=\"versionStatus\" style=\"display:none;\">有更新</span>\n </div>\n <div class=\"info-row\">\n <span class=\"info-label\">当前版本</span>\n <span class=\"info-value\" id=\"currentVersion\">-</span>\n </div>\n <div class=\"info-row\" id=\"latestVersionRow\" style=\"display:none;\">\n <span class=\"info-label\">最新版本</span>\n <span class=\"info-value\" id=\"latestVersion\" style=\"color:#4caf50;\">-</span>\n </div>\n <p id=\"updateHint\" style=\"font-size:11px;color:#ff9800;margin-top:8px;display:none;\">\n ⚠️ 发现新版本,请更新插件以获取最新功能\n </p>\n </div>\n \n <!-- 页脚 -->\n <div class=\"footer\">\n <div class=\"footer-row\">\n <div class=\"auto-start\">\n <span>自动启动</span>\n <label class=\"switch switch-sm\">\n <input type=\"checkbox\" id=\"autoStartSwitch\" checked>\n <span class=\"slider\"></span>\n </label>\n </div>\n <div class=\"cursor-version\">\n <span>Cursor</span>\n <span class=\"version-num\" id=\"cursorVersion\">0.0.0</span>\n </div>\n </div>\n <div class=\"footer-row\" style=\"margin-top: 8px;\">\n <div style=\"font-size: 10px; color: #666; word-break: break-all;\">\n <span>路径: </span>\n <span id=\"cursorPath\" style=\"color: #888;\">获取中...</span>\n </div>\n </div>\n </div>\n \n <!-- Toast 通知 -->\n <div class=\"toast-container\" id=\"toastContainer\">\n <div class=\"toast\" id=\"toast\">\n <span class=\"toast-icon\" id=\"toastIcon\">✅</span>\n <span class=\"toast-message\" id=\"toastMessage\"></span>\n </div>\n </div>\n \n <script nonce=\"" + _0x1d6267 + "\">\n const vscode = acquireVsCodeApi();\n \n // 元素引用\n const keyInput = document.getElementById('keyInput');\n const activateBtn = document.getElementById('activateBtn');\n const switchBtn = document.getElementById('switchBtn');\n const resetBtn = document.getElementById('resetBtn');\n const disableUpdateBtn = document.getElementById('disableUpdateBtn');\n const cleanEnvBtn = document.getElementById('cleanEnvBtn');\n const disableBtn = document.getElementById('disableBtn');\n const authStatus = document.getElementById('authStatus');\n const accountStatus = document.getElementById('accountStatus');\n const keyDisplay = document.getElementById('keyDisplay');\n const switchCount = document.getElementById('switchCount');\n const expireDate = document.getElementById('expireDate');\n const cursorVersion = document.getElementById('cursorVersion');\n const cursorPath = document.getElementById('cursorPath');\n \n // 离线状态元素\n const offlineBanner = document.getElementById('offlineBanner');\n const retryConnectBtn = document.getElementById('retryConnectBtn');\n \n // 无感换号元素\n const seamlessStatus = document.getElementById('seamlessStatus');\n const seamlessProxySwitch = document.getElementById('seamlessProxySwitch');\n const enableSeamlessBtn = document.getElementById('enableSeamlessBtn');\n const disableSeamlessBtn = document.getElementById('disableSeamlessBtn');\n const manualSwitchBtn = document.getElementById('manualSwitchBtn');\n const seamlessResetMachineBtn = document.getElementById('seamlessResetMachineBtn');\n const seamlessSwitchRemaining = document.getElementById('seamlessSwitchRemaining');\n const seamlessCurrentAccount = document.getElementById('seamlessCurrentAccount');\n \n // 用量显示元素\n const usageSection = document.getElementById('usageSection');\n const refreshUsageBtn = document.getElementById('refreshUsageBtn');\n const usageMemberType = document.getElementById('usageMemberType');\n const usageTrialDays = document.getElementById('usageTrialDays');\n const usageRequestCount = document.getElementById('usageRequestCount');\n const usageCostUSD = document.getElementById('usageCostUSD');\n const usageUpdateTime = document.getElementById('usageUpdateTime');\n \n // 公告元素\n const announcementSection = document.getElementById('announcementSection');\n const announcementIcon = document.getElementById('announcementIcon');\n const announcementBadge = document.getElementById('announcementBadge');\n const announcementTitle = document.getElementById('announcementTitle');\n const announcementContent = document.getElementById('announcementContent');\n const announcementTime = document.getElementById('announcementTime');\n \n // 版本元素\n const versionSection = document.getElementById('versionSection');\n const versionStatus = document.getElementById('versionStatus');\n const currentVersionEl = document.getElementById('currentVersion');\n const latestVersionEl = document.getElementById('latestVersion');\n const latestVersionRow = document.getElementById('latestVersionRow');\n const updateHint = document.getElementById('updateHint');\n \n // 顶部更新提醒条\n const updateBanner = document.getElementById('updateBanner');\n const updateBannerVersion = document.getElementById('updateBannerVersion');\n const updateBannerClose = document.getElementById('updateBannerClose');\n \n // Toast 元素\n const toast = document.getElementById('toast');\n const toastIcon = document.getElementById('toastIcon');\n const toastMessage = document.getElementById('toastMessage');\n let toastTimer = null;\n \n // 显示 Toast 通知\n function showToast(message, icon = '✅', duration = 10000) {\n // 清除之前的定时器\n if (toastTimer) {\n clearTimeout(toastTimer);\n }\n \n toastIcon.textContent = icon;\n toastMessage.textContent = message;\n toast.classList.add('show');\n \n // 设置自动隐藏\n toastTimer = setTimeout(() => {\n toast.classList.remove('show');\n }, duration);\n }\n \n // 禁用换号按钮并显示倒计时\n let switchBtnCountdownTimer = null;\n const originalSwitchBtnText = '一键换号(扣1积分)';\n \n function disableSwitchBtnWithCountdown(seconds) {\n // 清除之前的定时器\n if (switchBtnCountdownTimer) {\n clearInterval(switchBtnCountdownTimer);\n }\n \n let remaining = seconds;\n manualSwitchBtn.disabled = true;\n manualSwitchBtn.querySelector('.btn-text').textContent = remaining + '秒后可用';\n \n switchBtnCountdownTimer = setInterval(() => {\n remaining--;\n if (remaining <= 0) {\n clearInterval(switchBtnCountdownTimer);\n switchBtnCountdownTimer = null;\n manualSwitchBtn.disabled = false;\n manualSwitchBtn.querySelector('.btn-text').textContent = originalSwitchBtnText;\n } else {\n manualSwitchBtn.querySelector('.btn-text').textContent = remaining + '秒后可用';\n }\n }, 1000);\n }\n \n // 弹窗元素\n const adminModal = document.getElementById('adminModal');\n const adminModalClose = document.getElementById('adminModalClose');\n const resetPermissionModal = document.getElementById('resetPermissionModal');\n const resetPermissionClose = document.getElementById('resetPermissionClose');\n const restartModal = document.getElementById('restartModal');\n const restartModalTitle = document.getElementById('restartModalTitle');\n const restartNowBtn = document.getElementById('restartNowBtn');\n const restartLaterBtn = document.getElementById('restartLaterBtn');\n const expiredModal = document.getElementById('expiredModal');\n const expiredModalClose = document.getElementById('expiredModalClose');\n const cleanEnvModal = document.getElementById('cleanEnvModal');\n const cleanEnvConfirmBtn = document.getElementById('cleanEnvConfirmBtn');\n const cleanEnvCancelBtn = document.getElementById('cleanEnvCancelBtn');\n \n // 换号确认弹窗元素\n const switchConfirmModal = document.getElementById('switchConfirmModal');\n const switchConfirmEmail = document.getElementById('switchConfirmEmail');\n const switchConfirmCost = document.getElementById('switchConfirmCost');\n const switchConfirmBtn = document.getElementById('switchConfirmBtn');\n const switchCancelBtn = document.getElementById('switchCancelBtn');\n \n // 显示管理员权限弹窗\n function showAdminModal() {\n adminModal.classList.add('show');\n }\n \n // 显示重置机器码权限提示弹窗\n function showAdminPermissionModal() {\n resetPermissionModal.classList.add('show');\n }\n \n // 重置机器码权限弹窗 - 关闭按钮\n resetPermissionClose.addEventListener('click', () => {\n resetPermissionModal.classList.remove('show');\n });\n \n // 点击遮罩关闭权限提示弹窗\n resetPermissionModal.addEventListener('click', (e) => {\n if (e.target === resetPermissionModal) {\n resetPermissionModal.classList.remove('show');\n }\n });\n \n // 显示重启提示弹窗\n let restartModalAction = 'reload'; // 'reload' 或 'close'\n \n function showRestartModal(title, action = 'reload') {\n restartModalTitle.textContent = title || '操作成功';\n restartModalAction = action;\n // 根据操作类型更新按钮文字\n restartNowBtn.textContent = action === 'close' ? '立即关闭 Cursor' : '立即重启';\n restartModal.classList.add('show');\n }\n \n // 显示过期弹窗\n function showExpiredModal() {\n expiredModal.classList.add('show');\n }\n \n // 关闭管理员弹窗\n adminModalClose.addEventListener('click', () => {\n adminModal.classList.remove('show');\n });\n \n // 点击遮罩关闭管理员弹窗\n adminModal.addEventListener('click', (e) => {\n if (e.target === adminModal) {\n adminModal.classList.remove('show');\n }\n });\n \n // 立即重启/关闭按钮\n restartNowBtn.addEventListener('click', () => {\n restartModal.classList.remove('show');\n if (restartModalAction === 'close') {\n // 完全关闭 Cursor\n vscode.postMessage({ type: 'closeCursor' });\n } else {\n // 重新加载窗口\n vscode.postMessage({ type: 'reloadWindow' });\n }\n });\n \n // 稍后手动按钮\n restartLaterBtn.addEventListener('click', () => {\n restartModal.classList.remove('show');\n });\n \n // 点击遮罩关闭重启弹窗\n restartModal.addEventListener('click', (e) => {\n if (e.target === restartModal) {\n restartModal.classList.remove('show');\n }\n });\n \n // 关闭过期弹窗\n expiredModalClose.addEventListener('click', () => {\n expiredModal.classList.remove('show');\n });\n \n // 点击遮罩关闭过期弹窗\n expiredModal.addEventListener('click', (e) => {\n if (e.target === expiredModal) {\n expiredModal.classList.remove('show');\n }\n });\n \n // 当前账号邮箱(用于查询用量)\n let currentAccountEmail = '';\n let usageRefreshInterval = null;\n // 存储完整激活码(用于复制)\n let fullActivationKey = '';\n // 当前剩余换号次数\n let currentSwitchRemaining = 0;\n // 当前到期时间\n let currentExpireDate = '';\n \n // 检查卡密是否已过期\n function isKeyExpired() {\n if (!currentExpireDate) return true;\n try {\n const expireTime = new Date(currentExpireDate).getTime();\n return Date.now() > expireTime;\n } catch {\n return true;\n }\n }\n \n // 格式化到期时间为北京时间\n function formatExpireDate(dateStr) {\n if (!dateStr) return '';\n try {\n // 后端返回的时间没有时区标识,假设是 UTC 时间\n // 将空格替换为T并添加Z表示UTC\n let utcStr = dateStr;\n if (!dateStr.includes('T') && !dateStr.includes('Z') && !dateStr.includes('+')) {\n utcStr = dateStr.replace(' ', 'T') + 'Z';\n }\n const date = new Date(utcStr);\n \n // 使用中国时区格式化UTC+8\n return date.toLocaleString('zh-CN', {\n timeZone: 'Asia/Shanghai',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n });\n } catch {\n return dateStr; // 格式化失败返回原始值\n }\n }\n \n // 隐藏激活码后几位\n function maskKey(key) {\n if (!key || key.length <= 8) return key;\n return key.substring(0, key.length - 4) + '****';\n }\n \n // 点击激活码复制\n keyDisplay.addEventListener('click', () => {\n if (!fullActivationKey) return;\n navigator.clipboard.writeText(fullActivationKey).then(() => {\n keyDisplay.classList.add('copied');\n const originalText = keyDisplay.textContent;\n keyDisplay.textContent = '已复制!';\n setTimeout(() => {\n keyDisplay.textContent = maskKey(fullActivationKey);\n keyDisplay.classList.remove('copied');\n }, 1000);\n }).catch(() => {\n // 降级方案\n const textarea = document.createElement('textarea');\n textarea.value = fullActivationKey;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n keyDisplay.classList.add('copied');\n keyDisplay.textContent = '已复制!';\n setTimeout(() => {\n keyDisplay.textContent = maskKey(fullActivationKey);\n keyDisplay.classList.remove('copied');\n }, 1000);\n });\n });\n \n // Loading 状态控制\n function setButtonLoading(btn, loading) {\n if (loading) {\n btn.classList.add('loading');\n btn.disabled = true;\n } else {\n btn.classList.remove('loading');\n // 注意:某些按钮可能需要保持禁用状态,由调用方控制\n }\n }\n \n function setRefreshLoading(btn, loading) {\n if (loading) {\n btn.classList.add('loading');\n } else {\n btn.classList.remove('loading');\n }\n }\n \n // 获取初始状态\n vscode.postMessage({ type: 'getState' });\n vscode.postMessage({ type: 'getSeamlessStatus' });\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n vscode.postMessage({ type: 'getProxyStatus' });\n vscode.postMessage({ type: 'getAnnouncement' });\n vscode.postMessage({ type: 'checkVersion' });\n vscode.postMessage({ type: 'getCursorRunningPath' });\n \n // 激活按钮\n activateBtn.addEventListener('click', () => {\n const key = keyInput.value.trim();\n if (!key) {\n return;\n }\n setButtonLoading(activateBtn, true);\n vscode.postMessage({ type: 'activate', key });\n });\n \n // 换号按钮\n switchBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'switch' });\n });\n \n // 重置机器码按钮\n resetBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'resetMachineId' });\n });\n \n // 禁用自动更新按钮\n disableUpdateBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'disableUpdate' });\n });\n \n // 清理Cursor环境按钮 - 显示确认弹窗\n cleanEnvBtn.addEventListener('click', () => {\n cleanEnvModal.classList.add('show');\n });\n \n // 确认清理\n cleanEnvConfirmBtn.addEventListener('click', () => {\n cleanEnvModal.classList.remove('show');\n vscode.postMessage({ type: 'cleanEnv' });\n });\n \n // 取消清理\n cleanEnvCancelBtn.addEventListener('click', () => {\n cleanEnvModal.classList.remove('show');\n });\n \n // 点击遮罩关闭清理弹窗\n cleanEnvModal.addEventListener('click', (e) => {\n if (e.target === cleanEnvModal) {\n cleanEnvModal.classList.remove('show');\n }\n });\n \n // 停用按钮\n disableBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'disable' });\n });\n \n // 关闭更新提醒条\n updateBannerClose.addEventListener('click', () => {\n updateBanner.classList.remove('show');\n });\n \n // 免魔法开关\n seamlessProxySwitch.addEventListener('change', (e) => {\n const wantEnabled = e.target.checked;\n \n // 如果要开启免魔法,检查卡密是否过期(只要没过期就可以用,不管换号次数)\n if (wantEnabled && isKeyExpired()) {\n e.target.checked = false;\n showToast('授权码已过期,无法开启免魔法', '⚠️', 3000);\n return;\n }\n \n vscode.postMessage({ \n type: 'toggleProxy', \n enabled: wantEnabled,\n url: ''\n });\n });\n \n // 无感换号 - 启用按钮\n enableSeamlessBtn.addEventListener('click', () => {\n setButtonLoading(enableSeamlessBtn, true);\n vscode.postMessage({ type: 'injectSeamless' });\n });\n \n // 无感换号 - 禁用按钮\n disableSeamlessBtn.addEventListener('click', () => {\n setButtonLoading(disableSeamlessBtn, true);\n vscode.postMessage({ type: 'restoreSeamless' });\n });\n \n // 无感换号 - 手动换号按钮(先检查用量)\n manualSwitchBtn.addEventListener('click', () => {\n setButtonLoading(manualSwitchBtn, true);\n // 传递当前显示的账号邮箱\n vscode.postMessage({ type: 'checkUsageBeforeSwitch', email: currentAccountEmail });\n });\n \n // 换号确认弹窗 - 确认按钮\n switchConfirmBtn.addEventListener('click', () => {\n switchConfirmModal.classList.remove('show');\n setButtonLoading(manualSwitchBtn, true);\n vscode.postMessage({ type: 'confirmSwitch' });\n });\n \n // 换号确认弹窗 - 取消按钮\n switchCancelBtn.addEventListener('click', () => {\n switchConfirmModal.classList.remove('show');\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n });\n \n // 换号确认弹窗 - 点击遮罩关闭\n switchConfirmModal.addEventListener('click', (e) => {\n if (e.target === switchConfirmModal) {\n switchConfirmModal.classList.remove('show');\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n }\n });\n \n // 无感换号区域 - 重置机器码按钮\n seamlessResetMachineBtn.addEventListener('click', () => {\n vscode.postMessage({ type: 'resetMachineId' });\n });\n \n // 刷新用量按钮\n refreshUsageBtn.addEventListener('click', () => {\n if (currentAccountEmail) {\n setRefreshLoading(refreshUsageBtn, true);\n vscode.postMessage({ type: 'getAccountUsage', email: currentAccountEmail });\n }\n });\n \n // 刷新用量函数\n function refreshUsage() {\n if (currentAccountEmail) {\n vscode.postMessage({ type: 'getAccountUsage', email: currentAccountEmail });\n }\n }\n \n // 启动用量定时刷新 (每分钟一次)\n function startUsageRefresh() {\n if (usageRefreshInterval) {\n clearInterval(usageRefreshInterval);\n }\n // 立即刷新一次\n refreshUsage();\n // 每60秒刷新一次\n usageRefreshInterval = setInterval(refreshUsage, 60000);\n }\n \n // 停止用量刷新\n function stopUsageRefresh() {\n if (usageRefreshInterval) {\n clearInterval(usageRefreshInterval);\n usageRefreshInterval = null;\n }\n }\n \n // 更新用量显示\n function updateUsageDisplay(data) {\n if (!data) return;\n \n const subscription = data.subscription || {};\n const usage = data.usage || {};\n \n // 会员类型\n const memberTypeMap = {\n 'free_trial': '免费试用',\n 'pro': 'Pro会员',\n 'free': '免费版',\n 'business': '商业版'\n };\n usageMemberType.textContent = memberTypeMap[subscription.membershipType] || subscription.membershipType || '-';\n \n // 试用剩余天数\n if (subscription.daysRemainingOnTrial !== undefined && subscription.daysRemainingOnTrial !== null) {\n usageTrialDays.textContent = subscription.daysRemainingOnTrial + ' 天';\n usageTrialDays.style.color = subscription.daysRemainingOnTrial <= 3 ? '#f87171' : '#4ade80';\n } else {\n usageTrialDays.textContent = '-';\n usageTrialDays.style.color = '#fff';\n }\n \n // 请求次数\n usageRequestCount.textContent = (usage.totalUsageCount || 0) + ' 次';\n \n // 已用额度\n const costUSD = usage.totalCostUSD || 0;\n usageCostUSD.textContent = '$' + costUSD.toFixed(2);\n usageCostUSD.style.color = costUSD > 5 ? '#f87171' : (costUSD > 2 ? '#fbbf24' : '#4ade80');\n \n // 更新时间\n usageUpdateTime.textContent = '更新于 ' + new Date().toLocaleTimeString();\n }\n \n // 解析公告内容中的链接 {文字URL}\n function parseAnnouncementContent(content) {\n if (!content) return '';\n \n // 转义 HTML 特殊字符\n let escaped = content\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n \n // 匹配 {文字https://...} 或 {文字http://...} 格式\n const linkRegex = /\\{([^}]+?)(https?:\\/\\/[^}]+)\\}/g;\n \n escaped = escaped.replace(linkRegex, function(match, text, url) {\n return '<a href=\"' + url + '\" class=\"announcement-link\" target=\"_blank\">' + text + '</a>';\n });\n \n // 将换行符转换为 <br>\n escaped = escaped.replace(/\\n/g, '<br>');\n \n return escaped;\n }\n \n // 更新公告显示\n function updateAnnouncementDisplay(data) {\n if (!data || !data.is_active) {\n announcementSection.style.display = 'none';\n return;\n }\n \n // 显示公告区域\n announcementSection.style.display = 'block';\n \n // 设置图标和类型徽章\n const typeConfig = {\n 'info': { icon: '📢', text: '通知', class: 'info' },\n 'warning': { icon: '⚠️', text: '警告', class: 'warning' },\n 'error': { icon: '🚨', text: '重要', class: 'error' },\n 'success': { icon: '✅', text: '好消息', class: 'success' }\n };\n \n const config = typeConfig[data.type] || typeConfig.info;\n announcementIcon.textContent = config.icon;\n announcementBadge.textContent = config.text;\n announcementBadge.className = 'announcement-badge ' + config.class;\n \n // 设置标题和内容(解析链接)\n announcementTitle.textContent = data.title || '';\n announcementContent.innerHTML = parseAnnouncementContent(data.content || '');\n \n // 设置时间\n if (data.created_at) {\n const date = new Date(data.created_at);\n announcementTime.textContent = date.toLocaleDateString('zh-CN', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit'\n });\n } else {\n announcementTime.textContent = '';\n }\n }\n \n // 处理来自扩展的消息\n window.addEventListener('message', event => {\n const message = event.data;\n \n switch (message.type) {\n case 'state':\n updateUI(message);\n break;\n case 'activated':\n setButtonLoading(activateBtn, false);\n activateBtn.disabled = false;\n if (message.success) {\n // 调试日志\n console.log('[CursorPro] 前端收到激活成功消息:', message);\n \n authStatus.textContent = '已授权';\n authStatus.className = 'status-badge active';\n accountStatus.textContent = '已激活';\n accountStatus.className = 'status-badge active';\n switchBtn.disabled = false;\n // 更新激活码显示(使用后端返回的 key\n fullActivationKey = message.key || keyInput.value;\n keyDisplay.textContent = maskKey(fullActivationKey);\n // 更新到期时间\n console.log('[CursorPro] 更新到期时间:', message.expireDate);\n currentExpireDate = message.expireDate || '';\n expireDate.textContent = formatExpireDate(currentExpireDate) || '未知';\n // 更新换号次数\n if (message.switchRemaining !== undefined) {\n currentSwitchRemaining = message.switchRemaining;\n switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);\n }\n // 清空输入框\n keyInput.value = '';\n showToast('授权码激活成功!', '✅', 10000);\n } else {\n showToast(message.error || '激活失败', '❌', 10000);\n }\n break;\n case 'switched':\n if (message.success) {\n switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);\n showToast('换号成功: ' + (message.email || ''), '✅', 10000);\n } else {\n showToast(message.error || '换号失败', '❌', 10000);\n }\n break;\n case 'reset':\n authStatus.textContent = '未授权';\n authStatus.className = 'status-badge inactive';\n accountStatus.textContent = '未激活';\n accountStatus.className = 'status-badge inactive';\n switchBtn.disabled = true;\n keyInput.value = '';\n fullActivationKey = '';\n keyDisplay.textContent = '尚未激活';\n expireDate.textContent = '尚未激活';\n break;\n \n // 激活码状态检查结果\n case 'keyStatusChecked':\n if (message.valid) {\n // 激活码有效,更新显示\n currentExpireDate = message.expireDate || '';\n currentSwitchRemaining = message.switchRemaining || 0;\n expireDate.textContent = formatExpireDate(currentExpireDate);\n switchCount.textContent = message.switchRemaining + '/' + (message.switchLimit || 100);\n } else if (message.expired) {\n // 激活码已过期,显示提示并重置状态\n currentExpireDate = '';\n currentSwitchRemaining = 0;\n authStatus.textContent = '已过期';\n authStatus.className = 'status-badge inactive';\n authStatus.style.background = '#6e3232';\n authStatus.style.color = '#ff6b6b';\n expireDate.textContent = '已过期';\n expireDate.style.color = '#f87171';\n switchBtn.disabled = true;\n enableSeamlessBtn.disabled = true;\n // 如果免魔法已开启,自动关闭\n if (seamlessProxySwitch.checked) {\n seamlessProxySwitch.checked = false;\n vscode.postMessage({ type: 'toggleProxy', enabled: false, url: '' });\n }\n // 显示过期弹窗\n showExpiredModal();\n }\n break;\n \n // 用户换号状态\n case 'userSwitchStatus':\n const remaining = message.switchRemaining || 0;\n const canSwitch = remaining > 0;\n \n // 更新全局变量\n currentSwitchRemaining = remaining;\n \n seamlessSwitchRemaining.textContent = remaining.toString();\n seamlessSwitchRemaining.style.color = canSwitch ? '#4ade80' : '#f87171';\n \n if (message.lockedAccount) {\n seamlessCurrentAccount.textContent = message.lockedAccount.email;\n \n // 设置当前账号邮箱并启动用量刷新\n if (message.lockedAccount.email && message.lockedAccount.email !== currentAccountEmail) {\n currentAccountEmail = message.lockedAccount.email;\n usageSection.style.display = 'block';\n startUsageRefresh();\n }\n } else {\n seamlessCurrentAccount.textContent = '未分配';\n \n // 没有锁定账号时隐藏用量区域\n currentAccountEmail = '';\n usageSection.style.display = 'none';\n stopUsageRefresh();\n }\n \n // 根据剩余次数控制手动换号按钮状态\n if (!canSwitch) {\n manualSwitchBtn.disabled = true;\n }\n // 启用无感换号按钮不受积分限制,只有过期才禁用\n enableSeamlessBtn.disabled = isKeyExpired();\n \n // 如果无感换号已启用,显示手动换号按钮和重置机器码按钮\n if (message.seamlessEnabled && canSwitch) {\n manualSwitchBtn.style.display = 'block';\n manualSwitchBtn.disabled = false;\n setButtonLoading(manualSwitchBtn, false);\n seamlessResetMachineBtn.style.display = 'block';\n }\n break;\n \n // 账号用量\n case 'accountUsage':\n setRefreshLoading(refreshUsageBtn, false);\n if (message.success && message.data) {\n updateUsageDisplay(message.data);\n } else {\n usageUpdateTime.textContent = '获取失败: ' + (message.error || '未知错误');\n usageUpdateTime.style.color = '#f87171';\n }\n break;\n \n // 无感换号状态\n case 'seamlessStatus':\n if (message.is_injected) {\n seamlessStatus.textContent = '已启用';\n seamlessStatus.className = 'status-badge active';\n enableSeamlessBtn.style.display = 'none';\n disableSeamlessBtn.style.display = 'block';\n disableSeamlessBtn.disabled = false;\n setButtonLoading(disableSeamlessBtn, false);\n manualSwitchBtn.style.display = 'block';\n manualSwitchBtn.disabled = false;\n setButtonLoading(manualSwitchBtn, false);\n seamlessResetMachineBtn.style.display = 'block';\n } else {\n seamlessStatus.textContent = '未启用';\n seamlessStatus.className = 'status-badge inactive';\n enableSeamlessBtn.style.display = 'block';\n setButtonLoading(enableSeamlessBtn, false);\n // 启用按钮不受积分限制,只有过期才禁用\n enableSeamlessBtn.disabled = isKeyExpired();\n disableSeamlessBtn.style.display = 'none';\n manualSwitchBtn.style.display = 'none';\n seamlessResetMachineBtn.style.display = 'none';\n }\n break;\n \n case 'seamlessInjected':\n setButtonLoading(enableSeamlessBtn, false);\n enableSeamlessBtn.disabled = false;\n if (message.success) {\n seamlessStatus.textContent = '已启用';\n seamlessStatus.className = 'status-badge active';\n enableSeamlessBtn.style.display = 'none';\n disableSeamlessBtn.style.display = 'block';\n manualSwitchBtn.style.display = 'block';\n seamlessResetMachineBtn.style.display = 'block';\n // 刷新用户状态\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n // 显示重启提示弹窗\n if (message.needRestart) {\n showRestartModal(message.message || '无感换号已启用');\n }\n } else {\n // 如果是权限错误,显示自定义弹窗\n if (message.needAdmin) {\n // Mac/Linux 权限问题,显示详细提示\n var errorMsg = message.error || '没有写入权限';\n if (message.path) {\n errorMsg += '\\n路径: ' + message.path;\n }\n showToast(errorMsg, '🔐', 15000);\n } else {\n // 显示详细错误\n var detailMsg = message.error || '启用失败';\n if (message.details) {\n detailMsg += '\\n' + message.details;\n }\n showToast(detailMsg, '❌', 15000);\n }\n }\n break;\n \n case 'seamlessRestored':\n setButtonLoading(disableSeamlessBtn, false);\n disableSeamlessBtn.disabled = false;\n if (message.success) {\n seamlessStatus.textContent = '未启用';\n seamlessStatus.className = 'status-badge inactive';\n enableSeamlessBtn.style.display = 'block';\n disableSeamlessBtn.style.display = 'none';\n manualSwitchBtn.style.display = 'none';\n seamlessResetMachineBtn.style.display = 'none';\n // 显示重启提示弹窗\n if (message.needRestart) {\n showRestartModal(message.message || '无感换号已禁用');\n }\n } else {\n // 如果是权限错误,显示自定义弹窗\n if (message.needAdmin) {\n showAdminModal();\n } else {\n showToast(message.error || '禁用失败', '❌', 10000);\n }\n }\n break;\n \n // 用量检查结果\n case 'usageCheckResult':\n if (message.success) {\n if (message.needConfirm) {\n // 需要确认,显示弹窗(按钮保持可用状态,等用户选择)\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n switchConfirmEmail.textContent = message.email || '';\n switchConfirmCost.textContent = '$' + (message.costUSD || '0.00');\n switchConfirmModal.classList.add('show');\n } else {\n // 不需要确认,直接换号\n vscode.postMessage({ type: 'confirmSwitch' });\n }\n } else {\n setButtonLoading(manualSwitchBtn, false);\n manualSwitchBtn.disabled = false;\n showToast(message.error || '检查失败', '❌', 5000);\n }\n break;\n \n case 'manualSeamlessSwitched':\n setButtonLoading(manualSwitchBtn, false);\n if (message.success) {\n seamlessSwitchRemaining.textContent = (message.switchRemaining || 0).toString();\n seamlessCurrentAccount.textContent = message.email || '未知';\n // 显示 Toast 通知10秒后消失\n showToast('已切换到: ' + (message.email || '新账号') + '约10秒内自动生效', '✅', 10000);\n // 刷新状态\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n // 禁用按钮10秒显示倒计时\n disableSwitchBtnWithCountdown(10);\n } else {\n manualSwitchBtn.disabled = false;\n showToast(message.error || '换号失败', '❌', 5000);\n }\n break;\n \n case 'proxyStatus':\n // 设置免魔法开关状态\n seamlessProxySwitch.checked = message.enabled;\n break;\n \n // 公告\n case 'announcement':\n if (message.success && message.data) {\n updateAnnouncementDisplay(message.data);\n } else {\n announcementSection.style.display = 'none';\n }\n break;\n \n // 版本检查\n case 'versionCheck':\n currentVersionEl.textContent = message.currentVersion || '-';\n if (message.success && message.hasUpdate) {\n // 有更新\n latestVersionEl.textContent = message.latestVersion;\n latestVersionRow.style.display = 'flex';\n versionStatus.style.display = 'inline-block';\n versionStatus.style.background = '#ff9800';\n updateHint.style.display = 'block';\n \n // 显示顶部更新提醒条\n updateBannerVersion.textContent = 'v' + message.latestVersion;\n updateBanner.classList.add('show');\n } else if (message.success) {\n // 已是最新版\n versionStatus.textContent = '最新';\n versionStatus.style.display = 'inline-block';\n versionStatus.style.background = '#4caf50';\n latestVersionRow.style.display = 'none';\n updateHint.style.display = 'none';\n updateBanner.classList.remove('show');\n }\n break;\n \n // Cursor 运行路径\n case 'cursorRunningPath':\n if (message.path) {\n const pathText = message.path + (message.packageExists ? ' ✓' : ' ✗');\n cursorPath.textContent = pathText;\n cursorPath.style.color = message.packageExists ? '#4ade80' : '#f87171';\n // 同时更新版本号\n if (message.cursorVersion) {\n cursorVersion.textContent = message.cursorVersion;\n }\n } else {\n cursorPath.textContent = '未找到';\n cursorPath.style.color = '#f87171';\n }\n break;\n \n // 管理员权限不足提示\n case 'adminPermissionRequired':\n showAdminPermissionModal();\n break;\n \n // 机器码重置\n case 'machineIdReset':\n if (message.success && message.needRestart) {\n // 机器码重置需要完全关闭 Cursor不是 reload\n showRestartModal(message.message || '机器码重置成功', 'close');\n }\n break;\n \n // 通用 Toast 消息\n case 'showToast':\n showToast(message.message || '', message.icon || '📢', 10000);\n break;\n \n // 网络状态\n case 'networkStatus':\n updateOfflineStatus(!message.online);\n break;\n }\n });\n \n // 离线状态显示/隐藏\n let wasOffline = false; // 跟踪之前是否离线\n function updateOfflineStatus(isOffline) {\n if (isOffline) {\n offlineBanner.classList.add('show');\n wasOffline = true;\n } else {\n offlineBanner.classList.remove('show');\n // 只有从离线恢复到在线时才刷新状态\n if (wasOffline) {\n wasOffline = false;\n vscode.postMessage({ type: 'getState' });\n vscode.postMessage({ type: 'getUserSwitchStatus' });\n }\n }\n }\n \n // 重试连接按钮\n retryConnectBtn.addEventListener('click', async () => {\n retryConnectBtn.classList.add('loading');\n retryConnectBtn.textContent = '连接中...';\n \n // 发起真正的网络请求来测试网络\n vscode.postMessage({ type: 'retryConnect' });\n \n // 5秒后恢复按钮状态给网络请求足够时间\n setTimeout(() => {\n retryConnectBtn.classList.remove('loading');\n retryConnectBtn.textContent = '重试';\n }, 5000);\n });\n \n function updateUI(state) {\n if (state.isActivated) {\n authStatus.textContent = '已授权';\n authStatus.className = 'status-badge active';\n accountStatus.textContent = '已激活';\n accountStatus.className = 'status-badge active';\n switchBtn.disabled = false;\n fullActivationKey = state.key;\n keyDisplay.textContent = maskKey(fullActivationKey);\n // 更新到期时间\n currentExpireDate = state.expireDate || '';\n expireDate.textContent = formatExpireDate(currentExpireDate);\n // 更新换号次数\n if (state.switchRemaining !== undefined) {\n currentSwitchRemaining = state.switchRemaining;\n switchCount.textContent = state.switchRemaining + '/' + (state.switchLimit || 100);\n }\n // 启用无感换号按钮(只有过期才禁用)\n enableSeamlessBtn.disabled = isKeyExpired();\n }\n cursorVersion.textContent = state.cursorVersion || '0.0.0';\n \n // 根据网络状态显示/隐藏离线提示\n if (state.isOnline === false) {\n offlineBanner.classList.add('show');\n wasOffline = true;\n } else if (state.isOnline === true) {\n // 网络恢复,隐藏离线提示\n offlineBanner.classList.remove('show');\n wasOffline = false;\n }\n }\n </script>\n</body>\n</html>";
}
}
exports["CursorProViewProvider"] = CursorProViewProvider;
CursorProViewProvider["CURRENT_VERSION"] = '0.4.5';