aicodeswitch 2.1.5 → 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 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
@@ -0,0 +1,5 @@
1
+ 本次升级将会有破坏性影响,你需要注意:
2
+
3
+ * 升级后,不再使用数据库来持久化数据,而是使用json文件,你可以通过直接阅读json文件来查看数据
4
+ * 升级后,你需要重启服务,让新的数据持久化系统生效
5
+ * 升级后,如果遇到问题,不要惊慌,你可以直接重新安装老版本,老版本仍然使用原来的数据库文件,你可以先把老版本的数据备份后,安装新版本再来恢复数据
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;