功能: - 激活码管理 (Pro/Auto 两种类型) - 账号池管理 - 设备绑定记录 - 使用日志 - 搜索/筛选功能 - 禁用/启用功能 (支持退款参考) - 全局设置 (换号间隔、额度消耗等) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
264 lines
11 KiB
JavaScript
264 lines
11 KiB
JavaScript
'use strict';
|
||
|
||
// ============================================
|
||
// CursorPro 无感换号模块 - 详细分析
|
||
// ============================================
|
||
|
||
const vscode = require('vscode');
|
||
const client = require('./api/client');
|
||
const account = require('./utils/account');
|
||
|
||
/**
|
||
* ============================================
|
||
* 无感换号 (Seamless Mode) 工作原理
|
||
* ============================================
|
||
*
|
||
* 核心思路:
|
||
* 1. 用户配置一个"账号池",包含多个 Cursor 账号的 token
|
||
* 2. 当检测到当前账号额度用尽或即将用尽时
|
||
* 3. 自动从账号池中选择下一个可用账号
|
||
* 4. 无缝切换到新账号,用户无感知
|
||
*
|
||
* 关键 API 端点:
|
||
* - /api/seamless/status 获取无缝模式状态
|
||
* - /api/seamless/config 获取/更新无缝配置
|
||
* - /api/seamless/inject 注入无缝模式到本地
|
||
* - /api/seamless/restore 恢复原始设置
|
||
* - /api/seamless/accounts 获取账号池列表
|
||
* - /api/seamless/token 获取指定账号的 token
|
||
* - /api/seamless/switch 切换到指定账号
|
||
*/
|
||
|
||
// ============================================
|
||
// 无缝模式配置结构
|
||
// ============================================
|
||
|
||
/**
|
||
* @typedef {Object} SeamlessConfig
|
||
* @property {boolean} enabled - 是否启用无缝模式
|
||
* @property {string} mode - 切换模式: 'auto' | 'manual'
|
||
* @property {number} switchThreshold - 切换阈值 (剩余额度百分比)
|
||
* @property {string[]} accountPool - 账号池 (userKey 列表)
|
||
* @property {number} currentIndex - 当前使用的账号索引
|
||
*/
|
||
const defaultSeamlessConfig = {
|
||
enabled: false,
|
||
mode: 'auto', // 自动切换
|
||
switchThreshold: 10, // 当剩余额度低于 10% 时切换
|
||
accountPool: [],
|
||
currentIndex: 0
|
||
};
|
||
|
||
// ============================================
|
||
// 无缝模式核心函数
|
||
// ============================================
|
||
|
||
/**
|
||
* 获取无缝模式状态
|
||
* 检查服务端是否支持无缝模式,以及当前用户是否有权使用
|
||
*/
|
||
async function getSeamlessStatus() {
|
||
return client.request('/api/seamless/status');
|
||
}
|
||
|
||
/**
|
||
* 获取无缝模式配置
|
||
* 从服务端获取用户的无缝模式配置
|
||
*/
|
||
async function getSeamlessConfig() {
|
||
return client.request('/api/seamless/config');
|
||
}
|
||
|
||
/**
|
||
* 更新无缝模式配置
|
||
* @param {SeamlessConfig} config - 新的配置
|
||
*/
|
||
async function updateSeamlessConfig(config) {
|
||
return client.request('/api/seamless/config', 'POST', config);
|
||
}
|
||
|
||
/**
|
||
* 获取用户切换状态
|
||
* 检查指定用户当前的使用状态,判断是否需要切换
|
||
* @param {string} userKey - 用户标识
|
||
*/
|
||
async function getUserSwitchStatus(userKey) {
|
||
return client.request('/api/seamless/user-status?key=' + encodeURIComponent(userKey));
|
||
}
|
||
|
||
/**
|
||
* 注入无缝模式
|
||
* 将无缝模式的配置写入本地 Cursor
|
||
*
|
||
* 这是无感换号的核心!
|
||
* 它会修改 Cursor 的认证配置,使其指向一个代理服务器
|
||
* 代理服务器会自动处理账号切换
|
||
*
|
||
* @param {string} apiUrl - 无缝模式的 API 代理地址
|
||
* @param {string} userKey - 用户标识
|
||
*/
|
||
async function injectSeamless(apiUrl, userKey) {
|
||
const result = await client.request('/api/seamless/inject', 'POST', {
|
||
api_url: apiUrl,
|
||
user_key: userKey
|
||
});
|
||
|
||
if (result.success && result.data) {
|
||
// 将返回的账号数据写入本地
|
||
// 这里的关键是:写入的 token 是代理服务器的 token
|
||
// 代理服务器会根据使用情况自动切换真实账号
|
||
await account.writeAccountToLocal(result.data);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 恢复原始设置
|
||
* 移除无缝模式,恢复到单账号模式
|
||
*/
|
||
async function restoreSeamless() {
|
||
return client.request('/api/seamless/restore', 'POST');
|
||
}
|
||
|
||
/**
|
||
* 获取账号池列表
|
||
* 返回用户配置的所有账号
|
||
*/
|
||
async function getSeamlessAccounts() {
|
||
return client.request('/api/seamless/accounts');
|
||
}
|
||
|
||
/**
|
||
* 同步账号池
|
||
* 将本地账号列表同步到服务端
|
||
* @param {Array} accounts - 账号列表
|
||
*/
|
||
async function syncSeamlessAccounts(accounts) {
|
||
return client.request('/api/seamless/accounts', 'POST', { accounts });
|
||
}
|
||
|
||
/**
|
||
* 获取指定账号的 Token
|
||
* @param {string} userKey - 用户标识
|
||
*/
|
||
async function getSeamlessToken(userKey) {
|
||
return client.request('/api/seamless/token?key=' + encodeURIComponent(userKey));
|
||
}
|
||
|
||
/**
|
||
* 手动切换到指定账号
|
||
* @param {string} userKey - 要切换到的账号标识
|
||
*/
|
||
async function switchSeamlessToken(userKey) {
|
||
const result = await client.request('/api/seamless/switch', 'POST', {
|
||
mode: 'seamless',
|
||
userKey: userKey
|
||
});
|
||
|
||
if (result.success && result.data) {
|
||
await account.writeAccountToLocal(result.data);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
// ============================================
|
||
// 无感换号流程图
|
||
// ============================================
|
||
|
||
/**
|
||
*
|
||
* ┌─────────────────────────────────────────────────────────────────┐
|
||
* │ 无感换号工作流程 │
|
||
* ├─────────────────────────────────────────────────────────────────┤
|
||
* │ │
|
||
* │ ┌──────────────┐ │
|
||
* │ │ 用户请求 │ │
|
||
* │ │ (使用 Cursor) │ │
|
||
* │ └──────┬───────┘ │
|
||
* │ │ │
|
||
* │ ▼ │
|
||
* │ ┌──────────────┐ ┌──────────────┐ │
|
||
* │ │ Cursor 客户端 │────▶│ 代理服务器 │ (CursorPro API) │
|
||
* │ │ (本地修改后) │ │ │ │
|
||
* │ └──────────────┘ └──────┬───────┘ │
|
||
* │ │ │
|
||
* │ ▼ │
|
||
* │ ┌──────────────┐ │
|
||
* │ │ 检查当前账号 │ │
|
||
* │ │ 额度是否充足 │ │
|
||
* │ └──────┬───────┘ │
|
||
* │ │ │
|
||
* │ ┌───────────────┼───────────────┐ │
|
||
* │ │ │ │ │
|
||
* │ ▼ ▼ ▼ │
|
||
* │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||
* │ │ 账号 A │ │ 账号 B │ │ 账号 C │ (账号池) │
|
||
* │ │ 额度:5% │ │ 额度:80% │ │ 额度:60% │ │
|
||
* │ └─────────┘ └────┬────┘ └─────────┘ │
|
||
* │ │ │
|
||
* │ ▼ │
|
||
* │ ┌──────────────┐ │
|
||
* │ │ 使用账号 B │ (额度最充足) │
|
||
* │ │ 转发请求 │ │
|
||
* │ └──────┬───────┘ │
|
||
* │ │ │
|
||
* │ ▼ │
|
||
* │ ┌──────────────┐ │
|
||
* │ │ Cursor API │ │
|
||
* │ │ (官方服务器) │ │
|
||
* │ └──────┬───────┘ │
|
||
* │ │ │
|
||
* │ ▼ │
|
||
* │ ┌──────────────┐ │
|
||
* │ │ 返回结果给 │ │
|
||
* │ │ 用户 │ │
|
||
* │ └──────────────┘ │
|
||
* │ │
|
||
* │ 用户全程无感知,只要账号池中有任一账号有额度,就能继续使用 │
|
||
* │ │
|
||
* └─────────────────────────────────────────────────────────────────┘
|
||
*
|
||
*/
|
||
|
||
// ============================================
|
||
// 无感换号的技术实现细节
|
||
// ============================================
|
||
|
||
/**
|
||
* 关键技术点:
|
||
*
|
||
* 1. 代理注入
|
||
* - 修改本地 Cursor 的 API 端点指向代理服务器
|
||
* - 所有请求先经过代理,代理决定使用哪个真实账号
|
||
*
|
||
* 2. Token 管理
|
||
* - 代理服务器维护账号池的所有 token
|
||
* - 根据各账号的额度情况动态选择
|
||
*
|
||
* 3. 切换策略
|
||
* - 自动模式:当前账号额度 < 阈值时自动切换
|
||
* - 手动模式:用户手动选择要使用的账号
|
||
*
|
||
* 4. 本地写入的数据
|
||
* - accessToken: 代理服务器生成的特殊 token
|
||
* - refreshToken: 用于刷新代理 token
|
||
* - 设备 ID: 统一使用代理分配的 ID,避免被检测
|
||
*/
|
||
|
||
const seamlessModule = {
|
||
getSeamlessStatus,
|
||
getSeamlessConfig,
|
||
updateSeamlessConfig,
|
||
getUserSwitchStatus,
|
||
injectSeamless,
|
||
restoreSeamless,
|
||
getSeamlessAccounts,
|
||
syncSeamlessAccounts,
|
||
getSeamlessToken,
|
||
switchSeamlessToken
|
||
};
|
||
|
||
module.exports = seamlessModule;
|