coding-tool-x 3.4.3 → 3.4.4
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/web/assets/{Analytics-CbGxotgz.js → Analytics-_Byi9M6y.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-oP6nrFEb.js → ConfigTemplates-DIwosdtG.js} +1 -1
- package/dist/web/assets/{Home-DMntmEvh.js → Home-DdNMuQ9c.js} +1 -1
- package/dist/web/assets/{PluginManager-BUC_c7nH.js → PluginManager-iuY24cnW.js} +1 -1
- package/dist/web/assets/{ProjectList-oJIyIRkP.css → ProjectList-DL4JK6ci.css} +1 -1
- package/dist/web/assets/{ProjectList-CW8J49n7.js → ProjectList-DSkMulzL.js} +1 -1
- package/dist/web/assets/{SessionList-7lYnF92v.js → SessionList-B6pGquIr.js} +1 -1
- package/dist/web/assets/{SkillManager-Cs08216i.js → SkillManager-CHtQX5r8.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CY-oGtyB.js → WorkspaceManager-gNPs-VaI.js} +1 -1
- package/dist/web/assets/index-DGjGCo37.js +2 -0
- package/dist/web/assets/{index-5qy5NMIP.css → index-pMqqe9ei.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/commands/channels.js +13 -13
- package/src/commands/cli-type.js +5 -5
- package/src/commands/daemon.js +31 -31
- package/src/commands/doctor.js +14 -14
- package/src/commands/export-config.js +23 -23
- package/src/commands/list.js +4 -4
- package/src/commands/logs.js +19 -19
- package/src/commands/plugin.js +62 -62
- package/src/commands/port-config.js +4 -4
- package/src/commands/proxy-control.js +35 -35
- package/src/commands/proxy.js +28 -28
- package/src/commands/resume.js +4 -4
- package/src/commands/search.js +9 -9
- package/src/commands/security.js +5 -5
- package/src/commands/stats.js +18 -18
- package/src/commands/switch.js +1 -1
- package/src/commands/toggle-proxy.js +18 -18
- package/src/commands/ui.js +11 -11
- package/src/commands/update.js +9 -9
- package/src/commands/workspace.js +11 -11
- package/src/index.js +24 -24
- package/src/plugins/plugin-installer.js +1 -1
- package/src/reset-config.js +9 -9
- package/src/server/api/channels.js +1 -1
- package/src/server/api/claude-hooks.js +2 -2
- package/src/server/api/plugins.js +4 -0
- package/src/server/api/pm2-autostart.js +2 -2
- package/src/server/api/proxy.js +6 -6
- package/src/server/api/skills.js +4 -0
- package/src/server/dev-server.js +2 -2
- package/src/server/index.js +37 -37
- package/src/server/proxy-server.js +4 -4
- package/src/server/services/config-export-service.js +1 -1
- package/src/server/services/mcp-service.js +2 -1
- package/src/server/services/model-detector.js +2 -2
- package/src/server/services/native-keychain.js +1 -0
- package/src/server/services/plugins-service.js +7 -27
- package/src/server/services/settings-manager.js +3 -3
- package/src/server/services/skill-service.js +4 -12
- package/src/server/websocket-server.js +8 -8
- package/src/ui/menu.js +2 -2
- package/src/ui/prompts.js +5 -5
- package/dist/web/assets/index-ClCqKpvX.js +0 -2
|
@@ -151,7 +151,7 @@ async function handleToggleProxy() {
|
|
|
151
151
|
const cliType = config.currentCliType || 'claude';
|
|
152
152
|
const services = getProxyServices(cliType);
|
|
153
153
|
if (!services) {
|
|
154
|
-
console.log(chalk.red(`\n
|
|
154
|
+
console.log(chalk.red(`\n[ERROR] 当前 CLI 类型 (${cliType}) 暂不支持动态切换\n`));
|
|
155
155
|
return;
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -171,9 +171,9 @@ async function handleToggleProxy() {
|
|
|
171
171
|
*/
|
|
172
172
|
async function handleStartProxy(cliType, services) {
|
|
173
173
|
console.clear();
|
|
174
|
-
console.log(chalk.bold.cyan('\n
|
|
174
|
+
console.log(chalk.bold.cyan('\n╔=======================================╗'));
|
|
175
175
|
console.log(chalk.bold.cyan('║ 开启动态切换 ║'));
|
|
176
|
-
console.log(chalk.bold.cyan('
|
|
176
|
+
console.log(chalk.bold.cyan('╚=======================================╝\n'));
|
|
177
177
|
|
|
178
178
|
const toolNameMap = {
|
|
179
179
|
claude: 'Claude Code',
|
|
@@ -190,7 +190,7 @@ async function handleStartProxy(cliType, services) {
|
|
|
190
190
|
console.log(chalk.gray('• 通过 Web UI 或"渠道管理"功能快速调整启用的线路'));
|
|
191
191
|
console.log(chalk.gray(`• 代理服务地址: http://127.0.0.1:${defaultPort}\n`));
|
|
192
192
|
|
|
193
|
-
console.log(chalk.yellow('
|
|
193
|
+
console.log(chalk.yellow('[WARN] 重要提示:'));
|
|
194
194
|
console.log(chalk.yellow('• 开启期间请勿关闭 CLI 终端窗口'));
|
|
195
195
|
console.log(chalk.yellow('• 如果异常关闭导致代理失效,请运行: ctx reset'));
|
|
196
196
|
console.log(chalk.yellow('• 或使用主菜单的"恢复默认配置"功能\n'));
|
|
@@ -210,7 +210,7 @@ async function handleStartProxy(cliType, services) {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
try {
|
|
213
|
-
console.log(chalk.cyan('\n
|
|
213
|
+
console.log(chalk.cyan('\n[START] 正在启动代理服务...\n'));
|
|
214
214
|
|
|
215
215
|
// 启动代理服务器
|
|
216
216
|
const proxyResult = await services.startProxyServer();
|
|
@@ -219,19 +219,19 @@ async function handleStartProxy(cliType, services) {
|
|
|
219
219
|
throw new Error('代理服务器启动失败');
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
console.log(chalk.green(
|
|
222
|
+
console.log(chalk.green(`[OK] 代理服务已启动: http://127.0.0.1:${proxyResult.port}`));
|
|
223
223
|
|
|
224
224
|
// 修改配置文件
|
|
225
225
|
const settingsManager = getSettingsManager(cliType);
|
|
226
226
|
clearNativeOAuth(cliType);
|
|
227
227
|
settingsManager.setProxyConfig(proxyResult.port);
|
|
228
|
-
console.log(chalk.green('
|
|
228
|
+
console.log(chalk.green('[OK] 配置文件已更新'));
|
|
229
229
|
|
|
230
230
|
if (settingsManager.hasBackup()) {
|
|
231
|
-
console.log(chalk.green('
|
|
231
|
+
console.log(chalk.green('[OK] 原配置已备份'));
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
console.log(chalk.cyan('\n
|
|
234
|
+
console.log(chalk.cyan('\n[TIP] 动态切换已启用!'));
|
|
235
235
|
console.log(chalk.gray(` 现在可以通过"渠道管理"功能快速调整,无需重启 ${toolName}\n`));
|
|
236
236
|
|
|
237
237
|
await inquirer.prompt([
|
|
@@ -242,7 +242,7 @@ async function handleStartProxy(cliType, services) {
|
|
|
242
242
|
},
|
|
243
243
|
]);
|
|
244
244
|
} catch (error) {
|
|
245
|
-
console.log(chalk.red(`\n
|
|
245
|
+
console.log(chalk.red(`\n[ERROR] 启动失败: ${error.message}\n`));
|
|
246
246
|
|
|
247
247
|
await inquirer.prompt([
|
|
248
248
|
{
|
|
@@ -259,9 +259,9 @@ async function handleStartProxy(cliType, services) {
|
|
|
259
259
|
*/
|
|
260
260
|
async function handleStopProxy(cliType, services) {
|
|
261
261
|
console.clear();
|
|
262
|
-
console.log(chalk.bold.cyan('\n
|
|
262
|
+
console.log(chalk.bold.cyan('\n╔=======================================╗'));
|
|
263
263
|
console.log(chalk.bold.cyan('║ 关闭动态切换 ║'));
|
|
264
|
-
console.log(chalk.bold.cyan('
|
|
264
|
+
console.log(chalk.bold.cyan('╚=======================================╝\n'));
|
|
265
265
|
|
|
266
266
|
const toolNameMap = {
|
|
267
267
|
claude: 'Claude Code',
|
|
@@ -297,11 +297,11 @@ async function handleStopProxy(cliType, services) {
|
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
try {
|
|
300
|
-
console.log(chalk.cyan('\n
|
|
300
|
+
console.log(chalk.cyan('\n[STOP] 正在停止代理服务...\n'));
|
|
301
301
|
|
|
302
302
|
// 停止代理服务器
|
|
303
303
|
await services.stopProxyServer();
|
|
304
|
-
console.log(chalk.green('
|
|
304
|
+
console.log(chalk.green('[OK] 代理服务已停止'));
|
|
305
305
|
|
|
306
306
|
// 恢复配置文件
|
|
307
307
|
const settingsManager = getSettingsManager(cliType);
|
|
@@ -309,12 +309,12 @@ async function handleStopProxy(cliType, services) {
|
|
|
309
309
|
const restoredChannel = restoreSingleChannelMode(cliType);
|
|
310
310
|
removeActiveChannelMarker(cliType);
|
|
311
311
|
if (restoredChannel?.name) {
|
|
312
|
-
console.log(chalk.green(
|
|
312
|
+
console.log(chalk.green(`[OK] 已恢复到渠道: ${restoredChannel.name}`));
|
|
313
313
|
} else {
|
|
314
|
-
console.log(chalk.green('
|
|
314
|
+
console.log(chalk.green('[OK] 已清理代理接管状态'));
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
console.log(chalk.cyan('\n
|
|
317
|
+
console.log(chalk.cyan('\n[TIP] 动态切换已关闭'));
|
|
318
318
|
console.log(chalk.gray(` 现在调整渠道需要重启 ${toolName} 才能生效\n`));
|
|
319
319
|
|
|
320
320
|
await inquirer.prompt([
|
|
@@ -325,7 +325,7 @@ async function handleStopProxy(cliType, services) {
|
|
|
325
325
|
},
|
|
326
326
|
]);
|
|
327
327
|
} catch (error) {
|
|
328
|
-
console.log(chalk.red(`\n
|
|
328
|
+
console.log(chalk.red(`\n[ERROR] 停止失败: ${error.message}\n`));
|
|
329
329
|
|
|
330
330
|
await inquirer.prompt([
|
|
331
331
|
{
|
package/src/commands/ui.js
CHANGED
|
@@ -14,9 +14,9 @@ async function handleUI() {
|
|
|
14
14
|
|
|
15
15
|
if (!isDaemon) {
|
|
16
16
|
console.clear();
|
|
17
|
-
console.log(chalk.cyan.bold('\n
|
|
17
|
+
console.log(chalk.cyan.bold('\n[NET] 启动 Coding-Tool Web UI...\n'));
|
|
18
18
|
if (enableHost) {
|
|
19
|
-
console.log(chalk.yellow('
|
|
19
|
+
console.log(chalk.yellow('[WARN] LAN 访问已启用 (--host)\n'));
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -33,9 +33,9 @@ async function handleUI() {
|
|
|
33
33
|
setTimeout(async () => {
|
|
34
34
|
try {
|
|
35
35
|
await open(url);
|
|
36
|
-
console.log(chalk.green(
|
|
36
|
+
console.log(chalk.green(`[OK] 已在浏览器中打开: ${url}\n`));
|
|
37
37
|
} catch (err) {
|
|
38
|
-
console.log(chalk.yellow(
|
|
38
|
+
console.log(chalk.yellow(`[TIP] 请手动打开: ${url}\n`));
|
|
39
39
|
}
|
|
40
40
|
}, 1000);
|
|
41
41
|
}
|
|
@@ -43,18 +43,18 @@ async function handleUI() {
|
|
|
43
43
|
// 处理退出信号(仅非 daemon 模式)
|
|
44
44
|
if (!isDaemon) {
|
|
45
45
|
process.on('SIGINT', async () => {
|
|
46
|
-
console.log(chalk.yellow('\n\n
|
|
46
|
+
console.log(chalk.yellow('\n\n[BYE] 正在停止服务器...\n'));
|
|
47
47
|
|
|
48
48
|
// 检查代理状态并询问是否停止
|
|
49
49
|
try {
|
|
50
50
|
const proxyStatus = getProxyStatus();
|
|
51
51
|
if (proxyStatus.running) {
|
|
52
|
-
console.log(chalk.yellow('
|
|
52
|
+
console.log(chalk.yellow('[WARN] 检测到代理服务正在运行'));
|
|
53
53
|
console.log(chalk.gray(' - 代理端口: ' + proxyStatus.port));
|
|
54
54
|
console.log(chalk.gray(' - 如需保持代理运行,请直接关闭此窗口\n'));
|
|
55
55
|
|
|
56
56
|
// 自动停止代理(3秒后)
|
|
57
|
-
console.log(chalk.cyan('
|
|
57
|
+
console.log(chalk.cyan('[WAIT] 将在 3 秒后自动停止代理服务...'));
|
|
58
58
|
console.log(chalk.gray(' 按 Ctrl+C 再次可立即退出并保持代理运行\n'));
|
|
59
59
|
|
|
60
60
|
let stopProxy = true;
|
|
@@ -70,9 +70,9 @@ async function handleUI() {
|
|
|
70
70
|
if (stopProxy) {
|
|
71
71
|
const { stopProxyServer } = require('../server/proxy-server');
|
|
72
72
|
await stopProxyServer();
|
|
73
|
-
console.log(chalk.green('
|
|
73
|
+
console.log(chalk.green('[OK] 代理服务已停止\n'));
|
|
74
74
|
} else {
|
|
75
|
-
console.log(chalk.yellow('
|
|
75
|
+
console.log(chalk.yellow('[WARN] 代理服务保持运行状态'));
|
|
76
76
|
console.log(chalk.gray(' - 如需停止,请运行: ctx proxy stop\n'));
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -80,14 +80,14 @@ async function handleUI() {
|
|
|
80
80
|
// 忽略错误
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
console.log(chalk.green('
|
|
83
|
+
console.log(chalk.green('[OK] Web UI 已停止\n'));
|
|
84
84
|
process.exit(0);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
console.log(chalk.gray('按 Ctrl+C 停止服务器'));
|
|
88
88
|
} else {
|
|
89
89
|
// Daemon 模式:保持运行
|
|
90
|
-
console.log(chalk.green(
|
|
90
|
+
console.log(chalk.green(`[OK] Coding-Tool 服务已在后台启动 (端口: ${port})`));
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
} catch (error) {
|
package/src/commands/update.js
CHANGED
|
@@ -55,7 +55,7 @@ async function handleUpdate(options = {}) {
|
|
|
55
55
|
].filter(Boolean)));
|
|
56
56
|
const currentVersion = packageInfo.version;
|
|
57
57
|
|
|
58
|
-
console.log(chalk.cyan('\n
|
|
58
|
+
console.log(chalk.cyan('\n[SEARCH] 检查更新中...\n'));
|
|
59
59
|
|
|
60
60
|
let latestVersion;
|
|
61
61
|
let packageName = packageCandidates[0];
|
|
@@ -75,18 +75,18 @@ async function handleUpdate(options = {}) {
|
|
|
75
75
|
throw lastError || new Error('无法获取最新版本');
|
|
76
76
|
}
|
|
77
77
|
} catch (error) {
|
|
78
|
-
console.error(chalk.red(
|
|
79
|
-
console.log(chalk.gray('
|
|
78
|
+
console.error(chalk.red(`[ERROR] 检查更新失败: ${error.message}`));
|
|
79
|
+
console.log(chalk.gray('[TIP] 可手动执行: npm view coding-tool-x version'));
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
if (!semver.valid(currentVersion) || !semver.valid(latestVersion)) {
|
|
84
|
-
console.log(chalk.yellow(
|
|
84
|
+
console.log(chalk.yellow(`[WARN] 版本格式异常,当前: ${currentVersion}, 最新: ${latestVersion}`));
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
if (!semver.gt(latestVersion, currentVersion)) {
|
|
89
|
-
console.log(chalk.green(
|
|
89
|
+
console.log(chalk.green(`[OK] 已是最新版本: ${currentVersion}\n`));
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ async function handleUpdate(options = {}) {
|
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
console.log(chalk.cyan('\n
|
|
99
|
+
console.log(chalk.cyan('\n[DOWN] 正在更新...\n'));
|
|
100
100
|
|
|
101
101
|
try {
|
|
102
102
|
await runNpmInstall(packageName, latestVersion);
|
|
103
|
-
console.log(chalk.green(`\n
|
|
103
|
+
console.log(chalk.green(`\n[OK] 更新完成: ${latestVersion}`));
|
|
104
104
|
console.log(chalk.gray('请重新打开终端或重新执行 ctx --version 验证版本。\n'));
|
|
105
105
|
} catch (error) {
|
|
106
|
-
console.error(chalk.red(`\n
|
|
107
|
-
console.log(chalk.gray(
|
|
106
|
+
console.error(chalk.red(`\n[ERROR] 更新失败: ${error.message}`));
|
|
107
|
+
console.log(chalk.gray(`[TIP] 可手动执行: npm install -g ${packageName}@${latestVersion}\n`));
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -22,7 +22,7 @@ async function listWorkspaces() {
|
|
|
22
22
|
console.log(chalk.bold.cyan('\n工作区列表:\n'));
|
|
23
23
|
|
|
24
24
|
workspaces.forEach((ws, index) => {
|
|
25
|
-
const status = ws.exists ? chalk.green('
|
|
25
|
+
const status = ws.exists ? chalk.green('[v]') : chalk.red('[x]');
|
|
26
26
|
console.log(`${index + 1}. ${status} ${chalk.bold(ws.name)}`);
|
|
27
27
|
|
|
28
28
|
if (ws.description) {
|
|
@@ -35,7 +35,7 @@ async function listWorkspaces() {
|
|
|
35
35
|
console.log('');
|
|
36
36
|
});
|
|
37
37
|
} catch (error) {
|
|
38
|
-
console.error(chalk.red(`\n
|
|
38
|
+
console.error(chalk.red(`\n[ERROR] ${error.message}\n`));
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -132,7 +132,7 @@ async function createWorkspace() {
|
|
|
132
132
|
|
|
133
133
|
projectChoices.push(
|
|
134
134
|
new inquirer.Separator(chalk.gray('─'.repeat(14))),
|
|
135
|
-
{ name: chalk.gray('
|
|
135
|
+
{ name: chalk.gray('[v] 完成选择'), value: null }
|
|
136
136
|
);
|
|
137
137
|
|
|
138
138
|
const { selectedProject } = await inquirer.prompt([
|
|
@@ -226,7 +226,7 @@ async function createWorkspace() {
|
|
|
226
226
|
branch
|
|
227
227
|
});
|
|
228
228
|
|
|
229
|
-
console.log(chalk.green(`\n
|
|
229
|
+
console.log(chalk.green(`\n[v] 已添加: ${linkName}\n`));
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
if (projects.length === 0) {
|
|
@@ -274,12 +274,12 @@ async function createWorkspace() {
|
|
|
274
274
|
projects
|
|
275
275
|
});
|
|
276
276
|
|
|
277
|
-
console.log(chalk.green(`\n
|
|
277
|
+
console.log(chalk.green(`\n[OK] 工作区创建成功!\n`));
|
|
278
278
|
console.log(chalk.gray(`工作区路径: ${workspace.path}\n`));
|
|
279
279
|
console.log(chalk.gray(`提示: 可以在此路径下启动 Claude Code 以访问所有项目\n`));
|
|
280
280
|
|
|
281
281
|
} catch (error) {
|
|
282
|
-
console.error(chalk.red(`\n
|
|
282
|
+
console.error(chalk.red(`\n[ERROR] ${error.message}\n`));
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
@@ -324,8 +324,8 @@ async function viewWorkspace() {
|
|
|
324
324
|
console.log(chalk.bold.cyan(`\n包含项目 (${detail.projects.length}):\n`));
|
|
325
325
|
|
|
326
326
|
detail.projects.forEach((proj, index) => {
|
|
327
|
-
const linkStatus = proj.linkExists ? chalk.green('
|
|
328
|
-
const sourceStatus = proj.sourceExists ? chalk.green('
|
|
327
|
+
const linkStatus = proj.linkExists ? chalk.green('[v]') : chalk.red('[x]');
|
|
328
|
+
const sourceStatus = proj.sourceExists ? chalk.green('[v]') : chalk.red('[x]');
|
|
329
329
|
|
|
330
330
|
console.log(`${index + 1}. ${linkStatus} ${chalk.bold(proj.name)}`);
|
|
331
331
|
console.log(chalk.gray(` 源路径: ${sourceStatus} ${proj.sourcePath}`));
|
|
@@ -341,7 +341,7 @@ async function viewWorkspace() {
|
|
|
341
341
|
});
|
|
342
342
|
|
|
343
343
|
} catch (error) {
|
|
344
|
-
console.error(chalk.red(`\n
|
|
344
|
+
console.error(chalk.red(`\n[ERROR] ${error.message}\n`));
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
|
|
@@ -394,10 +394,10 @@ async function deleteWorkspace() {
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
workspaceService.deleteWorkspace(workspace.id, removeFiles);
|
|
397
|
-
console.log(chalk.green('\n
|
|
397
|
+
console.log(chalk.green('\n[OK] 工作区删除成功\n'));
|
|
398
398
|
|
|
399
399
|
} catch (error) {
|
|
400
|
-
console.error(chalk.red(`\n
|
|
400
|
+
console.error(chalk.red(`\n[ERROR] ${error.message}\n`));
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
|
package/src/index.js
CHANGED
|
@@ -43,13 +43,13 @@ function showHelp() {
|
|
|
43
43
|
console.log(chalk.cyan.bold(`\nCODING-TOOL v${version}`));
|
|
44
44
|
console.log(chalk.gray('Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控\n'));
|
|
45
45
|
|
|
46
|
-
console.log(chalk.yellow('
|
|
46
|
+
console.log(chalk.yellow('[START] 服务管理:'));
|
|
47
47
|
console.log(' ctx start 启动所有服务(后台运行)');
|
|
48
48
|
console.log(' ctx stop 停止所有服务');
|
|
49
49
|
console.log(' ctx restart 重启所有服务');
|
|
50
50
|
console.log(' ctx status 查看服务状态\n');
|
|
51
51
|
|
|
52
|
-
console.log(chalk.yellow('
|
|
52
|
+
console.log(chalk.yellow('[UI] UI 管理:'));
|
|
53
53
|
console.log(' ctx ui 前台启动 Web UI(仅本地访问)');
|
|
54
54
|
console.log(' ctx ui --host 前台启动 Web UI(允许 LAN 访问)');
|
|
55
55
|
console.log(' ctx ui start 后台启动 Web UI');
|
|
@@ -57,7 +57,7 @@ function showHelp() {
|
|
|
57
57
|
console.log(' ctx ui stop 停止 Web UI');
|
|
58
58
|
console.log(' ctx ui restart 重启 Web UI\n');
|
|
59
59
|
|
|
60
|
-
console.log(chalk.yellow('
|
|
60
|
+
console.log(chalk.yellow('[PROXY] 代理管理:'));
|
|
61
61
|
console.log(' ctx claude start 启动 Claude 代理');
|
|
62
62
|
console.log(' ctx claude stop 停止 Claude 代理');
|
|
63
63
|
console.log(' ctx claude status 查看 Claude 代理状态');
|
|
@@ -66,7 +66,7 @@ function showHelp() {
|
|
|
66
66
|
console.log(' ctx opencode start 启动 OpenCode 代理');
|
|
67
67
|
console.log(chalk.gray(' (codex/gemini/opencode 命令与 claude 类似)\n'));
|
|
68
68
|
|
|
69
|
-
console.log(chalk.yellow('
|
|
69
|
+
console.log(chalk.yellow('[LOG] 日志管理:'));
|
|
70
70
|
console.log(' ctx logs 查看所有日志');
|
|
71
71
|
console.log(' ctx logs ui 查看 UI 日志');
|
|
72
72
|
console.log(' ctx logs claude 查看 Claude 日志');
|
|
@@ -74,13 +74,13 @@ function showHelp() {
|
|
|
74
74
|
console.log(' ctx logs --follow 实时跟踪日志');
|
|
75
75
|
console.log(' ctx logs --clear 清空日志\n');
|
|
76
76
|
|
|
77
|
-
console.log(chalk.yellow('
|
|
77
|
+
console.log(chalk.yellow('[STATS] 统计信息:'));
|
|
78
78
|
console.log(' ctx stats 查看总体统计');
|
|
79
79
|
console.log(' ctx stats claude 查看 Claude 统计');
|
|
80
80
|
console.log(' ctx stats --today 查看今日统计');
|
|
81
81
|
console.log(' ctx stats export 导出统计数据\n');
|
|
82
82
|
|
|
83
|
-
console.log(chalk.yellow('
|
|
83
|
+
console.log(chalk.yellow('[TOOL] 其他命令:'));
|
|
84
84
|
console.log(' ctx update 检查并更新到最新版本');
|
|
85
85
|
console.log(' ctx doctor 系统诊断');
|
|
86
86
|
console.log(' ctx port 配置端口');
|
|
@@ -89,7 +89,7 @@ function showHelp() {
|
|
|
89
89
|
console.log(' ctx --version, -v 显示版本');
|
|
90
90
|
console.log(' ctx --help, -h 显示帮助\n');
|
|
91
91
|
|
|
92
|
-
console.log(chalk.yellow('
|
|
92
|
+
console.log(chalk.yellow('[PROXY] 插件管理:'));
|
|
93
93
|
console.log(' ctx plugin list 列出已安装插件');
|
|
94
94
|
console.log(' ctx plugin install <url> 从 Git 安装插件');
|
|
95
95
|
console.log(' ctx plugin remove <name> 卸载插件');
|
|
@@ -100,13 +100,13 @@ function showHelp() {
|
|
|
100
100
|
console.log(' ctx plugin update <name> 更新插件');
|
|
101
101
|
console.log(' ctx plugin update --all 更新所有插件\n');
|
|
102
102
|
|
|
103
|
-
console.log(chalk.yellow('
|
|
103
|
+
console.log(chalk.yellow('[TIP] 快速开始:'));
|
|
104
104
|
console.log(chalk.gray(' $ ctx start # 后台启动服务(推荐)'));
|
|
105
105
|
console.log(chalk.gray(' $ ctx status # 查看服务状态'));
|
|
106
106
|
console.log(chalk.gray(' $ ctx logs # 查看实时日志'));
|
|
107
107
|
console.log(chalk.gray(' $ ctx stop # 停止服务\n'));
|
|
108
108
|
|
|
109
|
-
console.log(chalk.yellow('
|
|
109
|
+
console.log(chalk.yellow('[STAR] 开机自启(可选):'));
|
|
110
110
|
console.log(chalk.gray(' $ pm2 startup # 启用开机自启'));
|
|
111
111
|
console.log(chalk.gray(' $ pm2 save # 保存配置'));
|
|
112
112
|
console.log(chalk.gray(' $ pm2 unstartup # 禁用开机自启\n'));
|
|
@@ -190,7 +190,7 @@ async function main() {
|
|
|
190
190
|
return;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
console.log(chalk.red(`\n
|
|
193
|
+
console.log(chalk.red(`\n[ERROR] 未知 daemon 子命令: ${subCommand}\n`));
|
|
194
194
|
console.log(chalk.gray('支持的命令: start, stop, restart, status, logs\n'));
|
|
195
195
|
return;
|
|
196
196
|
}
|
|
@@ -275,7 +275,7 @@ async function main() {
|
|
|
275
275
|
await proxyStatus(channel);
|
|
276
276
|
break;
|
|
277
277
|
default:
|
|
278
|
-
console.log(chalk.red(`\n
|
|
278
|
+
console.log(chalk.red(`\n[ERROR] 未知操作: ${action}\n`));
|
|
279
279
|
console.log(chalk.gray('支持的操作: start, stop, restart, status\n'));
|
|
280
280
|
}
|
|
281
281
|
return;
|
|
@@ -491,14 +491,14 @@ async function main() {
|
|
|
491
491
|
name: 'action',
|
|
492
492
|
message: chalk.cyan('选择插件操作:'),
|
|
493
493
|
choices: [
|
|
494
|
-
{ name: '
|
|
495
|
-
{ name: '
|
|
496
|
-
{ name: '
|
|
497
|
-
{ name: '
|
|
498
|
-
{ name: '
|
|
499
|
-
{ name: '
|
|
500
|
-
{ name: '
|
|
501
|
-
{ name: '
|
|
494
|
+
{ name: '[LOG] 列出已安装插件', value: 'list' },
|
|
495
|
+
{ name: '[PKG] 安装插件', value: 'install' },
|
|
496
|
+
{ name: '[DEL] 卸载插件', value: 'remove' },
|
|
497
|
+
{ name: '[SYNC] 启用/禁用插件', value: 'toggle' },
|
|
498
|
+
{ name: '[INFO] 查看插件信息', value: 'info' },
|
|
499
|
+
{ name: '[UP] 更新插件', value: 'update' },
|
|
500
|
+
{ name: '[CFG] 配置插件', value: 'config' },
|
|
501
|
+
{ name: '[BACK] 返回主菜单', value: 'back' }
|
|
502
502
|
]
|
|
503
503
|
}]);
|
|
504
504
|
|
|
@@ -558,8 +558,8 @@ async function main() {
|
|
|
558
558
|
name: 'operation',
|
|
559
559
|
message: '选择操作:',
|
|
560
560
|
choices: [
|
|
561
|
-
{ name: '
|
|
562
|
-
{ name: '
|
|
561
|
+
{ name: '[OK] 启用插件', value: 'enable' },
|
|
562
|
+
{ name: '[ERROR] 禁用插件', value: 'disable' }
|
|
563
563
|
]
|
|
564
564
|
}]);
|
|
565
565
|
|
|
@@ -603,8 +603,8 @@ async function main() {
|
|
|
603
603
|
name: 'option',
|
|
604
604
|
message: '选择更新选项:',
|
|
605
605
|
choices: [
|
|
606
|
-
{ name: '
|
|
607
|
-
{ name: '
|
|
606
|
+
{ name: '[SYNC] 更新指定插件', value: 'single' },
|
|
607
|
+
{ name: '[SYNC] 更新所有插件', value: 'all' }
|
|
608
608
|
]
|
|
609
609
|
}]);
|
|
610
610
|
|
|
@@ -656,7 +656,7 @@ async function main() {
|
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
case 'exit':
|
|
659
|
-
console.log('\n
|
|
659
|
+
console.log('\n[BYE] 再见!\n');
|
|
660
660
|
eventBus.emitSync('cli:shutdown', {});
|
|
661
661
|
PluginManager.shutdownPlugins();
|
|
662
662
|
process.exit(0);
|
|
@@ -214,7 +214,7 @@ async function installPlugin(gitUrl) {
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
// Step 2: Security warning and user confirmation
|
|
217
|
-
console.warn('\n
|
|
217
|
+
console.warn('\n[WARN] WARNING: Plugins have full system access!');
|
|
218
218
|
console.warn('Only install plugins from trusted sources.');
|
|
219
219
|
console.warn(`Source: ${gitUrl}\n`);
|
|
220
220
|
|
package/src/reset-config.js
CHANGED
|
@@ -15,7 +15,7 @@ async function resetConfig() {
|
|
|
15
15
|
if (status.running) {
|
|
16
16
|
console.log('检测到代理服务正在运行,正在停止...');
|
|
17
17
|
await stopProxyServer();
|
|
18
|
-
console.log('
|
|
18
|
+
console.log('[OK] 代理服务已停止');
|
|
19
19
|
}
|
|
20
20
|
} catch (err) {
|
|
21
21
|
// 代理服务未运行或模块加载失败,继续处理本地文件
|
|
@@ -31,7 +31,7 @@ async function resetConfig() {
|
|
|
31
31
|
const backupContent = fs.readFileSync(backupPath, 'utf8');
|
|
32
32
|
fs.writeFileSync(settingsPath, backupContent, 'utf8');
|
|
33
33
|
fs.unlinkSync(backupPath);
|
|
34
|
-
console.log('
|
|
34
|
+
console.log('[OK] 已从备份恢复 settings.json');
|
|
35
35
|
} else if (fs.existsSync(settingsPath)) {
|
|
36
36
|
// 检查是否是代理配置
|
|
37
37
|
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
@@ -59,28 +59,28 @@ async function resetConfig() {
|
|
|
59
59
|
settings.apiKeyHelper = `echo '${activeChannel.apiKey}'`;
|
|
60
60
|
|
|
61
61
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
62
|
-
console.log(
|
|
62
|
+
console.log(`[OK] 已恢复到渠道: ${activeChannel.name}`);
|
|
63
63
|
|
|
64
64
|
// 清理 active-channel.json
|
|
65
65
|
fs.unlinkSync(activeChannelPath);
|
|
66
66
|
} else {
|
|
67
|
-
console.log('
|
|
67
|
+
console.log('[WARN] 无法找到激活的渠道,请手动配置 Claude Code');
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
} else {
|
|
71
|
-
console.log('
|
|
71
|
+
console.log('[WARN] 未找到激活渠道信息,但已清除代理配置');
|
|
72
72
|
console.log('请手动配置 Claude Code 或通过 Web UI 管理渠道');
|
|
73
73
|
}
|
|
74
74
|
} else {
|
|
75
|
-
console.log('
|
|
75
|
+
console.log('[OK] 配置文件正常,无需恢复');
|
|
76
76
|
}
|
|
77
77
|
} else {
|
|
78
|
-
console.log('
|
|
78
|
+
console.log('[WARN] 未找到 settings.json 文件');
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
console.log('\n
|
|
81
|
+
console.log('\n[OK] 配置恢复完成!\n');
|
|
82
82
|
} catch (err) {
|
|
83
|
-
console.error('
|
|
83
|
+
console.error('[ERROR] 恢复配置时出错:', err.message);
|
|
84
84
|
console.log('\n您可以尝试手动恢复:');
|
|
85
85
|
console.log('1. 检查 ~/.claude/settings.json 文件');
|
|
86
86
|
console.log('2. 如果有 settings.json.cc-tool-backup 备份文件,手动恢复');
|
|
@@ -199,7 +199,7 @@ router.post('/:id/apply-to-settings', async (req, res) => {
|
|
|
199
199
|
// (stopProxyServer restores backup, then we overwrite it with current channel)
|
|
200
200
|
updateClaudeSettingsWithModelConfig(channel);
|
|
201
201
|
|
|
202
|
-
console.log(
|
|
202
|
+
console.log(`[OK] 已停���动态切换,默认使用当前渠道`);
|
|
203
203
|
broadcastLog({
|
|
204
204
|
type: 'action',
|
|
205
205
|
action: 'stop_proxy',
|
|
@@ -148,7 +148,7 @@ const feishuData = JSON.stringify({
|
|
|
148
148
|
msg_type: 'interactive',
|
|
149
149
|
card: {
|
|
150
150
|
header: {
|
|
151
|
-
title: { tag: 'plain_text', content: '
|
|
151
|
+
title: { tag: 'plain_text', content: '[DONE] Coding Tool - 任务完成' },
|
|
152
152
|
template: 'green'
|
|
153
153
|
},
|
|
154
154
|
elements: [
|
|
@@ -491,7 +491,7 @@ router.post('/test', (req, res) => {
|
|
|
491
491
|
msg_type: 'interactive',
|
|
492
492
|
card: {
|
|
493
493
|
header: {
|
|
494
|
-
title: { tag: 'plain_text', content: '
|
|
494
|
+
title: { tag: 'plain_text', content: '[TEST] Coding Tool - 测试通知' },
|
|
495
495
|
template: 'blue'
|
|
496
496
|
},
|
|
497
497
|
elements: [
|
|
@@ -58,7 +58,11 @@ router.get('/market', async (req, res) => {
|
|
|
58
58
|
try {
|
|
59
59
|
const { platform, service } = getPluginsService(req);
|
|
60
60
|
const forceRefresh = req.query.refresh === '1';
|
|
61
|
+
if (forceRefresh) {
|
|
62
|
+
console.log(`[Plugins API] Refreshing market plugins for ${platform}...`);
|
|
63
|
+
}
|
|
61
64
|
const plugins = await service.getMarketPlugins(forceRefresh);
|
|
65
|
+
console.log(`[Plugins API] ${platform}: ${plugins.length} market plugins loaded (refresh=${forceRefresh})`);
|
|
62
66
|
|
|
63
67
|
res.json({
|
|
64
68
|
success: true,
|
|
@@ -10,9 +10,9 @@ const execAsync = promisify(exec);
|
|
|
10
10
|
|
|
11
11
|
function getExecOptions(timeout = 30000, runtimePlatform = process.platform) {
|
|
12
12
|
if (runtimePlatform === 'win32') {
|
|
13
|
-
return { timeout };
|
|
13
|
+
return { timeout, windowsHide: true };
|
|
14
14
|
}
|
|
15
|
-
return { shell: '/bin/bash', timeout };
|
|
15
|
+
return { shell: '/bin/bash', timeout, windowsHide: true };
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
package/src/server/api/proxy.js
CHANGED
|
@@ -208,7 +208,7 @@ router.post('/start', async (req, res) => {
|
|
|
208
208
|
|
|
209
209
|
// 3. 保存当前激活渠道ID(用于代理模式)
|
|
210
210
|
saveActiveChannelId(currentChannel.id);
|
|
211
|
-
console.log(
|
|
211
|
+
console.log(`[OK] Saved active channel: ${currentChannel.name} (${currentChannel.id})`);
|
|
212
212
|
|
|
213
213
|
// 4. 启动代理服务器
|
|
214
214
|
const proxyResult = await startProxyServer();
|
|
@@ -256,11 +256,11 @@ router.post('/stop', async (req, res) => {
|
|
|
256
256
|
if (restoredChannel) {
|
|
257
257
|
if (hadBackup) {
|
|
258
258
|
deleteBackup();
|
|
259
|
-
console.log('
|
|
259
|
+
console.log('[OK] Discarded backup snapshot');
|
|
260
260
|
}
|
|
261
261
|
} else if (hadBackup) {
|
|
262
262
|
restoreSettings();
|
|
263
|
-
console.log('
|
|
263
|
+
console.log('[OK] Restored settings from backup');
|
|
264
264
|
const channels = getAllChannels();
|
|
265
265
|
const currentSettings = require('../services/channels').getCurrentSettings();
|
|
266
266
|
if (currentSettings) {
|
|
@@ -274,7 +274,7 @@ router.post('/stop', async (req, res) => {
|
|
|
274
274
|
if (restoredChannel) {
|
|
275
275
|
const { applyChannelToSettings } = require('../services/channels');
|
|
276
276
|
applyChannelToSettings(restoredChannel.id);
|
|
277
|
-
console.log(
|
|
277
|
+
console.log(`[OK] Single-channel mode restored: ${restoredChannel.name}`);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// 3. 删除备份文件和active-channel.json
|
|
@@ -282,14 +282,14 @@ router.post('/stop', async (req, res) => {
|
|
|
282
282
|
const backupPath = NATIVE_PATHS.claude.settingsBackup;
|
|
283
283
|
if (fs.existsSync(backupPath)) {
|
|
284
284
|
fs.unlinkSync(backupPath);
|
|
285
|
-
console.log('
|
|
285
|
+
console.log('[OK] Removed backup file');
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
const activeChannelPath = PATHS.activeChannel.claude;
|
|
290
290
|
if (fs.existsSync(activeChannelPath)) {
|
|
291
291
|
fs.unlinkSync(activeChannelPath);
|
|
292
|
-
console.log('
|
|
292
|
+
console.log('[OK] Removed active-channel.json');
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
// 4. 通过 WebSocket 推送代理状态更新
|
package/src/server/api/skills.js
CHANGED
|
@@ -50,7 +50,11 @@ router.get('/', async (req, res) => {
|
|
|
50
50
|
try {
|
|
51
51
|
const { platform, service } = getSkillService(req);
|
|
52
52
|
const forceRefresh = req.query.refresh === '1';
|
|
53
|
+
if (forceRefresh) {
|
|
54
|
+
console.log(`[Skills API] Refreshing skills for ${platform}...`);
|
|
55
|
+
}
|
|
53
56
|
const skills = await service.listSkills(forceRefresh);
|
|
57
|
+
console.log(`[Skills API] ${platform}: ${skills.length} skills loaded (refresh=${forceRefresh})`);
|
|
54
58
|
res.json({
|
|
55
59
|
success: true,
|
|
56
60
|
platform,
|