coding-tool-x 3.4.3 → 3.4.5
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-DFWyPf5C.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-oP6nrFEb.js → ConfigTemplates-BFE7hmKd.js} +1 -1
- package/dist/web/assets/{Home-DMntmEvh.js → Home-DZUuCrxk.js} +1 -1
- package/dist/web/assets/{PluginManager-BUC_c7nH.js → PluginManager-WyGY2BQN.js} +1 -1
- package/dist/web/assets/{ProjectList-CW8J49n7.js → ProjectList-CBc0QawN.js} +1 -1
- package/dist/web/assets/{ProjectList-oJIyIRkP.css → ProjectList-DL4JK6ci.css} +1 -1
- package/dist/web/assets/{SessionList-7lYnF92v.js → SessionList-CdPR7QLq.js} +1 -1
- package/dist/web/assets/{SkillManager-Cs08216i.js → SkillManager-B5-DxQOS.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CY-oGtyB.js → WorkspaceManager-C7yqFjpi.js} +1 -1
- package/dist/web/assets/index-BDsmoSfO.js +2 -0
- package/dist/web/assets/{index-5qy5NMIP.css → index-C1pzEgmj.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
- 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 +3 -2
- package/src/server/api/plugins.js +165 -14
- package/src/server/api/pm2-autostart.js +2 -2
- package/src/server/api/proxy.js +6 -6
- package/src/server/api/skills.js +66 -7
- package/src/server/codex-proxy-server.js +10 -2
- package/src/server/dev-server.js +2 -2
- package/src/server/gemini-proxy-server.js +10 -2
- package/src/server/index.js +37 -37
- package/src/server/opencode-proxy-server.js +10 -2
- package/src/server/proxy-server.js +14 -6
- package/src/server/services/codex-channels.js +64 -21
- package/src/server/services/codex-env-manager.js +44 -28
- 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 +1066 -261
- package/src/server/services/proxy-runtime.js +129 -5
- package/src/server/services/server-shutdown.js +79 -0
- package/src/server/services/settings-manager.js +3 -3
- package/src/server/services/skill-service.js +146 -29
- 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
package/src/commands/logs.js
CHANGED
|
@@ -46,7 +46,7 @@ async function handleLogs(type = null, options = {}) {
|
|
|
46
46
|
// 显示特定类型的日志
|
|
47
47
|
const logFile = LOG_FILES[type];
|
|
48
48
|
if (!logFile) {
|
|
49
|
-
console.error(chalk.red(`\n
|
|
49
|
+
console.error(chalk.red(`\n[ERROR] 无效的日志类型: ${type}\n`));
|
|
50
50
|
console.log(chalk.gray('支持的类型: ui, claude, codex, gemini, opencode\n'));
|
|
51
51
|
process.exit(1);
|
|
52
52
|
}
|
|
@@ -55,13 +55,13 @@ async function handleLogs(type = null, options = {}) {
|
|
|
55
55
|
|
|
56
56
|
// 检查日志文件是否存在
|
|
57
57
|
if (!fs.existsSync(logPath)) {
|
|
58
|
-
console.log(chalk.yellow(`\n
|
|
58
|
+
console.log(chalk.yellow(`\n[WARN] ${type} 日志文件不存在\n`));
|
|
59
59
|
console.log(chalk.gray(`日志路径: ${logPath}\n`));
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
console.log(chalk.cyan(`\n
|
|
64
|
-
console.log(chalk.gray(
|
|
63
|
+
console.log(chalk.cyan(`\n[LOG] ${type.toUpperCase()} 日志 ${follow ? '(实时)' : `(最近 ${lines} 行)`}\n`));
|
|
64
|
+
console.log(chalk.gray(`=`.repeat(60)) + '\n');
|
|
65
65
|
|
|
66
66
|
if (follow) {
|
|
67
67
|
// 实时跟踪日志
|
|
@@ -76,8 +76,8 @@ async function handleLogs(type = null, options = {}) {
|
|
|
76
76
|
* 显示所有日志(合并)
|
|
77
77
|
*/
|
|
78
78
|
function showAllLogs(lines, follow) {
|
|
79
|
-
console.log(chalk.cyan(`\n
|
|
80
|
-
console.log(chalk.gray(
|
|
79
|
+
console.log(chalk.cyan(`\n[LOG] 所有日志 ${follow ? '(实时)' : `(最近 ${lines} 行)`}\n`));
|
|
80
|
+
console.log(chalk.gray(`=`.repeat(60)) + '\n');
|
|
81
81
|
|
|
82
82
|
const allLogs = [];
|
|
83
83
|
|
|
@@ -115,8 +115,8 @@ function showAllLogs(lines, follow) {
|
|
|
115
115
|
console.log(typeColor(typeLabel) + chalk.gray(log.line));
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
console.log(chalk.gray(`\n
|
|
119
|
-
console.log(chalk.gray(`\n
|
|
118
|
+
console.log(chalk.gray(`\n=`.repeat(60)));
|
|
119
|
+
console.log(chalk.gray(`\n[TIP] 使用 `) + chalk.cyan(`ctx logs ${Object.keys(LOG_FILES).join('|')}`) + chalk.gray(` 查看特定类型日志\n`));
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/**
|
|
@@ -134,8 +134,8 @@ function showLastLines(filePath, lines) {
|
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
console.log(chalk.gray(`\n
|
|
138
|
-
console.log(chalk.gray(`\n
|
|
137
|
+
console.log(chalk.gray(`\n=`.repeat(60)));
|
|
138
|
+
console.log(chalk.gray(`\n[TIP] 使用 `) + chalk.cyan(`ctx logs <type> --follow`) + chalk.gray(` 实时跟踪日志\n`));
|
|
139
139
|
} catch (err) {
|
|
140
140
|
console.error(chalk.red(`读取日志失败: ${err.message}\n`));
|
|
141
141
|
process.exit(1);
|
|
@@ -181,7 +181,7 @@ function tailFile(filePath) {
|
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
followProcess.on('error', (err) => {
|
|
184
|
-
console.error(chalk.red(`\n
|
|
184
|
+
console.error(chalk.red(`\n[ERROR] 跟踪日志失败: ${err.message}\n`));
|
|
185
185
|
if (isWindows) {
|
|
186
186
|
console.log(chalk.gray('提示: 请确认系统可用 powershell 命令。\n'));
|
|
187
187
|
}
|
|
@@ -207,7 +207,7 @@ function tailFile(filePath) {
|
|
|
207
207
|
function clearLogs(type) {
|
|
208
208
|
if (!type) {
|
|
209
209
|
// 清空所有日志
|
|
210
|
-
console.log(chalk.cyan('\n
|
|
210
|
+
console.log(chalk.cyan('\n[DEL] 清空所有日志...\n'));
|
|
211
211
|
|
|
212
212
|
let cleared = 0;
|
|
213
213
|
Object.entries(LOG_FILES).forEach(([logType, filename]) => {
|
|
@@ -215,20 +215,20 @@ function clearLogs(type) {
|
|
|
215
215
|
if (fs.existsSync(logPath)) {
|
|
216
216
|
try {
|
|
217
217
|
fs.writeFileSync(logPath, '');
|
|
218
|
-
console.log(chalk.green(
|
|
218
|
+
console.log(chalk.green(`[OK] ${logType} 日志已清空`));
|
|
219
219
|
cleared++;
|
|
220
220
|
} catch (err) {
|
|
221
|
-
console.log(chalk.red(
|
|
221
|
+
console.log(chalk.red(`[ERROR] ${logType} 日志清空失败: ${err.message}`));
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
});
|
|
225
225
|
|
|
226
|
-
console.log(chalk.green(`\n
|
|
226
|
+
console.log(chalk.green(`\n[OK] 共清空 ${cleared} 个日志文件\n`));
|
|
227
227
|
} else {
|
|
228
228
|
// 清空特定类型日志
|
|
229
229
|
const logFile = LOG_FILES[type];
|
|
230
230
|
if (!logFile) {
|
|
231
|
-
console.error(chalk.red(`\n
|
|
231
|
+
console.error(chalk.red(`\n[ERROR] 无效的日志类型: ${type}\n`));
|
|
232
232
|
process.exit(1);
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -236,13 +236,13 @@ function clearLogs(type) {
|
|
|
236
236
|
if (fs.existsSync(logPath)) {
|
|
237
237
|
try {
|
|
238
238
|
fs.writeFileSync(logPath, '');
|
|
239
|
-
console.log(chalk.green(`\n
|
|
239
|
+
console.log(chalk.green(`\n[OK] ${type} 日志已清空\n`));
|
|
240
240
|
} catch (err) {
|
|
241
|
-
console.error(chalk.red(`\n
|
|
241
|
+
console.error(chalk.red(`\n[ERROR] 清空失败: ${err.message}\n`));
|
|
242
242
|
process.exit(1);
|
|
243
243
|
}
|
|
244
244
|
} else {
|
|
245
|
-
console.log(chalk.yellow(`\n
|
|
245
|
+
console.log(chalk.yellow(`\n[WARN] ${type} 日志文件不存在\n`));
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
}
|
package/src/commands/plugin.js
CHANGED
|
@@ -49,7 +49,7 @@ async function handlePluginCommand(args) {
|
|
|
49
49
|
showHelp();
|
|
50
50
|
break;
|
|
51
51
|
default:
|
|
52
|
-
console.error(chalk.red(`\n
|
|
52
|
+
console.error(chalk.red(`\n[ERROR] Unknown subcommand: ${subcommand}\n`));
|
|
53
53
|
showHelp();
|
|
54
54
|
process.exit(1);
|
|
55
55
|
}
|
|
@@ -63,18 +63,18 @@ async function handleInstall(args) {
|
|
|
63
63
|
const url = args[0];
|
|
64
64
|
|
|
65
65
|
if (!url) {
|
|
66
|
-
console.error(chalk.red('\n
|
|
66
|
+
console.error(chalk.red('\n[ERROR] Git URL is required\n'));
|
|
67
67
|
console.log(chalk.gray('Usage: ctx plugin install <git-url>\n'));
|
|
68
68
|
console.log(chalk.gray('Example: ctx plugin install https://github.com/user/ctx-plugin.git\n'));
|
|
69
69
|
process.exit(1);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
console.log(chalk.cyan(`\n
|
|
72
|
+
console.log(chalk.cyan(`\n[PKG] Installing plugin from ${url}...\n`));
|
|
73
73
|
|
|
74
74
|
const result = await installPlugin(url);
|
|
75
75
|
|
|
76
76
|
if (result.success) {
|
|
77
|
-
console.log(chalk.green('\n
|
|
77
|
+
console.log(chalk.green('\n[OK] Plugin installed successfully!\n'));
|
|
78
78
|
console.log(chalk.gray('─'.repeat(60)));
|
|
79
79
|
console.log(chalk.cyan('Name: ') + chalk.white(result.plugin.name));
|
|
80
80
|
console.log(chalk.cyan('Version: ') + chalk.white(result.plugin.version));
|
|
@@ -82,9 +82,9 @@ async function handleInstall(args) {
|
|
|
82
82
|
console.log(chalk.cyan('Commands: ') + chalk.white(result.plugin.commands || 0));
|
|
83
83
|
console.log(chalk.cyan('Hooks: ') + chalk.white(result.plugin.hooks || 0));
|
|
84
84
|
console.log(chalk.gray('─'.repeat(60)));
|
|
85
|
-
console.log(chalk.gray(`\n
|
|
85
|
+
console.log(chalk.gray(`\n[TIP] Run ${chalk.cyan(`ctx plugin info ${result.plugin.name}`)} for more details\n`));
|
|
86
86
|
} else {
|
|
87
|
-
console.error(chalk.red('\n
|
|
87
|
+
console.error(chalk.red('\n[ERROR] Installation failed:\n'));
|
|
88
88
|
console.error(chalk.red(result.error));
|
|
89
89
|
console.log();
|
|
90
90
|
process.exit(1);
|
|
@@ -99,7 +99,7 @@ async function handleRemove(args) {
|
|
|
99
99
|
const name = args[0];
|
|
100
100
|
|
|
101
101
|
if (!name) {
|
|
102
|
-
console.error(chalk.red('\n
|
|
102
|
+
console.error(chalk.red('\n[ERROR] Plugin name is required\n'));
|
|
103
103
|
console.log(chalk.gray('Usage: ctx plugin remove <name>\n'));
|
|
104
104
|
process.exit(1);
|
|
105
105
|
}
|
|
@@ -107,7 +107,7 @@ async function handleRemove(args) {
|
|
|
107
107
|
// Check if plugin exists
|
|
108
108
|
const plugin = getPlugin(name);
|
|
109
109
|
if (!plugin) {
|
|
110
|
-
console.error(chalk.red(`\n
|
|
110
|
+
console.error(chalk.red(`\n[ERROR] Plugin "${name}" is not installed\n`));
|
|
111
111
|
process.exit(1);
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -122,18 +122,18 @@ async function handleRemove(args) {
|
|
|
122
122
|
]);
|
|
123
123
|
|
|
124
124
|
if (!confirmed) {
|
|
125
|
-
console.log(chalk.yellow('\n
|
|
125
|
+
console.log(chalk.yellow('\n[WARN] Uninstall cancelled\n'));
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
console.log(chalk.cyan(`\n
|
|
129
|
+
console.log(chalk.cyan(`\n[DEL] Uninstalling plugin "${name}"...\n`));
|
|
130
130
|
|
|
131
131
|
const result = uninstallPlugin(name);
|
|
132
132
|
|
|
133
133
|
if (result.success) {
|
|
134
|
-
console.log(chalk.green(`\n
|
|
134
|
+
console.log(chalk.green(`\n[OK] ${result.message}\n`));
|
|
135
135
|
} else {
|
|
136
|
-
console.error(chalk.red('\n
|
|
136
|
+
console.error(chalk.red('\n[ERROR] Uninstall failed:\n'));
|
|
137
137
|
console.error(chalk.red(result.error));
|
|
138
138
|
console.log();
|
|
139
139
|
process.exit(1);
|
|
@@ -148,21 +148,21 @@ function handleList(args) {
|
|
|
148
148
|
const plugins = listPlugins();
|
|
149
149
|
|
|
150
150
|
if (plugins.length === 0) {
|
|
151
|
-
console.log(chalk.yellow('\n
|
|
152
|
-
console.log(chalk.gray('
|
|
151
|
+
console.log(chalk.yellow('\n[WARN] No plugins installed\n'));
|
|
152
|
+
console.log(chalk.gray('[TIP] Install a plugin with: ') + chalk.cyan('ctx plugin install <git-url>\n'));
|
|
153
153
|
return;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
console.log(chalk.cyan(`\n
|
|
157
|
-
console.log(chalk.gray('
|
|
156
|
+
console.log(chalk.cyan(`\n[PKG] Installed Plugins (${plugins.length})\n`));
|
|
157
|
+
console.log(chalk.gray('='.repeat(80)));
|
|
158
158
|
|
|
159
159
|
// Sort by name
|
|
160
160
|
plugins.sort((a, b) => a.name.localeCompare(b.name));
|
|
161
161
|
|
|
162
162
|
for (const plugin of plugins) {
|
|
163
163
|
const status = plugin.enabled
|
|
164
|
-
? chalk.green('
|
|
165
|
-
: chalk.gray('
|
|
164
|
+
? chalk.green('[v] enabled ')
|
|
165
|
+
: chalk.gray('[x] disabled');
|
|
166
166
|
|
|
167
167
|
console.log('\n' + chalk.white.bold(plugin.name) + ' ' + chalk.gray(`v${plugin.version}`) + ' ' + status);
|
|
168
168
|
|
|
@@ -189,8 +189,8 @@ function handleList(args) {
|
|
|
189
189
|
console.log(chalk.gray(` Installed: ${new Date(plugin.installedAt).toLocaleDateString()}`));
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
console.log('\n' + chalk.gray('
|
|
193
|
-
console.log(chalk.gray(`\n
|
|
192
|
+
console.log('\n' + chalk.gray('='.repeat(80)));
|
|
193
|
+
console.log(chalk.gray(`\n[TIP] Use ${chalk.cyan('ctx plugin info <name>')} for detailed information\n`));
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
/**
|
|
@@ -201,28 +201,28 @@ function handleEnable(args) {
|
|
|
201
201
|
const name = args[0];
|
|
202
202
|
|
|
203
203
|
if (!name) {
|
|
204
|
-
console.error(chalk.red('\n
|
|
204
|
+
console.error(chalk.red('\n[ERROR] Plugin name is required\n'));
|
|
205
205
|
console.log(chalk.gray('Usage: ctx plugin enable <name>\n'));
|
|
206
206
|
process.exit(1);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
const plugin = getPlugin(name);
|
|
210
210
|
if (!plugin) {
|
|
211
|
-
console.error(chalk.red(`\n
|
|
211
|
+
console.error(chalk.red(`\n[ERROR] Plugin "${name}" is not installed\n`));
|
|
212
212
|
process.exit(1);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
if (plugin.enabled) {
|
|
216
|
-
console.log(chalk.yellow(`\n
|
|
216
|
+
console.log(chalk.yellow(`\n[WARN] Plugin "${name}" is already enabled\n`));
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
try {
|
|
221
221
|
updatePluginRegistry(name, { enabled: true });
|
|
222
|
-
console.log(chalk.green(`\n
|
|
223
|
-
console.log(chalk.gray('
|
|
222
|
+
console.log(chalk.green(`\n[OK] Plugin "${name}" has been enabled\n`));
|
|
223
|
+
console.log(chalk.gray('[TIP] Restart ctx for changes to take effect\n'));
|
|
224
224
|
} catch (error) {
|
|
225
|
-
console.error(chalk.red(`\n
|
|
225
|
+
console.error(chalk.red(`\n[ERROR] Failed to enable plugin: ${error.message}\n`));
|
|
226
226
|
process.exit(1);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -235,28 +235,28 @@ function handleDisable(args) {
|
|
|
235
235
|
const name = args[0];
|
|
236
236
|
|
|
237
237
|
if (!name) {
|
|
238
|
-
console.error(chalk.red('\n
|
|
238
|
+
console.error(chalk.red('\n[ERROR] Plugin name is required\n'));
|
|
239
239
|
console.log(chalk.gray('Usage: ctx plugin disable <name>\n'));
|
|
240
240
|
process.exit(1);
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
const plugin = getPlugin(name);
|
|
244
244
|
if (!plugin) {
|
|
245
|
-
console.error(chalk.red(`\n
|
|
245
|
+
console.error(chalk.red(`\n[ERROR] Plugin "${name}" is not installed\n`));
|
|
246
246
|
process.exit(1);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
if (!plugin.enabled) {
|
|
250
|
-
console.log(chalk.yellow(`\n
|
|
250
|
+
console.log(chalk.yellow(`\n[WARN] Plugin "${name}" is already disabled\n`));
|
|
251
251
|
return;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
try {
|
|
255
255
|
updatePluginRegistry(name, { enabled: false });
|
|
256
|
-
console.log(chalk.green(`\n
|
|
257
|
-
console.log(chalk.gray('
|
|
256
|
+
console.log(chalk.green(`\n[OK] Plugin "${name}" has been disabled\n`));
|
|
257
|
+
console.log(chalk.gray('[TIP] Restart ctx for changes to take effect\n'));
|
|
258
258
|
} catch (error) {
|
|
259
|
-
console.error(chalk.red(`\n
|
|
259
|
+
console.error(chalk.red(`\n[ERROR] Failed to disable plugin: ${error.message}\n`));
|
|
260
260
|
process.exit(1);
|
|
261
261
|
}
|
|
262
262
|
}
|
|
@@ -269,21 +269,21 @@ function handleInfo(args) {
|
|
|
269
269
|
const name = args[0];
|
|
270
270
|
|
|
271
271
|
if (!name) {
|
|
272
|
-
console.error(chalk.red('\n
|
|
272
|
+
console.error(chalk.red('\n[ERROR] Plugin name is required\n'));
|
|
273
273
|
console.log(chalk.gray('Usage: ctx plugin info <name>\n'));
|
|
274
274
|
process.exit(1);
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
const plugin = getPlugin(name);
|
|
278
278
|
if (!plugin) {
|
|
279
|
-
console.error(chalk.red(`\n
|
|
279
|
+
console.error(chalk.red(`\n[ERROR] Plugin "${name}" is not installed\n`));
|
|
280
280
|
process.exit(1);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
// Read manifest
|
|
284
284
|
const manifestPath = path.join(INSTALLED_DIR, name, 'plugin.json');
|
|
285
285
|
if (!fs.existsSync(manifestPath)) {
|
|
286
|
-
console.error(chalk.red(`\n
|
|
286
|
+
console.error(chalk.red(`\n[ERROR] Plugin manifest not found: ${manifestPath}\n`));
|
|
287
287
|
process.exit(1);
|
|
288
288
|
}
|
|
289
289
|
|
|
@@ -291,13 +291,13 @@ function handleInfo(args) {
|
|
|
291
291
|
try {
|
|
292
292
|
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
293
293
|
} catch (error) {
|
|
294
|
-
console.error(chalk.red(`\n
|
|
294
|
+
console.error(chalk.red(`\n[ERROR] Failed to read plugin manifest: ${error.message}\n`));
|
|
295
295
|
process.exit(1);
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
// Display plugin information
|
|
299
|
-
console.log(chalk.cyan(`\n
|
|
300
|
-
console.log(chalk.gray('
|
|
299
|
+
console.log(chalk.cyan(`\n[PKG] Plugin Information: ${name}\n`));
|
|
300
|
+
console.log(chalk.gray('='.repeat(80)));
|
|
301
301
|
|
|
302
302
|
console.log(chalk.white('\nBasic Info:'));
|
|
303
303
|
console.log(chalk.cyan(' Name: ') + chalk.white(manifest.name));
|
|
@@ -360,7 +360,7 @@ function handleInfo(args) {
|
|
|
360
360
|
}
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
-
console.log('\n' + chalk.gray('
|
|
363
|
+
console.log('\n' + chalk.gray('='.repeat(80)) + '\n');
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
/**
|
|
@@ -371,7 +371,7 @@ function handleConfig(args) {
|
|
|
371
371
|
const [name, key, ...valueParts] = args;
|
|
372
372
|
|
|
373
373
|
if (!name) {
|
|
374
|
-
console.error(chalk.red('\n
|
|
374
|
+
console.error(chalk.red('\n[ERROR] Plugin name is required\n'));
|
|
375
375
|
console.log(chalk.gray('Usage: ctx plugin config <name> [key] [value]\n'));
|
|
376
376
|
console.log(chalk.gray('Examples:\n'));
|
|
377
377
|
console.log(chalk.gray(' ctx plugin config my-plugin # View all config'));
|
|
@@ -382,7 +382,7 @@ function handleConfig(args) {
|
|
|
382
382
|
|
|
383
383
|
const plugin = getPlugin(name);
|
|
384
384
|
if (!plugin) {
|
|
385
|
-
console.error(chalk.red(`\n
|
|
385
|
+
console.error(chalk.red(`\n[ERROR] Plugin "${name}" is not installed\n`));
|
|
386
386
|
process.exit(1);
|
|
387
387
|
}
|
|
388
388
|
|
|
@@ -400,15 +400,15 @@ function handleConfig(args) {
|
|
|
400
400
|
try {
|
|
401
401
|
config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
402
402
|
} catch (error) {
|
|
403
|
-
console.error(chalk.red(`\n
|
|
403
|
+
console.error(chalk.red(`\n[ERROR] Failed to read config: ${error.message}\n`));
|
|
404
404
|
process.exit(1);
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
// No key provided - view all config
|
|
409
409
|
if (!key) {
|
|
410
|
-
console.log(chalk.cyan(`\n
|
|
411
|
-
console.log(chalk.gray('
|
|
410
|
+
console.log(chalk.cyan(`\n[CFG] Configuration for "${name}"\n`));
|
|
411
|
+
console.log(chalk.gray('='.repeat(80)));
|
|
412
412
|
|
|
413
413
|
const keys = Object.keys(config);
|
|
414
414
|
if (keys.length === 0) {
|
|
@@ -425,16 +425,16 @@ function handleConfig(args) {
|
|
|
425
425
|
console.log();
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
-
console.log(chalk.gray('
|
|
428
|
+
console.log(chalk.gray('='.repeat(80)) + '\n');
|
|
429
429
|
return;
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
// No value provided - view specific key
|
|
433
433
|
if (valueParts.length === 0) {
|
|
434
434
|
if (config[key] === undefined) {
|
|
435
|
-
console.log(chalk.yellow(`\n
|
|
435
|
+
console.log(chalk.yellow(`\n[WARN] Key "${key}" is not set\n`));
|
|
436
436
|
} else {
|
|
437
|
-
console.log(chalk.cyan(`\n
|
|
437
|
+
console.log(chalk.cyan(`\n[CFG] ${key}: `) + chalk.white(JSON.stringify(config[key], null, 2)) + '\n');
|
|
438
438
|
}
|
|
439
439
|
return;
|
|
440
440
|
}
|
|
@@ -456,9 +456,9 @@ function handleConfig(args) {
|
|
|
456
456
|
|
|
457
457
|
try {
|
|
458
458
|
fs.writeFileSync(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
459
|
-
console.log(chalk.green(`\n
|
|
459
|
+
console.log(chalk.green(`\n[OK] Configuration updated: ${key} = ${JSON.stringify(parsedValue)}\n`));
|
|
460
460
|
} catch (error) {
|
|
461
|
-
console.error(chalk.red(`\n
|
|
461
|
+
console.error(chalk.red(`\n[ERROR] Failed to save config: ${error.message}\n`));
|
|
462
462
|
process.exit(1);
|
|
463
463
|
}
|
|
464
464
|
}
|
|
@@ -472,23 +472,23 @@ async function handleUpdate(args) {
|
|
|
472
472
|
const isUpdateAll = name === '--all' || name === '-a';
|
|
473
473
|
|
|
474
474
|
if (!name) {
|
|
475
|
-
console.error(chalk.red('\n
|
|
475
|
+
console.error(chalk.red('\n[ERROR] Plugin name is required\n'));
|
|
476
476
|
console.log(chalk.gray('Usage: ctx plugin update <name>\n'));
|
|
477
477
|
console.log(chalk.gray(' ctx plugin update --all\n'));
|
|
478
478
|
process.exit(1);
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
if (isUpdateAll) {
|
|
482
|
-
console.log(chalk.cyan('\n
|
|
482
|
+
console.log(chalk.cyan('\n[SYNC] Updating all plugins...\n'));
|
|
483
483
|
|
|
484
484
|
const result = await updateAllPlugins();
|
|
485
485
|
|
|
486
|
-
console.log(chalk.gray('
|
|
486
|
+
console.log(chalk.gray('='.repeat(80)));
|
|
487
487
|
|
|
488
488
|
for (const pluginResult of result.results) {
|
|
489
489
|
if (pluginResult.success) {
|
|
490
490
|
if (pluginResult.plugin && pluginResult.plugin.updated) {
|
|
491
|
-
console.log(chalk.green(
|
|
491
|
+
console.log(chalk.green(`[v] ${pluginResult.name}: `) +
|
|
492
492
|
chalk.gray(`v${pluginResult.plugin.oldVersion}`) +
|
|
493
493
|
chalk.white(' → ') +
|
|
494
494
|
chalk.green(`v${pluginResult.plugin.newVersion}`));
|
|
@@ -496,11 +496,11 @@ async function handleUpdate(args) {
|
|
|
496
496
|
console.log(chalk.gray(`○ ${pluginResult.name}: up to date`));
|
|
497
497
|
}
|
|
498
498
|
} else {
|
|
499
|
-
console.log(chalk.red(
|
|
499
|
+
console.log(chalk.red(`[x] ${pluginResult.name}: ${pluginResult.error}`));
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
-
console.log(chalk.gray('
|
|
503
|
+
console.log(chalk.gray('='.repeat(80)));
|
|
504
504
|
console.log(chalk.white('\nSummary:'));
|
|
505
505
|
console.log(chalk.green(` Updated: ${result.summary.updated}`));
|
|
506
506
|
console.log(chalk.gray(` Unchanged: ${result.summary.unchanged}`));
|
|
@@ -516,21 +516,21 @@ async function handleUpdate(args) {
|
|
|
516
516
|
// Update single plugin
|
|
517
517
|
const plugin = getPlugin(name);
|
|
518
518
|
if (!plugin) {
|
|
519
|
-
console.error(chalk.red(`\n
|
|
519
|
+
console.error(chalk.red(`\n[ERROR] Plugin "${name}" is not installed\n`));
|
|
520
520
|
process.exit(1);
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
-
console.log(chalk.cyan(`\n
|
|
523
|
+
console.log(chalk.cyan(`\n[SYNC] Updating plugin "${name}"...\n`));
|
|
524
524
|
|
|
525
525
|
const result = await updatePlugin(name);
|
|
526
526
|
|
|
527
527
|
if (result.success) {
|
|
528
|
-
console.log(chalk.green(`\n
|
|
528
|
+
console.log(chalk.green(`\n[OK] ${result.message}\n`));
|
|
529
529
|
if (result.plugin && result.plugin.updated) {
|
|
530
530
|
console.log(chalk.gray(` ${result.plugin.oldVersion} → ${result.plugin.newVersion}\n`));
|
|
531
531
|
}
|
|
532
532
|
} else {
|
|
533
|
-
console.error(chalk.red('\n
|
|
533
|
+
console.error(chalk.red('\n[ERROR] Update failed:\n'));
|
|
534
534
|
console.error(chalk.red(result.error));
|
|
535
535
|
console.log();
|
|
536
536
|
process.exit(1);
|
|
@@ -542,8 +542,8 @@ async function handleUpdate(args) {
|
|
|
542
542
|
* Show plugin command help
|
|
543
543
|
*/
|
|
544
544
|
function showHelp() {
|
|
545
|
-
console.log(chalk.cyan('\n
|
|
546
|
-
console.log(chalk.gray('
|
|
545
|
+
console.log(chalk.cyan('\n[PKG] Plugin Management Commands\n'));
|
|
546
|
+
console.log(chalk.gray('='.repeat(80)));
|
|
547
547
|
|
|
548
548
|
console.log(chalk.white('\nUsage: ') + chalk.cyan('ctx plugin <subcommand> [options]\n'));
|
|
549
549
|
|
|
@@ -577,7 +577,7 @@ function showHelp() {
|
|
|
577
577
|
console.log(chalk.gray(' ctx plugin disable my-plugin'));
|
|
578
578
|
console.log(chalk.gray(' ctx plugin remove my-plugin\n'));
|
|
579
579
|
|
|
580
|
-
console.log(chalk.gray('
|
|
580
|
+
console.log(chalk.gray('='.repeat(80)) + '\n');
|
|
581
581
|
}
|
|
582
582
|
|
|
583
583
|
module.exports = {
|
|
@@ -14,9 +14,9 @@ async function handlePortConfig() {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
console.clear();
|
|
17
|
-
console.log(chalk.bold.cyan('\n
|
|
17
|
+
console.log(chalk.bold.cyan('\n╔=======================================╗'));
|
|
18
18
|
console.log(chalk.bold.cyan('║ 端口配置 ║'));
|
|
19
|
-
console.log(chalk.bold.cyan('
|
|
19
|
+
console.log(chalk.bold.cyan('╚=======================================╝\n'));
|
|
20
20
|
|
|
21
21
|
const config = loadConfig();
|
|
22
22
|
|
|
@@ -116,8 +116,8 @@ async function handlePortConfig() {
|
|
|
116
116
|
ports: config.ports,
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
console.log(chalk.green('\n
|
|
120
|
-
console.log(chalk.yellow('
|
|
119
|
+
console.log(chalk.green('\n[OK] 端口配置已保存\n'));
|
|
120
|
+
console.log(chalk.yellow('[WARN] 提示:'));
|
|
121
121
|
console.log(chalk.gray('• 如果 Web UI 正在运行,请重启以使用新端口'));
|
|
122
122
|
console.log(chalk.gray('• 如果动态切换已开启,请关闭后重新开启\n'));
|
|
123
123
|
|