aicodeswitch 3.6.3 → 3.9.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/dist/server/database.js +1 -1
- package/dist/server/fs-database.js +20 -6
- package/dist/server/main.js +67 -2
- package/dist/server/original-config-reader.js +181 -0
- package/dist/server/proxy-server.js +377 -228
- package/dist/ui/assets/index-COkJEguF.js +511 -0
- package/dist/ui/index.html +1 -1
- package/package.json +1 -1
- package/dist/ui/assets/index-Y_qNeXCt.js +0 -511
package/dist/server/database.js
CHANGED
|
@@ -386,7 +386,7 @@ class DatabaseManager {
|
|
|
386
386
|
CREATE TABLE IF NOT EXISTS rules (
|
|
387
387
|
id TEXT PRIMARY KEY,
|
|
388
388
|
route_id TEXT NOT NULL,
|
|
389
|
-
content_type TEXT NOT NULL CHECK(content_type IN ('default', 'background', 'thinking', 'long-context', 'image-understanding', 'model-mapping')),
|
|
389
|
+
content_type TEXT NOT NULL CHECK(content_type IN ('default', 'background', 'thinking', 'long-context', 'image-understanding', 'model-mapping', 'high-iq')),
|
|
390
390
|
target_service_id TEXT NOT NULL,
|
|
391
391
|
target_model TEXT,
|
|
392
392
|
replaced_model TEXT,
|
|
@@ -1707,7 +1707,7 @@ class FileSystemDatabaseManager {
|
|
|
1707
1707
|
if (!rule.routeId || typeof rule.routeId !== 'string') {
|
|
1708
1708
|
return { valid: false, error: `规则[${index}](${rule.id}) 缺少有效的 routeId 字段` };
|
|
1709
1709
|
}
|
|
1710
|
-
const validContentTypes = ['default', 'background', 'thinking', 'long-context', 'image-understanding', 'model-mapping'];
|
|
1710
|
+
const validContentTypes = ['default', 'background', 'thinking', 'long-context', 'image-understanding', 'model-mapping', 'high-iq'];
|
|
1711
1711
|
if (!rule.contentType || !validContentTypes.includes(rule.contentType)) {
|
|
1712
1712
|
return { valid: false, error: `规则[${index}](${rule.id}) 的 contentType 无效` };
|
|
1713
1713
|
}
|
|
@@ -2264,11 +2264,22 @@ class FileSystemDatabaseManager {
|
|
|
2264
2264
|
existing.lastRequestAt = now;
|
|
2265
2265
|
existing.requestCount++;
|
|
2266
2266
|
existing.totalTokens += session.totalTokens || 0;
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2267
|
+
if (session.vendorId !== undefined)
|
|
2268
|
+
existing.vendorId = session.vendorId;
|
|
2269
|
+
if (session.vendorName !== undefined)
|
|
2270
|
+
existing.vendorName = session.vendorName;
|
|
2271
|
+
if (session.serviceId !== undefined)
|
|
2272
|
+
existing.serviceId = session.serviceId;
|
|
2273
|
+
if (session.serviceName !== undefined)
|
|
2274
|
+
existing.serviceName = session.serviceName;
|
|
2275
|
+
if (session.model !== undefined)
|
|
2276
|
+
existing.model = session.model;
|
|
2277
|
+
if (session.highIqMode !== undefined)
|
|
2278
|
+
existing.highIqMode = session.highIqMode;
|
|
2279
|
+
if (Object.prototype.hasOwnProperty.call(session, 'highIqRuleId'))
|
|
2280
|
+
existing.highIqRuleId = session.highIqRuleId;
|
|
2281
|
+
if (Object.prototype.hasOwnProperty.call(session, 'highIqEnabledAt'))
|
|
2282
|
+
existing.highIqEnabledAt = session.highIqEnabledAt;
|
|
2272
2283
|
}
|
|
2273
2284
|
else {
|
|
2274
2285
|
// 创建新 session
|
|
@@ -2285,6 +2296,9 @@ class FileSystemDatabaseManager {
|
|
|
2285
2296
|
serviceId: session.serviceId,
|
|
2286
2297
|
serviceName: session.serviceName,
|
|
2287
2298
|
model: session.model,
|
|
2299
|
+
highIqMode: session.highIqMode,
|
|
2300
|
+
highIqRuleId: session.highIqRuleId,
|
|
2301
|
+
highIqEnabledAt: session.highIqEnabledAt,
|
|
2288
2302
|
});
|
|
2289
2303
|
}
|
|
2290
2304
|
// 异步保存(不阻塞)
|
package/dist/server/main.js
CHANGED
|
@@ -104,7 +104,7 @@ const asyncHandler = (handler) => (req, res, next) => {
|
|
|
104
104
|
next(err);
|
|
105
105
|
});
|
|
106
106
|
};
|
|
107
|
-
const writeClaudeConfig = (dbManager, enableAgentTeams) => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
const writeClaudeConfig = (dbManager, enableAgentTeams, enableBypassPermissionsSupport) => __awaiter(void 0, void 0, void 0, function* () {
|
|
108
108
|
try {
|
|
109
109
|
const homeDir = os_1.default.homedir();
|
|
110
110
|
const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 4567;
|
|
@@ -153,6 +153,13 @@ const writeClaudeConfig = (dbManager, enableAgentTeams) => __awaiter(void 0, voi
|
|
|
153
153
|
const claudeSettings = {
|
|
154
154
|
env: claudeSettingsEnv
|
|
155
155
|
};
|
|
156
|
+
// 如果开启对bypassPermissions的支持,添加对应的配置项
|
|
157
|
+
if (enableBypassPermissionsSupport) {
|
|
158
|
+
claudeSettings.permissions = {
|
|
159
|
+
defaultMode: "bypassPermissions"
|
|
160
|
+
};
|
|
161
|
+
claudeSettings.skipDangerousModePermissionPrompt = true;
|
|
162
|
+
}
|
|
156
163
|
fs_1.default.writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2));
|
|
157
164
|
// Claude Code .claude.json
|
|
158
165
|
const claudeJsonPath = path_1.default.join(homeDir, '.claude.json');
|
|
@@ -243,6 +250,57 @@ const updateClaudeAgentTeamsConfig = (enableAgentTeams) => __awaiter(void 0, voi
|
|
|
243
250
|
return false;
|
|
244
251
|
}
|
|
245
252
|
});
|
|
253
|
+
/**
|
|
254
|
+
* 更新Claude Code配置中的bypassPermissions支持设置
|
|
255
|
+
* 此函数假设配置文件已经被代理覆盖,直接修改配置而不重新备份
|
|
256
|
+
*/
|
|
257
|
+
const updateClaudeBypassPermissionsSupportConfig = (enableBypassPermissionsSupport) => __awaiter(void 0, void 0, void 0, function* () {
|
|
258
|
+
try {
|
|
259
|
+
const homeDir = os_1.default.homedir();
|
|
260
|
+
const claudeSettingsPath = path_1.default.join(homeDir, '.claude/settings.json');
|
|
261
|
+
// 检查配置文件是否存在
|
|
262
|
+
if (!fs_1.default.existsSync(claudeSettingsPath)) {
|
|
263
|
+
console.error('Claude settings.json does not exist');
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
// 读取当前配置
|
|
267
|
+
const currentContent = fs_1.default.readFileSync(claudeSettingsPath, 'utf-8');
|
|
268
|
+
const currentConfig = JSON.parse(currentContent);
|
|
269
|
+
// 检查是否是代理配置
|
|
270
|
+
const configStatus = (0, config_metadata_1.checkClaudeConfigStatus)();
|
|
271
|
+
if (!configStatus.isOverwritten) {
|
|
272
|
+
console.error('Claude config is not overwritten by proxy. Please activate a route first.');
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
// 更新或删除bypassPermissions支持配置项
|
|
276
|
+
if (enableBypassPermissionsSupport) {
|
|
277
|
+
currentConfig.permissions = {
|
|
278
|
+
defaultMode: "bypassPermissions"
|
|
279
|
+
};
|
|
280
|
+
currentConfig.skipDangerousModePermissionPrompt = true;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
delete currentConfig.permissions;
|
|
284
|
+
delete currentConfig.skipDangerousModePermissionPrompt;
|
|
285
|
+
}
|
|
286
|
+
// 写入更新后的配置
|
|
287
|
+
fs_1.default.writeFileSync(claudeSettingsPath, JSON.stringify(currentConfig, null, 2));
|
|
288
|
+
// 更新元数据中的当前配置hash
|
|
289
|
+
const metadata = (0, config_metadata_1.loadMetadata)('claude');
|
|
290
|
+
if (metadata && metadata.files[0]) {
|
|
291
|
+
metadata.files[0].currentHash = (0, crypto_1.createHash)('sha256')
|
|
292
|
+
.update(fs_1.default.readFileSync(claudeSettingsPath, 'utf-8'))
|
|
293
|
+
.digest('hex');
|
|
294
|
+
metadata.timestamp = Date.now();
|
|
295
|
+
(0, config_metadata_1.saveMetadata)(metadata);
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
console.error('Failed to update Claude bypassPermissions support config:', error);
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
246
304
|
const VALID_CODEX_REASONING_EFFORTS = ['low', 'medium', 'high'];
|
|
247
305
|
const DEFAULT_CODEX_REASONING_EFFORT = 'high';
|
|
248
306
|
const isCodexReasoningEffort = (value) => {
|
|
@@ -1417,7 +1475,8 @@ ${instruction}
|
|
|
1417
1475
|
})));
|
|
1418
1476
|
app.post('/api/write-config/claude', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1419
1477
|
const enableAgentTeams = req.body.enableAgentTeams;
|
|
1420
|
-
const
|
|
1478
|
+
const enableBypassPermissionsSupport = req.body.enableBypassPermissionsSupport;
|
|
1479
|
+
const result = yield writeClaudeConfig(dbManager, enableAgentTeams, enableBypassPermissionsSupport);
|
|
1421
1480
|
res.json(result);
|
|
1422
1481
|
})));
|
|
1423
1482
|
app.post('/api/write-config/codex', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -1434,6 +1493,12 @@ ${instruction}
|
|
|
1434
1493
|
const result = yield updateClaudeAgentTeamsConfig(enableAgentTeams);
|
|
1435
1494
|
res.json(result);
|
|
1436
1495
|
})));
|
|
1496
|
+
// 更新Claude Code配置中的bypassPermissions支持设置(当路由已激活时)
|
|
1497
|
+
app.post('/api/update-claude-bypass-permissions-support', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1498
|
+
const { enableBypassPermissionsSupport } = req.body;
|
|
1499
|
+
const result = yield updateClaudeBypassPermissionsSupportConfig(enableBypassPermissionsSupport);
|
|
1500
|
+
res.json(result);
|
|
1501
|
+
})));
|
|
1437
1502
|
app.post('/api/update-codex-reasoning-effort', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1438
1503
|
const requestedEffort = req.body.modelReasoningEffort;
|
|
1439
1504
|
if (!isCodexReasoningEffort(requestedEffort)) {
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.readOriginalConfig = exports.readCodexOriginalConfig = exports.readClaudeOriginalConfig = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const types_1 = require("../types");
|
|
11
|
+
/**
|
|
12
|
+
* TOML 解析器(简单实现,仅用于解析 Codex config.toml)
|
|
13
|
+
*/
|
|
14
|
+
const parseToml = (content) => {
|
|
15
|
+
const result = {};
|
|
16
|
+
let currentSection = result;
|
|
17
|
+
const lines = content.split('\n');
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
// 跳过空行和注释
|
|
21
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// 检查是否是 section
|
|
25
|
+
const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
|
|
26
|
+
if (sectionMatch) {
|
|
27
|
+
const sectionPath = sectionMatch[1].split('.');
|
|
28
|
+
currentSection = result;
|
|
29
|
+
for (const key of sectionPath) {
|
|
30
|
+
if (!currentSection[key]) {
|
|
31
|
+
currentSection[key] = {};
|
|
32
|
+
}
|
|
33
|
+
currentSection = currentSection[key];
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// 解析键值对
|
|
38
|
+
const kvMatch = trimmed.match(/^([^=]+)=(.*)$/);
|
|
39
|
+
if (kvMatch) {
|
|
40
|
+
const key = kvMatch[1].trim();
|
|
41
|
+
let value = kvMatch[2].trim();
|
|
42
|
+
// 移除引号
|
|
43
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
44
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
45
|
+
value = value.slice(1, -1);
|
|
46
|
+
}
|
|
47
|
+
// 尝试转换为布尔值
|
|
48
|
+
if (value === 'true') {
|
|
49
|
+
value = true;
|
|
50
|
+
}
|
|
51
|
+
else if (value === 'false') {
|
|
52
|
+
value = false;
|
|
53
|
+
}
|
|
54
|
+
currentSection[key] = value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* 读取 Claude Code 原始配置
|
|
61
|
+
* 从备份文件或当前配置文件中读取(如果未激活路由)
|
|
62
|
+
*/
|
|
63
|
+
const readClaudeOriginalConfig = () => {
|
|
64
|
+
var _a, _b, _c;
|
|
65
|
+
try {
|
|
66
|
+
const homeDir = os_1.default.homedir();
|
|
67
|
+
const settingsPath = path_1.default.join(homeDir, '.claude/settings.json');
|
|
68
|
+
const settingsBakPath = path_1.default.join(homeDir, '.claude/settings.json.aicodeswitch_backup');
|
|
69
|
+
// 优先读取备份文件(原始配置)
|
|
70
|
+
let configPath = settingsBakPath;
|
|
71
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
72
|
+
// 如果没有备份,尝试读取当前配置
|
|
73
|
+
configPath = settingsPath;
|
|
74
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
75
|
+
console.log('No Claude config file found');
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const content = fs_1.default.readFileSync(configPath, 'utf-8');
|
|
80
|
+
const config = JSON.parse(content);
|
|
81
|
+
// 提取配置信息
|
|
82
|
+
const baseUrl = ((_a = config.env) === null || _a === void 0 ? void 0 : _a.ANTHROPIC_BASE_URL) || 'https://api.anthropic.com';
|
|
83
|
+
const apiKey = ((_b = config.env) === null || _b === void 0 ? void 0 : _b.ANTHROPIC_AUTH_TOKEN) || ((_c = config.env) === null || _c === void 0 ? void 0 : _c.ANTHROPIC_API_KEY) || '';
|
|
84
|
+
if (!apiKey) {
|
|
85
|
+
console.log('No API key found in Claude config');
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
apiUrl: baseUrl,
|
|
90
|
+
apiKey: apiKey,
|
|
91
|
+
authType: types_1.AuthType.AUTH_TOKEN,
|
|
92
|
+
sourceType: 'claude',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error('Failed to read Claude original config:', error);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
exports.readClaudeOriginalConfig = readClaudeOriginalConfig;
|
|
101
|
+
/**
|
|
102
|
+
* 读取 Codex 原始配置
|
|
103
|
+
* 从备份文件或当前配置文件中读取(如果未激活路由)
|
|
104
|
+
*/
|
|
105
|
+
const readCodexOriginalConfig = () => {
|
|
106
|
+
try {
|
|
107
|
+
const homeDir = os_1.default.homedir();
|
|
108
|
+
const configPath = path_1.default.join(homeDir, '.codex/config.toml');
|
|
109
|
+
const configBakPath = path_1.default.join(homeDir, '.codex/config.toml.aicodeswitch_backup');
|
|
110
|
+
const authPath = path_1.default.join(homeDir, '.codex/auth.json');
|
|
111
|
+
// 优先读取备份文件(原始配置)
|
|
112
|
+
let tomlPath = configBakPath;
|
|
113
|
+
if (!fs_1.default.existsSync(tomlPath)) {
|
|
114
|
+
// 如果没有备份,尝试读取当前配置
|
|
115
|
+
tomlPath = configPath;
|
|
116
|
+
if (!fs_1.default.existsSync(tomlPath)) {
|
|
117
|
+
console.log('No Codex config file found');
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const tomlContent = fs_1.default.readFileSync(tomlPath, 'utf-8');
|
|
122
|
+
const config = parseToml(tomlContent);
|
|
123
|
+
// 提取 base_url
|
|
124
|
+
let baseUrl = '';
|
|
125
|
+
let model = config.model;
|
|
126
|
+
// 从 model_providers 中查找配置
|
|
127
|
+
if (config.model_providers) {
|
|
128
|
+
const providerName = config.model_provider;
|
|
129
|
+
if (providerName && config.model_providers[providerName]) {
|
|
130
|
+
baseUrl = config.model_providers[providerName].base_url;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!baseUrl) {
|
|
134
|
+
console.log('No base_url found in Codex config');
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
// 读取 API key(从 auth.json)
|
|
138
|
+
let apiKey = '';
|
|
139
|
+
if (fs_1.default.existsSync(authPath)) {
|
|
140
|
+
try {
|
|
141
|
+
const authContent = fs_1.default.readFileSync(authPath, 'utf-8');
|
|
142
|
+
const authConfig = JSON.parse(authContent);
|
|
143
|
+
// Codex 的 auth.json 可能包含多个 provider 的 key
|
|
144
|
+
// 尝试读取常见的字段
|
|
145
|
+
apiKey = authConfig.api_key || authConfig.openai_api_key || authConfig.key || '';
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error('Failed to read Codex auth.json:', error);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!apiKey) {
|
|
152
|
+
console.log('No API key found in Codex auth.json');
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
apiUrl: baseUrl,
|
|
157
|
+
apiKey: apiKey,
|
|
158
|
+
authType: types_1.AuthType.API_KEY,
|
|
159
|
+
sourceType: 'openai',
|
|
160
|
+
model: model,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
console.error('Failed to read Codex original config:', error);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
exports.readCodexOriginalConfig = readCodexOriginalConfig;
|
|
169
|
+
/**
|
|
170
|
+
* 根据目标类型读取原始配置
|
|
171
|
+
*/
|
|
172
|
+
const readOriginalConfig = (targetType) => {
|
|
173
|
+
if (targetType === 'claude-code') {
|
|
174
|
+
return (0, exports.readClaudeOriginalConfig)();
|
|
175
|
+
}
|
|
176
|
+
else if (targetType === 'codex') {
|
|
177
|
+
return (0, exports.readCodexOriginalConfig)();
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
};
|
|
181
|
+
exports.readOriginalConfig = readOriginalConfig;
|