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 +1 -0
- package/bin/upgrade.js +29 -5
- package/dist/server/fs-database.js +80 -2
- package/dist/server/main.js +23 -0
- package/dist/server/proxy-server.js +345 -14
- package/dist/server/type-migration.js +68 -0
- package/dist/ui/assets/{index-BCdyCT1c.js → index-BtoE4g4L.js} +8 -7
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
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
|
|
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(
|
|
278
|
-
|
|
279
|
-
|
|
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 +
|
|
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 +
|
|
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 })));
|
package/dist/server/main.js
CHANGED
|
@@ -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);
|