aicodeswitch 3.0.20 → 3.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,6 +29,7 @@ AI Code Switch 是帮助你在本地管理 AI 编程工具接入大模型的工
29
29
  * 导入和导出:一键备份数据,在多太电脑间共享aicodeswitch配置
30
30
  * 自定义API Key,支持B/S架构,让aicodeswitch成为在线服务,提供给团队使用
31
31
  * 数据完全本地,自主可控
32
+ * 特殊语法:在发送的提示词最前面添加!!来直接切换为高智商模型服务,简单快捷
32
33
 
33
34
  ## 桌面客户端
34
35
 
package/bin/upgrade.js CHANGED
@@ -231,8 +231,7 @@ const upgrade = async () => {
231
231
  chalk.yellow.bold('⚠️ Sudo privileges required\n\n') +
232
232
  chalk.white('This operation requires ') + chalk.yellow.bold('sudo') + chalk.white(' privileges.\n\n') +
233
233
  chalk.white('Please run the following command to upgrade:\n\n') +
234
- chalk.cyan.bold(' sudo npm install -g ' + PACKAGE_NAME + '@latest\n\n') +
235
- chalk.gray('After upgrading, run ') + chalk.cyan('aicos restart') + chalk.gray(' to restart the server.'),
234
+ chalk.cyan.bold(' sudo npm install -g ' + PACKAGE_NAME + '@latest'),
236
235
  {
237
236
  padding: 1,
238
237
  margin: 1,
@@ -241,6 +240,19 @@ const upgrade = async () => {
241
240
  }
242
241
  ));
243
242
  console.log('');
243
+ console.log(boxen(
244
+ chalk.red.bold('⚠️ 重启服务以使更改生效\n\n') +
245
+ chalk.white('升级完成后,必须重启服务才能使用新版本!\n\n') +
246
+ chalk.white('执行命令: ') + chalk.cyan.bold('aicos restart'),
247
+ {
248
+ padding: 1,
249
+ margin: 1,
250
+ borderStyle: 'round',
251
+ borderColor: 'red',
252
+ backgroundColor: 'red'
253
+ }
254
+ ));
255
+ console.log('');
244
256
  process.exit(0);
245
257
  }
246
258
 
@@ -274,9 +286,21 @@ const upgrade = async () => {
274
286
  }
275
287
  ));
276
288
  console.log('');
277
- console.log(chalk.cyan('💡 Tips:\n'));
278
- console.log(chalk.white(' • Restart server: ') + chalk.cyan('aicos restart'));
279
- console.log(chalk.white(' • Check version: ') + chalk.cyan('aicos version'));
289
+ console.log(boxen(
290
+ chalk.red.bold('⚠️ 重启服务以使更改生效\n\n') +
291
+ chalk.white('升级完成后,必须重启服务才能使用新版本!\n\n') +
292
+ chalk.white('执行命令: ') + chalk.cyan.bold('aicos restart'),
293
+ {
294
+ padding: 1,
295
+ margin: 1,
296
+ borderStyle: 'round',
297
+ borderColor: 'red',
298
+ backgroundColor: 'red'
299
+ }
300
+ ));
301
+ console.log('');
302
+ console.log(chalk.cyan('💡 其他命令:\n'));
303
+ console.log(chalk.white(' • 查看版本: ') + chalk.cyan('aicos version'));
280
304
  console.log('\n');
281
305
  };
282
306
 
@@ -28,6 +28,7 @@ const path_1 = __importDefault(require("path"));
28
28
  const promises_1 = __importDefault(require("fs/promises"));
29
29
  const crypto_1 = __importDefault(require("crypto"));
30
30
  const crypto_js_1 = __importDefault(require("crypto-js"));
