@adversity/coding-tool-x 3.1.0 → 3.1.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/CHANGELOG.md +39 -18
- package/README.md +8 -8
- package/dist/web/assets/ConfigTemplates-Bidwfdf2.css +1 -0
- package/dist/web/assets/ConfigTemplates-DvcbKKdS.js +1 -0
- package/dist/web/assets/Home-BJKPCBuk.css +1 -0
- package/dist/web/assets/Home-Cw-F_Wnu.js +1 -0
- package/dist/web/assets/PluginManager-ROyoZ-6m.css +1 -0
- package/dist/web/assets/PluginManager-jy_4GVxI.js +1 -0
- package/dist/web/assets/ProjectList-C1fQb9OW.css +1 -0
- package/dist/web/assets/ProjectList-Df1-NcNr.js +1 -0
- package/dist/web/assets/SessionList-BGJWyneI.css +1 -0
- package/dist/web/assets/SessionList-UWcZtC2r.js +1 -0
- package/dist/web/assets/SkillManager-D7pd-d_P.css +1 -0
- package/dist/web/assets/SkillManager-IRdseMKB.js +1 -0
- package/dist/web/assets/Terminal-BasTyDut.js +1 -0
- package/dist/web/assets/Terminal-DGNJeVtc.css +1 -0
- package/dist/web/assets/WorkspaceManager-CrwgQgmP.css +1 -0
- package/dist/web/assets/WorkspaceManager-D-D2kK1V.js +1 -0
- package/dist/web/assets/icons-kcfLIMBB.js +1 -0
- package/dist/web/assets/index-CoB3zF0K.css +1 -0
- package/dist/web/assets/index-CryrSLv8.js +2 -0
- package/dist/web/assets/markdown-BfC0goYb.css +10 -0
- package/dist/web/assets/markdown-C9MYpaSi.js +1 -0
- package/dist/web/assets/naive-ui-CSrLusZZ.js +1 -0
- package/dist/web/assets/{vendors-D2HHw_aW.js → vendors-CO3Upi1d.js} +2 -2
- package/dist/web/assets/vue-vendor-DqyWIXEb.js +45 -0
- package/dist/web/assets/xterm-6GBZ9nXN.css +32 -0
- package/dist/web/assets/xterm-BJzAjXCH.js +13 -0
- package/dist/web/index.html +8 -6
- package/package.json +4 -2
- package/src/commands/channels.js +48 -1
- package/src/commands/cli-type.js +4 -2
- package/src/commands/daemon.js +81 -12
- package/src/commands/doctor.js +10 -9
- package/src/commands/list.js +1 -1
- package/src/commands/logs.js +6 -4
- package/src/commands/port-config.js +24 -4
- package/src/commands/proxy-control.js +12 -6
- package/src/commands/search.js +1 -1
- package/src/commands/security.js +3 -2
- package/src/commands/stats.js +226 -52
- package/src/commands/switch.js +1 -1
- package/src/commands/toggle-proxy.js +31 -6
- package/src/commands/update.js +97 -0
- package/src/commands/workspace.js +1 -1
- package/src/config/default.js +41 -2
- package/src/config/loader.js +74 -8
- package/src/config/model-metadata.js +415 -0
- package/src/config/model-pricing.js +23 -93
- package/src/config/paths.js +105 -33
- package/src/index.js +64 -3
- package/src/plugins/constants.js +3 -2
- package/src/plugins/plugin-api.js +1 -1
- package/src/reset-config.js +4 -2
- package/src/server/api/agents.js +57 -14
- package/src/server/api/channels.js +112 -33
- package/src/server/api/codex-channels.js +111 -18
- package/src/server/api/codex-proxy.js +14 -8
- package/src/server/api/commands.js +71 -18
- package/src/server/api/config-export.js +0 -6
- package/src/server/api/config-registry.js +11 -3
- package/src/server/api/config.js +376 -5
- package/src/server/api/convert.js +133 -0
- package/src/server/api/dashboard.js +22 -6
- package/src/server/api/gemini-channels.js +107 -18
- package/src/server/api/gemini-proxy.js +14 -8
- package/src/server/api/gemini-sessions.js +1 -1
- package/src/server/api/health-check.js +4 -3
- package/src/server/api/mcp.js +3 -3
- package/src/server/api/opencode-channels.js +497 -0
- package/src/server/api/opencode-projects.js +99 -0
- package/src/server/api/opencode-proxy.js +207 -0
- package/src/server/api/opencode-sessions.js +345 -0
- package/src/server/api/opencode-statistics.js +57 -0
- package/src/server/api/plugins.js +66 -19
- package/src/server/api/prompts.js +2 -2
- package/src/server/api/proxy.js +7 -4
- package/src/server/api/sessions.js +3 -0
- package/src/server/api/settings.js +111 -0
- package/src/server/api/skills.js +69 -18
- package/src/server/api/workspaces.js +78 -6
- package/src/server/codex-proxy-server.js +36 -22
- package/src/server/dev-server.js +1 -1
- package/src/server/gemini-proxy-server.js +21 -7
- package/src/server/index.js +174 -58
- package/src/server/opencode-proxy-server.js +5486 -0
- package/src/server/proxy-server.js +33 -22
- package/src/server/services/agents-service.js +61 -24
- package/src/server/services/channel-scheduler.js +9 -5
- package/src/server/services/channels.js +64 -37
- package/src/server/services/codex-channels.js +56 -43
- package/src/server/services/codex-sessions.js +105 -6
- package/src/server/services/codex-settings-manager.js +271 -49
- package/src/server/services/codex-statistics-service.js +2 -2
- package/src/server/services/commands-service.js +84 -25
- package/src/server/services/config-export-service.js +7 -45
- package/src/server/services/config-registry-service.js +63 -17
- package/src/server/services/config-sync-manager.js +160 -7
- package/src/server/services/config-templates-service.js +204 -51
- package/src/server/services/env-checker.js +50 -13
- package/src/server/services/env-manager.js +155 -19
- package/src/server/services/favorites.js +5 -3
- package/src/server/services/gemini-channels.js +33 -44
- package/src/server/services/gemini-statistics-service.js +2 -2
- package/src/server/services/mcp-service.js +350 -9
- package/src/server/services/model-detector.js +707 -221
- package/src/server/services/network-access.js +80 -0
- package/src/server/services/opencode-channels.js +208 -0
- package/src/server/services/opencode-gateway-converter.js +639 -0
- package/src/server/services/opencode-sessions.js +931 -0
- package/src/server/services/opencode-settings-manager.js +478 -0
- package/src/server/services/opencode-statistics-service.js +255 -0
- package/src/server/services/plugins-service.js +479 -22
- package/src/server/services/prompts-service.js +53 -11
- package/src/server/services/proxy-runtime.js +1 -1
- package/src/server/services/repo-scanner-base.js +1 -1
- package/src/server/services/response-decoder.js +21 -0
- package/src/server/services/security-config.js +1 -1
- package/src/server/services/session-cache.js +1 -1
- package/src/server/services/skill-service.js +300 -46
- package/src/server/services/speed-test.js +464 -186
- package/src/server/services/statistics-service.js +2 -2
- package/src/server/services/terminal-commands.js +10 -3
- package/src/server/services/terminal-config.js +1 -1
- package/src/server/services/ui-config.js +1 -1
- package/src/server/services/workspace-service.js +57 -100
- package/src/server/websocket-server.js +156 -8
- package/src/ui/menu.js +49 -40
- package/src/utils/port-helper.js +22 -8
- package/src/utils/session.js +5 -4
- package/dist/web/assets/icons-CO_2OFES.js +0 -1
- package/dist/web/assets/index-DI8QOi-E.js +0 -14
- package/dist/web/assets/index-uLHGdeZh.css +0 -41
- package/dist/web/assets/naive-ui-B1re3c-e.js +0 -1
- package/dist/web/assets/vue-vendor-6JaYHOiI.js +0 -44
- package/src/server/api/oauth.js +0 -294
- package/src/server/api/permissions.js +0 -385
- package/src/server/config/oauth-providers.js +0 -68
- package/src/server/services/oauth-callback-server.js +0 -284
- package/src/server/services/oauth-service.js +0 -378
- package/src/server/services/oauth-token-storage.js +0 -135
- package/src/server/services/permission-templates-service.js +0 -308
package/src/server/index.js
CHANGED
|
@@ -3,6 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
5
|
const { loadConfig } = require('../config/loader');
|
|
6
|
+
const { ensureStorageDirMigrated } = require('../config/paths');
|
|
6
7
|
const { startWebSocketServer: attachWebSocketServer } = require('./websocket-server');
|
|
7
8
|
const { isPortInUse, killProcessByPort, waitForPortRelease } = require('../utils/port-helper');
|
|
8
9
|
const { isProxyConfig } = require('./services/settings-manager');
|
|
@@ -10,41 +11,71 @@ const {
|
|
|
10
11
|
isProxyConfig: isCodexProxyConfig,
|
|
11
12
|
setProxyConfig: setCodexProxyConfig
|
|
12
13
|
} = require('./services/codex-settings-manager');
|
|
14
|
+
const { setProxyConfig: setOpenCodeProxyConfig } = require('./services/opencode-settings-manager');
|
|
13
15
|
const { startProxyServer } = require('./proxy-server');
|
|
14
16
|
const { startCodexProxyServer } = require('./codex-proxy-server');
|
|
15
17
|
const { startGeminiProxyServer } = require('./gemini-proxy-server');
|
|
18
|
+
const { startOpenCodeProxyServer, collectProxyModelList } = require('./opencode-proxy-server');
|
|
19
|
+
const { createRemoteMutationGuard, createRemoteRouteGuard } = require('./services/network-access');
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
function isInteractivePortConflictMode(options = {}) {
|
|
22
|
+
if (options.interactive === false) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (process.argv.includes('--daemon')) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return Boolean(process.stdin && process.stdin.isTTY && process.stdout && process.stdout.isTTY);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function printPortConflictHelp(port) {
|
|
32
|
+
console.log(chalk.yellow('\n💡 解决方案:'));
|
|
33
|
+
console.log(chalk.gray(' 1. 运行 ctx 命令,选择"配置端口"修改端口'));
|
|
34
|
+
console.log(chalk.gray(` 2. 或手动关闭占用端口 ${port} 的程序\n`));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function startServer(port, host = '127.0.0.1', options = {}) {
|
|
38
|
+
ensureStorageDirMigrated();
|
|
18
39
|
const config = loadConfig();
|
|
19
40
|
// 使用配置的端口,如果没有传入参数
|
|
20
41
|
if (!port) {
|
|
21
|
-
port = config.ports?.webUI ||
|
|
42
|
+
port = config.ports?.webUI || 19999;
|
|
22
43
|
}
|
|
23
44
|
|
|
24
45
|
// 检查端口是否被占用
|
|
25
|
-
const portInUse = await isPortInUse(port);
|
|
46
|
+
const portInUse = await isPortInUse(port, host);
|
|
26
47
|
if (portInUse) {
|
|
27
48
|
console.log(chalk.yellow(`\n⚠️ 端口 ${port} 已被占用\n`));
|
|
28
49
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
const interactiveMode = isInteractivePortConflictMode(options);
|
|
51
|
+
let shouldKill = false;
|
|
52
|
+
|
|
53
|
+
if (options.forceKillPort === true) {
|
|
54
|
+
shouldKill = true;
|
|
55
|
+
} else if (interactiveMode) {
|
|
56
|
+
// 询问用户是否关闭占用端口的进程
|
|
57
|
+
const answer = await inquirer.prompt([
|
|
58
|
+
{
|
|
59
|
+
type: 'list',
|
|
60
|
+
name: 'shouldKill',
|
|
61
|
+
message: '是否关闭占用该端口的进程并启动服务?',
|
|
62
|
+
choices: [
|
|
63
|
+
{ name: '是,关闭进程并启动', value: true },
|
|
64
|
+
{ name: '否,取消启动', value: false }
|
|
65
|
+
],
|
|
66
|
+
default: 0 // 默认选择"是"
|
|
67
|
+
}
|
|
68
|
+
]);
|
|
69
|
+
shouldKill = answer.shouldKill;
|
|
70
|
+
} else {
|
|
71
|
+
console.error(chalk.red('❌ 当前为非交互模式,无法确认端口清理操作,已取消启动。'));
|
|
72
|
+
printPortConflictHelp(port);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
42
75
|
|
|
43
76
|
if (!shouldKill) {
|
|
44
77
|
console.log(chalk.gray('\n已取消启动'));
|
|
45
|
-
|
|
46
|
-
console.log(chalk.gray(' 1. 运行 ctx 命令,选择"配置端口"修改端口'));
|
|
47
|
-
console.log(chalk.gray(` 2. 或手动关闭占用端口 ${port} 的程序\n`));
|
|
78
|
+
printPortConflictHelp(port);
|
|
48
79
|
process.exit(0);
|
|
49
80
|
}
|
|
50
81
|
|
|
@@ -60,7 +91,7 @@ async function startServer(port, host = '127.0.0.1') {
|
|
|
60
91
|
|
|
61
92
|
// 等待端口释放
|
|
62
93
|
console.log(chalk.cyan('等待端口释放...'));
|
|
63
|
-
const released = await waitForPortRelease(port);
|
|
94
|
+
const released = await waitForPortRelease(port, 3000, host);
|
|
64
95
|
|
|
65
96
|
if (!released) {
|
|
66
97
|
console.error(chalk.red('\n❌ 端口释放超时'));
|
|
@@ -72,6 +103,9 @@ async function startServer(port, host = '127.0.0.1') {
|
|
|
72
103
|
}
|
|
73
104
|
|
|
74
105
|
const app = express();
|
|
106
|
+
const lanMode = host === '0.0.0.0';
|
|
107
|
+
const allowRemoteMutation = process.env.CC_TOOL_ALLOW_REMOTE_WRITE === 'true';
|
|
108
|
+
const allowRemoteTerminal = process.env.CC_TOOL_ALLOW_REMOTE_TERMINAL === 'true';
|
|
75
109
|
|
|
76
110
|
// Middleware
|
|
77
111
|
app.use(express.json({ limit: '100mb' }));
|
|
@@ -88,6 +122,20 @@ async function startServer(port, host = '127.0.0.1') {
|
|
|
88
122
|
next();
|
|
89
123
|
});
|
|
90
124
|
|
|
125
|
+
if (lanMode) {
|
|
126
|
+
app.use('/api', createRemoteMutationGuard({
|
|
127
|
+
enabled: true,
|
|
128
|
+
allowRemoteMutation,
|
|
129
|
+
message: '出于安全考虑,LAN 模式默认仅允许本机执行写操作。可设置 CC_TOOL_ALLOW_REMOTE_WRITE=true 覆盖。'
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
app.use('/api/terminal', createRemoteRouteGuard({
|
|
133
|
+
enabled: true,
|
|
134
|
+
allowRemoteAccess: allowRemoteTerminal,
|
|
135
|
+
message: '出于安全考虑,Web 终端仅允许本机访问。可设置 CC_TOOL_ALLOW_REMOTE_TERMINAL=true 覆盖。'
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
91
139
|
// API Routes
|
|
92
140
|
app.use('/api/projects', require('./api/projects')(config));
|
|
93
141
|
app.use('/api/sessions', require('./api/sessions')(config));
|
|
@@ -103,6 +151,13 @@ async function startServer(port, host = '127.0.0.1') {
|
|
|
103
151
|
app.use('/api/gemini/channels', require('./api/gemini-channels')(config));
|
|
104
152
|
app.use('/api/gemini/proxy', require('./api/gemini-proxy'));
|
|
105
153
|
|
|
154
|
+
// OpenCode API Routes
|
|
155
|
+
app.use('/api/opencode/projects', require('./api/opencode-projects')(config));
|
|
156
|
+
app.use('/api/opencode/sessions', require('./api/opencode-sessions')(config));
|
|
157
|
+
app.use('/api/opencode/channels', require('./api/opencode-channels')(config));
|
|
158
|
+
app.use('/api/opencode/proxy', require('./api/opencode-proxy'));
|
|
159
|
+
app.use('/api/opencode/statistics', require('./api/opencode-statistics'));
|
|
160
|
+
|
|
106
161
|
// 会话格式转换 API
|
|
107
162
|
app.use('/api/convert', require('./api/convert'));
|
|
108
163
|
|
|
@@ -145,18 +200,12 @@ async function startServer(port, host = '127.0.0.1') {
|
|
|
145
200
|
// 配置模板 API
|
|
146
201
|
app.use('/api/config-templates', require('./api/config-templates'));
|
|
147
202
|
|
|
148
|
-
// 命令执行权限 API
|
|
149
|
-
app.use('/api/permissions', require('./api/permissions'));
|
|
150
|
-
|
|
151
203
|
// 配置导出/导入 API
|
|
152
204
|
app.use('/api/config-export', require('./api/config-export'));
|
|
153
205
|
|
|
154
206
|
// 配置同步 API
|
|
155
207
|
app.use('/api/config-sync', require('./api/config-sync'));
|
|
156
208
|
|
|
157
|
-
// OAuth API
|
|
158
|
-
app.use('/api/oauth', require('./api/oauth'));
|
|
159
|
-
|
|
160
209
|
// 配置注册表 API (集中管理 skills/commands/agents/rules 的启用/禁用)
|
|
161
210
|
app.use('/api/config-registry', require('./api/config-registry'));
|
|
162
211
|
|
|
@@ -172,38 +221,56 @@ async function startServer(port, host = '127.0.0.1') {
|
|
|
172
221
|
});
|
|
173
222
|
}
|
|
174
223
|
|
|
175
|
-
// Start server
|
|
176
|
-
const server = app.listen(port, host
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
224
|
+
// Start server(确保监听成功后才返回,避免命令误报“已启动”)
|
|
225
|
+
const server = app.listen(port, host);
|
|
226
|
+
await new Promise((resolve) => {
|
|
227
|
+
const onListening = () => {
|
|
228
|
+
server.off('error', onError);
|
|
229
|
+
resolve();
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const onError = (err) => {
|
|
233
|
+
server.off('listening', onListening);
|
|
234
|
+
if (err.code === 'EADDRINUSE') {
|
|
235
|
+
console.error(chalk.red(`\n❌ 端口 ${port} 已被占用`));
|
|
236
|
+
console.error(chalk.yellow('\n💡 解决方案:'));
|
|
237
|
+
console.error(chalk.gray(' 1. 运行 ctx 命令,选择"配置端口"修改端口'));
|
|
238
|
+
console.error(chalk.gray(` 2. 或关闭占用端口 ${port} 的程序\n`));
|
|
239
|
+
} else {
|
|
240
|
+
console.error(chalk.red(`\n❌ 启动服务器失败: ${err.message}\n`));
|
|
241
|
+
}
|
|
242
|
+
process.exit(1);
|
|
243
|
+
};
|
|
185
244
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
245
|
+
server.once('listening', onListening);
|
|
246
|
+
server.once('error', onError);
|
|
247
|
+
});
|
|
189
248
|
|
|
190
|
-
|
|
191
|
-
|
|
249
|
+
console.log(`\n🚀 Coding-Tool Web UI running at:`);
|
|
250
|
+
if (host === '0.0.0.0') {
|
|
251
|
+
console.log(chalk.yellow(` ⚠️ 警告: 服务正在监听所有网络接口 (LAN 可访问)`));
|
|
252
|
+
console.log(` http://localhost:${port}`);
|
|
253
|
+
console.log(chalk.gray(` http://<your-ip>:${port} (LAN 访问)`));
|
|
254
|
+
} else {
|
|
255
|
+
console.log(` http://localhost:${port}`);
|
|
256
|
+
}
|
|
192
257
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
});
|
|
258
|
+
// 附加 WebSocket 服务器到同一个端口
|
|
259
|
+
attachWebSocketServer(server, { host, allowRemoteTerminal });
|
|
260
|
+
console.log(` ws://localhost:${port}/ws\n`);
|
|
196
261
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
262
|
+
if (host === '0.0.0.0' && !allowRemoteMutation) {
|
|
263
|
+
console.log(chalk.yellow(' 🔒 已启用 LAN 安全保护:远程写操作默认禁用'));
|
|
264
|
+
}
|
|
265
|
+
if (host === '0.0.0.0' && !allowRemoteTerminal) {
|
|
266
|
+
console.log(chalk.yellow(' 🔒 已启用 LAN 安全保护:远程 Web 终端默认禁用'));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// 自动恢复代理状态
|
|
270
|
+
autoRestoreProxies();
|
|
271
|
+
|
|
272
|
+
// 延迟执行健康检查,避免阻塞启动
|
|
273
|
+
setTimeout(() => performStartupHealthCheck(), 2000);
|
|
207
274
|
|
|
208
275
|
return server;
|
|
209
276
|
}
|
|
@@ -215,13 +282,13 @@ function autoRestoreProxies() {
|
|
|
215
282
|
const fs = require('fs');
|
|
216
283
|
const path = require('path');
|
|
217
284
|
|
|
218
|
-
const ccToolDir = path.join(os.homedir(), '.
|
|
285
|
+
const ccToolDir = path.join(os.homedir(), '.cc-tool');
|
|
219
286
|
|
|
220
287
|
// 检查 Claude 代理状态文件
|
|
221
288
|
const claudeActiveFile = path.join(ccToolDir, 'active-channel.json');
|
|
222
289
|
if (fs.existsSync(claudeActiveFile)) {
|
|
223
290
|
console.log(chalk.cyan('\n🔄 检测到 Claude 代理状态文件,正在自动启动...'));
|
|
224
|
-
const proxyPort = config.ports?.proxy ||
|
|
291
|
+
const proxyPort = config.ports?.proxy || 20088;
|
|
225
292
|
startProxyServer(proxyPort)
|
|
226
293
|
.then(() => {
|
|
227
294
|
console.log(chalk.green(`✅ Claude 代理已自动启动,端口: ${proxyPort}`));
|
|
@@ -235,7 +302,7 @@ function autoRestoreProxies() {
|
|
|
235
302
|
const codexActiveFile = path.join(ccToolDir, 'codex-active-channel.json');
|
|
236
303
|
if (fs.existsSync(codexActiveFile)) {
|
|
237
304
|
console.log(chalk.cyan('\n🔄 检测到 Codex 代理状态文件,正在自动启动...'));
|
|
238
|
-
const codexProxyPort = config.ports?.codexProxy ||
|
|
305
|
+
const codexProxyPort = config.ports?.codexProxy || 20089;
|
|
239
306
|
startCodexProxyServer(codexProxyPort)
|
|
240
307
|
.then((result) => {
|
|
241
308
|
const port = result?.port || codexProxyPort;
|
|
@@ -260,7 +327,7 @@ function autoRestoreProxies() {
|
|
|
260
327
|
const geminiActiveFile = path.join(ccToolDir, 'gemini-active-channel.json');
|
|
261
328
|
if (fs.existsSync(geminiActiveFile)) {
|
|
262
329
|
console.log(chalk.cyan('\n🔄 检测到 Gemini 代理状态文件,正在自动启动...'));
|
|
263
|
-
const geminiProxyPort = config.ports?.geminiProxy ||
|
|
330
|
+
const geminiProxyPort = config.ports?.geminiProxy || 20090;
|
|
264
331
|
startGeminiProxyServer(geminiProxyPort)
|
|
265
332
|
.then((result) => {
|
|
266
333
|
if (result.success) {
|
|
@@ -275,6 +342,55 @@ function autoRestoreProxies() {
|
|
|
275
342
|
} else {
|
|
276
343
|
console.log(chalk.gray('\n💡 提示: 如需使用 Gemini 代理,请在前端界面激活 Gemini 渠道'));
|
|
277
344
|
}
|
|
345
|
+
|
|
346
|
+
// 检查 OpenCode 代理状态文件
|
|
347
|
+
const opencodeActiveFile = path.join(ccToolDir, 'opencode-active-channel.json');
|
|
348
|
+
if (fs.existsSync(opencodeActiveFile)) {
|
|
349
|
+
console.log(chalk.cyan('\n🔄 检测到 OpenCode 代理状态文件,正在自动启动...'));
|
|
350
|
+
const opencodeProxyPort = config.ports?.opencodeProxy || 20091;
|
|
351
|
+
startOpenCodeProxyServer(opencodeProxyPort)
|
|
352
|
+
.then(async (result) => {
|
|
353
|
+
if (result.success) {
|
|
354
|
+
console.log(chalk.green(`✅ OpenCode 代理已自动启动,端口: ${result.port}`));
|
|
355
|
+
try {
|
|
356
|
+
const { getEnabledChannels: getEnabledOpenCodeChannels } = require('./services/opencode-channels');
|
|
357
|
+
const enabledChs = getEnabledOpenCodeChannels();
|
|
358
|
+
const allModels = [];
|
|
359
|
+
const seen = new Set();
|
|
360
|
+
enabledChs.forEach((ch) => {
|
|
361
|
+
[ch.model, ch.speedTestModel].forEach((m) => {
|
|
362
|
+
if (typeof m === 'string' && m.trim() && !seen.has(m.trim().toLowerCase())) {
|
|
363
|
+
seen.add(m.trim().toLowerCase());
|
|
364
|
+
allModels.push(m.trim());
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
const detectedModels = await collectProxyModelList(enabledChs, { useCacheOnly: true });
|
|
369
|
+
if (Array.isArray(detectedModels)) {
|
|
370
|
+
detectedModels.forEach((m) => {
|
|
371
|
+
if (typeof m === 'string' && m.trim() && !seen.has(m.trim().toLowerCase())) {
|
|
372
|
+
seen.add(m.trim().toLowerCase());
|
|
373
|
+
allModels.push(m.trim());
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
const firstChannel = enabledChs[0];
|
|
378
|
+
const activeModel = firstChannel && (firstChannel.model || firstChannel.speedTestModel) || null;
|
|
379
|
+
const cfgResult = setOpenCodeProxyConfig(result.port, { model: activeModel, models: allModels });
|
|
380
|
+
if (cfgResult?.success) {
|
|
381
|
+
console.log(chalk.gray(' 已同步 OpenCode 配置文件'));
|
|
382
|
+
}
|
|
383
|
+
} catch (err) {
|
|
384
|
+
console.error(chalk.red(`❌ OpenCode 代理配置同步失败: ${err.message}`));
|
|
385
|
+
}
|
|
386
|
+
} else {
|
|
387
|
+
console.error(chalk.red(`❌ OpenCode 代理启动失败: ${result.error || 'Unknown error'}`));
|
|
388
|
+
}
|
|
389
|
+
})
|
|
390
|
+
.catch((err) => {
|
|
391
|
+
console.error(chalk.red(`❌ OpenCode 代理启动失败: ${err.message}`));
|
|
392
|
+
});
|
|
393
|
+
}
|
|
278
394
|
}
|
|
279
395
|
|
|
280
396
|
// 启动时执行健康检查
|