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

4308 lines
298 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 (arg1, arg2, arg3, arg4) {
const var1 = {
'uKmJw': function (arg5, arg6) {
return arg5 === arg6;
},
'TAoYL': function (arg7, arg8) {
return arg7 in arg8;
},
'aPyeo': "get"
};
if (var1.uKmJw(arg4, undefined)) {
arg4 = arg3;
}
var var2 = Object.getOwnPropertyDescriptor(arg2, arg3);
if (!var2 || (var1.aPyeo in var2 ? !arg2.__esModule : var2.writable || var2.configurable)) {
var2 = {
'enumerable': true,
'get': function () {
return arg2[arg3];
}
};
}
Object.defineProperty(arg1, arg4, var2);
} : function (arg9, arg10, arg11, arg12) {
const var3 = {
'SeNEr': function (arg13, arg14) {
return arg13 === arg14;
}
};
if (var3.SeNEr(arg12, undefined)) {
arg12 = arg11;
}
arg9[arg12] = arg10[arg11];
});
var __setModuleDefault = this && this.__setModuleDefault || (Object.create ? function (arg15, arg16) {
const var4 = {
'FTXnn': "default"
};
Object.defineProperty(arg15, var4.FTXnn, {
'enumerable': true,
'value': arg16
});
} : function (arg17, arg18) {
const var5 = {
'kZOut': "default"
};
arg17[var5.kZOut] = arg18;
});
var __importStar = this && this.__importStar || function () {
const var6 = {
'fsNNJ': function (arg19, arg20) {
return arg19(arg20);
},
'srHxh': '1|4|0|3|2',
'MoXZb': function (arg21, arg22) {
return arg21 != arg22;
},
'VqBsb': function (arg23, arg24) {
return arg23 < arg24;
},
'mymIw': function (arg25, arg26) {
return arg25 !== arg26;
},
'zFOle': function (arg27, arg28, arg29, arg30) {
return arg27(arg28, arg29, arg30);
},
'zPdmk': function (arg31, arg32, arg33) {
return arg31(arg32, arg33);
}
};
var var7 = function (arg34) {
var7 = Object.getOwnPropertyNames || function (arg35) {
var var8 = [];
for (var var9 in arg35) if (Object.prototype.hasOwnProperty.call(arg35, var9)) {
var8[var8.length] = var9;
}
return var8;
};
return var6.fsNNJ(var7, arg34);
};
return function (arg36) {
const var10 = var6.srHxh.split('|');
let var11 = 0x0;
while (true) {
switch (var10[var11++]) {
case '0':
if (var6.MoXZb(arg36, null)) {
var var12 = var7(arg36);
for (var var13 = 0x0; var6.VqBsb(var13, var12.length); var13++) {
if (var6.mymIw(var12[var13], "default")) {
var6.zFOle(__createBinding, v14, arg36, var12[var13]);
}
}
}
continue;
case '1':
if (arg36 && arg36.__esModule) {
return arg36;
}
continue;
case '2':
return v14;
case '3':
var6.zPdmk(__setModuleDefault, v14, arg36);
continue;
case '4':
var v14 = {};
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(arg37, arg38) {
const var15 = {
'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 = arg37;
this._context = arg38;
this._hostsPermissionGranted = false;
this.SNI_PROXY_IP = var15.NNvQE;
this.CURSOR_DOMAINS = [var15.HENcW, var15.vVEYg];
this.HOSTS_MARKER_START = var15.xOuBX;
this.HOSTS_MARKER_END = var15.gbbhA;
this._cachedCursorPath = null;
0x0;
this._onlineStatusUnsubscribe = client_1.onOnlineStatusChange(arg39 => {
this._postMessage({
'type': var15.dJwJk,
'online': arg39
});
});
}
resolveWebviewView(arg40, arg41, arg42) {
const var16 = {
'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 = arg40;
arg40.webview.options = {
'enableScripts': true,
'localResourceRoots': [this._extensionUri]
};
arg40.webview.html = this._getHtmlContent(arg40.webview);
arg40.webview.onDidReceiveMessage(async arg43 => {
const var17 = {
'WZyWQ': var16.NRTxb,
'ZXhkG': var16.MCtQT
};
if (var16.RCwUS !== var16.gHWzN) {
switch (arg43.type) {
case "activate":
await this._handleActivate(arg43.key);
break;
case var16.HxMUq:
await this._handleSwitch();
break;
case "resetMachineId":
await this._handleResetMachineId();
break;
case var16.mVWLv:
await this._handleDisableUpdate();
break;
case var16.kIVSE:
await this._handleCleanEnv();
break;
case var16.ayNzd:
await this._handleDisable();
break;
case var16.XJsJS:
await this._handleToggleProxy(arg43.enabled, arg43.url);
break;
case 'getProxyStatus':
await this._handleGetProxyStatus();
break;
case var16.TwlLk:
await this._sendState();
break;
case "retryConnect":
await this._handleRetryConnect();
break;
case var16.Yecgn:
await this._handleGetSeamlessStatus();
break;
case var16.ekYOQ:
await this._handleInjectSeamless();
break;
case "restoreSeamless":
await this._handleRestoreSeamless();
break;
case var16.sJjTI:
await this._handleToggleSeamless(arg43.enabled);
break;
case var16.FtmLf:
await this._handleGetUserSwitchStatus();
break;
case "manualSeamlessSwitch":
await this._handleManualSeamlessSwitch();
break;
case var16.EflLA:
await this._handleCheckUsageBeforeSwitch(arg43.email);
break;
case var16.rXOaA:
await this._handleManualSeamlessSwitch();
break;
case var16.OkEoz:
await this._handleGetCursorPath();
break;
case 'getAccountUsage':
await this._handleGetAccountUsage(arg43.email);
break;
case "getAnnouncement":
await this._handleGetAnnouncement();
break;
case var16.ehEEN:
await this._handleCheckVersion();
break;
case var16.myCHL:
await this._handleGetCursorRunningPath();
break;
case var16.KPDvL:
vscode.commands.executeCommand(var16.LHHus);
break;
case 'closeCursor':
0x0;
await account_1.closeCursor();
break;
}
} else {
const var18 = var17.WZyWQ;
this._postMessage({
'type': var17.ZXhkG,
'success': false,
'error': var18,
'needAdmin': true
});
return;
}
});
this._sendState();
this._checkKeyStatus();
}
async _checkKeyStatus() {
const var19 = {
'TLsxY': "utf-8",
'KqsKI': "cursorpro.key",
'OEKzo': function (arg44, arg45) {
return arg44 !== arg45;
},
'krxOp': "FAZar",
'lSeSm': "QlWcq",
'ubmNf': function (arg46, arg47) {
return arg46 === arg47;
},
'yoPVW': 'EtMGw',
'UGSnZ': 'DVTND',
'jEejJ': 'cursorpro.expireDate',
'lpyMQ': 'cursorpro.switchRemaining',
'Auayd': "cursorpro.switchLimit",
'sbaFL': "keyStatusChecked",
'dyUVf': "激活码已过期或无效"
};
const var20 = this._context.globalState.get(var19.KqsKI);
if (!var20) {
if (var19.OEKzo('NCQkd', var19.krxOp)) {
return;
} else {
this._postMessage({
'type': "accountUsage",
'success': false,
'error': "未提供账号邮箱"
});
return;
}
}
try {
if (var19.lSeSm !== 'QlWcq') {
v21.writeFileSync(v22, v23, var19.TLsxY);
} else {
0x0;
const var24 = await client_1.verifyKey(var20);
if (var24.success && var24.valid) {
if (var19.ubmNf(var19.yoPVW, var19.UGSnZ)) {
const var25 = v26.readFileSync(v27, var19.TLsxY);
v28 = this._checkInjected(var25);
} else {
await this._context.globalState.update(var19.jEejJ, var24.expire_date);
await this._context.globalState.update(var19.lpyMQ, var24.switch_remaining);
await this._context.globalState.update(var19.Auayd, var24.switch_limit);
this._postMessage({
'type': var19.sbaFL,
'valid': true,
'expireDate': var24.expire_date,
'switchRemaining': var24.switch_remaining,
'switchLimit': var24.switch_limit
});
}
} else {
this._postMessage({
'type': var19.sbaFL,
'valid': false,
'expired': true,
'error': var24.error || var19.dyUVf
});
}
}
} catch (v29) {
console.error("[CursorPro] 检查激活码状态失败:", v29);
}
}
async _handleActivate(arg48) {
const var30 = {
'cduDC': "utf-8",
'dWzRy': function (arg49, arg50) {
return arg49(arg50);
},
'yiKQp': "vscode",
'loOtc': "[CursorPro] 使用 VS Code API 获取版本:",
'fCoyb': function (arg51, arg52) {
return arg51 === arg52;
},
'hneyF': "ZPKij",
'MeNSD': "无感换号已启用,请先禁用后再更换授权码",
'jfGyX': function (arg53, arg54) {
return arg53 === arg54;
},
'vAxgQ': 'ZyMNB',
'IStwX': "activated",
'RiXWk': "cursorpro.expireDate",
'tkwFD': "cursorpro.key",
'oRfTW': "cursorpro.switchLimit",
'lnDvM': "aVnan",
'bgJHu': "SOGed",
'lRVPz': "授权码无效",
'mbyBU': "连接服务器失败"
};
try {
const var31 = await this._isSeamlessInjected();
if (var31) {
if (var30.fCoyb(var30.hneyF, "ZPKij")) {
this._postMessage({
'type': "activated",
'success': false,
'error': var30.MeNSD
});
return;
} else {
const var32 = this._getHostsPath();
if (v33.existsSync(var32)) {
return v34.readFileSync(var32, var30.cduDC);
}
}
}
this._cleanProxySettings();
0x0;
const var35 = await client_1.verifyKey(arg48);
if (var35.success && var35.valid) {
if (var30.jfGyX('ZyMNB', var30.vAxgQ)) {
console.log("[CursorPro] 激活成功,后端返回:", {
'expire_date': var35.expire_date,
'switch_remaining': var35.switch_remaining,
'switch_limit': var35.switch_limit
});
await this._context.globalState.update(var30.tkwFD, arg48);
await this._context.globalState.update(var30.RiXWk, var35.expire_date);
await this._context.globalState.update("cursorpro.switchRemaining", var35.switch_remaining);
await this._context.globalState.update(var30.oRfTW, var35.switch_limit);
this._postMessage({
'type': var30.IStwX,
'success': true,
'key': arg48,
'expireDate': var35.expire_date,
'switchRemaining': var35.switch_remaining,
'switchLimit': var35.switch_limit
});
0x0;
extension_1.showStatusBar();
await this._handleGetUserSwitchStatus();
} else {
v36.warn("[CursorPro] 清理失败: " + v37, v38);
}
} else {
if (var30.lnDvM === var30.bgJHu) {
const var39 = var30.dWzRy(v40, var30.yiKQp);
if (var39.version) {
v41.log(var30.loOtc, var39.version);
return var39.version;
}
} else {
this._postMessage({
'type': var30.IStwX,
'success': false,
'error': var35.error || var30.lRVPz
});
}
}
} catch (v42) {
this._postMessage({
'type': var30.IStwX,
'success': false,
'error': var30.mbyBU
});
}
}
async _handleSwitch() {
const var43 = {
'QReae': "[CursorPro] WMIC 获取路径失败:",
'OVooV': "cursorpro.key",
'SpDeq': 'showToast',
'PTQOe': "请先激活授权码",
'YLEHJ': "cursorpro.switchRemaining",
'eBTDM': 'switched',
'kCeYh': "cursorpro.switchLimit",
'omFtC': "userSwitchStatus",
'XbTBi': function (arg55, arg56) {
return arg55 > arg56;
},
'pyrHY': function (arg57, arg58) {
return arg57 !== arg58;
},
'VqcBN': "kqrkg",
'bfgAG': "QcuMv"
};
const var44 = this._context.globalState.get(var43.OVooV);
if (!var44) {
this._postMessage({
'type': var43.SpDeq,
'message': var43.PTQOe,
'icon': '⚠️'
});
return;
}
try {
0x0;
const var45 = await client_1.switchSeamlessToken(var44);
if (var45.switched) {
await this._context.globalState.update(var43.YLEHJ, var45.switchRemaining);
this._postMessage({
'type': var43.eBTDM,
'success': true,
'email': var45.email,
'switchRemaining': var45.switchRemaining,
'switchLimit': this._context.globalState.get(var43.kCeYh) || 0x64
});
const var46 = var45.switchRemaining ?? 0x0;
this._postMessage({
'type': var43.omFtC,
'switchRemaining': var46,
'canSwitch': var46 > 0x0,
'lockedAccount': var45.email ? {
'email': var45.email
} : null
});
} else if (var43.pyrHY("yFoId", var43.VqcBN)) {
this._postMessage({
'type': var43.eBTDM,
'success': false,
'error': var45.message || '换号失败'
});
} else {
v47 = v48[0x1];
}
} catch (v49) {
if (var43.pyrHY("CyYkO", var43.bfgAG)) {
this._postMessage({
'type': 'switched',
'success': false,
'error': "连接服务器失败"
});
} else {
v50.log(var43.QReae, v51);
}
}
}
async _writeAccountToLocal(arg59) {
const var52 = {
'jAygU': function (arg60, arg61) {
return arg60 === arg61;
},
'lWsen': "Contents",
'ujkvI': "app",
'nHvFA': 'out',
'WYIiR': "workbench",
'HukDC': "workbench.desktop.main.js",
'lAqMN': function (arg62, arg63) {
return arg62 === arg63;
},
'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 (arg64, arg65) {
return arg64 === arg65;
},
'GXvhF': "hdUrt",
'tFDff': "Cursor",
'IFUbF': 'User',
'RqMFq': "globalStorage",
'tSjWJ': "state.vscdb",
'WnTYM': "machineid",
'ByhnO': "cursorAuth/accessToken",
'MPCdN': "cursorAuth/refreshToken",
'hrJHc': function (arg66, arg67) {
return arg66 === arg67;
},
'atmmx': "rmAmZ",
'qyuJo': "cursorAuth/cachedEmail",
'iOndu': "pAlKG",
'tfSWx': "cursorAuth/stripeMembershipType",
'UnRdA': function (arg68, arg69) {
return arg68 !== arg69;
},
'FNcgD': "ptOKi",
'JVIPE': 'yLQZc',
'btARC': "cursorAuth/cachedSignUpType",
'pTffC': "eNCnU",
'taMeX': "storage.serviceMachineId",
'QhViN': function (arg70, arg71) {
return arg70 === arg71;
},
'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 (arg72, arg73) {
return arg72(arg73);
},
'dxmvV': "[CursorPro] 注册表写入失败(可能需要管理员权限):"
};
try {
if ("MClbP" === var52.GXvhF) {
let var53;
if (var52.jAygU(v54, "darwin")) {
var53 = v55.join(this._cachedCursorPath, var52.lWsen, 'Resources', var52.ujkvI, var52.nHvFA, 'vs', var52.WYIiR, var52.HukDC);
} else {
var53 = v56.join(this._cachedCursorPath, "resources", var52.ujkvI, var52.nHvFA, 'vs', var52.WYIiR, var52.HukDC);
}
if (v57.existsSync(var53)) {
return var53;
}
} else {
const var58 = process.env.APPDATA || '';
const var59 = path.join(var58, var52.tFDff, var52.IFUbF, var52.RqMFq, var52.tSjWJ);
const var60 = path.join(var58, "Cursor", var52.IFUbF, var52.RqMFq, 'storage.json');
const var61 = path.join(var58, var52.tFDff, var52.WnTYM);
if (fs.existsSync(var59)) {
const var62 = [];
if (arg59.accessToken) {
var62.push([var52.ByhnO, arg59.accessToken]);
}
if (arg59.refreshToken) {
var62.push([var52.MPCdN, arg59.refreshToken]);
}
if (arg59.email) {
if (var52.atmmx === 'mIiuu') {
v63 = v64.dirname(v65.trim());
} else {
var62.push([var52.qyuJo, arg59.email]);
}
}
if (arg59.membership_type) {
if ('vhcuB' === var52.iOndu) {
const var66 = v67.platform;
let var68 = '没有写入权限';
if (var52.lAqMN(var66, var52.uJtvK)) {
var68 = var52.klERN;
} else if (var52.lAqMN(var66, var52.qVIKa)) {
var68 = var52.uJMyy;
}
this._postMessage({
'type': 'seamlessInjected',
'success': false,
'error': var68,
'needAdmin': true,
'path': v69
});
return;
} else {
var62.push([var52.tfSWx, arg59.membership_type]);
}
}
if (arg59.sign_up_type) {
if (var52.UnRdA(var52.FNcgD, 'yLQZc')) {
var62.push([var52.btARC, arg59.sign_up_type]);
} else {
v70 = v71.dirname(v72);
}
}
if (arg59.serviceMachineId) {
if ('fYfXI' !== var52.pTffC) {
var62.push([var52.taMeX, arg59.serviceMachineId]);
} else {
this._postMessage({
'type': var52.oogyg,
'success': true,
'needConfirm': true,
'costUSD': v73.toFixed(0x2),
'email': v74
});
}
}
0x0;
await sqlite_1.sqliteSetBatch(var59, var62);
console.log("[CursorPro] SQLite 数据库已更新");
}
if (fs.existsSync(var60)) {
if (var52.QhViN(var52.IenCN, "nqqWG")) {
const var75 = v76.message || v77.error || var52.UUaYi;
this._postMessage({
'type': var52.NEcQR,
'success': false,
'error': var75
});
} else {
const var78 = JSON.parse(fs.readFileSync(var60, 'utf-8'));
if (arg59.machineId) {
var78[var52.ktByd] = arg59.machineId;
}
if (arg59.macMachineId) {
var78['telemetry.macMachineId'] = arg59.macMachineId;
}
if (arg59.devDeviceId) {
var78["telemetry.devDeviceId"] = arg59.devDeviceId;
}
if (arg59.sqmId) {
if (var52.hYviy === var52.ltTAn) {
this._postMessage({
'type': var52.BPXIz,
'success': false,
'error': "修改 hosts 文件失败,请确保有管理员权限"
});
this._postMessage({
'type': var52.pgeAO,
'message': "需要管理员权限修改 hosts 文件",
'icon': '⚠️'
});
} else {
var78["telemetry.sqmId"] = arg59.sqmId;
}
}
fs.writeFileSync(var60, JSON.stringify(var78, null, 0x4));
console.log(var52.WtTZw);
}
}
if (arg59.machineId) {
fs.writeFileSync(var61, arg59.machineId);
console.log(var52.bohEI);
}
if (arg59.registryGuid && process.platform === var52.tqMKz) {
if (var52.KhYFK === var52.KhYFK) {
try {
const var79 = 'reg add "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid /t REG_SZ /d "' + arg59.registryGuid + '" /f';
await execAsync(var79);
console.log("[CursorPro] 注册表 MachineGuid 已更新");
} catch (v80) {
console.warn(var52.dxmvV, v80);
}
} else {
v81 = var52.uJMyy;
}
}
return true;
}
} catch (v82) {
console.error("[CursorPro] 写入本地失败:", v82);
vscode.window.showErrorMessage("写入失败: " + v82);
return false;
}
}
async _handleReset() {
const var83 = {
'SWWgG': '4|0|3|5|2|1',
'uEcXh': 'reset',
'eMKRt': 'cursorpro.switchRemaining',
'FOwUP': "cursorpro.key"
};
const var84 = '4|0|3|5|2|1'.split('|');
let var85 = 0x0;
while (true) {
switch (var84[var85++]) {
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(var83.eMKRt, undefined);
continue;
case '4':
await this._context.globalState.update(var83.FOwUP, undefined);
continue;
case '5':
0x0;
extension_1.hideStatusBar();
continue;
}
break;
}
}
async _handleDisable() {
await this._handleReset();
vscode.window.showInformationMessage("插件已停用");
}
async _checkAdminPrivilege() {
const var86 = {
'fAfUV': "Resources",
'Llgfj': function (arg74, arg75) {
return arg74 !== arg75;
},
'pImJb': function (arg76, arg77) {
return arg76(arg77);
},
'wncyL': "net session 2>nul"
};
if (process.platform !== "win32") {
if ("FIUZS" === 'FIUZS') {
return true;
} else {
v87 = v88.join(v89, 'Contents', var86.fAfUV, 'app', "package.json");
}
}
try {
await var86.pImJb(execAsync, 'reg query "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid 2>nul');
const var90 = await execAsync(var86.wncyL).catch(() => ({
'stdout': '',
'stderr': 'error'
}));
return !var90.stderr;
} catch (v91) {
return false;
}
}
async _handleResetMachineId() {
const var92 = {
'lElIk': function (arg78, arg79) {
return arg78 === arg79;
},
'yJQQD': "darwin",
'oTJSZ': 'Contents',
'sJMHZ': 'Resources',
'tIdJk': "app",
'rNqfB': "workbench",
'PaBhO': "workbench.desktop.main.js",
'cDXTK': "out",
'mseLD': function (arg80, arg81) {
return arg80(arg81);
},
'GpfdI': function (arg82, arg83) {
return arg82 != arg83;
},
'jGfgE': function (arg84, arg85) {
return arg84 !== arg85;
},
'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 (arg86, arg87) {
return arg86 === arg87;
},
'hazjj': "OKDBI",
'sltuA': "[CursorPro] storage.json 更新失败:",
'kdlCx': "storage.json",
'yAadA': "AGUOM",
'dVXng': function (arg88, arg89) {
return arg88 > arg89;
},
'jVCTI': function (arg90, arg91) {
return arg90 !== arg91;
},
'NgEqy': "XygLc",
'JHBVl': "[CursorPro] machineid 文件已更新",
'ihOph': "machineid",
'CUSOw': function (arg92, arg93) {
return arg92 > arg93;
},
'DXmLl': 'UbSjF',
'XMamy': function (arg94, arg95) {
return arg94 !== arg95;
},
'TStTT': "SxHmQ",
'xXEyx': function (arg96, arg97) {
return arg96 !== arg97;
},
'iiJFH': 'edqsV',
'dLXnX': function (arg98, arg99) {
return arg98 === arg99;
},
'IMEYC': function (arg100, arg101) {
return arg100 === arg101;
},
'aYwpG': "EvLtz",
'EdOfO': "[CursorPro] SQLite 更新失败:",
'wSpvM': "win32",
'hhSrG': function (arg102, arg103) {
return arg102 === arg103;
},
'DAvAD': "uxdjv",
'BkSzQ': "qWEGL",
'WYomd': "[CursorPro] 注册表 MachineGuid 已更新",
'ZaPkC': function (arg104, arg105) {
return arg104 >= arg105;
},
'fVMJA': 'machineIdReset',
'HiGXJ': "机器码重置成功",
'SEsMN': function (arg106, arg107) {
return arg106 === arg107;
},
'dGXfv': "gGIGL",
'pKuzu': function (arg108, arg109) {
return arg108 !== arg109;
},
'YfRLt': "KokEE"
};
try {
const var93 = process.platform;
if (var92.lElIk(var93, 'win32')) {
const var94 = await this._checkAdminPrivilege();
if (!var94) {
this._postMessage({
'type': var92.BmSwh
});
return;
}
}
0x0;
const var95 = account_1.getCursorPaths();
const {
dbPath: v96,
storagePath: v97,
machineidPath: v98
} = var95;
const var99 = var92.mseLD(require, var92.DUzlm);
const var100 = var99.randomBytes(0x20).toString(var92.iOJby);
const var101 = var99.randomBytes(0x20).toString(var92.iOJby);
const var102 = var99.randomUUID();
const var103 = '{' + var99.randomUUID().toUpperCase() + '}';
let var104 = 0x0;
let var105 = [];
if (fs.existsSync(v97)) {
if (var92.SizrD !== "EIFLO") {
let var106;
if (var92.lElIk(v107, var92.yJQQD)) {
var106 = v108.join(v109, 'Contents', var92.sJMHZ, var92.tIdJk, "out", 'vs', var92.rNqfB, var92.PaBhO);
} else {
var106 = v110.join(v111, "resources", "app", var92.cDXTK, 'vs', var92.rNqfB, var92.PaBhO);
}
if (v112.existsSync(var106)) {
return var106;
}
} else {
let var113 = 0x3;
while (var113 > 0x0) {
try {
const var114 = JSON.parse(fs.readFileSync(v97, var92.kVXre));
var114["telemetry.machineId"] = var100;
var114[var92.OoOvL] = var101;
var114[var92.NrAHw] = var102;
var114["telemetry.sqmId"] = var103;
fs.writeFileSync(v97, JSON.stringify(var114, null, 0x4));
console.log(var92.DYlNA);
var104++;
break;
} catch (v115) {
var113--;
if (var113 === 0x0) {
if (var92.oWHkO("VbcUu", var92.hazjj)) {
v116.rmSync(v117, {
'recursive': true,
'force': true
});
v118++;
v119.log("[CursorPro] 已清理: " + v120);
} else {
console.warn(var92.sltuA, v115.message);
var105.push(var92.kdlCx);
}
} else {
await new Promise(arg110 => setTimeout(arg110, 0x64));
}
}
}
}
}
{
if (var92.oWHkO(var92.yAadA, "omtSK")) {
var var121 = [];
for (var var122 in v123) if (v124.prototype.hasOwnProperty.call(v125, var122)) {
var121[var121.length] = var122;
}
return var121;
} else {
let var126 = 0x3;
while (var126 > 0x0) {
try {
const var127 = path.dirname(v98);
if (!fs.existsSync(var127)) {
if (var92.jVCTI('UjEXX', var92.NgEqy)) {
fs.mkdirSync(var127, {
'recursive': true
});
} else {
return v128;
}
}
fs.writeFileSync(v98, var100);
console.log(var92.JHBVl);
var104++;
break;
} catch (v129) {
var126--;
if (var126 === 0x0) {
console.warn("[CursorPro] machineid 更新失败:", v129.message);
var105.push(var92.ihOph);
} else {
await new Promise(arg111 => setTimeout(arg111, 0x64));
}
}
}
}
}
if (fs.existsSync(v96)) {
let var130 = 0x3;
while (var92.CUSOw(var130, 0x0)) {
if ("UbSjF" === var92.DXmLl) {
try {
if ("EvWMl" !== var92.TStTT) {
const var131 = var99.randomUUID();
0x0;
const var132 = await sqlite_1.sqliteSetBatch(v96, [['storage.serviceMachineId', var131]]);
if (var132) {
console.log("[CursorPro] SQLite 数据库已更新");
var104++;
break;
} else {
if ('edqsV' !== "edqsV") {
const var133 = {
'JDiGp': function (arg112, arg113) {
return var92.GpfdI(arg112, arg113);
},
'UJfLB': function (arg114, arg115) {
return var92.jGfgE(arg114, arg115);
},
'YIhbu': var92.SKKxx,
'hQSHL': function (arg116, arg117, arg118, arg119) {
return arg116(arg117, arg118, arg119);
},
'iFgQw': function (arg120, arg121, arg122) {
return arg120(arg121, arg122);
}
};
var var134 = function (arg123) {
var134 = v135.getOwnPropertyNames || function (arg124) {
var var136 = [];
for (var var137 in arg124) if (v138.prototype.hasOwnProperty.call(arg124, var137)) {
var136[var136.length] = var137;
}
return var136;
};
return var92.mseLD(var134, arg123);
};
return function (arg125) {
if (arg125 && arg125.__esModule) {
return arg125;
}
var var139 = {};
if (var133.JDiGp(arg125, null)) {
var var140 = var134(arg125);
for (var var141 = 0x0; var141 < var140.length; var141++) {
if (var92.jGfgE(var140[var141], var133.YIhbu)) {
var133.hQSHL(v142, var139, arg125, var140[var141]);
}
}
}
var133.iFgQw(v143, var139, arg125);
return var139;
};
} else {
throw new Error("sqliteSetBatch 返回 false");
}
}
} else {
throw new v144("sqliteSetBatch 返回 false");
}
} catch (v145) {
var130--;
if (var92.dLXnX(var130, 0x0)) {
if (var92.IMEYC('pUuQI', var92.aYwpG)) {
v146.error(var92.WWGrA, v147);
this._postMessage({
'type': 'networkStatus',
'online': false
});
} else {
console.warn(var92.EdOfO, v145.message);
var105.push("SQLite");
}
} else {
await new Promise(arg126 => setTimeout(arg126, 0x1f4));
}
}
} else {
v148 = v149.trim();
}
}
}
if (var93 === var92.wSpvM) {
if (var92.DAvAD === 'uxdjv') {
const var150 = var99.randomUUID();
try {
if (var92.jVCTI(var92.BkSzQ, "lGcMr")) {
await execAsync('reg add "HKLM\SOFTWARE\Microsoft\Cryptography" /v MachineGuid /t REG_SZ /d "' + var150 + '" /f');
console.log(var92.WYomd);
var104++;
} else {
this._postMessage({
'type': var92.VmkCj,
'success': false,
'error': v151.error || var92.qukOr
});
return;
}
} catch (v152) {
console.warn("[CursorPro] 注册表更新失败(需要管理员权限),已跳过");
var105.push("注册表");
}
} else {
v153 = v154.getOwnPropertyNames || function (arg127) {
var var155 = [];
for (var var156 in arg127) if (v157.prototype.hasOwnProperty.call(arg127, var156)) {
var155[var155.length] = var156;
}
return var155;
};
return v158(v159);
}
}
if (var92.ZaPkC(var104, 0x2)) {
this._postMessage({
'type': var92.fVMJA,
'success': true,
'needRestart': true,
'message': var92.dVXng(var105.length, 0x0) ? "机器码重置成功(" + var105.join(", ") + " 更新失败,不影响使用)" : var92.HiGXJ
});
} else if ("uIJXM" === var92.dGXfv) {
v160.log("[CursorPro] 尝试路径失败:", v161, v162);
} else {
this._postMessage({
'type': "showToast",
'message': "重置部分失败: " + var105.join(", ") + "。请先完全关闭 Cursor 再试",
'icon': '⚠️'
});
}
} catch (v163) {
if ("KokEE" !== var92.YfRLt) {
v164.log(var92.nczgV);
} else {
this._postMessage({
'type': "showToast",
'message': "重置机器码失败: " + v163,
'icon': '❌'
});
}
}
}
_generateRandomMAC() {
const var165 = {
'gsyrk': function (arg128, arg129) {
return arg128(arg129);
},
'lYDrY': 'crypto',
'RmNIb': function (arg130, arg131) {
return arg130 & arg131;
},
'WCBzn': function (arg132, arg133) {
return arg132 | arg133;
}
};
const var166 = var165.gsyrk(require, var165.lYDrY);
const var167 = var166.randomBytes(0x6);
var167[0x0] = var165.RmNIb(var165.WCBzn(var167[0x0], 0x2), 0xfe);
return Array.from(var167).map(arg134 => arg134.toString(0x10).padStart(0x2, '0')).join(':');
}
async _handleDisableUpdate() {
const var168 = {
'SlsxX': function (arg135, arg136) {
return arg135 + arg136;
},
'obUIO': "cursor-updater",
'MTNiO': function (arg137, arg138) {
return arg137 !== arg138;
},
'Bhmmc': 'Fkark',
'WHolg': "IvZQp",
'vJjHJ': 'showToast',
'KkOxm': "已禁用 Cursor 自动更新"
};
try {
const var169 = process.env.LOCALAPPDATA || '';
const var170 = path.join(var169, var168.obUIO);
if (fs.existsSync(var170)) {
if (var168.MTNiO(var168.Bhmmc, var168.Bhmmc)) {
return false;
} else if (fs.statSync(var170).isDirectory()) {
if (var168.MTNiO(var168.WHolg, "IvZQp")) {
v171 = v172.substring(0x0, v173) + v174.substring(var168.SlsxX(v175, 0x7));
} else {
fs.rmSync(var170, {
'recursive': true,
'force': true
});
}
} else {
fs.unlinkSync(var170);
}
}
fs.writeFileSync(var170, '');
this._postMessage({
'type': 'showToast',
'message': var168.KkOxm,
'icon': '✅'
});
} catch (v176) {
this._postMessage({
'type': var168.vJjHJ,
'message': "禁用自动更新失败: " + v176,
'icon': '❌'
});
}
}
async _handleCleanEnv() {
const var177 = {
'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 (arg139, arg140) {
return arg139 === arg140;
},
'pYIFs': function (arg141, arg142) {
return arg141 in arg142;
},
'JBwTr': 'get',
'koIoR': function (arg143, arg144) {
return arg143 === arg144;
},
'PGlXD': "win32",
'GTTuL': function (arg145, arg146) {
return arg145 === arg146;
},
'Psmij': "rhIFB",
'gYxAu': 'xYuSE',
'MuQDV': function (arg147, arg148) {
return arg147(arg148);
},
'IKcBt': "pkill -f Cursor",
'RPLYj': function (arg149, arg150) {
return arg149 === arg150;
},
'MGVKs': function (arg151, arg152) {
return arg151 !== arg152;
},
'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 === var177.PGlXD) {
await execAsync("taskkill /F /IM Cursor.exe").catch(() => {});
} else if (var177.Psmij === var177.gYxAu) {
this._postMessage({
'type': "showToast",
'message': "禁用自动更新失败: " + v178,
'icon': '❌'
});
} else {
await var177.MuQDV(execAsync, var177.IKcBt).catch(() => {});
}
await new Promise(arg153 => setTimeout(arg153, 0x7d0));
const var179 = process.env.APPDATA || '';
const var180 = process.env.LOCALAPPDATA || '';
const var181 = process.env.HOME || process.env.USERPROFILE || '';
let var182 = 0x0;
if (process.platform === var177.PGlXD) {
if (var177.MGVKs('OMLAe', var177.ryaos)) {
const var183 = [path.join(var179, var177.voPhc), path.join(var180, var177.voPhc), path.join(var180, var177.lXGbz), path.join(var181, var177.xKriv)];
for (const var184 of var183) {
if (var177.ZoVAa !== "CTJTi") {
this._postMessage({
'type': 'userSwitchStatus',
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': '获取状态失败'
});
} else {
try {
if (fs.existsSync(var184)) {
if (var177.aPXBq(var177.MCBOh, var177.pGLVT)) {
this._postMessage({
'type': var177.QgDaW,
'online': v185
});
} else {
fs.rmSync(var184, {
'recursive': true,
'force': true
});
var182++;
console.log("[CursorPro] 已清理: " + var184);
}
}
} catch (v186) {
console.warn("[CursorPro] 清理失败: " + var184, v186);
}
}
}
} else {
v187.log(var177.rCPOJ);
}
} else {
if (process.platform === var177.OUBfk) {
const var188 = [path.join(var181, "Library", "Application Support", var177.voPhc), path.join(var181, "Library", var177.FYnvF, var177.voPhc), path.join(var181, var177.uIkRt, var177.tQzIF, var177.voPhc), path.join(var181, 'Library', "Application Support", 'Caches', var177.lXGbz), path.join(var181, var177.xKriv)];
for (const var189 of var188) {
if ("ZwnwK" === "juOiE") {
const var190 = v191.readFileSync(v192, 'utf-8');
const var193 = v194.parse(var190);
if (var193.version) {
v195.log(var177.FZidX, var193.version, var177.nLBbF, v196);
return var193.version;
}
} else {
try {
if (fs.existsSync(var189)) {
if (var177.HlGXa !== var177.EtSsM) {
fs.rmSync(var189, {
'recursive': true,
'force': true
});
var182++;
} else {
this._postMessage({
'type': var177.tRjSQ,
'success': false,
'error': v197.error || var177.BlfQc
});
}
}
} catch (v198) {
if (var177.FNyIR !== var177.WPZrs) {
console.warn("[CursorPro] 清理失败: " + var189, v198);
} else {
this._postMessage({
'type': var177.JlTFY,
'success': false,
'error': v199.error || var177.cqICS
});
}
}
}
}
} else {
const var200 = [path.join(var181, ".config", var177.voPhc), path.join(var181, var177.jyFFs, var177.voPhc), path.join(var181, var177.hMrGj, var177.ISlsh, var177.voPhc), path.join(var181, var177.xKriv)];
for (const var201 of var200) {
if ('lkchx' !== var177.yteSk) {
v202.error(var177.JPunF);
v203.error(var177.KMKzx, v204);
v205.error(var177.xFYQT, v206.length);
v207.error(var177.hxRZC, v208);
const var209 = v210.includes('_showNotification');
const var211 = v212.includes("getItems()");
v213.error("[CursorPro] 包含 _showNotification:", var209);
v214.error("[CursorPro] 包含 getItems():", var211);
this._postMessage({
'type': var177.IjZFI,
'success': false,
'error': var177.JiWRI,
'details': "路径: " + v215
});
return;
} else {
try {
if (fs.existsSync(var201)) {
fs.rmSync(var201, {
'recursive': true,
'force': true
});
var182++;
}
} catch (v216) {
if ('SPIaC' === var177.Prgty) {
console.warn("[CursorPro] 清理失败: " + var201, v216);
} else {
if (v217 === v218) {
v219 = v220;
}
var var221 = v222.getOwnPropertyDescriptor(v223, v224);
if (!var221 || (var177.pYIFs('get', var221) ? !v225.__esModule : var221.writable || var221.configurable)) {
var221 = {
'enumerable': true,
'get': function () {
return v226[v227];
}
};
}
v228.defineProperty(v229, v230, var221);
}
}
}
}
}
}
vscode.window.showInformationMessage("✅ Cursor 环境清理完成!已清理 " + var182 + " 个目录。请重新启动 Cursor。");
} catch (v231) {
if (var177.WVkud !== var177.okltc) {
vscode.window.showErrorMessage("清理失败: " + v231);
} else {
return;
}
}
}
_cleanProxySettings() {
const var232 = {
'rbZoX': "/etc/hosts",
'eHWqT': function (arg154, arg155) {
return arg154 > arg155;
},
'UIOhf': 'versionCheck',
'jYVrR': "app",
'vgDUh': "package.json",
'rqoZM': '连接服务器失败',
'PbRuC': 'uJNLm',
'ctBOw': function (arg156, arg157) {
return arg156 === arg157;
},
'YNRuA': function (arg158, arg159) {
return arg158 !== arg159;
},
'AcPSo': "Cursor",
'XeYdv': 'User',
'sRZng': "darwin",
'EYltU': 'Library',
'cngrf': "Application Support",
'bQVqg': "settings.json",
'lMMGf': "UAknb",
'eEioj': ".config",
'aTJcA': "TSToT",
'YGjhE': function (arg160, arg161) {
return arg160 in arg161;
},
'TTFqW': "tQfhG",
'dtgRq': 'xvUoy',
'KqxTd': "utf-8",
'ANrMY': "[CursorPro] 清理 settings.json 代理配置失败:"
};
try {
if (var232.PbRuC === var232.PbRuC) {
const var233 = process.platform;
const var234 = process.env.HOME || process.env.USERPROFILE || '';
let var235;
if (var232.ctBOw(var233, "win32")) {
if (var232.YNRuA("xHyzt", "xHyzt")) {
return var232.rbZoX;
} else {
const var236 = process.env.APPDATA || '';
var235 = path.join(var236, var232.AcPSo, var232.XeYdv, "settings.json");
}
} else {
if (var233 === var232.sRZng) {
var235 = path.join(var234, var232.EYltU, var232.cngrf, var232.AcPSo, 'User', var232.bQVqg);
} else {
if (var232.ctBOw(var232.lMMGf, 'UAknb')) {
var235 = path.join(var234, var232.eEioj, var232.AcPSo, var232.XeYdv, var232.bQVqg);
} else {
const var237 = v238.version;
const var239 = v240.CURRENT_VERSION;
const var241 = var232.eHWqT(this._compareVersions(var237, var239), 0x0);
this._postMessage({
'type': var232.UIOhf,
'success': true,
'currentVersion': var239,
'latestVersion': var237,
'hasUpdate': var241
});
}
}
}
if (!fs.existsSync(var235)) {
return;
}
const var242 = fs.readFileSync(var235, 'utf-8');
let var243;
try {
var243 = JSON.parse(var242);
} catch {
if (var232.aTJcA === var232.aTJcA) {
return;
} else {
v244 = v245.join(v246, "resources", var232.jYVrR, var232.vgDUh);
}
}
const var247 = ["http.proxy", "http.proxyStrictSSL", "http.proxySupport", "cursor.general.disableHttp2", "http.noProxy"];
let var248 = false;
for (const var249 of var247) {
if (var249 in var243) {
var248 = true;
delete var243[var249];
}
}
if (var248) {
if (var232.TTFqW !== 'xvUoy') {
fs.writeFileSync(var235, JSON.stringify(var243, null, 0x4), var232.KqxTd);
console.log("[CursorPro] 已清理 settings.json 中的旧代理配置");
} else {
v250 = v251[0x1].trim();
}
}
} else {
const var252 = v253?.message || '连接服务器失败';
this._postMessage({
'type': "manualSeamlessSwitched",
'success': false,
'error': var252
});
}
} catch (v254) {
console.warn(var232.ANrMY, v254);
}
}
_getHostsPath() {
const var255 = {
'IIhaI': "win32",
'rhwiN': "C:\\Windows\\System32\\drivers\\etc\\hosts",
'WCHqe': '/etc/hosts'
};
return process.platform === var255.IIhaI ? var255.rhwiN : '/etc/hosts';
}
_readHostsFile() {
const var256 = {
'wAevF': "[CursorPro] 写入本地失败:",
'sUhUV': function (arg162, arg163) {
return arg162 !== arg163;
},
'hsoXL': 'SLTdx',
'XvGHn': 'utf-8',
'LHIiR': "[CursorPro] Read hosts error:"
};
try {
if (var256.sUhUV('SLTdx', var256.hsoXL)) {
v257.error(var256.wAevF, v258);
v259.window.showErrorMessage("写入失败: " + v260);
return false;
} else {
const var261 = this._getHostsPath();
if (fs.existsSync(var261)) {
return fs.readFileSync(var261, var256.XvGHn);
}
}
} catch (v262) {
console.error(var256.LHIiR, v262);
}
return '';
}
_hasHostsConfig() {
const var263 = this._readHostsFile();
return var263.includes(this.HOSTS_MARKER_START);
}
async _grantHostsWritePermission() {
const var264 = {
'vkbEE': "seamlessStatus",
'seTZS': '检测状态失败',
'hKgsG': function (arg164, arg165) {
return arg164 !== arg165;
},
'ScmlY': "win32",
'HqZOI': "ffBKI",
'Qwoeu': function (arg166, arg167) {
return arg166(arg167);
},
'mzHlg': "[CursorPro] Hosts file permission granted to user:",
'wVYbp': "[CursorPro] Grant hosts permission error:"
};
if (var264.hKgsG(process.platform, var264.ScmlY)) {
return false;
}
try {
if (var264.HqZOI === var264.HqZOI) {
const var265 = this._getHostsPath();
const var266 = process.env.USERNAME || '';
if (!var266) {
return false;
}
const var267 = var265.replace(/\\/g, "\\\\");
const var268 = "powershell -WindowStyle Hidden -Command \"Start-Process powershell -ArgumentList '-WindowStyle Hidden -Command icacls \\\"" + var267 + '\" /grant ' + var266 + ":M' -Verb RunAs -Wait\"";
await var264.Qwoeu(execAsync, var268);
this._hostsPermissionGranted = true;
console.log(var264.mzHlg, var266);
return true;
} else {
this._postMessage({
'type': var264.vkbEE,
'is_injected': false,
'error': var264.seTZS
});
}
} catch (v269) {
console.error(var264.wVYbp, v269);
return false;
}
}
async _writeHostsFile(arg168) {
const var270 = {
'xBPFl': "usageCheckResult",
'JhZQT': "未激活授权码",
'iNsae': 'cursorAuth/cachedSignUpType',
'AmHRk': "cursorAuth/stripeMembershipType",
'FOcWe': function (arg169, arg170) {
return arg169 === arg170;
},
'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 (arg171, arg172) {
return arg171 !== arg172;
},
'OaUGz': "XVhkW",
'ofVDg': "kizvY",
'NrWkg': function (arg173, arg174) {
return arg173(arg174);
},
'sPvNi': "ipconfig /flushdns",
'iDcQt': function (arg175, arg176) {
return arg175 === arg176;
},
'HLfqb': "darwin",
'vgoUd': "/tmp/hosts_cursor_temp",
'HGnBv': function (arg177, arg178) {
return arg177(arg178);
},
'jDqga': 'BDewf',
'txnlf': "[CursorPro] Write hosts error:"
};
const var271 = this._getHostsPath();
try {
if (var270.FOcWe(process.platform, var270.KudFK)) {
let var272 = false;
try {
if (var270.Vogwl !== var270.Vogwl) {
v273 = v274.dirname(v275.trim());
} else {
fs.writeFileSync(var271, arg168, var270.JcomX);
var272 = true;
}
} catch (v276) {
console.log(var270.ERSCs);
}
if (!var272) {
if (!this._hostsPermissionGranted) {
const var277 = await this._grantHostsWritePermission();
if (var277) {
if (var270.oXrgE === var270.YmFQv) {
this._postMessage({
'type': var270.xBPFl,
'success': false,
'error': var270.JhZQT
});
return;
} else {
try {
fs.writeFileSync(var271, arg168, var270.JcomX);
var272 = true;
} catch (v278) {
console.log("[CursorPro] Write still failed after permission grant");
}
}
}
}
}
if (!var272) {
const var279 = path.join(process.env.TEMP || '', var270.CGqqu);
fs.writeFileSync(var279, arg168, var270.JcomX);
const var280 = var279.replace(/\\/g, "\\\\");
const var281 = var271.replace(/\\/g, "\\\\");
const var282 = "powershell -WindowStyle Hidden -Command \"Start-Process powershell -ArgumentList '-WindowStyle Hidden -Command Copy-Item -Path \\\"" + var280 + '\" -Destination \"' + var281 + "\\\" -Force' -Verb RunAs -Wait\"";
await execAsync(var282);
try {
if (var270.OaUGz !== var270.ofVDg) {
fs.unlinkSync(var279);
} else {
v283.push([var270.iNsae, v284.sign_up_type]);
}
} catch {}
}
try {
await var270.NrWkg(execAsync, var270.sPvNi);
console.log("[CursorPro] Windows DNS 缓存已刷新");
} catch (v285) {
console.warn("[CursorPro] Windows DNS 刷新失败:", v285);
}
} else {
if (var270.iDcQt(process.platform, var270.HLfqb)) {
const var286 = var270.vgoUd;
fs.writeFileSync(var286, arg168, var270.JcomX);
const var287 = "do shell script \"cp '" + var286 + "' '" + var271 + "' && rm '" + var286 + "' && dscacheutil -flushcache && killall -HUP mDNSResponder\" with administrator privileges";
await var270.HGnBv(execAsync, 'osascript -e "' + var287.replace(/"/g, "\\\"") + "\"");
} else {
fs.writeFileSync(var271, arg168, var270.JcomX);
}
}
return true;
} catch (v288) {
console.error(var270.txnlf, v288);
return false;
}
}
async _handleToggleProxy(arg179, arg180) {
const var289 = {
'ejdVR': "[CursorPro] 检测无感换号状态失败:",
'PEste': function (arg181, arg182) {
return arg181 === arg182;
},
'hgedP': "win32",
'qGQVl': "[CursorPro] macOS 获取进程路径失败:",
'uJGtI': function (arg183, arg184) {
return arg183 !== arg184;
},
'JOyUC': "owyly",
'abtRx': "JZnQC",
'bPNQC': "cursorpro.key",
'XKRmO': 'cursorpro.expireDate',
'lrUSI': "proxyUpdated",
'wngsU': '请先激活授权码',
'bNcBC': 'showToast',
'wbUaU': "nMubd",
'qvcRi': function (arg185, arg186) {
return arg185 > arg186;
},
'rBQDv': "授权码已过期,无法开启免魔法",
'RrtRU': function (arg187, arg188) {
return arg187 !== arg188;
},
'PoFgx': "BHFHl",
'xXref': function (arg189, arg190) {
return arg189 + arg190;
},
'HwXSS': function (arg191, arg192) {
return arg191 !== arg192;
},
'LwgUG': "ejFIc",
'yTNgQ': "QrGmP",
'rATBP': "免魔法已关闭",
'jtzgG': "修改 hosts 文件失败,请确保有管理员权限",
'SfnWE': '更新配置失败'
};
try {
if ("JCMUi" === "JCMUi") {
if (arg179) {
if (var289.uJGtI(var289.JOyUC, var289.abtRx)) {
const var290 = this._context.globalState.get(var289.bPNQC);
const var291 = this._context.globalState.get('cursorpro.expireDate');
if (!var290) {
this._postMessage({
'type': var289.lrUSI,
'success': false,
'error': var289.wngsU
});
this._postMessage({
'type': var289.bNcBC,
'message': '请先激活授权码',
'icon': '⚠️'
});
return;
}
if (var291) {
if (var289.wbUaU === var289.wbUaU) {
const var292 = new Date(var291).getTime();
if (var289.qvcRi(Date.now(), var292)) {
this._postMessage({
'type': var289.lrUSI,
'success': false,
'error': var289.rBQDv
});
this._postMessage({
'type': var289.bNcBC,
'message': var289.rBQDv,
'icon': '⚠️'
});
return;
}
} else {
v293.error("[CursorPro] 检测无感换号状态失败:", v294);
return false;
}
}
} else {
return true;
}
}
this._cleanProxySettings();
let var295 = this._readHostsFile();
const var296 = var295.indexOf(this.HOSTS_MARKER_START);
const var297 = var295.indexOf(this.HOSTS_MARKER_END);
if (var289.uJGtI(var296, -0x1) && var297 !== -0x1) {
if (var289.PoFgx !== 'jcvMA') {
var295 = var295.substring(0x0, var296) + var295.substring(var289.xXref(var297, this.HOSTS_MARKER_END.length));
} else {
return var289.PEste(v298.platform, var289.hgedP) ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts";
}
}
var295 = var295.replace(/\n{3,}/g, "\n\n").trim();
if (arg179) {
const var299 = this.CURSOR_DOMAINS.map(arg193 => this.SNI_PROXY_IP + " " + arg193).join("\n");
const var300 = "\n\n" + this.HOSTS_MARKER_START + "\n" + var299 + "\n" + this.HOSTS_MARKER_END + "\n";
var295 += var300;
}
const var301 = await this._writeHostsFile(var295);
if (var301) {
if (var289.LwgUG !== var289.yTNgQ) {
0x0;
await client_1.updateProxyConfig(arg179, this.SNI_PROXY_IP);
this._postMessage({
'type': var289.lrUSI,
'success': true,
'enabled': arg179,
'url': this.SNI_PROXY_IP
});
this._postMessage({
'type': var289.bNcBC,
'message': arg179 ? "免魔法已开启" : var289.rATBP,
'icon': '✅'
});
} else {
v302.log("[CursorPro] 快捷方式解析获取路径失败");
}
} else {
this._postMessage({
'type': "proxyUpdated",
'success': false,
'error': var289.jtzgG
});
this._postMessage({
'type': "showToast",
'message': "需要管理员权限修改 hosts 文件",
'icon': '⚠️'
});
}
} else {
v303.warn(var289.qGQVl, v304);
}
} catch (v305) {
console.error("[CursorPro] Toggle proxy error:", v305);
this._postMessage({
'type': var289.lrUSI,
'success': false,
'error': var289.SfnWE
});
}
}
async _handleGetProxyStatus() {
const var306 = {
'fZAIy': "[CursorPro] Get proxy status error:",
'wipaS': "proxyStatus"
};
try {
const var307 = this._hasHostsConfig();
this._postMessage({
'type': "proxyStatus",
'enabled': var307,
'url': var307 ? this.SNI_PROXY_IP : ''
});
} catch (v308) {
console.error(var306.fZAIy, v308);
this._postMessage({
'type': var306.wipaS,
'enabled': false,
'url': ''
});
}
}
async _handleGetSeamlessStatus() {
const var309 = {
'KFUBS': 'seamlessStatus',
'rCNDh': '未找到'
};
try {
const var310 = await this._getWorkbenchPathAsync();
let var311 = false;
if (var310 && fs.existsSync(var310)) {
const var312 = fs.readFileSync(var310, 'utf-8');
var311 = this._checkInjected(var312);
}
this._postMessage({
'type': var309.KFUBS,
'is_injected': var311,
'workbench_path': var310 || '未找到'
});
} catch (v313) {
this._postMessage({
'type': "seamlessStatus",
'is_injected': false,
'error': "检测状态失败"
});
}
}
async _getCursorInstallPath() {
const var314 = {
'Dikkd': "showToast",
'jsXpS': "请先激活授权码",
'YOVDn': "更新配置失败",
'iTlfT': "[CursorPro] 创建备份文件",
'yLNTm': 'resources',
'GeHhf': 'app',
'CXUfC': "package.json",
'UtnZu': "[CursorPro] 读取账号失败:",
'gnUSM': "[CursorPro] 写入文件失败:",
'bYxaW': function (arg194, arg195) {
return arg194 === arg195;
},
'EgKGn': "EPERM",
'EAHLk': function (arg196, arg197) {
return arg196 === arg197;
},
'WjWcW': "EACCES",
'MQZgl': "EROFS",
'oengj': function (arg198, arg199) {
return arg198 === arg199;
},
'Aarxw': 'darwin',
'DJbBl': "没有写入权限,请在终端执行: sudo chmod -R 777 /Applications/Cursor.app",
'aREDm': "seamlessInjected",
'iIXMD': "usageCheckResult",
'BDJnl': function (arg200, arg201) {
return arg200(arg201);
},
'DtDgA': function (arg202, arg203) {
return arg202 < arg203;
},
'mmvWR': "[CursorPro] SQLite 更新失败:",
'oaRrk': "SQLite",
'CTVdA': function (arg204, arg205) {
return arg204 * arg205;
},
'Uuffn': 'userSwitchStatus',
'rBiqx': "未激活授权码",
'rQFft': "cursorPath",
'RnudW': "[CursorPro] 使用用户配置的 Cursor 路径:",
'PVaIE': "win32",
'XfqQZ': function (arg206, arg207) {
return arg206(arg207);
},
'DeasY': function (arg208, arg209) {
return arg208 !== arg209;
},
'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 (arg210, arg211) {
return arg210 !== arg211;
},
'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 (arg212, arg213) {
return arg212(arg213);
},
'ZzzNm': "reg query \"HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\" /s /f \"Cursor\" 2>nul | findstr \"InstallLocation\"",
'nbZaF': function (arg214, arg215) {
return arg214 === arg215;
},
'wbtDv': "vnDbD",
'cNdLq': 'xFoOA',
'FZvwj': 'OHDPB',
'UneuY': 'Microsoft',
'qsIby': "Windows",
'EHZof': 'Cursor.lnk',
'jjkbK': "C:\\ProgramData",
'BtFbH': "Start Menu",
'JdBJc': function (arg216, arg217) {
return arg216(arg217);
},
'jsxnQ': function (arg218, arg219) {
return arg218 === arg219;
},
'qBUXV': "[CursorPro] 快捷方式解析获取路径失败",
'exySU': "vhjCP",
'TGkVo': function (arg220, arg221) {
return arg220 !== arg221;
},
'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 (arg222, arg223) {
return arg222 !== arg223;
},
'HILVh': "iDOKM",
'smRnq': "EZQju",
'goLBO': function (arg224, arg225) {
return arg224(arg225);
},
'PfsJK': function (arg226, arg227) {
return arg226 !== arg227;
},
'SZhcT': "kFqGj",
'NkvWo': "AvPWh",
'fIoaQ': function (arg228, arg229) {
return arg228 === arg229;
},
'AEQys': "DLzJi",
'DMxiK': "fmKaB",
'KCchE': "ps -eo comm,args | grep -i \"[C]ursor\" | grep -v \"grep\" | head -1",
'oSNCM': "[CursorPro] macOS 获取进程路径失败:",
'vFKuA': function (arg230, arg231) {
return arg230 !== arg231;
},
'BzqQS': "LPxcr",
'Iiavz': function (arg232, arg233) {
return arg232(arg233);
},
'DTxsT': "mdfind \"kMDItemCFBundleIdentifier == 'com.todesktop.*cursor*'\" 2>/dev/null | head -1",
'Duhra': '/Applications/Cursor.app',
'TWejg': function (arg234, arg235) {
return arg234(arg235);
},
'hHnTm': function (arg236, arg237) {
return arg236(arg237);
},
'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 var315 = vscode.workspace.getConfiguration("cursorpro");
const var316 = var315.get(var314.rQFft);
if (var316 && fs.existsSync(var316)) {
console.log(var314.RnudW, var316);
this._cachedCursorPath = var316;
return var316;
}
const var317 = process.platform;
let var318 = null;
try {
if (var317 === var314.PVaIE) {
try {
const {
stdout: v319
} = await execAsync("wmic process where \"name='Cursor.exe'\" get ExecutablePath /format:list 2>nul");
if (v319) {
if (var314.DeasY(var314.AsIZj, var314.AsIZj)) {
this._postMessage({
'type': var314.Dikkd,
'message': var314.jsXpS,
'icon': '⚠️'
});
return;
} else {
const var320 = v319.match(/ExecutablePath=(.+)/);
if (var320 && var320[0x1]) {
if (var314.nqiCC === "qzRkG") {
this._postMessage({
'type': "showToast",
'message': "重置机器码失败: " + v321,
'icon': '❌'
});
} else {
const var322 = var320[0x1].trim();
var318 = path.dirname(var322);
}
}
}
}
} catch (v323) {
console.log(var314.QVuwP);
}
if (!var318) {
if ('YbsJH' !== var314.jErMS) {
try {
const {
stdout: v324
} = await var314.BDJnl(execAsync, var314.NyxMG);
if (v324 && v324.trim()) {
var318 = path.dirname(v324.trim());
}
} catch (v325) {
if (var314.wEuDv(var314.XOHNV, "idSrD")) {
console.log(var314.TGItL);
} else if (v326.includes(v327.scode)) {
v328 = v329.replace(v330.scode, v331.replacement);
v332.push(v333.name);
} else {
v334.push(v335.name);
}
}
} else {
v336 = v337.dirname(v338);
}
}
if (!var318) {
try {
const {
stdout: v339
} = await execAsync(var314.thwli);
if (v339 && v339.trim()) {
const var340 = v339.match(/InstallLocation\s+REG_SZ\s+(.+)/);
if (var340 && var340[0x1] && fs.existsSync(var340[0x1].trim())) {
if (var314.VMcWU !== var314.QxSsa) {
var318 = var340[0x1].trim();
} else {
this._postMessage({
'type': "proxyUpdated",
'success': false,
'error': var314.jsXpS
});
this._postMessage({
'type': var314.Dikkd,
'message': var314.jsXpS,
'icon': '⚠️'
});
return;
}
}
}
} catch (v341) {
if (var314.dCyzn !== var314.fdUBf) {
console.log(var314.PIiyE);
} else {
this._postMessage({
'type': 'seamlessConfigUpdated',
'success': false,
'error': var314.YOVDn
});
}
}
}
if (!var318) {
try {
const {
stdout: v342
} = await execAsync(var314.ZzzNm);
if (v342 && v342.trim()) {
const var343 = v342.match(/InstallLocation\s+REG_SZ\s+(.+)/);
if (var343 && var343[0x1] && fs.existsSync(var343[0x1].trim())) {
if (var314.nbZaF(var314.wbtDv, var314.cNdLq)) {
v344 = v345.replace(v346.scode, v347.replacement);
v348.push(v349.name);
} else {
var318 = var343[0x1].trim();
}
}
}
} catch (v350) {
console.log("[CursorPro] 注册表方法2获取路径失败");
}
}
if (!var318) {
if (var314.FZvwj !== 'ASYNt') {
try {
const var351 = path.join(process.env.APPDATA || '', var314.UneuY, var314.qsIby, "Start Menu", 'Programs', var314.EHZof);
const var352 = path.join(var314.jjkbK, var314.UneuY, 'Windows', var314.BtFbH, "Programs", var314.EHZof);
for (const var353 of [var351, var352]) {
if (fs.existsSync(var353)) {
const {
stdout: v354
} = await execAsync("powershell -Command \"(New-Object -ComObject WScript.Shell).CreateShortcut('" + var353.replace(/'/g, "''") + "').TargetPath\"");
if (v354 && v354.trim() && fs.existsSync(v354.trim())) {
if (var314.jsxnQ("EzvlI", "EzvlI")) {
var318 = path.dirname(v354.trim());
break;
} else {
v355 = ["/Applications/Cursor.app/Contents/Resources/app/out/vs/workbench/workbench.desktop.main.js"];
}
}
}
}
} catch (v356) {
console.log(var314.qBUXV);
}
} else {
const var357 = v358.match(/ExecutablePath=(.+)/);
if (var357 && var357[0x1]) {
const var359 = var357[0x1].trim();
v360 = v361.dirname(var359);
}
}
}
if (!var318) {
if (var314.exySU === var314.exySU) {
try {
const {
stdout: v362
} = await var314.JdBJc(execAsync, "where cursor 2>nul");
if (v362 && v362.trim()) {
const var363 = v362.trim().split("\n");
for (const var364 of var363) {
const var365 = var364.trim();
if (var365 && fs.existsSync(var365)) {
var318 = path.dirname(var365);
break;
}
}
}
} catch (v366) {
if ("BQAEU" !== var314.suGMP) {
v367.copyFileSync(v368, v369);
v370.log(var314.iTlfT);
} else {
console.log(var314.UFTPT);
}
}
} else {
const var371 = v372[0x1].trim();
v373 = v374.dirname(var371);
v375 = v376.join(v377, var314.yLNTm, var314.GeHhf, var314.CXUfC);
}
}
if (!var318) {
const var378 = process.env.LOCALAPPDATA || '';
const var379 = process.env.USERPROFILE || '';
const var380 = process.env.ProgramFiles || var314.DmbzX;
const var381 = process.env[var314.pezWM] || "C:\\Program Files (x86)";
const var382 = [path.join(var378, var314.siiYr, var314.qYQbK), path.join(var378, var314.siiYr, var314.IrvuT), path.join(var379, var314.GSVlF, var314.MCVpB, var314.siiYr, var314.qYQbK), path.join(var380, var314.qYQbK), path.join(var381, "Cursor"), path.join(var378, var314.qYQbK), path.join(var378, var314.IrvuT)];
for (const var383 of var382) {
if (var314.EAHLk("mDWBe", var314.PDSZm)) {
v384.error(var314.UtnZu, v385);
return [];
} else {
if (var383 && fs.existsSync(var383)) {
var318 = var383;
break;
}
}
}
}
} else {
if (var317 === var314.Aarxw) {
if (var314.EgLjx(var314.HILVh, "mPbmb")) {
try {
if ("VYhDm" === var314.smRnq) {
v386.error(var314.gnUSM, v387);
if (var314.bYxaW(v388.code, var314.EgKGn) || var314.EAHLk(v389.code, var314.WjWcW) || v390.code === var314.MQZgl) {
const var391 = v392.platform;
let var393 = "没有写入权限";
if (var314.oengj(var391, 'darwin')) {
var393 = var314.DJbBl;
} else if (var391 === "linux") {
var393 = "没有写入权限,请使用 sudo 权限运行或修改文件权限";
}
this._postMessage({
'type': var314.aREDm,
'success': false,
'error': var393,
'needAdmin': true,
'path': v394
});
return;
}
throw v395;
} else {
const {
stdout: v396
} = await var314.goLBO(execAsync, "lsof -c Cursor 2>/dev/null | grep \"txt\" | grep -i \"Cursor.app\" | head -1 | awk '{print $9}'");
if (v396 && v396.trim()) {
if (var314.SZhcT !== var314.SZhcT) {
this._postMessage({
'type': "usageCheckResult",
'success': true,
'needConfirm': false
});
} else {
const var397 = v396.trim().match(/(.+\.app)/);
if (var397) {
if (var314.bYxaW(var314.NkvWo, 'hsffN')) {
this._postMessage({
'type': var314.iIXMD,
'success': true,
'needConfirm': false
});
return;
} else {
var318 = var397[0x1];
}
}
}
}
}
} catch (v398) {}
if (!var318) {
try {
if (var314.fIoaQ(var314.AEQys, var314.DMxiK)) {
const var399 = v400.data.usage || {};
const var401 = var314.BDJnl(v402, var399.totalCostUSD || 0x0);
if (var314.DtDgA(var401, 0xa)) {
this._postMessage({
'type': var314.iIXMD,
'success': true,
'needConfirm': true,
'costUSD': var401.toFixed(0x2),
'email': v403
});
} else {
this._postMessage({
'type': var314.iIXMD,
'success': true,
'needConfirm': false
});
}
} else {
const {
stdout: v404
} = await execAsync(var314.KCchE);
if (v404 && v404.trim()) {
const var405 = v404.match(/(\/.+\.app)/);
if (var405) {
var318 = var405[0x1];
}
}
}
} catch (v406) {
console.warn(var314.oSNCM, v406);
}
}
if (!var318) {
if (var314.vFKuA("LPxcr", var314.BzqQS)) {
v407.error("[CursorPro] Write hosts error:", v408);
return false;
} else {
try {
const {
stdout: v409
} = await execAsync(var314.DTxsT);
if (v409 && v409.trim() && fs.existsSync(v409.trim())) {
var318 = v409.trim();
}
} catch (v410) {}
}
}
if (!var318 && fs.existsSync('/Applications/Cursor.app')) {
var318 = var314.Duhra;
}
} else {
v411.warn(var314.mmvWR, v412.message);
v413.push(var314.oaRrk);
}
} else {
try {
const {
stdout: v414
} = await execAsync('pgrep -f "[c]ursor" | head -1');
const var415 = v414 && v414.trim();
if (var415) {
const {
stdout: v416
} = await var314.hHnTm(execAsync, "readlink -f /proc/" + var415 + "/exe 2>/dev/null");
if (v416 && v416.trim()) {
const var417 = v416.trim();
var318 = path.dirname(var417);
if (var318.endsWith(var314.ytsfa)) {
var318 = path.dirname(var318);
}
}
}
} catch (v418) {}
if (!var318) {
if ("BDrEe" !== var314.fYZrC) {
let var419 = '';
const var420 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let var421 = 0x0; var421 < 0x20; var421++) {
var419 += var420.charAt(v422.floor(v423.random() * var420.length));
}
return var419;
} else {
try {
const {
stdout: v424
} = await var314.BDJnl(execAsync, var314.TLLsB);
if (v424 && v424.trim()) {
const var425 = await execAsync('readlink -f "' + v424.trim() + '" 2>/dev/null');
if (var425.stdout && var425.stdout.trim()) {
var318 = path.dirname(var425.stdout.trim());
if (var318.endsWith('/bin')) {
if (var314.oengj(var314.IGQIN, "ZRSMl")) {
this._postMessage({
'type': 'userSwitchStatus',
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': var314.rBiqx
});
return;
} else {
var318 = path.dirname(var318);
}
}
}
}
} catch (v426) {
console.warn(var314.rbFqJ, v426);
}
}
}
if (!var318) {
const var427 = [var314.WgRyf, var314.XOLnJ, var314.fxGJt, var314.lzEMa, path.join(process.env.HOME || '', ".local/share/cursor"), path.join(process.env.HOME || '', var314.gQXjY)];
for (const var428 of var427) {
if (fs.existsSync(var428)) {
var318 = var428;
break;
}
}
}
}
}
} catch (v429) {
console.error(var314.EghBP, v429);
}
if (var318) {
this._cachedCursorPath = var318;
}
return var318;
}
_getWorkbenchPath() {
return this._getWorkbenchPathSync();
}
_getWorkbenchPathSync() {
const var430 = {
'UfpAf': "storage.serviceMachineId",
'Anviz': "[CursorPro] machineid 更新失败:",
'VVCFs': "machineid",
'JyreV': function (arg238, arg239) {
return arg238(arg239);
},
'LuKVI': 'crypto',
'SWJRm': function (arg240, arg241) {
return arg240 & arg241;
},
'FQssd': function (arg242, arg243) {
return arg242 !== arg243;
},
'eUATr': function (arg244, arg245) {
return arg244 === arg245;
},
'jTUqv': "darwin",
'VLslV': 'xuLZV',
'UWqNM': "app",
'sQFsh': "out",
'eRJjA': "workbench",
'gkqWe': "workbench.desktop.main.js",
'ZSOkm': function (arg246, arg247) {
return arg246 !== arg247;
},
'SccyE': "kWVws",
'dVhNW': "resources",
'VfwmP': function (arg248, arg249) {
return arg248 === arg249;
},
'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 var431 = process.platform;
if (this._cachedCursorPath) {
if (var430.FQssd('zZyLK', "PQRiM")) {
let var432;
if (var430.eUATr(var431, var430.jTUqv)) {
if (var430.eUATr("xuLZV", 'xuLZV')) {
var432 = path.join(this._cachedCursorPath, 'Contents', "Resources", var430.UWqNM, var430.sQFsh, 'vs', var430.eRJjA, var430.gkqWe);
} else {
v433.push([var430.UfpAf, v434.serviceMachineId]);
}
} else if (var430.ZSOkm("XbfIf", var430.SccyE)) {
var432 = path.join(this._cachedCursorPath, var430.dVhNW, "app", var430.sQFsh, 'vs', var430.eRJjA, "workbench.desktop.main.js");
} else {
v435.warn(var430.Anviz, v436.message);
v437.push(var430.VVCFs);
}
if (fs.existsSync(var432)) {
return var432;
}
} else {
return [];
}
}
if (var430.eUATr(var431, 'win32')) {
return null;
}
let var438 = [];
if (var430.VfwmP(var431, var430.jTUqv)) {
var438 = [var430.NyLwi];
} else {
if ('DESET' !== var430.aJjyB) {
var438 = [var430.bWpPz, '/usr/share/cursor/resources/app/out/vs/workbench/workbench.desktop.main.js'];
} else {
const var439 = var430.JyreV(v440, 'crypto');
const var441 = var439.randomBytes(0x6);
var441[0x0] = var430.SWJRm(var441[0x0] | 0x2, 0xfe);
return v442.from(var441).map(arg250 => arg250.toString(0x10).padStart(0x2, '0')).join(':');
}
}
for (const var443 of var438) {
if (fs.existsSync(var443)) {
return var443;
}
}
return null;
}
async _getWorkbenchPathAsync() {
const var444 = {
'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 (arg251, arg252) {
return arg251 === arg252;
},
'fYTsi': "EUUHA",
'idevD': "eXeOK",
'SJHtk': function (arg253, arg254) {
return arg253 === arg254;
},
'AJPrD': "darwin",
'qcilt': function (arg255, arg256) {
return arg255 === arg256;
},
'yQEWX': "vUlDT",
'Knhyl': "Contents",
'NPYXr': "Resources",
'xDNVo': "out",
'Lnhsa': "workbench",
'ejmIv': "workbench.desktop.main.js",
'yfprZ': "dtGAS"
};
const var445 = process.platform;
const var446 = await this._getCursorInstallPath();
if (var446) {
if (var444.ktVBs(var444.fYTsi, var444.idevD)) {
const var447 = v448[0x1].trim();
v449 = v450.dirname(var447);
} else {
let var451;
if (var445 === var444.AJPrD) {
if (var444.qcilt(var444.yQEWX, var444.yQEWX)) {
var451 = path.join(var446, var444.Knhyl, var444.NPYXr, var444.JBwsK, var444.xDNVo, 'vs', var444.Lnhsa, var444.ejmIv);
} else {
const var452 = v453.env.LOCALAPPDATA || '';
const var454 = v455.env.USERPROFILE || '';
const var456 = v457.env.ProgramFiles || var444.diJhY;
const var458 = v459.env[var444.BHmwx] || var444.xDKiN;
v460.push(v461.join(var452, var444.aIUry, var444.oemiO, var444.wNjLv, "app", var444.BzPhh), v462.join(var452, var444.aIUry, var444.dNHJx, var444.wNjLv, var444.JBwsK, var444.BzPhh), v463.join(var454, var444.NoEGQ, var444.GOKzJ, var444.aIUry, var444.oemiO, "resources", var444.JBwsK, "package.json"), v464.join(var456, "Cursor", "resources", "app", var444.BzPhh), v465.join(var456, var444.dNHJx, var444.wNjLv, var444.JBwsK, var444.BzPhh), v466.join(var458, var444.oemiO, "resources", var444.JBwsK, "package.json"));
}
} else {
var451 = path.join(var446, var444.wNjLv, var444.JBwsK, var444.xDNVo, 'vs', var444.Lnhsa, "workbench.desktop.main.js");
}
if (fs.existsSync(var451)) {
if (var444.yfprZ === var444.yfprZ) {
return var451;
} else {
this._postMessage({
'type': var444.okosv,
'success': false,
'currentVersion': v467.CURRENT_VERSION,
'error': v468.message || "请求失败"
});
}
}
}
}
return this._getWorkbenchPathSync();
}
_checkInjected(arg257) {
const var469 = {
'WkvEt': "/*i0*/"
};
return arg257.includes(var469.WkvEt) || arg257.includes('/*i1s*/');
}
async _isSeamlessInjected() {
const var470 = {
'gPIxP': "utf-8",
'ntlpp': "[CursorPro] 检测无感换号状态失败:"
};
try {
const var471 = await this._getWorkbenchPathAsync();
if (var471 && fs.existsSync(var471)) {
const var472 = fs.readFileSync(var471, var470.gPIxP);
return this._checkInjected(var472);
}
return false;
} catch (v473) {
console.error(var470.ntlpp, v473);
return false;
}
}
_getInjectionConfig(arg258, arg259) {
const var474 = {
'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': var474.FgaCg,
'replacement': "_showNotification(){/*i0*/}_showNotificationOld(){",
'restore': {
'find': var474.OHrmM,
'replace_with': var474.FgaCg
}
}, {
'name': "注入点1: 核心模块初始化",
'scode': var474.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='" + arg258 + "';window.__cpUserKey='" + arg259 + "';window.__cpVersion=0;console.log('[CP] Initialized with key:','" + arg259 + "'.substring(0,15)+'...')}})(this)/*i1e*/",
'restore': {
'find_start': var474.MqHGw,
'find_end': var474.OSWSK
}
}, {
'name': var474.QXMFr,
'scode': var474.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': var474.hxXLs
}
}];
}
async _handleInjectSeamless() {
const var475 = {
'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 (arg260, arg261) {
return arg260 !== arg261;
},
'mZDVz': 'reoBh',
'XlzQa': "seamlessInjected",
'RKaZM': "授权码无效",
'wFOsZ': function (arg262, arg263) {
return arg262 === arg263;
},
'uTxRa': "wecNx",
'NQBnu': "启用失败",
'QwROM': function (arg264, arg265) {
return arg264 + arg265;
},
'KPHtC': ".backup",
'BJIgK': "cursorpro.seamlessInjected",
'asGDz': function (arg266, arg267) {
return arg266 === arg267;
},
'AvMcE': "grpZy",
'NFNQK': "[CursorPro] 首次启用,从备份恢复干净的 workbench 文件",
'ApEZm': "[CursorPro] 备份恢复成功",
'WEdcP': function (arg268, arg269) {
return arg268 === arg269;
},
'NwiBk': "jYehy",
'fWqWm': "gRHmI",
'PuBtb': function (arg270, arg271) {
return arg270 === arg271;
},
'QPTVv': "[CursorPro] 注入失败,未找到任何注入点",
'bwZyq': "[CursorPro] 文件路径:",
'isjyP': "[CursorPro] 文件大小:",
'nGlvY': "_showNotification",
'eLVeH': "getItems()",
'JDsIJ': "[CursorPro] 包含 _showNotification:",
'Spptx': "[CursorPro] 包含 getItems():",
'OaqMs': "Cursor 版本不兼容,注入点未找到",
'CqvrX': function (arg272, arg273) {
return arg272 > arg273;
},
'tdJex': "[CursorPro] 未找到的注入点:",
'IsXFU': function (arg274, arg275) {
return arg274 === arg275;
},
'NpueJ': "txcqo",
'chYLS': "[CursorPro] 写入文件失败:",
'qFuwX': 'EACCES',
'jWyZD': "没有写入权限,请在终端执行: sudo chmod -R 777 /Applications/Cursor.app",
'nsFtB': function (arg276, arg277) {
return arg276 === arg277;
},
'vryqQ': "linux",
'FiwIr': "gWxzY",
'NnBbT': "qchHx",
'kofbg': "没有写入权限,请使用 sudo 权限运行或修改文件权限",
'WedEJ': "无感换号已启用",
'jiObk': "nUNdq",
'chXsS': "[CursorPro] Inject error:",
'PfOPU': "EPERM",
'GZrDV': function (arg278, arg279) {
return arg278 === arg279;
},
'SUpCK': 'TKgrk',
'JOonS': "rIkKS",
'uvZZD': "没有写入权限"
};
try {
const var476 = this._context.globalState.get("cursorpro.key");
if (!var476) {
if (var475.nmpHW("dlteM", 'reoBh')) {
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': "请先激活授权码"
});
return;
} else {
v477.push(v478.join(v479, var475.eAudc, var475.ZnFEJ, var475.QGTLQ));
}
}
0x0;
const var480 = await client_1.getUserSwitchStatus(var476);
if (!var480.valid) {
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': var480.error || var475.RKaZM
});
return;
}
const var481 = await this._getWorkbenchPathAsync();
if (!var481) {
if (var475.wFOsZ(var475.uTxRa, var475.uTxRa)) {
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': var475.NQBnu
});
return;
} else {
this._postMessage({
'type': 'keyStatusChecked',
'valid': false,
'expired': true,
'error': v482.error || var475.yDFID
});
}
}
const var483 = var475.QwROM(var481, var475.KPHtC);
const var484 = !this._context.globalState.get(var475.BJIgK);
if (var484 && fs.existsSync(var483)) {
if (var475.asGDz("xfseF", var475.AvMcE)) {
v485 = v486;
if (v487 === var475.XoRrm) {
v488 = v489.join(v490, var475.zcMpa, var475.cTyAN, var475.ZnFEJ, 'package.json');
} else {
v491 = v492.join(v493, var475.eAudc, var475.ZnFEJ, 'package.json');
}
v494.log(var475.UNUES, v495);
} else {
console.log(var475.NFNQK);
try {
fs.copyFileSync(var483, var481);
console.log(var475.ApEZm);
} catch (v496) {
console.error(var475.gzoYo, v496);
}
}
}
let var497 = fs.readFileSync(var481, 'utf-8');
if (this._checkInjected(var497)) {
this._postMessage({
'type': "showToast",
'message': "已启用",
'icon': '✅'
});
return;
}
if (!fs.existsSync(var483)) {
fs.copyFileSync(var481, var483);
console.log("[CursorPro] 创建备份文件");
}
0x0;
const var498 = client_1.getApiUrl();
const var499 = this._getInjectionConfig(var498, var476);
const var500 = [];
const var501 = [];
for (const var502 of var499) {
if (var475.NwiBk === var475.fWqWm) {
v503 = var475.IJzdz;
} else if (var497.includes(var502.scode)) {
var497 = var497.replace(var502.scode, var502.replacement);
var500.push(var502.name);
} else {
var501.push(var502.name);
}
}
if (var475.PuBtb(var500.length, 0x0)) {
console.error(var475.QPTVv);
console.error(var475.bwZyq, var481);
console.error(var475.isjyP, var497.length);
console.error("[CursorPro] 未找到的注入点:", var501);
const var504 = var497.includes(var475.nGlvY);
const var505 = var497.includes(var475.eLVeH);
console.error(var475.JDsIJ, var504);
console.error(var475.Spptx, var505);
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': var475.OaqMs,
'details': "路径: " + var481
});
return;
}
console.log("[CursorPro] 注入成功,应用的注入点:", var500);
if (var475.CqvrX(var501.length, 0x0)) {
console.warn(var475.tdJex, var501);
}
try {
if (var475.IsXFU("nYkuW", "oAKop")) {
v506.warn("[CursorPro] 获取进程路径失败:", v507);
} else {
fs.writeFileSync(var481, var497, "utf-8");
}
} catch (v508) {
if (var475.nmpHW("txcqo", var475.NpueJ)) {
this._postMessage({
'type': var475.VGOST,
'success': false,
'error': var475.vySBX
});
return;
} else {
console.error(var475.chYLS, v508);
if (var475.IsXFU(v508.code, "EPERM") || var475.WEdcP(v508.code, var475.qFuwX) || v508.code === "EROFS") {
const var509 = process.platform;
let var510 = "没有写入权限";
if (var475.WEdcP(var509, var475.XoRrm)) {
var510 = var475.jWyZD;
} else if (var509 === var475.vryqQ) {
if (var475.FiwIr === var475.NnBbT) {
v511.error(var475.OUNoh, v512);
} else {
var510 = var475.kofbg;
}
}
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': var510,
'needAdmin': true,
'path': var481
});
return;
}
throw v508;
}
}
await this._context.globalState.update(var475.BJIgK, true);
this._postMessage({
'type': 'seamlessInjected',
'success': true,
'applied': var500,
'needRestart': true,
'message': var475.WedEJ
});
} catch (v513) {
if (var475.jiObk !== 'nUNdq') {
const var514 = this._readHostsFile();
return var514.includes(this.HOSTS_MARKER_START);
} else {
console.error(var475.chXsS, v513);
if (v513.code === var475.PfOPU || v513.code === var475.qFuwX) {
if (var475.SUpCK === var475.JOonS) {
v515.error(var475.gzoYo, v516);
} else {
const var517 = var475.uvZZD;
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': var517,
'needAdmin': true
});
return;
}
}
this._postMessage({
'type': var475.XlzQa,
'success': false,
'error': v513.message || '注入失败'
});
}
}
}
async _handleRestoreSeamless() {
const var518 = {
'fNFwN': function (arg280, arg281) {
return arg280 === arg281;
},
'qzWvm': "gPXAj",
'iIeEk': "utf-8",
'hXGdP': "_showNotification(){/*i0*/}_showNotificationOld(){",
'TTVZf': "_showNotification(){",
'gtuTM': "/*i1e*/",
'GRbOi': function (arg282, arg283) {
return arg282 !== arg283;
},
'SIJlB': function (arg284, arg285) {
return arg284 + arg285;
},
'lhoIl': '/*i2s*/',
'rihJn': "/*i2e*/",
'UKjaP': function (arg286, arg287) {
return arg286 !== arg287;
},
'gfXYq': "kmqvv",
'oXUXx': function (arg288, arg289) {
return arg288 + arg289;
},
'hFPNQ': function (arg290, arg291) {
return arg290 === arg291;
},
'iKOOs': function (arg292, arg293) {
return arg292 === arg293;
},
'yKkFV': "uoVdW",
'uxIzt': "tzZLb",
'PVsoN': "没有写入权限",
'dzulQ': "seamlessRestored",
'wYcDp': "[CursorPro] Restore error:",
'yoKCW': "EPERM",
'dGgrN': function (arg294, arg295) {
return arg294 === arg295;
},
'ybPXs': "EACCES"
};
try {
const var519 = await this._getWorkbenchPathAsync();
if (!var519) {
if ("JnQIK" === var518.qzWvm) {
return v520;
} else {
this._postMessage({
'type': "seamlessRestored",
'success': false,
'error': '未找到Cursor安装目录'
});
return;
}
}
let var521 = fs.readFileSync(var519, var518.iIeEk);
if (!this._checkInjected(var521)) {
return;
}
var521 = var521.replace(var518.hXGdP, var518.TTVZf);
const var522 = var521.indexOf("/*i1s*/");
const var523 = var521.indexOf(var518.gtuTM);
if (var522 !== -0x1 && var523 !== -0x1) {
var521 = var521.substring(0x0, var522) + var521.substring(var523 + 0x7);
}
const var524 = var521.indexOf(var518.lhoIl);
const var525 = var521.indexOf(var518.rihJn);
if (var524 !== -0x1 && var525 !== -0x1) {
if (var518.UKjaP('kmqvv', var518.gfXYq)) {
v526.unlinkSync(v527);
} else {
var521 = var518.oXUXx(var521.substring(0x0, var524), var521.substring(var525 + 0x7));
}
}
try {
fs.writeFileSync(var519, var521, var518.iIeEk);
} catch (v528) {
if (var518.hFPNQ(v528.code, "EPERM") || v528.code === "EACCES") {
if (var518.iKOOs(var518.yKkFV, var518.uxIzt)) {
v529 = v530[0x1];
} else {
const var531 = var518.PVsoN;
this._postMessage({
'type': var518.dzulQ,
'success': false,
'error': var531,
'needAdmin': true
});
return;
}
}
throw v528;
}
this._postMessage({
'type': var518.dzulQ,
'success': true,
'needRestart': true,
'message': "无感换号已禁用"
});
} catch (v532) {
console.error(var518.wYcDp, v532);
if (v532.code === var518.yoKCW || var518.dGgrN(v532.code, var518.ybPXs)) {
const var533 = "没有写入权限";
this._postMessage({
'type': var518.dzulQ,
'success': false,
'error': var533,
'needAdmin': true
});
return;
}
this._postMessage({
'type': var518.dzulQ,
'success': false,
'error': v532.message || '还原失败'
});
}
}
async _handleToggleSeamless(arg296) {
const var534 = {
'uMKkd': "dSScr",
'puuTf': 'OoEdP',
'GMeLW': "seamlessConfigUpdated",
'xfsPC': function (arg297, arg298) {
return arg297 === arg298;
},
'gwHNY': "SZovO",
'DbkSk': "更新配置失败"
};
try {
if (var534.uMKkd === 'OoEdP') {
try {
if (v535.existsSync(v536)) {
v537.rmSync(v538, {
'recursive': true,
'force': true
});
v539++;
}
} catch (v540) {
v541.warn("[CursorPro] 清理失败: " + v542, v540);
}
} else {
0x0;
await client_1.updateSeamlessConfig({
'enabled': arg296
});
this._postMessage({
'type': var534.GMeLW,
'success': true,
'enabled': arg296
});
}
} catch (v543) {
if (var534.xfsPC("lzzwb", var534.gwHNY)) {
return this._getWorkbenchPathSync();
} else {
this._postMessage({
'type': var534.GMeLW,
'success': false,
'error': var534.DbkSk
});
}
}
}
async _handleGetUserSwitchStatus() {
const var544 = {
'iTdeY': "tFzAd",
'sJbdj': 'userSwitchStatus',
'Bzqze': 'TSpKd',
'HRNLC': function (arg299, arg300) {
return arg299 !== arg300;
},
'BIPgO': "NMuKY",
'zFtlx': "获取状态失败"
};
try {
if (var544.iTdeY !== var544.iTdeY) {
v545.push(["cursorAuth/cachedEmail", v546.email]);
} else {
const var547 = this._context.globalState.get('cursorpro.key');
if (!var547) {
this._postMessage({
'type': var544.sJbdj,
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': "未激活授权码"
});
return;
}
0x0;
const var548 = await client_1.getUserSwitchStatus(var547);
let var549 = false;
try {
if ('TSpKd' === "TSpKd") {
0x0;
const var550 = await client_1.getSeamlessStatus();
var549 = var550.is_injected || false;
} else {
v551.warn("[CursorPro] 清理失败: " + v552, v553);
}
} catch (v554) {}
this._postMessage({
'type': 'userSwitchStatus',
...var548,
'seamlessEnabled': var549
});
}
} catch (v555) {
if ("ObXTw" !== var544.BIPgO) {
this._postMessage({
'type': "userSwitchStatus",
'valid': false,
'switchRemaining': 0x0,
'canSwitch': false,
'error': var544.zFtlx
});
} else {
const var556 = 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-" + var556 + "'; img-src " + v557.cspSource + " https: data:; font-src " + v558.cspSource + "; worker-src 'none';\">\n <title>CursorPro</title>\n <script nonce=\"" + var556 + "\">\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=\"" + var556 + "\">\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(arg301) {
const var559 = {
'kwSDs': "[CursorPro] Toggle proxy error:",
'cuNHx': "proxyUpdated",
'AlVbI': '更新配置失败',
'cBprM': "accountUsage",
'pLAQo': "未提供账号邮箱",
'XCtgT': function (arg302, arg303) {
return arg302(arg303);
},
'LcuLD': "获取用量失败",
'JvSqa': "NYkng",
'rptjh': "请求失败"
};
try {
if (!arg301) {
this._postMessage({
'type': var559.cBprM,
'success': false,
'error': var559.pLAQo
});
return;
}
0x0;
const var560 = client_1.getApiUrl() + "/api/cursor-accounts/query?email=" + var559.XCtgT(encodeURIComponent, arg301) + '&refresh=true';
const var561 = await var559.XCtgT(fetch, var560);
const var562 = await var561.json();
if (var562.success && var562.data) {
this._postMessage({
'type': var559.cBprM,
'success': true,
'data': var562.data
});
const var563 = var562.data.usage || {};
const var564 = var563.totalUsageCount || 0x0;
const var565 = var559.XCtgT(parseFloat, var563.totalCostUSD || 0x0);
0x0;
extension_1.updateUsageStatusBar(var564, var565);
} else {
this._postMessage({
'type': var559.cBprM,
'success': false,
'error': var562.error || var559.LcuLD
});
}
} catch (v566) {
if (var559.JvSqa !== 'NYkng') {
v567.error(var559.kwSDs, v568);
this._postMessage({
'type': var559.cuNHx,
'success': false,
'error': var559.AlVbI
});
} else {
this._postMessage({
'type': var559.cBprM,
'success': false,
'error': v566.message || var559.rptjh
});
}
}
}
async _handleGetAnnouncement() {
const var569 = {
'eXcSu': "cursorpro.key",
'wCuhU': "cursorpro.expireDate",
'tQyYP': '请先激活授权码',
'fEjcy': function (arg304, arg305) {
return arg304 > arg305;
},
'GLUmw': "proxyUpdated",
'Bjkrw': '授权码已过期,无法开启免魔法',
'trGXG': 'showToast',
'aCZjy': function (arg306, arg307) {
return arg306(arg307);
},
'aHNrz': 'announcement',
'PynOc': function (arg308, arg309) {
return arg308 === arg309;
},
'LjnPR': 'ysOwe',
'RdeWm': "获取公告失败",
'XcVTX': "请求失败"
};
try {
0x0;
const var570 = client_1.getApiUrl() + "/api/announcements/latest";
const var571 = await var569.aCZjy(fetch, var570);
const var572 = await var571.json();
if (var572.success && var572.data) {
this._postMessage({
'type': var569.aHNrz,
'success': true,
'data': var572.data
});
} else {
if ('ysOwe' === var569.LjnPR) {
this._postMessage({
'type': "announcement",
'success': false,
'error': var572.error || var569.RdeWm
});
} else {
const var573 = this._context.globalState.get(var569.eXcSu);
const var574 = this._context.globalState.get(var569.wCuhU);
if (!var573) {
this._postMessage({
'type': 'proxyUpdated',
'success': false,
'error': '请先激活授权码'
});
this._postMessage({
'type': "showToast",
'message': var569.tQyYP,
'icon': '⚠️'
});
return;
}
if (var574) {
const var575 = new v576(var574).getTime();
if (var569.fEjcy(v577.now(), var575)) {
this._postMessage({
'type': var569.GLUmw,
'success': false,
'error': var569.Bjkrw
});
this._postMessage({
'type': var569.trGXG,
'message': "授权码已过期,无法开启免魔法",
'icon': '⚠️'
});
return;
}
}
}
}
} catch (v578) {
this._postMessage({
'type': var569.aHNrz,
'success': false,
'error': v578.message || var569.XcVTX
});
}
}
async _handleCheckVersion() {
const var579 = {
'HgWOc': "[CursorPro] 使用用户配置的 Cursor 路径:",
'QXFeq': function (arg310, arg311) {
return arg310 > arg311;
},
'lYCxA': "versionCheck",
'QtoxZ': function (arg312, arg313) {
return arg312 === arg313;
},
'xqknY': "vUHCr",
'GbNrd': "请求失败"
};
try {
0x0;
const var580 = await client_1.getLatestVersion();
if (var580.success && var580.version) {
const var581 = var580.version;
const var582 = CursorProViewProvider.CURRENT_VERSION;
const var583 = var579.QXFeq(this._compareVersions(var581, var582), 0x0);
this._postMessage({
'type': var579.lYCxA,
'success': true,
'currentVersion': var582,
'latestVersion': var581,
'hasUpdate': var583
});
} else {
this._postMessage({
'type': var579.lYCxA,
'success': false,
'currentVersion': CursorProViewProvider.CURRENT_VERSION,
'error': var580.error || "获取版本失败"
});
}
} catch (v584) {
if (var579.QtoxZ(var579.xqknY, "LOWQh")) {
v585.log(var579.HgWOc, v586);
this._cachedCursorPath = v587;
return v588;
} else {
this._postMessage({
'type': "versionCheck",
'success': false,
'currentVersion': CursorProViewProvider.CURRENT_VERSION,
'error': v584.message || var579.GbNrd
});
}
}
}
_compareVersions(arg314, arg315) {
const var589 = {
'PMKNW': function (arg316, arg317) {
return arg316 < arg317;
},
'qyNxu': function (arg318, arg319) {
return arg318 > arg319;
},
'HZvmu': function (arg320, arg321) {
return arg320 < arg321;
}
};
const var590 = arg314.split('.').map(Number);
const var591 = arg315.split('.').map(Number);
const var592 = Math.max(var590.length, var591.length);
for (let var593 = 0x0; var593 < var592; var593++) {
const var594 = var590[var593] || 0x0;
const var595 = var591[var593] || 0x0;
if (var589.qyNxu(var594, var595)) {
return 0x1;
}
if (var594 < var595) {
return -0x1;
}
}
return 0x0;
}
async _handleGetCursorRunningPath() {
const var596 = {
'SsULC': "[CursorPro] 使用 VS Code API 获取版本:",
'AwKfF': 'utf-8',
'zAvXx': "UBmxB",
'QhWXL': "未找到",
'bZBTW': 'cursorpro',
'vlHDb': 'cursorPath',
'ONVXL': function (arg322, arg323) {
return arg322 === arg323;
},
'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 (arg324, arg325) {
return arg324 === arg325;
},
'rEwYQ': "snkgX",
'YxYZp': "BoVlO",
'Qvzam': function (arg326, arg327) {
return arg326 === arg327;
},
'FyfZA': function (arg328, arg329) {
return arg328 !== arg329;
},
'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" !== var596.zAvXx) {
return [{
'email': v597,
'access_token': v598,
'refresh_token': v599 || v600
}];
} else {
const var601 = process.platform;
let var602 = var596.QhWXL;
let var603 = '';
const var604 = vscode.workspace.getConfiguration(var596.bZBTW);
const var605 = var604.get(var596.vlHDb);
if (var605 && fs.existsSync(var605)) {
var602 = var605;
if (var601 === var596.JPYoo) {
var603 = path.join(var605, var596.nEYhA, var596.EbBLW, var596.lMfdt, var596.MFjtx);
} else {
var603 = path.join(var605, "resources", var596.lMfdt, var596.MFjtx);
}
console.log(var596.NjVqB, var605);
} else {
if (var601 === var596.Wxyfp) {
try {
if (var596.JSWuW === "eKgQY") {
v606 = true;
delete v607[v608];
} else {
const {
stdout: v609
} = await execAsync(var596.ACRef);
const var610 = v609.match(/ExecutablePath=(.+)/);
if (var610 && var610[0x1]) {
const var611 = var610[0x1].trim();
var602 = path.dirname(var611);
var603 = path.join(var602, var596.ydRHF, var596.lMfdt, var596.MFjtx);
}
}
} catch (v612) {
if (var596.rEwYQ === var596.YxYZp) {
v613.log(var596.SsULC, v614.version);
return v615.version;
} else {
console.log("[CursorPro] WMIC 获取路径失败:", v612);
}
}
if (var602 === var596.QhWXL) {
if (var596.FyfZA("DZGqD", var596.eCMQp)) {
try {
const var616 = this._getHostsPath();
if (v617.existsSync(var616)) {
return v618.readFileSync(var616, var596.AwKfF);
}
} catch (v619) {
v620.error("[CursorPro] Read hosts error:", v619);
}
return '';
} else {
const var621 = process.env.LOCALAPPDATA || '';
const var622 = [path.join(var621, var596.QKwAH, 'cursor'), path.join(var621, var596.eEobw)];
for (const var623 of var622) {
const var624 = path.join(var623, var596.ydRHF, "app", var596.MFjtx);
if (fs.existsSync(var624)) {
var602 = var623;
var603 = var624;
break;
}
}
}
}
} else {
if (var601 === "darwin") {
if (var596.Qvzam(var596.aouCU, var596.XXRrw)) {
return null;
} else {
var602 = (await this._getCursorInstallPath()) || var596.biXGl;
var603 = path.join(var602, var596.nEYhA, var596.EbBLW, 'app', var596.MFjtx);
}
} else {
const var625 = process.env.HOME || '';
const var626 = [var596.ErbAO, path.join(var625, var596.vvvXG, var596.kVBXU, var596.eEobw)];
for (const var627 of var626) {
if (fs.existsSync(var627)) {
var602 = var627;
var603 = path.join(var627, var596.ydRHF, 'app', "package.json");
break;
}
}
}
}
}
const var628 = var603 && fs.existsSync(var603);
let var629 = '';
if (var628) {
try {
if (var596.sxYuF === var596.sYfMC) {
if (v630.existsSync(v631)) {
return v632;
}
} else {
const var633 = fs.readFileSync(var603, var596.AwKfF);
const var634 = JSON.parse(var633);
var629 = var634.version || '';
console.log(var596.UFfHe, var629);
}
} catch (v635) {
console.log("[CursorPro] 读取 package.json 失败:", v635);
}
}
this._postMessage({
'type': 'cursorRunningPath',
'path': var602,
'packageJsonPath': var603,
'packageExists': var628,
'cursorVersion': var629
});
}
} catch (v636) {
this._postMessage({
'type': var596.HLsOj,
'path': "获取失败: " + (v636.message || v636),
'packageJsonPath': '',
'packageExists': false,
'cursorVersion': ''
});
}
}
async _handleCheckUsageBeforeSwitch(arg330) {
const var637 = {
'sEVKj': "[CursorPro] PowerShell Get-Process 获取路径失败",
'kcIfn': "[CursorPro] Direct write failed, trying to grant permission",
'qVzhF': function (arg331, arg332) {
return arg331 === arg332;
},
'NTZfw': "klkmy",
'LnwIK': 'usageCheckResult',
'yCHku': "未激活授权码",
'wnjiM': function (arg333, arg334) {
return arg333 === arg334;
},
'FHkCa': "taehn",
'Elfrz': function (arg335, arg336) {
return arg335(arg336);
},
'uXXMl': function (arg337, arg338) {
return arg337(arg338);
},
'rMdug': "Drfmf",
'KaGPw': "lZGGL",
'DqgLz': function (arg339, arg340) {
return arg339 < arg340;
},
'nMItX': "aCFwf",
'YHdCp': 'MhURV',
'zYseP': function (arg341, arg342) {
return arg341 !== arg342;
},
'XaQBc': "PgKQl",
'PYWHP': 'hlMgj',
'EKVNJ': "zdYFk"
};
try {
if ('pydTE' !== var637.NTZfw) {
const var638 = this._context.globalState.get("cursorpro.key");
if (!var638) {
this._postMessage({
'type': var637.LnwIK,
'success': false,
'error': var637.yCHku
});
return;
}
if (!arg330) {
if (var637.FHkCa === var637.FHkCa) {
this._postMessage({
'type': "usageCheckResult",
'success': true,
'needConfirm': false
});
return;
} else {
v639.window.showErrorMessage("清理失败: " + v640);
}
}
0x0;
const var641 = client_1.getApiUrl() + '/api/cursor-accounts/query?email=' + encodeURIComponent(arg330) + "&refresh=false";
const var642 = await fetch(var641);
const var643 = await var642.json();
if (var643.success && var643.data) {
if (var637.rMdug !== var637.KaGPw) {
const var644 = var643.data.usage || {};
const var645 = parseFloat(var644.totalCostUSD || 0x0);
if (var637.DqgLz(var645, 0xa)) {
if (var637.wnjiM(var637.nMItX, var637.YHdCp)) {
v646.log(var637.sEVKj);
} else {
this._postMessage({
'type': var637.LnwIK,
'success': true,
'needConfirm': true,
'costUSD': var645.toFixed(0x2),
'email': arg330
});
}
} else {
this._postMessage({
'type': var637.LnwIK,
'success': true,
'needConfirm': false
});
}
} else {
v647.rmSync(v648, {
'recursive': true,
'force': true
});
v649++;
}
} else if (var637.zYseP('GbpRm', var637.XaQBc)) {
this._postMessage({
'type': var637.LnwIK,
'success': true,
'needConfirm': false
});
} else {
v650.log(var637.kcIfn);
}
} else {
if (var637.qVzhF(v651, v652)) {
v653 = v654;
}
v655[v656] = v657[v658];
}
} catch (v659) {
if (var637.zYseP(var637.PYWHP, var637.EKVNJ)) {
this._postMessage({
'type': 'usageCheckResult',
'success': true,
'needConfirm': false
});
} else {
v660.push(v661.name);
}
}
}
async _handleManualSeamlessSwitch() {
const var662 = {
'BIFqO': "utf-8",
'BfPph': "[CursorPro] Linux 获取进程路径失败:",
'loKNV': 'cursorRunningPath',
'HrshN': function (arg343, arg344) {
return arg343 + arg344;
},
'ByJnO': "获取失败: ",
'yJBIQ': 'exYVj',
'KvCvh': 'manualSeamlessSwitched',
'VLaZZ': "未激活授权码",
'tbDpF': function (arg345, arg346) {
return arg345 !== arg346;
},
'yPImL': 'ingEM',
'mlftM': function (arg347, arg348) {
return arg347 !== arg348;
},
'jnyry': "FYJZv",
'HxZxj': "换号失败",
'sLjSr': "连接服务器失败"
};
try {
if (var662.yJBIQ === 'exYVj') {
const var663 = this._context.globalState.get("cursorpro.key");
if (!var663) {
this._postMessage({
'type': var662.KvCvh,
'success': false,
'error': var662.VLaZZ
});
return;
}
0x0;
const var664 = await client_1.switchSeamlessToken(var663);
if (var664.switched) {
if (var664.email) {
await this._context.globalState.update("cursorpro.seamlessCurrentAccount", var664.email);
}
this._postMessage({
'type': var662.KvCvh,
'success': true,
'email': var664.email,
'switchRemaining': var664.switchRemaining
});
} else {
if (var662.mlftM("JYbEY", var662.jnyry)) {
const var665 = var664.message || var664.error || var662.HxZxj;
this._postMessage({
'type': var662.KvCvh,
'success': false,
'error': var665
});
} else {
v666.warn(var662.BfPph, v667);
}
}
} else {
this._postMessage({
'type': 'cursorRunningPath',
'path': var662.HrshN(var662.ByJnO, v668.message || v669),
'packageJsonPath': '',
'packageExists': false,
'cursorVersion': ''
});
}
} catch (v670) {
const var671 = v670?.message || var662.sLjSr;
this._postMessage({
'type': var662.KvCvh,
'success': false,
'error': var671
});
}
}
async _handleGetCursorPath() {
const var672 = {
'tbZpe': function (arg349, arg350) {
return arg349 === arg350;
},
'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 (arg351, arg352) {
return arg351(arg352);
},
'LurDi': "wmic process where \"name='Cursor.exe'\" get ExecutablePath /format:list 2>nul",
'VtoJO': 'hKLIf',
'KDsFj': function (arg353, arg354) {
return arg353 === arg354;
},
'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 (arg355, arg356) {
return arg355 !== arg356;
},
'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 (arg357, arg358) {
return arg357 !== arg358;
},
'EYQCn': "EvRNl",
'MiEkS': "cursorPath",
'HiXkV': function (arg359, arg360) {
return arg359 || arg360;
},
'hlIYy': 'ZzJmG',
'GONGu': '获取失败'
};
try {
const var673 = process.platform;
let var674 = '';
let var675 = '';
if (var672.tbZpe(var673, var672.TFAWN)) {
try {
const {
stdout: v676
} = await var672.VsfTO(execAsync, var672.LurDi);
const var677 = v676.match(/ExecutablePath=(.+)/);
if (var677 && var677[0x1]) {
const var678 = var677[0x1].trim();
var674 = path.dirname(var678);
}
} catch (v679) {
if (var672.VtoJO !== "hKLIf") {
if (var672.tbZpe(v680.code, var672.pcUwb) || var672.tbZpe(v681.code, "EACCES")) {
const var682 = var672.WPzlq;
this._postMessage({
'type': var672.drojl,
'success': false,
'error': var682,
'needAdmin': true
});
return;
}
throw v683;
} else {
try {
if (var672.KDsFj(var672.rLwGW, var672.rLwGW)) {
const {
stdout: v684
} = await execAsync('powershell -Command "Get-Process Cursor -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Path"');
if (v684.trim()) {
if (var672.ePJAJ !== var672.WxyNi) {
var674 = path.dirname(v684.trim());
} else {
this._postMessage({
'type': var672.fTNeN,
'success': false,
'error': '连接服务器失败'
});
}
}
} else {
v685 = v686.substring(0x0, v687) + v688.substring(v689 + this.HOSTS_MARKER_END.length);
}
} catch (v690) {
console.warn(var672.lqoLD, v690);
}
}
}
const var691 = process.env.APPDATA || '';
var675 = path.join(var691, var672.oVgdC);
} else {
if (var673 === "darwin") {
try {
const {
stdout: v692
} = await var672.VsfTO(execAsync, var672.USGWH);
if (v692.trim()) {
const var693 = v692.trim();
const var694 = var693.match(/(.+\.app)/);
if (var694) {
var674 = var694[0x1];
} else {
var674 = path.dirname(var693);
}
}
} catch (v695) {
console.warn("[CursorPro] 获取进程路径失败:", v695);
}
const var696 = process.env.HOME || '';
var675 = path.join(var696, 'Library', "Application Support", var672.oVgdC);
} else {
try {
const {
stdout: v697
} = await execAsync(var672.gDuYC);
if (v697.trim()) {
if (var672.tbZpe(var672.bwLpU, var672.bwLpU)) {
var674 = path.dirname(v697.trim());
} else {
v698 = var672.TbbUg;
}
}
} catch (v699) {
console.warn(var672.lqoLD, v699);
}
const var700 = process.env.HOME || '';
var675 = path.join(var700, var672.sWGNb, var672.oVgdC);
}
}
if (!var674) {
if ("dWdoR" === var672.KbfNq) {
this._postMessage({
'type': var672.NwHIv,
'success': false,
'error': var672.jmXuW
});
return;
} else {
var674 = var672.dALzw;
}
}
let var701 = '';
if (var674 && !var674.includes(var672.mOngd)) {
if (var673 === var672.TFAWN) {
if (var672.GdGfE('lPhmJ', "lPhmJ")) {
v702["telemetry.devDeviceId"] = v703.devDeviceId;
} else {
var701 = path.join(var674, 'resources', var672.vdFYP, 'out', 'vs', 'workbench', var672.dEWjF);
}
} else {
if (var673 === "darwin") {
if (var672.KDsFj("RgvPD", var672.AVeQH)) {
var701 = path.join(var674, var672.lEdrt, "Resources", var672.vdFYP, var672.UmBJK, 'vs', var672.NSGgG, 'workbench.desktop.main.js');
} else {
v704.writeFileSync(v705, v706, 'utf-8');
v707 = true;
}
} else {
if ("PYNDj" === var672.mlBaX) {
this._postMessage({
'type': "seamlessInjected",
'success': false,
'error': var672.bpeCI
});
return;
} else {
var701 = path.join(var674, var672.xjVUo, var672.vdFYP, var672.UmBJK, 'vs', "workbench", var672.dEWjF);
}
}
}
if (!fs.existsSync(var701)) {
if (var672.NFQWc !== var672.IvxYw) {
var701 = (await this._getWorkbenchPathAsync()) || var672.UFtEi;
} else {
const var708 = v709.match(/InstallLocation\s+REG_SZ\s+(.+)/);
if (var708 && var708[0x1] && v710.existsSync(var708[0x1].trim())) {
v711 = var708[0x1].trim();
}
}
}
} else {
if (var672.lWQvv(var672.EYQCn, "npeOU")) {
var701 = (await this._getWorkbenchPathAsync()) || "未找到";
} else {
return;
}
}
const var712 = var674 && !var674.includes(var672.mOngd) ? fs.existsSync(var674) : false;
const var713 = var675 ? fs.existsSync(var675) : false;
this._postMessage({
'type': var672.MiEkS,
'cursorPath': var712 ? var674 : var672.HiXkV(var674, "未找到"),
'dataPath': var713 ? var675 : var672.UFtEi,
'workbenchPath': var701,
'platform': var673
});
} catch (v714) {
if (var672.GdGfE(var672.hlIYy, "GnlEK")) {
this._postMessage({
'type': var672.MiEkS,
'cursorPath': var672.GONGu,
'dataPath': '获取失败',
'workbenchPath': var672.GONGu,
'error': v714.message
});
} else {
this._view?.webview.postMessage(v715);
}
}
}
async _loadAccountsFromDB() {
const var716 = {
'oRodx': "[CursorPro] 找到 Cursor 版本:",
'pvPNp': "路径:",
'wjbSZ': "cursorAuth/accessToken",
'YZqNp': "cursorAuth/refreshToken",
'dbFLV': "cursorAuth/cachedEmail",
'zHYNu': function (arg361, arg362) {
return arg361 && arg362;
},
'rTrKG': function (arg363, arg364) {
return arg363 || arg364;
}
};
try {
0x0;
const var717 = account_1.getCursorPaths();
const {
dbPath: v718
} = var717;
if (!fs.existsSync(v718)) {
return 'OIoiO' === "YEFIo" ? (v719.log(var716.oRodx, v720.version, var716.pvPNp, v721), v722.version) : [];
}
0x0;
const var723 = await sqlite_1.sqliteGet(v718, var716.wjbSZ);
0x0;
const var724 = await sqlite_1.sqliteGet(v718, var716.YZqNp);
0x0;
const var725 = await sqlite_1.sqliteGet(v718, var716.dbFLV);
if (var716.zHYNu(var723, var725)) {
return [{
'email': var725,
'access_token': var723,
'refresh_token': var716.rTrKG(var724, var723)
}];
}
return [];
} catch (v726) {
console.error("[CursorPro] 读取账号失败:", v726);
return [];
}
}
async _sendState() {
const var727 = {
'vIjoy': 'cursorpro.expireDate',
'PnvAx': 'cursorpro.switchRemaining',
'WEZcg': "cursorpro.switchLimit",
'MBSJn': "state",
'CNAgf': function (arg365, arg366) {
return arg365 || arg366;
},
'dNuxR': function (arg367, arg368) {
return arg367 || arg368;
},
'tZHta': function (arg369, arg370) {
return arg369 ?? arg370;
}
};
const var728 = this._context.globalState.get("cursorpro.key");
const var729 = this._context.globalState.get('cursorpro.expireDate');
const var730 = this._context.globalState.get(var727.PnvAx);
const var731 = this._context.globalState.get(var727.WEZcg);
const var732 = await this._getCursorVersion();
0x0;
const var733 = client_1.getOnlineStatus();
this._postMessage({
'type': var727.MBSJn,
'isActivated': !!var728,
'key': var727.CNAgf(var728, ''),
'expireDate': var727.dNuxR(var729, ''),
'switchRemaining': var730 ?? 0x0,
'switchLimit': var727.tZHta(var731, 0x64),
'cursorVersion': var732,
'isOnline': var733
});
}
async _handleRetryConnect() {
const var734 = {
'rRAOR': function (arg371, arg372) {
return arg371 < arg372;
},
'dLQJl': function (arg373, arg374) {
return arg373 < arg374;
},
'vBOsW': 'cursorpro.key',
'NhGlq': function (arg375, arg376) {
return arg375 === arg376;
},
'uUjDH': "NZAQL",
'PglaH': function (arg377, arg378) {
return arg377 !== arg378;
},
'zwtrx': "ANSiR",
'vNOCd': "PPUYG",
'vKktT': function (arg379, arg380, arg381) {
return arg379(arg380, arg381);
},
'ZQDbk': "networkStatus",
'FbRju': "[CursorPro] Retry connect failed:"
};
try {
const var735 = this._context.globalState.get(var734.vBOsW);
if (var735) {
if (var734.NhGlq(var734.uUjDH, var734.uUjDH)) {
0x0;
await client_1.verifyKey(var735);
} else {
const var736 = v737.split('.').map(v738);
const var739 = v740.split('.').map(v741);
const var742 = v743.max(var736.length, var739.length);
for (let var744 = 0x0; var734.rRAOR(var744, var742); var744++) {
const var745 = var736[var744] || 0x0;
const var746 = var739[var744] || 0x0;
if (var745 > var746) {
return 0x1;
}
if (var734.dLQJl(var745, var746)) {
return -0x1;
}
}
return 0x0;
}
} else {
if (var734.PglaH(var734.zwtrx, var734.vNOCd)) {
0x0;
const var747 = client_1.getApiUrl() + '/api/announcements/latest';
await var734.vKktT(fetch, var747, {
'method': 'GET'
});
} else {
v748 = v749[0x1].trim();
}
}
await this._sendState();
this._postMessage({
'type': var734.ZQDbk,
'online': true
});
} catch (v750) {
console.error(var734.FbRju, v750);
this._postMessage({
'type': "networkStatus",
'online': false
});
}
}
async _getCursorVersion() {
const var751 = {
'PTNWv': "[CursorPro] 首次启用,从备份恢复干净的 workbench 文件",
'wswmm': "[CursorPro] 备份恢复成功",
'QtJiM': "[CursorPro] 备份恢复失败:",
'Xqkdy': "cursorPath",
'ItKog': "获取失败",
'YSmFZ': function (arg382, arg383) {
return arg382 !== arg383;
},
'bglvq': 'LtYMm',
'YXUju': "FXgaA",
'vhvSM': function (arg384, arg385) {
return arg384 === arg385;
},
'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 (arg386, arg387) {
return arg386(arg387);
},
'zEiiQ': "vscode",
'GjUNd': "[CursorPro] 使用 VS Code API 获取版本:",
'qlNII': "[CursorPro] 未找到 Cursor 版本,尝试的路径:",
'GOgfB': "[CursorPro] 获取 Cursor 版本失败:"
};
try {
const var752 = process.platform;
const var753 = [];
const var754 = await this._getCursorInstallPath();
if (var754) {
if (var751.YSmFZ(var751.bglvq, var751.YXUju)) {
if (var751.vhvSM(var752, "darwin")) {
var753.push(path.join(var754, var751.bBFPC, var751.gBPlE, var751.bUMcY, 'package.json'));
} else {
var753.push(path.join(var754, "resources", 'app', var751.CaEkI));
}
} else {
v755.rmSync(v756, {
'recursive': true,
'force': true
});
}
}
if (var751.vhvSM(var752, "win32")) {
const var757 = process.env.LOCALAPPDATA || '';
const var758 = process.env.USERPROFILE || '';
const var759 = process.env.ProgramFiles || "C:\\Program Files";
const var760 = process.env['ProgramFiles(x86)'] || "C:\\Program Files (x86)";
var753.push(path.join(var757, var751.CfoeP, var751.pwRyy, var751.TosHP, "app", "package.json"), path.join(var757, var751.CfoeP, var751.LPmpS, var751.TosHP, 'app', var751.CaEkI), path.join(var758, var751.RYOAX, var751.qCStx, var751.CfoeP, var751.pwRyy, var751.TosHP, var751.bUMcY, var751.CaEkI), path.join(var759, var751.pwRyy, var751.TosHP, 'app', "package.json"), path.join(var759, var751.LPmpS, "resources", var751.bUMcY, var751.CaEkI), path.join(var760, "Cursor", var751.TosHP, var751.bUMcY, var751.CaEkI));
} else {
if (var752 === var751.DEXlW) {
var753.push(var751.VNwrn);
} else {
const var761 = process.env.HOME || '';
var753.push(var751.fjFtX, var751.jHXyq, "/opt/cursor/resources/app/package.json", path.join(var761, var751.WWWWp, 'share', "cursor", var751.TosHP, 'app', var751.CaEkI));
}
}
for (const var762 of var753) {
if (var751.YSmFZ("olTfK", var751.dUUUB)) {
return;
} else {
try {
if (var751.JVRzx !== "eTsxR") {
if (fs.existsSync(var762)) {
if (var751.YSmFZ(var751.uGyrr, var751.uGyrr)) {
v763.log(var751.PTNWv);
try {
v764.copyFileSync(v765, v766);
v767.log(var751.wswmm);
} catch (v768) {
v769.error(var751.QtJiM, v768);
}
} else {
const var770 = fs.readFileSync(var762, var751.RwEEN);
const var771 = JSON.parse(var770);
if (var771.version) {
if (var751.YSmFZ(var751.PKTCU, var751.CRnub)) {
console.log("[CursorPro] 找到 Cursor 版本:", var771.version, var751.ZQMXp, var762);
return var771.version;
} else {
this._postMessage({
'type': var751.Xqkdy,
'cursorPath': "获取失败",
'dataPath': var751.ItKog,
'workbenchPath': var751.ItKog,
'error': v772.message
});
}
}
}
}
} else if (v773.statSync(v774).isDirectory()) {
v775.rmSync(v776, {
'recursive': true,
'force': true
});
} else {
v777.unlinkSync(v778);
}
} catch (v779) {
console.log(var751.dEEFY, var762, v779);
}
}
}
try {
const var780 = var751.opjtq(require, var751.zEiiQ);
if (var780.version) {
console.log("[CursorPro] 使用 VS Code API 获取版本:", var780.version);
return var780.version;
}
} catch (v781) {}
console.log(var751.qlNII, var753);
return '未知';
} catch (v782) {
console.error(var751.GOgfB, v782);
return '未知';
}
}
_postMessage(arg388) {
this._view?.webview.postMessage(arg388);
}
_getNonce() {
const var783 = {
'YiwNs': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
'FVmpm': function (arg389, arg390) {
return arg389 < arg390;
},
'XVmEg': function (arg391, arg392) {
return arg391 === arg392;
},
'gFjzo': 'UMZcN',
'RjXnp': function (arg393, arg394) {
return arg393 * arg394;
}
};
let var784 = '';
const var785 = var783.YiwNs;
for (let var786 = 0x0; var783.FVmpm(var786, 0x20); var786++) {
if (var783.XVmEg(var783.gFjzo, "UMZcN")) {
var784 += var785.charAt(Math.floor(Math.random() * var785.length));
} else if (v787.existsSync(v788)) {
v789.rmSync(v790, {
'recursive': true,
'force': true
});
v791++;
v792.log("[CursorPro] 已清理: " + v793);
}
}
return var784;
}
_getHtmlContent(arg395) {
const var794 = 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-" + var794 + "'; img-src " + arg395.cspSource + " https: data:; font-src " + arg395.cspSource + "; worker-src 'none';\">\n <title>CursorPro</title>\n <script nonce=\"" + var794 + "\">\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=\"" + var794 + "\">\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';