@adversity/coding-tool-x 2.2.0

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.
Files changed (125) hide show
  1. package/CHANGELOG.md +333 -0
  2. package/LICENSE +21 -0
  3. package/README.md +404 -0
  4. package/bin/ctx.js +8 -0
  5. package/dist/web/assets/index-D1AYlFLZ.js +3220 -0
  6. package/dist/web/assets/index-aL3cKxSK.css +41 -0
  7. package/dist/web/favicon.ico +0 -0
  8. package/dist/web/index.html +14 -0
  9. package/dist/web/logo.png +0 -0
  10. package/docs/CHANGELOG.md +582 -0
  11. package/docs/DIRECTORY_MIGRATION.md +112 -0
  12. package/docs/PROJECT_STRUCTURE.md +396 -0
  13. package/docs/bannel.png +0 -0
  14. package/docs/home.png +0 -0
  15. package/docs/logo.png +0 -0
  16. package/docs/multi-channel-load-balancing.md +249 -0
  17. package/package.json +73 -0
  18. package/src/commands/channels.js +504 -0
  19. package/src/commands/cli-type.js +99 -0
  20. package/src/commands/daemon.js +286 -0
  21. package/src/commands/doctor.js +332 -0
  22. package/src/commands/list.js +222 -0
  23. package/src/commands/logs.js +259 -0
  24. package/src/commands/port-config.js +115 -0
  25. package/src/commands/proxy-control.js +258 -0
  26. package/src/commands/proxy.js +152 -0
  27. package/src/commands/resume.js +137 -0
  28. package/src/commands/search.js +190 -0
  29. package/src/commands/stats.js +224 -0
  30. package/src/commands/switch.js +48 -0
  31. package/src/commands/toggle-proxy.js +222 -0
  32. package/src/commands/ui.js +92 -0
  33. package/src/commands/workspace.js +454 -0
  34. package/src/config/default.js +40 -0
  35. package/src/config/loader.js +75 -0
  36. package/src/config/paths.js +121 -0
  37. package/src/index.js +373 -0
  38. package/src/reset-config.js +92 -0
  39. package/src/server/api/agents.js +248 -0
  40. package/src/server/api/aliases.js +36 -0
  41. package/src/server/api/channels.js +258 -0
  42. package/src/server/api/claude-hooks.js +480 -0
  43. package/src/server/api/codex-channels.js +312 -0
  44. package/src/server/api/codex-projects.js +91 -0
  45. package/src/server/api/codex-proxy.js +182 -0
  46. package/src/server/api/codex-sessions.js +491 -0
  47. package/src/server/api/codex-statistics.js +57 -0
  48. package/src/server/api/commands.js +245 -0
  49. package/src/server/api/config-templates.js +182 -0
  50. package/src/server/api/config.js +147 -0
  51. package/src/server/api/convert.js +127 -0
  52. package/src/server/api/dashboard.js +125 -0
  53. package/src/server/api/env.js +144 -0
  54. package/src/server/api/favorites.js +77 -0
  55. package/src/server/api/gemini-channels.js +261 -0
  56. package/src/server/api/gemini-projects.js +91 -0
  57. package/src/server/api/gemini-proxy.js +160 -0
  58. package/src/server/api/gemini-sessions.js +397 -0
  59. package/src/server/api/gemini-statistics.js +57 -0
  60. package/src/server/api/health-check.js +118 -0
  61. package/src/server/api/mcp.js +336 -0
  62. package/src/server/api/pm2-autostart.js +269 -0
  63. package/src/server/api/projects.js +124 -0
  64. package/src/server/api/prompts.js +279 -0
  65. package/src/server/api/proxy.js +235 -0
  66. package/src/server/api/rules.js +271 -0
  67. package/src/server/api/sessions.js +595 -0
  68. package/src/server/api/settings.js +61 -0
  69. package/src/server/api/skills.js +305 -0
  70. package/src/server/api/statistics.js +91 -0
  71. package/src/server/api/terminal.js +202 -0
  72. package/src/server/api/ui-config.js +64 -0
  73. package/src/server/api/workspaces.js +407 -0
  74. package/src/server/codex-proxy-server.js +538 -0
  75. package/src/server/dev-server.js +26 -0
  76. package/src/server/gemini-proxy-server.js +518 -0
  77. package/src/server/index.js +305 -0
  78. package/src/server/proxy-server.js +469 -0
  79. package/src/server/services/agents-service.js +354 -0
  80. package/src/server/services/alias.js +71 -0
  81. package/src/server/services/channel-health.js +234 -0
  82. package/src/server/services/channel-scheduler.js +234 -0
  83. package/src/server/services/channels.js +347 -0
  84. package/src/server/services/codex-channels.js +625 -0
  85. package/src/server/services/codex-config.js +90 -0
  86. package/src/server/services/codex-parser.js +322 -0
  87. package/src/server/services/codex-sessions.js +665 -0
  88. package/src/server/services/codex-settings-manager.js +397 -0
  89. package/src/server/services/codex-speed-test-template.json +24 -0
  90. package/src/server/services/codex-statistics-service.js +255 -0
  91. package/src/server/services/commands-service.js +360 -0
  92. package/src/server/services/config-templates-service.js +732 -0
  93. package/src/server/services/env-checker.js +307 -0
  94. package/src/server/services/env-manager.js +300 -0
  95. package/src/server/services/favorites.js +163 -0
  96. package/src/server/services/gemini-channels.js +333 -0
  97. package/src/server/services/gemini-config.js +73 -0
  98. package/src/server/services/gemini-sessions.js +689 -0
  99. package/src/server/services/gemini-settings-manager.js +263 -0
  100. package/src/server/services/gemini-statistics-service.js +253 -0
  101. package/src/server/services/health-check.js +399 -0
  102. package/src/server/services/mcp-service.js +1188 -0
  103. package/src/server/services/prompts-service.js +492 -0
  104. package/src/server/services/proxy-runtime.js +79 -0
  105. package/src/server/services/pty-manager.js +435 -0
  106. package/src/server/services/rules-service.js +401 -0
  107. package/src/server/services/session-cache.js +127 -0
  108. package/src/server/services/session-converter.js +577 -0
  109. package/src/server/services/sessions.js +757 -0
  110. package/src/server/services/settings-manager.js +163 -0
  111. package/src/server/services/skill-service.js +965 -0
  112. package/src/server/services/speed-test.js +545 -0
  113. package/src/server/services/statistics-service.js +386 -0
  114. package/src/server/services/terminal-commands.js +155 -0
  115. package/src/server/services/terminal-config.js +140 -0
  116. package/src/server/services/terminal-detector.js +306 -0
  117. package/src/server/services/ui-config.js +130 -0
  118. package/src/server/services/workspace-service.js +662 -0
  119. package/src/server/utils/pricing.js +41 -0
  120. package/src/server/websocket-server.js +557 -0
  121. package/src/ui/menu.js +129 -0
  122. package/src/ui/prompts.js +100 -0
  123. package/src/utils/format.js +43 -0
  124. package/src/utils/port-helper.js +94 -0
  125. package/src/utils/session.js +239 -0