31
+ const type_migration_1 = require("./type-migration");
31
32
  /**
32
33
  * 基于文件系统的数据库管理器
33
34
  * 使用 JSON 文件存储数据,无需编译依赖
@@ -206,6 +207,8 @@ class FileSystemDatabaseManager {
206
207
  yield promises_1.default.mkdir(this.dataPath, { recursive: true });
207
208
  // 加载所有数据
208
209
  yield this.loadAllData();
210
+ // 执行数据源类型迁移(在加载数据之后)
211
+ yield this.migrateSourceTypes();
209
212
  // 确保默认配置
210
213
  yield this.ensureDefaultConfig();
211
214
  });
@@ -293,6 +296,77 @@ class FileSystemDatabaseManager {
293
296
  }
294
297
  });
295
298
  }
299
+ /**
300
+ * 迁移数据源类型(在初始化时执行)
301
+ * 处理 vendors.json 中的 services[].sourceType
302
+ * 将旧类型 ('claude-code', 'openai-responses') 迁移为新类型 ('claude', 'openai')
303
+ */
304
+ migrateSourceTypes() {
305
+ return __awaiter(this, void 0, void 0, function* () {
306
+ console.log('[TypeMigration] Checking for source type migration...');
307
+ let needsMigration = false;
308
+ // 检查是否需要迁移
309
+ for (const vendor of this.vendors) {
310
+ if (vendor.services) {
311
+ for (const service of vendor.services) {
312
+ if (service.sourceType && (0, type_migration_1.isLegacySourceType)(service.sourceType)) {
313
+ needsMigration = true;
314
+ break;
315
+ }
316
+ }
317
+ }
318
+ if (needsMigration)
319
+ break;
320
+ }
321
+ if (!needsMigration) {
322
+ console.log('[TypeMigration] No migration needed');
323
+ return;
324
+ }
325
+ console.log('[TypeMigration] Starting source type migration...');
326
+ // 备份当前数据到 ~/.aicodeswitch/backup/YYYY-MM-DD-HH-MM/
327
+ const now = new Date();
328
+ const year = now.getFullYear();
329
+ const month = String(now.getMonth() + 1).padStart(2, '0');
330
+ const day = String(now.getDate()).padStart(2, '0');
331
+ const hours = String(now.getHours()).padStart(2, '0');
332
+ const minutes = String(now.getMinutes()).padStart(2, '0');
333
+ const dateStr = `${year}-${month}-${day}-${hours}-${minutes}`;
334
+ const appDir = path_1.default.dirname(this.dataPath); // ~/.aicodeswitch/
335
+ const backupBaseDir = path_1.default.join(appDir, 'backup');
336
+ const backupDir = path_1.default.join(backupBaseDir, dateStr);
337
+ yield promises_1.default.mkdir(backupDir, { recursive: true });
338
+ const vendorsBackupPath = path_1.default.join(backupDir, 'vendors.json');
339
+ yield promises_1.default.writeFile(vendorsBackupPath, JSON.stringify(this.vendors, null, 2));
340
+ console.log(`[TypeMigration] Backup created: ${vendorsBackupPath}`);
341
+ // 执行迁移
342
+ let migratedCount = 0;
343
+ for (const vendor of this.vendors) {
344
+ if (vendor.services) {
345
+ for (const service of vendor.services) {
346
+ if (service.sourceType && (0, type_migration_1.isLegacySourceType)(service.sourceType)) {
347
+ const oldType = service.sourceType;
348
+ service.sourceType = (0, type_migration_1.migrateSourceType)(service.sourceType);
349
+ console.log(`[TypeMigration] Migrated service "${service.name}": ${oldType} -> ${service.sourceType}`);
350
+ migratedCount++;
351
+ }
352
+ }
353
+ }
354
+ }
355
+ // 保存迁移后的数据
356
+ yield this.saveVendors();
357
+ console.log(`[TypeMigration] Migration completed. Migrated ${migratedCount} services.`);
358
+ });
359
+ }
360
+ /**
361
+ * 迁移导入数据中的类型
362
+ * 用于导入功能,自动将旧类型转换为新类型
363
+ */
364
+ migrateVendorsOnImport(vendors) {
365
+ return vendors.map(vendor => {
366
+ var _a;
367
+ return (Object.assign(Object.assign({}, vendor), { services: (_a = vendor.services) === null || _a === void 0 ? void 0 : _a.map(service => (Object.assign(Object.assign({}, service), { sourceType: service.sourceType ? (0, type_migration_1.normalizeSourceType)(service.sourceType) : undefined }))) }));
368
+ });
369
+ }
296
370
  saveVendors() {
297
371
  return __awaiter(this, void 0, void 0, function* () {
298
372
  // 确保每个供应商都有 services 数组
@@ -1507,7 +1581,7 @@ class FileSystemDatabaseManager {
1507
1581
  const existing = this.blacklist.get(key);
1508
1582
  if (existing) {
1509
1583
  existing.blacklistedAt = now;
1510
- existing.expiresAt = now + 10 * 60 * 1000;
1584
+ existing.expiresAt = now + 2 * 60 * 1000; // 2分钟黑名单(从10分钟缩短)
1511
1585
  existing.errorCount++;
1512
1586
  existing.lastError = errorMessage;
1513
1587
  existing.lastStatusCode = statusCode;
@@ -1519,7 +1593,7 @@ class FileSystemDatabaseManager {
1519
1593
  routeId,
1520
1594
  contentType,
1521
1595
  blacklistedAt: now,
1522
- expiresAt: now + 10 * 60 * 1000,
1596
+ expiresAt: now + 2 * 60 * 1000, // 2分钟黑名单(从10分钟缩短)
1523
1597
  errorCount: 1,
1524
1598
  lastError: errorMessage,
1525
1599
  lastStatusCode: statusCode,
@@ -1807,6 +1881,10 @@ class FileSystemDatabaseManager {
1807
1881
  if (!validation.valid) {
1808
1882
  return { success: false, message: '导入失败', details: `数据验证失败:${validation.error}` };
1809
1883
  }
1884
+ // 自动迁移导入数据中的旧类型
1885
+ if (importData.vendors) {
1886
+ importData.vendors = this.migrateVendorsOnImport(importData.vendors);
1887
+ }
1810
1888
  // 导入数据(更新 updatedAt)
1811
1889
  const now = Date.now();
1812
1890
  this.vendors = importData.vendors.map((v) => (Object.assign(Object.assign({}, v), { updatedAt: now })));
@@ -28,6 +28,7 @@ const utils_1 = require("./utils");
28
28
  const tools_service_1 = require("./tools-service");
29
29
  const websocket_service_1 = require("./websocket-service");
30
30
  const rules_status_service_1 = require("./rules-status-service");
31
+ const type_migration_1 = require("./type-migration");
31
32
  const config_metadata_1 = require("./config-metadata");
32
33
  const config_1 = require("./config");
33
34
  const appDir = path_1.default.join(os_1.default.homedir(), '.aicodeswitch');
@@ -75,6 +76,28 @@ const app = (0, express_1.default)();
75
76
  app.use((0, cors_1.default)());
76
77
  app.use(express_1.default.json({ limit: 'Infinity' }));
77
78
  app.use(express_1.default.urlencoded({ extended: true, limit: 'Infinity' }));
79
+ // 类型转换中间件:自动将旧的数据源类型转换为新类型
80
+ app.use((req, _res, next) => {
81
+ if (req.body && typeof req.body === 'object') {
82
+ // 转换 sourceType
83
+ if (req.body.sourceType && typeof req.body.sourceType === 'string') {
84
+ if ((0, type_migration_1.isLegacySourceType)(req.body.sourceType)) {
85
+ console.log(`[API] Converting legacy sourceType: ${req.body.sourceType} -> ${(0, type_migration_1.normalizeSourceType)(req.body.sourceType)}`);
86
+ req.body.sourceType = (0, type_migration_1.normalizeSourceType)(req.body.sourceType);
87
+ }
88
+ }
89
+ // 转换数组中的 sourceType(如 vendors 的 services)
90
+ if (Array.isArray(req.body.services)) {
91
+ req.body.services = req.body.services.map((service) => {
92
+ if (service.sourceType && (0, type_migration_1.isLegacySourceType)(service.sourceType)) {
93
+ return Object.assign(Object.assign({}, service), { sourceType: (0, type_migration_1.normalizeSourceType)(service.sourceType) });
94
+ }
95
+ return service;
96
+ });
97
+ }
98
+ }
99
+ next();
100
+ });
78
101
  const asyncHandler = (handler) => (req, res, next) => {
79
102
  Promise.resolve(handler(req, res, next)).catch((err) => {
80
103
  console.error('[asyncHandler] Caught error:', err);