aicodeswitch 2.1.6 → 3.0.1
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 +2 -4
- package/UPGRADE.md +5 -0
- package/bin/restore.js +56 -0
- package/dist/server/database-factory.js +158 -0
- package/dist/server/fs-database.js +1510 -0
- package/dist/server/main.js +40 -42
- package/dist/server/migrate-to-fs.js +253 -0
- package/dist/server/proxy-server.js +80 -17
- package/dist/server/transformers/chunk-collector.js +2 -1
- package/dist/ui/assets/index-Bo5rJH01.js +472 -0
- package/dist/ui/assets/index-uPfIRVTr.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +7 -4
- package/dist/ui/assets/index-BQXOnRap.js +0 -470
- package/dist/ui/assets/index-BVblbmz5.css +0 -1
- package/dist/ui/migration.md +0 -7
package/README.md
CHANGED
|
@@ -10,10 +10,6 @@ AI Code Switch 是帮助你在本地管理 AI 编程工具接入大模型的工
|
|
|
10
10
|
- 视频演示:[https://www.bilibili.com/video/BV1uEznBuEJd/](https://www.bilibili.com/video/BV1uEznBuEJd/?from=github)
|
|
11
11
|
- 1分钟让Claude Code接入GLM国产模型:[https://www.bilibili.com/video/BV1a865B8ErA/](https://www.bilibili.com/video/BV1a865B8ErA/)
|
|
12
12
|
|
|
13
|
-
## 桌面版
|
|
14
|
-
|
|
15
|
-
桌面端应用下载:[https://github.com/tangshuang/aicodeswitch/releases](https://github.com/tangshuang/aicodeswitch/releases)
|
|
16
|
-
|
|
17
13
|
## 命令行工具
|
|
18
14
|
|
|
19
15
|
### 安装
|
|
@@ -22,6 +18,8 @@ AI Code Switch 是帮助你在本地管理 AI 编程工具接入大模型的工
|
|
|
22
18
|
npm install -g aicodeswitch
|
|
23
19
|
```
|
|
24
20
|
|
|
21
|
+
**注意:**由于工具依赖sqlite和leveldb作为数据存储,在安装过程中,会执行这两个数据库的编译,如果你是在windows电脑上安装,你需要安装 visual studio 2017 以上版本,才能正常编译数据库,macos 和 linux 系统中一般都自带了编译工具,因此大部分情况下都能正确编译。
|
|
22
|
+
|
|
25
23
|
### 使用方法
|
|
26
24
|
|
|
27
25
|
**启动服务**
|
package/UPGRADE.md
ADDED
package/bin/restore.js
CHANGED
|
@@ -5,6 +5,43 @@ const chalk = require('chalk');
|
|
|
5
5
|
const boxen = require('boxen');
|
|
6
6
|
const ora = require('ora');
|
|
7
7
|
|
|
8
|
+
// 停用所有激活的路由(直接操作数据库文件)
|
|
9
|
+
const deactivateAllRoutes = () => {
|
|
10
|
+
const appDir = path.join(os.homedir(), '.aicodeswitch');
|
|
11
|
+
const routesFilePath = path.join(appDir, 'data', 'routes.json');
|
|
12
|
+
|
|
13
|
+
// 如果数据文件不存在,说明没有路由需要停用
|
|
14
|
+
if (!fs.existsSync(routesFilePath)) {
|
|
15
|
+
return { success: true, deactivatedCount: 0, reason: 'no_data_file' };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
// 读取路由数据
|
|
20
|
+
const routesData = JSON.parse(fs.readFileSync(routesFilePath, 'utf-8'));
|
|
21
|
+
|
|
22
|
+
if (!Array.isArray(routesData)) {
|
|
23
|
+
return { success: false, error: 'Invalid routes data format' };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let deactivatedCount = 0;
|
|
27
|
+
|
|
28
|
+
// 将所有激活的路由设置为停用状态
|
|
29
|
+
routesData.forEach(route => {
|
|
30
|
+
if (route.isActive === true) {
|
|
31
|
+
route.isActive = false;
|
|
32
|
+
deactivatedCount++;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 保存修改后的数据
|
|
37
|
+
fs.writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2));
|
|
38
|
+
|
|
39
|
+
return { success: true, deactivatedCount };
|
|
40
|
+
} catch (err) {
|
|
41
|
+
return { success: false, error: err.message };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
8
45
|
// 恢复 Claude Code 配置
|
|
9
46
|
const restoreClaudeConfig = () => {
|
|
10
47
|
const results = {
|
|
@@ -218,6 +255,25 @@ const restore = async () => {
|
|
|
218
255
|
showRestoreResult('codex', codexResults);
|
|
219
256
|
}
|
|
220
257
|
|
|
258
|
+
// 停用所有激活的路由
|
|
259
|
+
console.log('');
|
|
260
|
+
const routesSpinner = ora({
|
|
261
|
+
text: chalk.yellow('Deactivating all active routes...'),
|
|
262
|
+
color: 'yellow'
|
|
263
|
+
}).start();
|
|
264
|
+
|
|
265
|
+
const routesResult = deactivateAllRoutes();
|
|
266
|
+
|
|
267
|
+
if (routesResult.success) {
|
|
268
|
+
if (routesResult.deactivatedCount > 0) {
|
|
269
|
+
routesSpinner.succeed(chalk.green(`Deactivated ${routesResult.deactivatedCount} active route(s)`));
|
|
270
|
+
} else {
|
|
271
|
+
routesSpinner.info(chalk.gray('No active routes to deactivate'));
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
routesSpinner.fail(chalk.red(`Failed to deactivate routes: ${routesResult.error}`));
|
|
275
|
+
}
|
|
276
|
+
|
|
221
277
|
console.log('');
|
|
222
278
|
console.log(chalk.cyan('💡 Tips:\n'));
|
|
223
279
|
console.log(chalk.white(' • Restart server: ') + chalk.cyan('aicos restart'));
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.DatabaseFactory = void 0;
|
|
49
|
+
const path_1 = __importDefault(require("path"));
|
|
50
|
+
const fs_database_1 = require("./fs-database");
|
|
51
|
+
const migrateToFs = __importStar(require("./migrate-to-fs"));
|
|
52
|
+
/**
|
|
53
|
+
* 数据库工厂
|
|
54
|
+
* 根据配置创建相应的数据库实例
|
|
55
|
+
*/
|
|
56
|
+
class DatabaseFactory {
|
|
57
|
+
/**
|
|
58
|
+
* 创建数据库实例
|
|
59
|
+
* @param dataPath 数据存储路径
|
|
60
|
+
* @param type 数据库类型,默认使用文件系统
|
|
61
|
+
*/
|
|
62
|
+
static create(dataPath_1) {
|
|
63
|
+
return __awaiter(this, arguments, void 0, function* (dataPath, type = 'filesystem') {
|
|
64
|
+
if (type === 'filesystem') {
|
|
65
|
+
const db = new fs_database_1.FileSystemDatabaseManager(dataPath);
|
|
66
|
+
yield db.initialize();
|
|
67
|
+
return db;
|
|
68
|
+
}
|
|
69
|
+
// 如果用户明确要求使用 SQLite,尝试加载
|
|
70
|
+
if (type === 'sqlite') {
|
|
71
|
+
try {
|
|
72
|
+
const { DatabaseManager } = yield Promise.resolve().then(() => __importStar(require('./database.js')));
|
|
73
|
+
const db = new DatabaseManager(dataPath);
|
|
74
|
+
yield db.initialize();
|
|
75
|
+
return db;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error('[Database] Failed to load SQLite database, falling back to filesystem:', error);
|
|
79
|
+
console.log('[Database] Using filesystem database instead');
|
|
80
|
+
const db = new fs_database_1.FileSystemDatabaseManager(dataPath);
|
|
81
|
+
yield db.initialize();
|
|
82
|
+
return db;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Unknown database type: ${type}`);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 自动检测并创建数据库实例
|
|
90
|
+
* 优先使用文件系统数据库,如果存在旧的 SQLite 数据库则自动迁移
|
|
91
|
+
*/
|
|
92
|
+
static createAuto(dataPath) {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
const fs = yield Promise.resolve().then(() => __importStar(require('fs/promises')));
|
|
95
|
+
// 检查迁移完成标记文件
|
|
96
|
+
const migrationMarkerPath = path_1.default.join(dataPath, '.migration-completed');
|
|
97
|
+
const hasMigrationMarker = yield fs.access(migrationMarkerPath)
|
|
98
|
+
.then(() => true)
|
|
99
|
+
.catch(() => false);
|
|
100
|
+
// 检查是否存在文件系统数据库
|
|
101
|
+
const fsDbExists = yield fs.access(path_1.default.join(dataPath, 'config.json'))
|
|
102
|
+
.then(() => true)
|
|
103
|
+
.catch(() => false);
|
|
104
|
+
// 如果存在迁移标记且文件系统数据库存在,使用文件系统数据库
|
|
105
|
+
if (hasMigrationMarker && fsDbExists) {
|
|
106
|
+
console.log('[Database] Migration marker found, using filesystem database');
|
|
107
|
+
return this.create(dataPath, 'filesystem');
|
|
108
|
+
}
|
|
109
|
+
// 如果不存在迁移标记但存在文件系统数据库,可能是用户手动删除了标记
|
|
110
|
+
// 这种情况下仍然使用文件系统数据库(避免数据丢失)
|
|
111
|
+
if (fsDbExists) {
|
|
112
|
+
console.log('[Database] Using existing filesystem database (no migration marker)');
|
|
113
|
+
return this.create(dataPath, 'filesystem');
|
|
114
|
+
}
|
|
115
|
+
// 检查是否存在旧的 SQLite 数据库
|
|
116
|
+
const sqliteDbExists = yield fs.access(path_1.default.join(dataPath, 'app.db'))
|
|
117
|
+
.then(() => true)
|
|
118
|
+
.catch(() => false);
|
|
119
|
+
if (sqliteDbExists) {
|
|
120
|
+
console.log('[Database] Found old SQLite database, migrating to filesystem...');
|
|
121
|
+
try {
|
|
122
|
+
// 执行迁移
|
|
123
|
+
yield migrateToFs.migrateToFileSystem(dataPath);
|
|
124
|
+
// 验证迁移结果
|
|
125
|
+
console.log('[Database] Verifying migration...');
|
|
126
|
+
const verification = yield migrateToFs.verifyMigration(dataPath);
|
|
127
|
+
if (verification.success) {
|
|
128
|
+
console.log('[Database] ✅ Migration verified successfully');
|
|
129
|
+
if (verification.warnings.length > 0) {
|
|
130
|
+
console.log('[Database] Warnings:', verification.warnings);
|
|
131
|
+
}
|
|
132
|
+
// 只有在验证成功后才创建标记文件
|
|
133
|
+
const migrationMarkerPath = path_1.default.join(dataPath, '.migration-completed');
|
|
134
|
+
yield fs.writeFile(migrationMarkerPath, new Date().toISOString(), 'utf-8');
|
|
135
|
+
console.log('[Database] Migration marker file created:', migrationMarkerPath);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
console.error('[Database] ❌ Migration verification failed');
|
|
139
|
+
console.error('[Database] Errors:', verification.errors);
|
|
140
|
+
throw new Error('Migration verification failed');
|
|
141
|
+
}
|
|
142
|
+
console.log('[Database] Migration completed, using filesystem database');
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.error('[Database] Migration failed:', error);
|
|
146
|
+
console.log('[Database] Creating new filesystem database');
|
|
147
|
+
// 迁移失败时,原始数据库文件保持不变
|
|
148
|
+
// 用户可以使用老版本继续运行,或手动重新配置
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.log('[Database] No existing database found, creating new filesystem database');
|
|
153
|
+
}
|
|
154
|
+
return this.create(dataPath, 'filesystem');
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.DatabaseFactory = DatabaseFactory;
|