@@ -0,0 +1,121 @@
1
+ // CTX 工具路径配置
2
+ // 所有路径统一使用 ~/.claude/ctx 目录,避免与原始 cc-tool 冲突
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ // 基础目录
7
+ const CTX_BASE_DIR = path.join(os.homedir(), '.claude', 'ctx');
8
+
9
+ // 路径配置
10
+ const PATHS = {
11
+ // 基础目录
12
+ base: CTX_BASE_DIR,
13
+
14
+ // 项目目录(存储项目配置和会话)
15
+ projects: path.join(CTX_BASE_DIR, 'projects'),
16
+
17
+ // 配置文件目录
18
+ config: path.join(CTX_BASE_DIR, 'config'),
19
+ configFile: path.join(CTX_BASE_DIR, 'config.json'),
20
+
21
+ // 日志目录
22
+ logs: path.join(CTX_BASE_DIR, 'logs'),
23
+
24
+ // 别名存储
25
+ aliases: path.join(CTX_BASE_DIR, 'aliases.json'),
26
+
27
+ // 收藏夹存储
28
+ favorites: path.join(CTX_BASE_DIR, 'favorites.json'),
29
+
30
+ // 渠道配置
31
+ channels: {
32
+ claude: path.join(CTX_BASE_DIR, 'channels.json'),
33
+ codex: path.join(CTX_BASE_DIR, 'codex-channels.json'),
34
+ gemini: path.join(CTX_BASE_DIR, 'gemini-channels.json')
35
+ },
36
+
37
+ // 激活渠道标记
38
+ activeChannel: {
39
+ claude: path.join(CTX_BASE_DIR, 'active-channel.json'),
40
+ codex: path.join(CTX_BASE_DIR, 'codex-active-channel.json'),
41
+ gemini: path.join(CTX_BASE_DIR, 'gemini-active-channel.json')
42
+ },
43
+
44
+ // 统计数据
45
+ statistics: {
46
+ claude: path.join(CTX_BASE_DIR, 'statistics.json'),
47
+ codex: path.join(CTX_BASE_DIR, 'codex-statistics.json'),
48
+ gemini: path.join(CTX_BASE_DIR, 'gemini-statistics.json'),
49
+ dailyStats: {
50
+ claude: path.join(CTX_BASE_DIR, 'daily-stats'),
51
+ codex: path.join(CTX_BASE_DIR, 'codex-daily-stats'),
52
+ gemini: path.join(CTX_BASE_DIR, 'gemini-daily-stats')
53
+ }
54
+ },
55
+
56
+ // 会话缓存
57
+ sessionCache: path.join(CTX_BASE_DIR, 'session-cache.json'),
58
+
59
+ // 项目顺序
60
+ projectOrder: path.join(CTX_BASE_DIR, 'project-order.json'),
61
+
62
+ // 环境备份
63
+ envBackups: path.join(CTX_BASE_DIR, 'env-backups'),
64
+
65
+ // UI 配置
66
+ uiConfig: path.join(CTX_BASE_DIR, 'ui-config.json'),
67
+
68
+ // 飞书通知脚本
69
+ notifyHook: path.join(CTX_BASE_DIR, 'notify-hook.js'),
70
+
71
+ // Skills 安装目录(注意:这个仍使用 Claude 原生路径)
72
+ skills: path.join(os.homedir(), '.claude', 'skills'),
73
+
74
+ // MCP 配置(注意:这个仍使用 Claude 原生路径)
75
+ mcpConfig: path.join(CTX_BASE_DIR, 'mcp-config.json'),
76
+
77
+ // Terminal 配置
78
+ terminalConfig: path.join(CTX_BASE_DIR, 'terminal-config.json'),
79
+
80
+ // Prompts
81
+ prompts: path.join(CTX_BASE_DIR, 'prompts.json'),
82
+
83
+ // 代理运行时状态
84
+ proxyRuntime: {
85
+ claude: path.join(CTX_BASE_DIR, 'proxy-runtime.json'),
86
+ codex: path.join(CTX_BASE_DIR, 'codex-proxy-runtime.json'),
87
+ gemini: path.join(CTX_BASE_DIR, 'gemini-proxy-runtime.json')
88
+ }
89
+ };
90
+
91
+ // 工具特定的原生配置路径(不改变)
92
+ const NATIVE_PATHS = {
93
+ // Claude Code 原生配置
94
+ claude: {
95
+ settings: path.join(os.homedir(), '.claude', 'settings.json'),
96
+ settingsBackup: path.join(os.homedir(), '.claude', 'settings.json.cc-tool-backup'),
97
+ projects: path.join(os.homedir(), '.claude', 'projects')
98
+ },
99
+
100
+ // Codex 原生配置
101
+ codex: {
102
+ config: path.join(os.homedir(), '.codex', 'config.toml'),
103
+ configBackup: path.join(os.homedir(), '.codex', 'config.toml.cc-tool-backup'),
104
+ auth: path.join(os.homedir(), '.codex', 'auth.json'),
105
+ authBackup: path.join(os.homedir(), '.codex', 'auth.json.cc-tool-backup'),
106
+ sessions: path.join(os.homedir(), '.codex', 'sessions')
107
+ },
108
+
109
+ // Gemini 原生配置
110
+ gemini: {
111
+ env: path.join(os.homedir(), '.gemini', '.env'),
112
+ envBackup: path.join(os.homedir(), '.gemini', '.env.cc-tool-backup'),
113
+ tmp: path.join(os.homedir(), '.gemini', 'tmp')
114
+ }
115
+ };
116
+
117
+ module.exports = {
118
+ PATHS,
119
+ NATIVE_PATHS,
120
+ CTX_BASE_DIR
121
+ };
package/src/index.js ADDED
@@ -0,0 +1,373 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CC-CLI - Claude Code 会话管理工具
5
+ * 主入口文件
6
+ */
7
+
8
+ const { loadConfig } = require('./config/loader');
9
+ const { showMainMenu } = require('./ui/menu');
10
+ const { handleList } = require('./commands/list');
11
+ const { handleSearch } = require('./commands/search');
12
+ const { switchProject } = require('./commands/switch');
13
+ const { handleUI } = require('./commands/ui');
14
+ const { handleProxyStart, handleProxyStop, handleProxyStatus } = require('./commands/proxy');
15
+ const { resetConfig } = require('./reset-config');
16
+ const { handleChannelManagement, handleAddChannel, handleChannelStatus } = require('./commands/channels');
17
+ const { handleToggleProxy } = require('./commands/toggle-proxy');
18
+ const { handlePortConfig } = require('./commands/port-config');
19
+ const { handleSwitchCliType } = require('./commands/cli-type');
20
+ const { handleStart, handleStop, handleRestart, handleStatus } = require('./commands/daemon');
21
+ const { handleProxyStart: proxyStart, handleProxyStop: proxyStop, handleProxyRestart, handleProxyStatus: proxyStatus } = require('./commands/proxy-control');
22
+ const { handleLogs } = require('./commands/logs');
23
+ const { handleStats, handleStatsExport } = require('./commands/stats');
24
+ const { handleDoctor } = require('./commands/doctor');
25
+ const { workspaceMenu } = require('./commands/workspace');
26
+ const chalk = require('chalk');
27
+ const path = require('path');
28
+ const fs = require('fs');
29
+
30
+ // 读取版本号
31
+ function getVersion() {
32
+ const packagePath = path.join(__dirname, '../package.json');
33
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
34
+ return packageJson.version;
35
+ }
36
+
37
+ // 显示帮助信息
38
+ function showHelp() {
39
+ const version = getVersion();
40
+ console.log(chalk.cyan.bold(`\nCODING-TOOL v${version}`));
41
+ console.log(chalk.gray('Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控\n'));
42
+
43
+ console.log(chalk.yellow('🚀 服务管理:'));
44
+ console.log(' ctx start 启动所有服务(后台运行)');
45
+ console.log(' ctx stop 停止所有服务');
46
+ console.log(' ctx restart 重启所有服务');
47
+ console.log(' ctx status 查看服务状态\n');
48
+
49
+ console.log(chalk.yellow('📱 UI 管理:'));
50
+ console.log(' ctx ui 前台启动 Web UI(默认)');
51
+ console.log(' ctx ui start 后台启动 Web UI');
52
+ console.log(' ctx ui stop 停止 Web UI');
53
+ console.log(' ctx ui restart 重启 Web UI\n');
54
+
55
+ console.log(chalk.yellow('🔌 代理管理:'));
56
+ console.log(' ctx claude start 启动 Claude 代理');
57
+ console.log(' ctx claude stop 停止 Claude 代理');
58
+ console.log(' ctx claude status 查看 Claude 代理状态');
59
+ console.log(' ctx codex start 启动 Codex 代理');
60
+ console.log(' ctx gemini start 启动 Gemini 代理');
61
+ console.log(chalk.gray(' (codex/gemini 命令与 claude 类似)\n'));
62
+
63
+ console.log(chalk.yellow('📋 日志管理:'));
64
+ console.log(' ctx logs 查看所有日志');
65
+ console.log(' ctx logs ui 查看 UI 日志');
66
+ console.log(' ctx logs claude 查看 Claude 日志');
67
+ console.log(' ctx logs --lines 100 查看最近 100 行');
68
+ console.log(' ctx logs --follow 实时跟踪日志');
69
+ console.log(' ctx logs --clear 清空日志\n');
70
+
71
+ console.log(chalk.yellow('📊 统计信息:'));
72
+ console.log(' ctx stats 查看总体统计');
73
+ console.log(' ctx stats claude 查看 Claude 统计');
74
+ console.log(' ctx stats --today 查看今日统计');
75
+ console.log(' ctx stats export 导出统计数据\n');
76
+
77
+ console.log(chalk.yellow('🛠️ 其他命令:'));
78
+ console.log(' ctx doctor 系统诊断');
79
+ console.log(' ctx reset 重置配置');
80
+ console.log(' ctx --version, -v 显示版本');
81
+ console.log(' ctx --help, -h 显示帮助\n');
82
+
83
+ console.log(chalk.yellow('💡 快速开始:'));
84
+ console.log(chalk.gray(' $ ctx start # 后台启动服务(推荐)'));
85
+ console.log(chalk.gray(' $ ctx status # 查看服务状态'));
86
+ console.log(chalk.gray(' $ ctx logs # 查看实时日志'));
87
+ console.log(chalk.gray(' $ ctx stop # 停止服务\n'));
88
+
89
+ console.log(chalk.yellow('⭐ 开机自启(可选):'));
90
+ console.log(chalk.gray(' $ pm2 startup # 启用开机自启'));
91
+ console.log(chalk.gray(' $ pm2 save # 保存配置'));
92
+ console.log(chalk.gray(' $ pm2 unstartup # 禁用开机自启\n'));
93
+
94
+ console.log(chalk.yellow('更多信息:'));
95
+ console.log(chalk.gray(' 官网: https://github.com/CooperJiang/cc-tool'));
96
+ console.log(chalk.gray(' 文档: 运行 ctx start 后在 Web UI 右上角点击帮助'));
97
+ console.log(chalk.gray(' 问题: https://github.com/CooperJiang/cc-tool/issues\n'));
98
+ }
99
+
100
+ // 全局错误处理
101
+ process.on('uncaughtException', (err) => {
102
+ // 忽略终端相关的错误(通常在 Ctrl+C 时发生)
103
+ if (err.code === 'EIO' || err.code === 'ENOTTY' || err.code === 'EPIPE') {
104
+ process.exit(0);
105
+ }
106
+ throw err;
107
+ });
108
+
109
+ // 处理 SIGINT 信号(Ctrl+C)
110
+ process.on('SIGINT', () => {
111
+ process.exit(0);
112
+ });
113
+
114
+ /**
115
+ * 主函数
116
+ */
117
+ async function main() {
118
+ // 处理命令行参数
119
+ const args = process.argv.slice(2);
120
+
121
+ // --version 或 -v - 显示版本号
122
+ if (args[0] === '--version' || args[0] === '-v') {
123
+ console.log(getVersion());
124
+ return;
125
+ }
126
+
127
+ // --help 或 -h - 显示帮助信息
128
+ if (args[0] === '--help' || args[0] === '-h') {
129
+ showHelp();
130
+ return;
131
+ }
132
+
133
+ // reset 命令 - 恢复默认配置
134
+ if (args[0] === 'reset') {
135
+ await resetConfig();
136
+ return;
137
+ }
138
+
139
+ // start 命令 - 启动服务(后台)
140
+ if (args[0] === 'start') {
141
+ await handleStart();
142
+ return;
143
+ }
144
+
145
+ // stop 命令 - 停止服务
146
+ if (args[0] === 'stop') {
147
+ await handleStop();
148
+ return;
149
+ }
150
+
151
+ // restart 命令 - 重启服务
152
+ if (args[0] === 'restart') {
153
+ await handleRestart();
154
+ return;
155
+ }
156
+
157
+ // status 命令 - 查看服务状态
158
+ if (args[0] === 'status') {
159
+ await handleStatus();
160
+ return;
161
+ }
162
+
163
+ // ui 命令 - Web UI 管理
164
+ if (args[0] === 'ui') {
165
+ const subCommand = args[1];
166
+ if (subCommand === 'start') {
167
+ await handleStart(); // UI start 实际上就是启动整个服务
168
+ } else if (subCommand === 'stop') {
169
+ await handleStop();
170
+ } else if (subCommand === 'restart') {
171
+ await handleRestart();
172
+ } else {
173
+ // 默认前台运行
174
+ await handleUI();
175
+ }
176
+ return;
177
+ }
178
+
179
+ // claude/codex/gemini 代理管理命令
180
+ const channels = ['claude', 'codex', 'gemini'];
181
+ if (channels.includes(args[0])) {
182
+ const channel = args[0];
183
+ const action = args[1] || 'status';
184
+
185
+ switch (action) {
186
+ case 'start':
187
+ await proxyStart(channel);
188
+ break;
189
+ case 'stop':
190
+ await proxyStop(channel);
191
+ break;
192
+ case 'restart':
193
+ await handleProxyRestart(channel);
194
+ break;
195
+ case 'status':
196
+ await proxyStatus(channel);
197
+ break;
198
+ default:
199
+ console.log(chalk.red(`\n❌ 未知操作: ${action}\n`));
200
+ console.log(chalk.gray('支持的操作: start, stop, restart, status\n'));
201
+ }
202
+ return;
203
+ }
204
+
205
+ // logs 命令 - 日志管理
206
+ if (args[0] === 'logs') {
207
+ const type = args[1] && !args[1].startsWith('--') ? args[1] : null;
208
+ const options = {};
209
+
210
+ // 解析选项
211
+ for (let i = type ? 2 : 1; i < args.length; i++) {
212
+ if (args[i] === '--lines' && args[i + 1]) {
213
+ options.lines = parseInt(args[i + 1]);
214
+ i++;
215
+ } else if (args[i] === '--follow' || args[i] === '-f') {
216
+ options.follow = true;
217
+ } else if (args[i] === '--clear') {
218
+ options.clear = true;
219
+ }
220
+ }
221
+
222
+ await handleLogs(type, options);
223
+ return;
224
+ }
225
+
226
+ // stats 命令 - 统计信息
227
+ if (args[0] === 'stats') {
228
+ if (args[1] === 'export') {
229
+ const type = args[2] || null;
230
+ await handleStatsExport(type);
231
+ } else {
232
+ const type = args[1] && !args[1].startsWith('--') ? args[1] : null;
233
+ const options = {};
234
+
235
+ // 解析选项
236
+ for (let i = type ? 2 : 1; i < args.length; i++) {
237
+ if (args[i] === '--today') options.today = true;
238
+ else if (args[i] === '--week') options.week = true;
239
+ else if (args[i] === '--month') options.month = true;
240
+ }
241
+
242
+ await handleStats(type, options);
243
+ }
244
+ return;
245
+ }
246
+
247
+ // doctor 命令 - 系统诊断
248
+ if (args[0] === 'doctor') {
249
+ await handleDoctor();
250
+ return;
251
+ }
252
+
253
+ // 代理命令
254
+ if (args[0] === 'proxy') {
255
+ const subCommand = args[1] || 'start';
256
+
257
+ switch (subCommand) {
258
+ case 'start':
259
+ await handleProxyStart();
260
+ return;
261
+
262
+ case 'stop':
263
+ await handleProxyStop();
264
+ return;
265
+
266
+ case 'status':
267
+ handleProxyStatus();
268
+ return;
269
+
270
+ default:
271
+ // 默认执行 start
272
+ await handleProxyStart();
273
+ return;
274
+ }
275
+ }
276
+
277
+ // 加载配置
278
+ let config = loadConfig();
279
+
280
+ while (true) {
281
+ // 显示主菜单
282
+ const action = await showMainMenu(config);
283
+
284
+ switch (action) {
285
+ case 'list':
286
+ await handleList(config, async () => {
287
+ const switched = await switchProject(config);
288
+ if (switched) {
289
+ // 重新加载配置以获取最新的项目设置
290
+ config = loadConfig();
291
+ }
292
+ return switched;
293
+ }, true); // crossProject = true,跨项目显示最近会话
294
+ break;
295
+
296
+ case 'search':
297
+ await handleSearch(config, async () => {
298
+ const switched = await switchProject(config);
299
+ if (switched) {
300
+ config = loadConfig();
301
+ }
302
+ return switched;
303
+ });
304
+ break;
305
+
306
+ case 'switch':
307
+ const switched = await switchProject(config);
308
+ if (switched) {
309
+ config = loadConfig();
310
+ // 切换成功后自动进入会话列表
311
+ await handleList(config, async () => {
312
+ const switched = await switchProject(config);
313
+ if (switched) {
314
+ config = loadConfig();
315
+ }
316
+ return switched;
317
+ });
318
+ }
319
+ break;
320
+
321
+ case 'workspace':
322
+ await workspaceMenu();
323
+ break;
324
+
325
+ case 'switch-cli-type':
326
+ await handleSwitchCliType();
327
+ config = loadConfig(); // 重新加载配置以获取新的类型
328
+ break;
329
+
330
+ case 'switch-channel':
331
+ await handleChannelManagement();
332
+ break;
333
+ case 'channel-status':
334
+ await handleChannelStatus();
335
+ break;
336
+
337
+ case 'toggle-proxy':
338
+ await handleToggleProxy();
339
+ break;
340
+
341
+ case 'add-channel':
342
+ await handleAddChannel();
343
+ break;
344
+
345
+ case 'ui':
346
+ await handleUI();
347
+ break;
348
+
349
+ case 'port-config':
350
+ await handlePortConfig();
351
+ break;
352
+
353
+ case 'reset':
354
+ await resetConfig();
355
+ break;
356
+
357
+ case 'exit':
358
+ console.log('\n👋 再见!\n');
359
+ process.exit(0);
360
+ break;
361
+
362
+ default:
363
+ console.log('未知操作');
364
+ break;
365
+ }
366
+ }
367
+ }
368
+
369
+ // 启动应用
370
+ main().catch((error) => {
371
+ console.error('程序出错:', error);
372
+ process.exit(1);
373
+ });
@@ -0,0 +1,92 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ // 恢复配置到默认状态
6
+ async function resetConfig() {
7
+ console.log('\n开始恢复默认配置...\n');
8
+
9
+ try {
10
+ // 1. 尝试停止代理服务器(如果正在运行)
11
+ try {
12
+ const { stopProxyServer, getProxyStatus } = require('./server/proxy-server');
13
+ const status = getProxyStatus();
14
+
15
+ if (status.running) {
16
+ console.log('检测到代理服务正在运行,正在停止...');
17
+ await stopProxyServer();
18
+ console.log('✅ 代理服务已停止');
19
+ }
20
+ } catch (err) {
21
+ // 代理服务未运行或模块加载失败,继续处理本地文件
22
+ console.log('代理服务未运行,继续恢复配置...');
23
+ }
24
+
25
+ // 2. 检查并恢复 settings.json
26
+ const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
27
+ const backupPath = path.join(os.homedir(), '.claude', 'settings.json.cc-tool-backup');
28
+
29
+ if (fs.existsSync(backupPath)) {
30
+ console.log('发现备份文件,正在恢复...');
31
+ const backupContent = fs.readFileSync(backupPath, 'utf8');
32
+ fs.writeFileSync(settingsPath, backupContent, 'utf8');
33
+ fs.unlinkSync(backupPath);
34
+ console.log('✅ 已从备份恢复 settings.json');
35
+ } else if (fs.existsSync(settingsPath)) {
36
+ // 检查是否是代理配置
37
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
38
+ const baseUrl = settings?.env?.ANTHROPIC_BASE_URL || '';
39
+ const apiKey = settings?.env?.ANTHROPIC_API_KEY || '';
40
+
41
+ if (baseUrl.includes('127.0.0.1') || apiKey === 'PROXY_KEY') {
42
+ console.log('检测到代理配置,尝试恢复到正常渠道...');
43
+
44
+ // 读取激活的渠道
45
+ const activeChannelPath = path.join(os.homedir(), '.claude', 'cc-tool', 'active-channel.json');
46
+ if (fs.existsSync(activeChannelPath)) {
47
+ const activeChannelData = JSON.parse(fs.readFileSync(activeChannelPath, 'utf8'));
48
+ const channelsPath = path.join(os.homedir(), '.claude', 'cc-tool', 'channels.json');
49
+
50
+ if (fs.existsSync(channelsPath)) {
51
+ const channelsData = JSON.parse(fs.readFileSync(channelsPath, 'utf8'));
52
+ const activeChannel = channelsData.channels.find(ch => ch.id === activeChannelData.activeChannelId);
53
+
54
+ if (activeChannel) {
55
+ // 恢复到激活的渠道
56
+ if (!settings.env) settings.env = {};
57
+ settings.env.ANTHROPIC_BASE_URL = activeChannel.baseUrl;
58
+ settings.env.ANTHROPIC_API_KEY = activeChannel.apiKey;
59
+ settings.apiKeyHelper = `echo '${activeChannel.apiKey}'`;
60
+
61
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
62
+ console.log(`✅ 已恢复到渠道: ${activeChannel.name}`);
63
+
64
+ // 清理 active-channel.json
65
+ fs.unlinkSync(activeChannelPath);
66
+ } else {
67
+ console.log('⚠️ 无法找到激活的渠道,请手动配置 Claude Code');
68
+ }
69
+ }
70
+ } else {
71
+ console.log('⚠️ 未找到激活渠道信息,但已清除代理配置');
72
+ console.log('请手动配置 Claude Code 或通过 Web UI 管理渠道');
73
+ }
74
+ } else {
75
+ console.log('✅ 配置文件正常,无需恢复');
76
+ }
77
+ } else {
78
+ console.log('⚠️ 未找到 settings.json 文件');
79
+ }
80
+
81
+ console.log('\n✅ 配置恢复完成!\n');
82
+ } catch (err) {
83
+ console.error('❌ 恢复配置时出错:', err.message);
84
+ console.log('\n您可以尝试手动恢复:');
85
+ console.log('1. 检查 ~/.claude/settings.json 文件');
86
+ console.log('2. 如果有 settings.json.cc-tool-backup 备份文件,手动恢复');
87
+ console.log('3. 或者通过 Web UI 重新配置渠道\n');
88
+ process.exit(1);
89
+ }
90
+ }
91
+
92
+ module.exports = { resetConfig };