4308 lines
298 KiB
JavaScript
4308 lines
298 KiB
JavaScript
'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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\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'; |