@shi_zhen/code-helper 0.1.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.
@@ -0,0 +1,3687 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __commonJS = (cb, mod) => function __require() {
12
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
27
+ // If the importer is in node compatibility mode or this is not an ESM
28
+ // file that has been converted to a CommonJS file using a Babel-
29
+ // compatible transform (i.e. "__esModule" has not been set), then set
30
+ // "default" to the CommonJS "module.exports" for node compatibility.
31
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
32
+ mod
33
+ ));
34
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
+
36
+ // package.json
37
+ var require_package = __commonJS({
38
+ "package.json"(exports2, module2) {
39
+ module2.exports = {
40
+ name: "@shi_zhen/code-helper",
41
+ version: "0.1.0",
42
+ description: "Code Helper - A unified tool to manage your Claude Code",
43
+ repository: {
44
+ type: "git",
45
+ url: "https://github.com/shirenchuang/code-helper.git"
46
+ },
47
+ author: "shirenchuang",
48
+ module: "dist/index.js",
49
+ typings: "dist/index.d.ts",
50
+ bin: {
51
+ ch: "./bin/code-helper.js",
52
+ "code-helper": "./bin/code-helper.js"
53
+ },
54
+ files: [
55
+ "bin",
56
+ "dist",
57
+ "LEGAL.md"
58
+ ],
59
+ scripts: {
60
+ build: "tsup",
61
+ "build:watch": "tsup --watch",
62
+ dev: "tsup --watch",
63
+ lint: "eslint src --ext .ts",
64
+ test: "jest",
65
+ prepublishOnly: "npm run build"
66
+ },
67
+ dependencies: {
68
+ "@babel/runtime": "^7.18.0",
69
+ boxen: "^5.1.2",
70
+ chalk: "^4.1.2",
71
+ execa: "^5.1.1",
72
+ figlet: "^1.7.0",
73
+ inquirer: "^8.2.6",
74
+ ora: "^5.4.1"
75
+ },
76
+ devDependencies: {
77
+ "@types/figlet": "^1.5.8",
78
+ "@types/inquirer": "^8.2.10",
79
+ "@types/node": "^20.0.0",
80
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
81
+ "@typescript-eslint/parser": "^6.0.0",
82
+ eslint: "^8.0.0",
83
+ tsup: "^8.0.0",
84
+ typescript: "^5.0.0"
85
+ },
86
+ engines: {
87
+ node: ">=20"
88
+ },
89
+ keywords: [
90
+ "claude",
91
+ "claude-code",
92
+ "mcp",
93
+ "ai",
94
+ "cli",
95
+ "tools"
96
+ ],
97
+ license: "MIT"
98
+ };
99
+ }
100
+ });
101
+
102
+ // src/cli/utils/exec.ts
103
+ async function executeCommand(command, envVars) {
104
+ try {
105
+ let finalCommand = command;
106
+ if (command.includes("|")) {
107
+ finalCommand = `set -o pipefail && ${command}`;
108
+ }
109
+ const { stdout } = await import_execa.default.command(finalCommand, {
110
+ shell: true,
111
+ stdio: "inherit",
112
+ env: envVars ? { ...process.env, ...envVars } : void 0
113
+ });
114
+ return stdout || "";
115
+ } catch (error) {
116
+ const execError = error;
117
+ throw new Error(execError.stderr || execError.message || "\u547D\u4EE4\u6267\u884C\u5931\u8D25");
118
+ }
119
+ }
120
+ async function executeCommandQuiet(command) {
121
+ try {
122
+ const { stdout } = await import_execa.default.command(command, {
123
+ shell: true
124
+ });
125
+ return stdout || "";
126
+ } catch (error) {
127
+ const execError = error;
128
+ throw new Error(execError.stderr || execError.message || "\u547D\u4EE4\u6267\u884C\u5931\u8D25");
129
+ }
130
+ }
131
+ async function commandExists(command) {
132
+ try {
133
+ await import_execa.default.command(`which ${command}`, { shell: true });
134
+ return true;
135
+ } catch {
136
+ return false;
137
+ }
138
+ }
139
+ var import_execa;
140
+ var init_exec = __esm({
141
+ "src/cli/utils/exec.ts"() {
142
+ "use strict";
143
+ import_execa = __toESM(require("execa"));
144
+ }
145
+ });
146
+
147
+ // src/cli/utils/webui.ts
148
+ var webui_exports = {};
149
+ __export(webui_exports, {
150
+ launchWebUI: () => launchWebUI
151
+ });
152
+ async function launchWebUI() {
153
+ console.log(import_chalk2.default.cyan("\n\u{1F680} ClaudeCode UI \u542F\u52A8\u6307\u5357\n"));
154
+ console.log(import_chalk2.default.yellow("\u8BF7\u5728\u7EC8\u7AEF\u4E2D\u624B\u52A8\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u542F\u52A8 Web UI\uFF1A\n"));
155
+ console.log(import_chalk2.default.green.bold(" npx @siteboon/claude-code-ui\n"));
156
+ console.log(
157
+ import_chalk2.default.dim("\u8BF4\u660E: \u4F7F\u7528\u5F00\u6E90\u7248\u672C\u7684 Claude Code UI")
158
+ );
159
+ console.log(import_chalk2.default.dim(" \u8FD9\u6837\u53EF\u4EE5\u786E\u4FDD\u4F7F\u7528\u6B63\u786E\u7684 Node.js \u7248\u672C\u548C\u4F9D\u8D56"));
160
+ console.log();
161
+ await import_inquirer8.default.prompt([
162
+ {
163
+ type: "input",
164
+ name: "confirm",
165
+ message: "\u6309 Enter \u952E\u8FD4\u56DE\u4E3B\u83DC\u5355"
166
+ }
167
+ ]);
168
+ }
169
+ var import_chalk2, import_inquirer8;
170
+ var init_webui = __esm({
171
+ "src/cli/utils/webui.ts"() {
172
+ "use strict";
173
+ import_chalk2 = __toESM(require("chalk"));
174
+ import_inquirer8 = __toESM(require("inquirer"));
175
+ }
176
+ });
177
+
178
+ // src/cli/utils/version.ts
179
+ var version_exports = {};
180
+ __export(version_exports, {
181
+ checkAndUpdate: () => checkAndUpdate,
182
+ testUpdate: () => testUpdate
183
+ });
184
+ function getLocalVersion() {
185
+ const pkg3 = require_package();
186
+ return pkg3.version;
187
+ }
188
+ async function getRemoteVersion() {
189
+ try {
190
+ const result = await executeCommandQuiet(
191
+ "npm view code-helper version"
192
+ );
193
+ return result.trim();
194
+ } catch (error) {
195
+ console.error(import_chalk3.default.yellow("\u26A0\uFE0F \u65E0\u6CD5\u68C0\u67E5\u7248\u672C\u66F4\u65B0"));
196
+ return null;
197
+ }
198
+ }
199
+ function readCache() {
200
+ try {
201
+ if (!fs9.existsSync(CACHE_FILE)) {
202
+ return null;
203
+ }
204
+ const content = fs9.readFileSync(CACHE_FILE, "utf-8");
205
+ return JSON.parse(content);
206
+ } catch {
207
+ return null;
208
+ }
209
+ }
210
+ function writeCache(data) {
211
+ try {
212
+ if (!fs9.existsSync(CACHE_DIR)) {
213
+ fs9.mkdirSync(CACHE_DIR, { recursive: true });
214
+ }
215
+ fs9.writeFileSync(CACHE_FILE, JSON.stringify(data, null, 2));
216
+ } catch (error) {
217
+ }
218
+ }
219
+ function compareVersions(v1, v2) {
220
+ const parts1 = v1.split(".").map(Number);
221
+ const parts2 = v2.split(".").map(Number);
222
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
223
+ const part1 = parts1[i] || 0;
224
+ const part2 = parts2[i] || 0;
225
+ if (part1 > part2) return 1;
226
+ if (part1 < part2) return -1;
227
+ }
228
+ return 0;
229
+ }
230
+ async function updateToLatest() {
231
+ const spinner = (0, import_ora7.default)("\u6B63\u5728\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C...").start();
232
+ try {
233
+ await executeCommand("npm install -g code-helper@latest");
234
+ spinner.succeed(import_chalk3.default.green("\u2705 \u66F4\u65B0\u6210\u529F\uFF01"));
235
+ return true;
236
+ } catch (error) {
237
+ spinner.fail(import_chalk3.default.red("\u274C \u66F4\u65B0\u5931\u8D25"));
238
+ console.error(import_chalk3.default.red(`\u9519\u8BEF: ${error}`));
239
+ return false;
240
+ }
241
+ }
242
+ async function checkAndUpdate(forceCheck = false) {
243
+ const localVersion = getLocalVersion();
244
+ const cache = readCache();
245
+ const now = Date.now();
246
+ if (!forceCheck && cache && now - cache.lastCheck < CHECK_INTERVAL) {
247
+ if (compareVersions(cache.latestVersion, localVersion) > 0) {
248
+ console.log(
249
+ import_chalk3.default.yellow(
250
+ `
251
+ \u{1F4A1} \u63D0\u793A: \u6709\u65B0\u7248\u672C ${cache.latestVersion} \u53EF\u7528 (\u5F53\u524D\u7248\u672C: ${localVersion})`
252
+ )
253
+ );
254
+ console.log(import_chalk3.default.gray(" \u4E0B\u6B21\u542F\u52A8\u65F6\u5C06\u81EA\u52A8\u66F4\u65B0...\n"));
255
+ }
256
+ return;
257
+ }
258
+ const spinner = (0, import_ora7.default)("\u6B63\u5728\u68C0\u67E5\u7248\u672C\u66F4\u65B0...").start();
259
+ const remoteVersion = await getRemoteVersion();
260
+ if (!remoteVersion) {
261
+ spinner.stop();
262
+ return;
263
+ }
264
+ writeCache({
265
+ lastCheck: now,
266
+ latestVersion: remoteVersion
267
+ });
268
+ if (compareVersions(remoteVersion, localVersion) > 0) {
269
+ spinner.succeed(
270
+ import_chalk3.default.cyan(`\u53D1\u73B0\u65B0\u7248\u672C: ${remoteVersion} (\u5F53\u524D\u7248\u672C: ${localVersion})`)
271
+ );
272
+ console.log(import_chalk3.default.gray("\u6B63\u5728\u81EA\u52A8\u66F4\u65B0...\n"));
273
+ const success = await updateToLatest();
274
+ if (success) {
275
+ console.log(
276
+ import_chalk3.default.green("\n\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01\u8BF7\u91CD\u65B0\u8FD0\u884C\u547D\u4EE4\u4EE5\u4F7F\u7528\u6700\u65B0\u7248\u672C\u3002\n")
277
+ );
278
+ process.exit(0);
279
+ } else {
280
+ console.log(
281
+ import_chalk3.default.yellow(
282
+ "\n\u26A0\uFE0F \u81EA\u52A8\u66F4\u65B0\u5931\u8D25\uFF0C\u4F60\u53EF\u4EE5\u624B\u52A8\u8FD0\u884C: npm install -g code-helper@latest\n"
283
+ )
284
+ );
285
+ }
286
+ } else {
287
+ spinner.succeed(import_chalk3.default.green(`\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C v${localVersion}`));
288
+ }
289
+ }
290
+ async function testUpdate() {
291
+ const localVersion = getLocalVersion();
292
+ console.log(import_chalk3.default.cyan("\n\u{1F9EA} \u6D4B\u8BD5\u6A21\u5F0F: \u6A21\u62DF\u7248\u672C\u66F4\u65B0\u6D41\u7A0B\n"));
293
+ console.log(import_chalk3.default.gray(`\u5F53\u524D\u7248\u672C: ${localVersion}`));
294
+ console.log(import_chalk3.default.gray("\u6B63\u5728\u68C0\u67E5\u8FDC\u7A0B\u7248\u672C...\n"));
295
+ const remoteVersion = await getRemoteVersion();
296
+ if (!remoteVersion) {
297
+ console.log(import_chalk3.default.red("\u274C \u65E0\u6CD5\u83B7\u53D6\u8FDC\u7A0B\u7248\u672C"));
298
+ return;
299
+ }
300
+ console.log(import_chalk3.default.gray(`\u8FDC\u7A0B\u7248\u672C: ${remoteVersion}
301
+ `));
302
+ if (compareVersions(remoteVersion, localVersion) > 0) {
303
+ console.log(import_chalk3.default.green("\u2705 \u8FDC\u7A0B\u7248\u672C\u66F4\u65B0\uFF0C\u4F1A\u89E6\u53D1\u81EA\u52A8\u66F4\u65B0"));
304
+ } else if (compareVersions(remoteVersion, localVersion) === 0) {
305
+ console.log(import_chalk3.default.yellow("\u26A0\uFE0F \u8FDC\u7A0B\u7248\u672C\u4E0E\u672C\u5730\u7248\u672C\u76F8\u540C"));
306
+ console.log(import_chalk3.default.gray(" \u771F\u5B9E\u4F7F\u7528\u65F6\u4E0D\u4F1A\u89E6\u53D1\u66F4\u65B0"));
307
+ } else {
308
+ console.log(import_chalk3.default.yellow("\u26A0\uFE0F \u672C\u5730\u7248\u672C\u9AD8\u4E8E\u8FDC\u7A0B\u7248\u672C"));
309
+ console.log(import_chalk3.default.gray(" \u8FD9\u901A\u5E38\u53D1\u751F\u5728\u672C\u5730\u5F00\u53D1\u65F6"));
310
+ }
311
+ console.log(
312
+ import_chalk3.default.cyan("\n\u{1F4A1} \u63D0\u793A: \u53D1\u5E03\u65B0\u7248\u672C\u540E\uFF0C\u7528\u6237\u9996\u6B21\u542F\u52A8\u65F6\u4F1A\u81EA\u52A8\u66F4\u65B0\n")
313
+ );
314
+ }
315
+ var import_chalk3, import_ora7, os10, path10, fs9, CACHE_DIR, CACHE_FILE, CHECK_INTERVAL;
316
+ var init_version = __esm({
317
+ "src/cli/utils/version.ts"() {
318
+ "use strict";
319
+ import_chalk3 = __toESM(require("chalk"));
320
+ import_ora7 = __toESM(require("ora"));
321
+ init_exec();
322
+ os10 = require("os");
323
+ path10 = require("path");
324
+ fs9 = require("fs");
325
+ CACHE_DIR = path10.join(os10.homedir(), ".code-helper");
326
+ CACHE_FILE = path10.join(CACHE_DIR, "version-check.json");
327
+ CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
328
+ }
329
+ });
330
+
331
+ // src/cli/menus/main.ts
332
+ var import_inquirer9 = __toESM(require("inquirer"));
333
+
334
+ // src/cli/ui.ts
335
+ var import_boxen = __toESM(require("boxen"));
336
+ var import_chalk = __toESM(require("chalk"));
337
+ var import_figlet = __toESM(require("figlet"));
338
+ var pkg = require_package();
339
+ var VERSION = pkg.version;
340
+ var theme = {
341
+ primary: import_chalk.default.hex("#FF8C00"),
342
+ // 深橙色
343
+ secondary: import_chalk.default.hex("#FFA500"),
344
+ // 橙色
345
+ success: import_chalk.default.green,
346
+ error: import_chalk.default.red,
347
+ warning: import_chalk.default.yellow,
348
+ info: import_chalk.default.cyan,
349
+ dim: import_chalk.default.gray
350
+ };
351
+ function generateTitle() {
352
+ try {
353
+ const title = import_figlet.default.textSync("CODE HELPER", {
354
+ font: "Standard",
355
+ horizontalLayout: "default"
356
+ });
357
+ return theme.primary(title);
358
+ } catch {
359
+ return theme.primary("CODE HELPER");
360
+ }
361
+ }
362
+ function showHeader() {
363
+ console.clear();
364
+ const title = generateTitle();
365
+ const subtitle = `Code Helper v${VERSION}
366
+ A unified tool to manage your Claude Code`;
367
+ const header = (0, import_boxen.default)(
368
+ `${title}
369
+
370
+ ${theme.secondary(subtitle)}`,
371
+ {
372
+ padding: 1,
373
+ margin: 1,
374
+ borderStyle: "round",
375
+ borderColor: "yellow",
376
+ textAlignment: "center"
377
+ }
378
+ );
379
+ console.log(header);
380
+ }
381
+ function showSuccess(message) {
382
+ console.log(theme.success(`\u2713 ${message}`));
383
+ }
384
+ function showError(message) {
385
+ console.log(theme.error(`\u2717 ${message}`));
386
+ }
387
+ function showWarning(message) {
388
+ console.log(theme.warning(`\u26A0 ${message}`));
389
+ }
390
+ function showInfo(message) {
391
+ console.log(theme.info(`\u2139 ${message}`));
392
+ }
393
+ function createBoxTitle(title) {
394
+ return (0, import_boxen.default)(theme.primary(title), {
395
+ padding: { left: 2, right: 2, top: 0, bottom: 0 },
396
+ borderStyle: "round",
397
+ borderColor: "yellow",
398
+ textAlignment: "center"
399
+ });
400
+ }
401
+
402
+ // src/cli/utils/claude.ts
403
+ var import_child_process = require("child_process");
404
+ var import_fs = __toESM(require("fs"));
405
+ var import_os = __toESM(require("os"));
406
+ var import_path = __toESM(require("path"));
407
+ var cachedInfo = null;
408
+ var lastCheckTime = 0;
409
+ var CACHE_DURATION = 5e3;
410
+ function execSyncWithTimeout(command, timeoutMs = 2e3) {
411
+ try {
412
+ return (0, import_child_process.execSync)(command, {
413
+ encoding: "utf-8",
414
+ stdio: ["pipe", "pipe", "ignore"],
415
+ timeout: timeoutMs
416
+ }).trim();
417
+ } catch {
418
+ return "";
419
+ }
420
+ }
421
+ function detectClaudeInstallationSync() {
422
+ try {
423
+ const whichResult = execSyncWithTimeout("which claude", 1e3);
424
+ if (!whichResult) {
425
+ return { installed: false };
426
+ }
427
+ let installMethod = "unknown";
428
+ const officialPaths = [
429
+ import_path.default.join(import_os.default.homedir(), ".local/bin/claude"),
430
+ import_path.default.join(import_os.default.homedir(), ".claude/bin/claude")
431
+ ];
432
+ for (const officialPath of officialPaths) {
433
+ if (whichResult === officialPath || import_fs.default.existsSync(officialPath)) {
434
+ installMethod = "official";
435
+ break;
436
+ }
437
+ }
438
+ if (installMethod === "unknown" && whichResult.includes("node_modules")) {
439
+ installMethod = "npm";
440
+ }
441
+ if (installMethod === "unknown" && process.platform === "darwin" && whichResult.includes("homebrew")) {
442
+ installMethod = "homebrew";
443
+ }
444
+ let version;
445
+ try {
446
+ const versionOutput = execSyncWithTimeout("claude --version", 1500);
447
+ if (versionOutput) {
448
+ const versionMatch = versionOutput.match(/(\d+\.\d+\.\d+)/);
449
+ version = versionMatch ? versionMatch[1] : versionOutput;
450
+ }
451
+ } catch {
452
+ version = void 0;
453
+ }
454
+ return {
455
+ installed: true,
456
+ version,
457
+ installMethod,
458
+ binaryPath: whichResult
459
+ };
460
+ } catch {
461
+ return { installed: false };
462
+ }
463
+ }
464
+ function formatInstallMethod(method) {
465
+ switch (method) {
466
+ case "npm":
467
+ return "npm \u5168\u5C40\u5B89\u88C5";
468
+ case "official":
469
+ return "\u5B98\u65B9\u811A\u672C\u5B89\u88C5";
470
+ case "homebrew":
471
+ return "Homebrew \u5B89\u88C5";
472
+ case "unknown":
473
+ default:
474
+ return "\u672A\u77E5\u65B9\u5F0F";
475
+ }
476
+ }
477
+ function detectClaudeInstallation() {
478
+ const now = Date.now();
479
+ if (cachedInfo && now - lastCheckTime < CACHE_DURATION) {
480
+ return cachedInfo;
481
+ }
482
+ cachedInfo = detectClaudeInstallationSync();
483
+ lastCheckTime = now;
484
+ return cachedInfo;
485
+ }
486
+ function getCachedClaudeInfo() {
487
+ return cachedInfo;
488
+ }
489
+ function clearClaudeCache() {
490
+ cachedInfo = null;
491
+ lastCheckTime = 0;
492
+ }
493
+ function formatClaudeStatus(info) {
494
+ if (!info.installed) {
495
+ return "\u672A\u5B89\u88C5";
496
+ }
497
+ const parts = ["\u5DF2\u5B89\u88C5"];
498
+ if (info.version) {
499
+ parts.push(`v${info.version}`);
500
+ }
501
+ if (info.installMethod) {
502
+ parts.push(`(${formatInstallMethod(info.installMethod)})`);
503
+ }
504
+ return parts.join(" ");
505
+ }
506
+
507
+ // src/cli/utils/config.ts
508
+ var import_fs2 = __toESM(require("fs"));
509
+ var import_os2 = __toESM(require("os"));
510
+ var import_path2 = __toESM(require("path"));
511
+ var CLAUDE_DIR = import_path2.default.join(import_os2.default.homedir(), ".claude");
512
+ var SETTINGS_FILE = import_path2.default.join(CLAUDE_DIR, "settings.json");
513
+ var CODE_HELPER_CONFIG_FILE = import_path2.default.join(CLAUDE_DIR, "code-helper.json");
514
+ var CODE_HELPER_DIR = import_path2.default.join(import_os2.default.homedir(), ".code-helper");
515
+ var PROFILES_FILE = import_path2.default.join(CODE_HELPER_DIR, "profiles.json");
516
+ var GLM_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
517
+ var KIMI_BASE_URL = "https://api.kimi.com/coding";
518
+ var DEFAULT_BASE_URL = "https://api.anthropic.com";
519
+ function ensureClaudeDir() {
520
+ if (!import_fs2.default.existsSync(CLAUDE_DIR)) {
521
+ import_fs2.default.mkdirSync(CLAUDE_DIR, { recursive: true });
522
+ }
523
+ }
524
+ function readClaudeSettings() {
525
+ try {
526
+ if (import_fs2.default.existsSync(SETTINGS_FILE)) {
527
+ const content = import_fs2.default.readFileSync(SETTINGS_FILE, "utf-8");
528
+ return JSON.parse(content);
529
+ }
530
+ } catch {
531
+ }
532
+ return {};
533
+ }
534
+ function writeClaudeSettings(settings) {
535
+ ensureClaudeDir();
536
+ import_fs2.default.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
537
+ }
538
+ function readCodeHelperConfig() {
539
+ try {
540
+ if (import_fs2.default.existsSync(CODE_HELPER_CONFIG_FILE)) {
541
+ const content = import_fs2.default.readFileSync(CODE_HELPER_CONFIG_FILE, "utf-8");
542
+ return JSON.parse(content);
543
+ }
544
+ } catch {
545
+ }
546
+ return {
547
+ version: "0.1.0",
548
+ installedMcps: [],
549
+ installedPlugins: [],
550
+ preferences: {
551
+ defaultBaseUrl: DEFAULT_BASE_URL
552
+ }
553
+ };
554
+ }
555
+ function writeCodeHelperConfig(config) {
556
+ ensureClaudeDir();
557
+ import_fs2.default.writeFileSync(CODE_HELPER_CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
558
+ }
559
+ function getApiKeyStatus() {
560
+ const settings = readClaudeSettings();
561
+ const apiKey = settings.env?.ANTHROPIC_AUTH_TOKEN;
562
+ if (apiKey && apiKey.length > 0) {
563
+ const masked = apiKey.substring(0, 4) + "****";
564
+ return theme.success(`\u5DF2\u8BBE\u7F6E (${masked})`);
565
+ }
566
+ return theme.dim("\u672A\u8BBE\u7F6E");
567
+ }
568
+ function getBaseUrlStatus() {
569
+ const settings = readClaudeSettings();
570
+ const baseUrl = settings.env?.ANTHROPIC_BASE_URL;
571
+ if (baseUrl && baseUrl.length > 0) {
572
+ try {
573
+ const url = new URL(baseUrl);
574
+ return theme.success(url.host);
575
+ } catch {
576
+ return theme.success(baseUrl);
577
+ }
578
+ }
579
+ return theme.dim("\u672A\u8BBE\u7F6E");
580
+ }
581
+ async function saveApiConfig(baseUrl, apiKey, options) {
582
+ const settings = readClaudeSettings();
583
+ if (!settings.env) {
584
+ settings.env = {};
585
+ }
586
+ delete settings.env.ANTHROPIC_MODEL;
587
+ delete settings.env.ANTHROPIC_SMALL_FAST_MODEL;
588
+ delete settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
589
+ delete settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL;
590
+ delete settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL;
591
+ delete settings.env.API_TIMEOUT_MS;
592
+ delete settings.skipWebFetchPreflight;
593
+ settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
594
+ settings.env.ANTHROPIC_BASE_URL = baseUrl;
595
+ settings.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1";
596
+ if (options?.model) {
597
+ settings.env.ANTHROPIC_MODEL = options.model;
598
+ }
599
+ if (options?.smallFastModel) {
600
+ settings.env.ANTHROPIC_SMALL_FAST_MODEL = options.smallFastModel;
601
+ }
602
+ if (options?.haikuModel) {
603
+ settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = options.haikuModel;
604
+ }
605
+ if (options?.opusModel) {
606
+ settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = options.opusModel;
607
+ }
608
+ if (options?.sonnetModel) {
609
+ settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = options.sonnetModel;
610
+ }
611
+ if (options?.skipWebFetchPreflight) {
612
+ settings.skipWebFetchPreflight = true;
613
+ }
614
+ if (options?.timeout) {
615
+ settings.env.API_TIMEOUT_MS = options.timeout;
616
+ }
617
+ writeClaudeSettings(settings);
618
+ const helperConfig = readCodeHelperConfig();
619
+ helperConfig.preferences.defaultBaseUrl = baseUrl;
620
+ writeCodeHelperConfig(helperConfig);
621
+ }
622
+ function ensureCodeHelperDir() {
623
+ if (!import_fs2.default.existsSync(CODE_HELPER_DIR)) {
624
+ import_fs2.default.mkdirSync(CODE_HELPER_DIR, { recursive: true });
625
+ }
626
+ }
627
+ function readProfiles() {
628
+ try {
629
+ if (import_fs2.default.existsSync(PROFILES_FILE)) {
630
+ const content = import_fs2.default.readFileSync(PROFILES_FILE, "utf-8");
631
+ return JSON.parse(content);
632
+ }
633
+ } catch {
634
+ }
635
+ return {
636
+ version: "1.0.0",
637
+ currentProfileId: null,
638
+ profiles: []
639
+ };
640
+ }
641
+ function writeProfiles(config) {
642
+ ensureCodeHelperDir();
643
+ import_fs2.default.writeFileSync(PROFILES_FILE, JSON.stringify(config, null, 2), "utf-8");
644
+ }
645
+ function getAllProfiles() {
646
+ return readProfiles().profiles;
647
+ }
648
+ function getCurrentProfile() {
649
+ const config = readProfiles();
650
+ if (!config.currentProfileId) return null;
651
+ return config.profiles.find((p) => p.id === config.currentProfileId) || null;
652
+ }
653
+ function addProfile(profile) {
654
+ const config = readProfiles();
655
+ const now = (/* @__PURE__ */ new Date()).toISOString();
656
+ const newProfile = {
657
+ ...profile,
658
+ id: `profile_${Date.now()}`,
659
+ createdAt: now,
660
+ updatedAt: now
661
+ };
662
+ config.profiles.push(newProfile);
663
+ writeProfiles(config);
664
+ return newProfile;
665
+ }
666
+ function deleteProfile(id) {
667
+ const config = readProfiles();
668
+ const index = config.profiles.findIndex((p) => p.id === id);
669
+ if (index === -1) return false;
670
+ config.profiles.splice(index, 1);
671
+ if (config.currentProfileId === id) {
672
+ config.currentProfileId = null;
673
+ }
674
+ writeProfiles(config);
675
+ return true;
676
+ }
677
+ function switchProfile(id) {
678
+ const config = readProfiles();
679
+ const profile = config.profiles.find((p) => p.id === id);
680
+ if (!profile) return false;
681
+ const settings = readClaudeSettings();
682
+ if (!settings.env) {
683
+ settings.env = {};
684
+ }
685
+ delete settings.env.ANTHROPIC_MODEL;
686
+ delete settings.env.ANTHROPIC_SMALL_FAST_MODEL;
687
+ delete settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
688
+ delete settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL;
689
+ delete settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL;
690
+ delete settings.env.API_TIMEOUT_MS;
691
+ delete settings.skipWebFetchPreflight;
692
+ settings.env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
693
+ settings.env.ANTHROPIC_BASE_URL = profile.baseUrl;
694
+ settings.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1";
695
+ if (profile.model) {
696
+ settings.env.ANTHROPIC_MODEL = profile.model;
697
+ }
698
+ if (profile.timeout) {
699
+ settings.env.API_TIMEOUT_MS = profile.timeout;
700
+ }
701
+ writeClaudeSettings(settings);
702
+ config.currentProfileId = id;
703
+ writeProfiles(config);
704
+ return true;
705
+ }
706
+ function getCurrentProfileStatus() {
707
+ const current = getCurrentProfile();
708
+ if (current) {
709
+ return theme.success(`${current.name}`);
710
+ }
711
+ return theme.dim("\u672A\u9009\u62E9\u914D\u7F6E");
712
+ }
713
+
714
+ // src/cli/menus/auth.ts
715
+ var import_inquirer = __toESM(require("inquirer"));
716
+ var import_ora = __toESM(require("ora"));
717
+
718
+ // src/cli/utils/api.ts
719
+ var import_http = __toESM(require("http"));
720
+ var import_https = __toESM(require("https"));
721
+ async function verifyApiKey(baseUrl, apiKey) {
722
+ return new Promise((resolve) => {
723
+ try {
724
+ const url = new URL(baseUrl);
725
+ const isHttps = url.protocol === "https:";
726
+ const client = isHttps ? import_https.default : import_http.default;
727
+ const testPayload = JSON.stringify({
728
+ model: "claude-3-5-sonnet-20241022",
729
+ max_tokens: 1,
730
+ messages: [{ role: "user", content: "test" }]
731
+ });
732
+ const requestOptions = {
733
+ hostname: url.hostname,
734
+ port: url.port || (isHttps ? 443 : 80),
735
+ path: `${url.pathname}/v1/messages`.replace(/\/+/g, "/"),
736
+ method: "POST",
737
+ headers: {
738
+ "x-api-key": apiKey,
739
+ "anthropic-version": "2023-06-01",
740
+ "Content-Type": "application/json",
741
+ "Content-Length": Buffer.byteLength(testPayload)
742
+ },
743
+ timeout: 15e3
744
+ // 15秒超时
745
+ };
746
+ const req = client.request(requestOptions, (res) => {
747
+ let responseData = "";
748
+ res.on("data", (chunk) => {
749
+ responseData += chunk;
750
+ });
751
+ res.on("end", () => {
752
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
753
+ resolve({ valid: true });
754
+ } else if (res.statusCode === 401 || res.statusCode === 403) {
755
+ resolve({ valid: false, error: "API Key \u65E0\u6548\u6216\u672A\u6388\u6743" });
756
+ } else if (res.statusCode === 400) {
757
+ try {
758
+ const errorData = JSON.parse(responseData);
759
+ if (errorData.error?.message) {
760
+ if (errorData.error.message.includes("model") || errorData.error.message.includes("\u4E0D\u652F\u6301")) {
761
+ resolve({ valid: true });
762
+ return;
763
+ }
764
+ }
765
+ } catch {
766
+ }
767
+ resolve({ valid: true });
768
+ } else {
769
+ resolve({
770
+ valid: false,
771
+ error: `\u670D\u52A1\u5668\u8FD4\u56DE\u9519\u8BEF (${res.statusCode})`
772
+ });
773
+ }
774
+ });
775
+ });
776
+ req.on("error", (error) => {
777
+ if (error.message.includes("ENOTFOUND")) {
778
+ resolve({
779
+ valid: false,
780
+ error: "Base URL \u65E0\u6CD5\u8BBF\u95EE\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216 URL \u662F\u5426\u6B63\u786E"
781
+ });
782
+ } else if (error.message.includes("ETIMEDOUT") || error.message.includes("ECONNREFUSED")) {
783
+ resolve({ valid: false, error: "\u8FDE\u63A5\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u4EE3\u7406\u8BBE\u7F6E" });
784
+ } else {
785
+ resolve({ valid: false, error: `\u7F51\u7EDC\u9519\u8BEF: ${error.message}` });
786
+ }
787
+ });
788
+ req.on("timeout", () => {
789
+ req.destroy();
790
+ resolve({ valid: false, error: "\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5" });
791
+ });
792
+ req.write(testPayload);
793
+ req.end();
794
+ } catch (error) {
795
+ resolve({
796
+ valid: false,
797
+ error: `\u9A8C\u8BC1\u5931\u8D25: ${error.message}`
798
+ });
799
+ }
800
+ });
801
+ }
802
+
803
+ // src/cli/menus/auth.ts
804
+ async function showAuthMenu() {
805
+ while (true) {
806
+ showHeader();
807
+ console.log(createBoxTitle("\u6388\u6743\u767B\u5F55"));
808
+ console.log();
809
+ const currentProfile = getCurrentProfile();
810
+ if (currentProfile) {
811
+ console.log(
812
+ `${theme.primary("\u5F53\u524D\u914D\u7F6E\uFF1A")} ${theme.success(currentProfile.name)}`
813
+ );
814
+ console.log(`${theme.dim(" Base URL:")} ${currentProfile.baseUrl}`);
815
+ console.log(
816
+ `${theme.dim(" API Key:")} ${maskApiKey(currentProfile.apiKey)}`
817
+ );
818
+ console.log();
819
+ }
820
+ const savedProfiles = getAllProfiles();
821
+ const choices = [
822
+ {
823
+ name: `Claude API ${theme.dim("(\u63A8\u8350 - \u5B98\u65B9 API)")}`,
824
+ value: { type: "claude" }
825
+ },
826
+ {
827
+ name: `\u667A\u8C31 GLM AI ${theme.dim("(\u5F00\u653E\u5E73\u53F0)")}`,
828
+ value: { type: "glm" }
829
+ },
830
+ {
831
+ name: `Kimi AI ${theme.dim("(\u6708\u4E4B\u6697\u9762)")}`,
832
+ value: { type: "kimi" }
833
+ },
834
+ {
835
+ name: `\u624B\u52A8\u8F93\u5165\u5BC6\u94A5 ${theme.dim("(\u81EA\u5B9A\u4E49 Base URL)")}`,
836
+ value: { type: "manual" }
837
+ }
838
+ ];
839
+ if (savedProfiles.length > 0) {
840
+ choices.push(new import_inquirer.default.Separator());
841
+ choices.push(new import_inquirer.default.Separator(theme.dim("\u2500\u2500 \u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E \u2500\u2500")));
842
+ for (const profile of savedProfiles) {
843
+ const isCurrent = currentProfile?.id === profile.id;
844
+ if (isCurrent) {
845
+ choices.push({
846
+ name: `${theme.success("\u2713")} ${theme.info("\u6062\u590D")} ${profile.name} ${theme.dim("(\u5F53\u524D)")}`,
847
+ value: { type: "restore", profile }
848
+ });
849
+ } else {
850
+ choices.push({
851
+ name: ` ${theme.info("\u6062\u590D")} ${profile.name}`,
852
+ value: { type: "restore", profile }
853
+ });
854
+ }
855
+ }
856
+ choices.push({
857
+ name: ` ${theme.error("\u2715")} \u7BA1\u7406\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E`,
858
+ value: { type: "manage" }
859
+ });
860
+ }
861
+ choices.push(
862
+ new import_inquirer.default.Separator(),
863
+ {
864
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
865
+ value: { type: "back" }
866
+ },
867
+ {
868
+ name: `${theme.dim("X")} \u9000\u51FA`,
869
+ value: { type: "exit" }
870
+ }
871
+ );
872
+ const { choice } = await import_inquirer.default.prompt([
873
+ {
874
+ type: "list",
875
+ name: "choice",
876
+ message: "\u8BF7\u9009\u62E9\u6388\u6743\u65B9\u5F0F\uFF1A",
877
+ pageSize: 15,
878
+ choices
879
+ }
880
+ ]);
881
+ switch (choice.type) {
882
+ case "claude":
883
+ await handleClaudeAuth();
884
+ break;
885
+ case "glm":
886
+ await handleGlmAuth();
887
+ break;
888
+ case "kimi":
889
+ await handleKimiAuth();
890
+ break;
891
+ case "manual":
892
+ await handleManualAuth();
893
+ break;
894
+ case "restore":
895
+ await handleRestoreProfile(choice.profile);
896
+ break;
897
+ case "manage":
898
+ await handleManageProfiles();
899
+ break;
900
+ case "back":
901
+ return;
902
+ case "exit":
903
+ process.exit(0);
904
+ }
905
+ }
906
+ }
907
+ async function handleClaudeAuth() {
908
+ console.log();
909
+ console.log(theme.primary("Claude API \u6388\u6743"));
910
+ console.log();
911
+ console.log(theme.dim("Base URL: ") + DEFAULT_BASE_URL);
912
+ console.log();
913
+ showInfo("\u83B7\u53D6 API Key \u65B9\u5F0F\uFF1A");
914
+ console.log(
915
+ theme.dim(" 1. \u8BBF\u95EE https://console.anthropic.com/settings/keys")
916
+ );
917
+ console.log(theme.dim(" 2. \u521B\u5EFA\u6216\u590D\u5236 API Key"));
918
+ console.log(theme.dim(" 3. \u7C98\u8D34\u5230\u4E0B\u65B9"));
919
+ console.log();
920
+ console.log(theme.dim(" (\u76F4\u63A5\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE)"));
921
+ console.log();
922
+ const { apiKey } = await import_inquirer.default.prompt([
923
+ {
924
+ type: "password",
925
+ name: "apiKey",
926
+ message: "\u8BF7\u8F93\u5165 Claude API Key:",
927
+ mask: "*"
928
+ }
929
+ ]);
930
+ if (!apiKey || apiKey.trim().length === 0) {
931
+ return;
932
+ }
933
+ console.log();
934
+ const spinner = (0, import_ora.default)("\u6B63\u5728\u9A8C\u8BC1 API Key...").start();
935
+ const verification = await verifyApiKey(DEFAULT_BASE_URL, apiKey.trim());
936
+ if (!verification.valid) {
937
+ spinner.fail("API Key \u9A8C\u8BC1\u5931\u8D25");
938
+ console.log();
939
+ showError(verification.error || "\u672A\u77E5\u9519\u8BEF");
940
+ await waitForEnter();
941
+ return;
942
+ }
943
+ spinner.succeed("API Key \u9A8C\u8BC1\u901A\u8FC7");
944
+ try {
945
+ await saveApiConfig(DEFAULT_BASE_URL, apiKey.trim());
946
+ console.log();
947
+ showSuccess("Claude API \u6388\u6743\u914D\u7F6E\u5DF2\u751F\u6548");
948
+ displaySavedConfig();
949
+ await askToSaveProfile(
950
+ "Claude API",
951
+ DEFAULT_BASE_URL,
952
+ apiKey.trim()
953
+ );
954
+ } catch (error) {
955
+ console.log();
956
+ showError(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${error.message}`);
957
+ await waitForEnter();
958
+ }
959
+ }
960
+ async function handleGlmAuth() {
961
+ console.log();
962
+ console.log(theme.primary("\u667A\u8C31 GLM AI \u6388\u6743"));
963
+ console.log();
964
+ console.log(theme.dim("Base URL: ") + GLM_BASE_URL);
965
+ console.log();
966
+ showInfo("\u83B7\u53D6 API Key \u65B9\u5F0F\uFF1A");
967
+ console.log(
968
+ theme.dim(" 1. \u8BBF\u95EE https://bigmodel.cn/usercenter/proj-mgmt/apikeys")
969
+ );
970
+ console.log(theme.dim(" 2. \u521B\u5EFA\u6216\u590D\u5236 API Key"));
971
+ console.log(theme.dim(" 3. \u7C98\u8D34\u5230\u4E0B\u65B9"));
972
+ console.log();
973
+ console.log(theme.dim(" (\u76F4\u63A5\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE)"));
974
+ console.log();
975
+ const { apiKey } = await import_inquirer.default.prompt([
976
+ {
977
+ type: "password",
978
+ name: "apiKey",
979
+ message: "\u8BF7\u8F93\u5165\u667A\u8C31 API Key:",
980
+ mask: "*"
981
+ }
982
+ ]);
983
+ if (!apiKey || apiKey.trim().length === 0) {
984
+ return;
985
+ }
986
+ console.log();
987
+ const spinner = (0, import_ora.default)("\u6B63\u5728\u9A8C\u8BC1 API Key...").start();
988
+ const verification = await verifyApiKey(GLM_BASE_URL, apiKey.trim());
989
+ if (!verification.valid) {
990
+ spinner.fail("API Key \u9A8C\u8BC1\u5931\u8D25");
991
+ console.log();
992
+ showError(verification.error || "\u672A\u77E5\u9519\u8BEF");
993
+ await waitForEnter();
994
+ return;
995
+ }
996
+ spinner.succeed("API Key \u9A8C\u8BC1\u901A\u8FC7");
997
+ try {
998
+ await saveApiConfig(GLM_BASE_URL, apiKey.trim(), {
999
+ timeout: "3000000"
1000
+ });
1001
+ console.log();
1002
+ showSuccess("\u667A\u8C31 GLM AI \u6388\u6743\u914D\u7F6E\u5DF2\u751F\u6548");
1003
+ displaySavedConfig();
1004
+ await askToSaveProfile(
1005
+ "\u667A\u8C31 GLM",
1006
+ GLM_BASE_URL,
1007
+ apiKey.trim(),
1008
+ void 0,
1009
+ "3000000"
1010
+ );
1011
+ } catch (error) {
1012
+ console.log();
1013
+ showError(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${error.message}`);
1014
+ await waitForEnter();
1015
+ }
1016
+ }
1017
+ async function handleKimiAuth() {
1018
+ console.log();
1019
+ console.log(theme.primary("Kimi AI \u6388\u6743"));
1020
+ console.log();
1021
+ console.log(theme.dim("Base URL: ") + KIMI_BASE_URL);
1022
+ console.log();
1023
+ showInfo("\u83B7\u53D6 API Key \u65B9\u5F0F\uFF1A");
1024
+ console.log(theme.dim(" 1. \u8BBF\u95EE Kimi AI \u5B98\u7F51\u83B7\u53D6 API Key"));
1025
+ console.log(theme.dim(" 2. \u521B\u5EFA\u6216\u590D\u5236 API Key"));
1026
+ console.log(theme.dim(" 3. \u7C98\u8D34\u5230\u4E0B\u65B9"));
1027
+ console.log();
1028
+ console.log(theme.dim(" (\u76F4\u63A5\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE)"));
1029
+ console.log();
1030
+ const { apiKey } = await import_inquirer.default.prompt([
1031
+ {
1032
+ type: "password",
1033
+ name: "apiKey",
1034
+ message: "\u8BF7\u8F93\u5165 Kimi API Key:",
1035
+ mask: "*"
1036
+ }
1037
+ ]);
1038
+ if (!apiKey || apiKey.trim().length === 0) {
1039
+ return;
1040
+ }
1041
+ console.log();
1042
+ const spinner = (0, import_ora.default)("\u6B63\u5728\u9A8C\u8BC1 API Key...").start();
1043
+ const verification = await verifyApiKey(KIMI_BASE_URL, apiKey.trim());
1044
+ if (!verification.valid) {
1045
+ spinner.fail("API Key \u9A8C\u8BC1\u5931\u8D25");
1046
+ console.log();
1047
+ showError(verification.error || "\u672A\u77E5\u9519\u8BEF");
1048
+ await waitForEnter();
1049
+ return;
1050
+ }
1051
+ spinner.succeed("API Key \u9A8C\u8BC1\u901A\u8FC7");
1052
+ try {
1053
+ await saveApiConfig(KIMI_BASE_URL, apiKey.trim(), {
1054
+ timeout: "3000000"
1055
+ });
1056
+ console.log();
1057
+ showSuccess("Kimi AI \u6388\u6743\u914D\u7F6E\u5DF2\u751F\u6548");
1058
+ displaySavedConfig();
1059
+ await askToSaveProfile(
1060
+ "Kimi AI",
1061
+ KIMI_BASE_URL,
1062
+ apiKey.trim(),
1063
+ void 0,
1064
+ "3000000"
1065
+ );
1066
+ } catch (error) {
1067
+ console.log();
1068
+ showError(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${error.message}`);
1069
+ await waitForEnter();
1070
+ }
1071
+ }
1072
+ async function handleManualAuth() {
1073
+ console.log();
1074
+ console.log(theme.primary("\u624B\u52A8\u8F93\u5165\u914D\u7F6E"));
1075
+ console.log();
1076
+ console.log(theme.dim("\u53EA\u9700\u914D\u7F6E\u4EE5\u4E0B\u5FC5\u8981\u5B57\u6BB5\uFF1A"));
1077
+ console.log(theme.dim(" - ANTHROPIC_AUTH_TOKEN"));
1078
+ console.log(theme.dim(" - ANTHROPIC_BASE_URL"));
1079
+ console.log(theme.dim(" - API_TIMEOUT_MS (\u53EF\u9009)"));
1080
+ console.log(
1081
+ theme.dim(" - CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC (\u9ED8\u8BA4\u7981\u7528)")
1082
+ );
1083
+ console.log();
1084
+ console.log(theme.dim("(\u4EFB\u610F\u6B65\u9AA4\u76F4\u63A5\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE)"));
1085
+ console.log();
1086
+ const { baseUrl } = await import_inquirer.default.prompt([
1087
+ {
1088
+ type: "input",
1089
+ name: "baseUrl",
1090
+ message: "\u8BF7\u8F93\u5165 ANTHROPIC_BASE_URL:",
1091
+ default: DEFAULT_BASE_URL
1092
+ }
1093
+ ]);
1094
+ if (!baseUrl || baseUrl.trim().length === 0) {
1095
+ return;
1096
+ }
1097
+ const { apiKey } = await import_inquirer.default.prompt([
1098
+ {
1099
+ type: "password",
1100
+ name: "apiKey",
1101
+ message: "\u8BF7\u8F93\u5165 ANTHROPIC_AUTH_TOKEN:",
1102
+ mask: "*"
1103
+ }
1104
+ ]);
1105
+ if (!apiKey || apiKey.trim().length === 0) {
1106
+ return;
1107
+ }
1108
+ const { timeout } = await import_inquirer.default.prompt([
1109
+ {
1110
+ type: "input",
1111
+ name: "timeout",
1112
+ message: "\u8BF7\u8F93\u5165 API_TIMEOUT_MS\uFF08\u6BEB\u79D2\uFF0C\u76F4\u63A5\u56DE\u8F66\u8DF3\u8FC7\uFF09:",
1113
+ default: "",
1114
+ validate: (input) => {
1115
+ if (!input || input.trim() === "") return true;
1116
+ const num = parseInt(input.trim(), 10);
1117
+ return !isNaN(num) && num > 0 || "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57";
1118
+ }
1119
+ }
1120
+ ]);
1121
+ console.log();
1122
+ const spinner = (0, import_ora.default)("\u6B63\u5728\u9A8C\u8BC1 API Key...").start();
1123
+ const verification = await verifyApiKey(baseUrl.trim(), apiKey.trim());
1124
+ if (!verification.valid) {
1125
+ spinner.fail("API Key \u9A8C\u8BC1\u5931\u8D25");
1126
+ console.log();
1127
+ showError(verification.error || "\u672A\u77E5\u9519\u8BEF");
1128
+ await waitForEnter();
1129
+ return;
1130
+ }
1131
+ spinner.succeed("API Key \u9A8C\u8BC1\u901A\u8FC7");
1132
+ try {
1133
+ const options = {};
1134
+ if (timeout && timeout.trim()) {
1135
+ options.timeout = timeout.trim();
1136
+ }
1137
+ await saveApiConfig(baseUrl.trim(), apiKey.trim(), options);
1138
+ console.log();
1139
+ showSuccess("\u914D\u7F6E\u5DF2\u751F\u6548");
1140
+ displaySavedConfig();
1141
+ await askToSaveProfile(
1142
+ "\u81EA\u5B9A\u4E49\u914D\u7F6E",
1143
+ baseUrl.trim(),
1144
+ apiKey.trim(),
1145
+ void 0,
1146
+ timeout && timeout.trim() ? timeout.trim() : void 0
1147
+ );
1148
+ } catch (error) {
1149
+ console.log();
1150
+ showError(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${error.message}`);
1151
+ await waitForEnter();
1152
+ }
1153
+ }
1154
+ async function askToSaveProfile(defaultName, baseUrl, apiKey, model, timeout) {
1155
+ console.log();
1156
+ const { save } = await import_inquirer.default.prompt([
1157
+ {
1158
+ type: "confirm",
1159
+ name: "save",
1160
+ message: "\u662F\u5426\u4FDD\u5B58\u6B64\u914D\u7F6E\u4EE5\u4FBF\u4E0B\u6B21\u5FEB\u901F\u6062\u590D\uFF1F",
1161
+ default: true
1162
+ }
1163
+ ]);
1164
+ if (!save) {
1165
+ await waitForEnter();
1166
+ return;
1167
+ }
1168
+ const { name } = await import_inquirer.default.prompt([
1169
+ {
1170
+ type: "input",
1171
+ name: "name",
1172
+ message: "\u8BF7\u8F93\u5165\u914D\u7F6E\u540D\u79F0\uFF1A",
1173
+ default: defaultName,
1174
+ validate: (input) => input.trim() !== "" || "\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A"
1175
+ }
1176
+ ]);
1177
+ try {
1178
+ const newProfile = addProfile({
1179
+ name: name.trim(),
1180
+ baseUrl,
1181
+ apiKey,
1182
+ model,
1183
+ timeout
1184
+ });
1185
+ switchProfile(newProfile.id);
1186
+ showSuccess(`\u914D\u7F6E "${name.trim()}" \u5DF2\u4FDD\u5B58`);
1187
+ showInfo('\u4E0B\u6B21\u53EF\u4EE5\u76F4\u63A5\u9009\u62E9"\u6062\u590D"\u6765\u5FEB\u901F\u5207\u6362');
1188
+ } catch (error) {
1189
+ showError(`\u4FDD\u5B58\u5931\u8D25: ${error.message}`);
1190
+ }
1191
+ await waitForEnter();
1192
+ }
1193
+ async function handleRestoreProfile(profile) {
1194
+ console.log();
1195
+ try {
1196
+ const success = switchProfile(profile.id);
1197
+ if (success) {
1198
+ showSuccess(`\u5DF2\u5207\u6362\u5230\uFF1A${profile.name}`);
1199
+ showInfo("\u914D\u7F6E\u5DF2\u751F\u6548");
1200
+ } else {
1201
+ showError("\u5207\u6362\u5931\u8D25");
1202
+ }
1203
+ } catch (error) {
1204
+ showError(`\u5207\u6362\u5931\u8D25: ${error.message}`);
1205
+ }
1206
+ await waitForEnter();
1207
+ }
1208
+ async function handleManageProfiles() {
1209
+ while (true) {
1210
+ const profiles = getAllProfiles();
1211
+ const currentProfile = getCurrentProfile();
1212
+ if (profiles.length === 0) {
1213
+ console.log();
1214
+ showWarning("\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E");
1215
+ await waitForEnter();
1216
+ return;
1217
+ }
1218
+ showHeader();
1219
+ console.log(createBoxTitle("\u7BA1\u7406\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E"));
1220
+ console.log();
1221
+ const choices = profiles.map((p) => {
1222
+ const isCurrent = currentProfile?.id === p.id;
1223
+ const suffix = isCurrent ? theme.warning(" (\u5F53\u524D\u4F7F\u7528\u4E2D)") : "";
1224
+ return {
1225
+ name: `${theme.error("\u2715")} \u5220\u9664 ${p.name}${suffix} ${theme.dim(
1226
+ `- ${p.baseUrl}`
1227
+ )}`,
1228
+ value: p
1229
+ };
1230
+ });
1231
+ choices.push(new import_inquirer.default.Separator(), {
1232
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
1233
+ value: null
1234
+ });
1235
+ const { profile } = await import_inquirer.default.prompt([
1236
+ {
1237
+ type: "list",
1238
+ name: "profile",
1239
+ message: "\u8BF7\u9009\u62E9\u8981\u5220\u9664\u7684\u914D\u7F6E\uFF1A",
1240
+ pageSize: 10,
1241
+ choices
1242
+ }
1243
+ ]);
1244
+ if (!profile) return;
1245
+ const { confirm } = await import_inquirer.default.prompt([
1246
+ {
1247
+ type: "confirm",
1248
+ name: "confirm",
1249
+ message: `\u786E\u5B9A\u8981\u5220\u9664\u914D\u7F6E "${profile.name}" \u5417\uFF1F`,
1250
+ default: false
1251
+ }
1252
+ ]);
1253
+ if (!confirm) {
1254
+ continue;
1255
+ }
1256
+ try {
1257
+ deleteProfile(profile.id);
1258
+ showSuccess(`\u914D\u7F6E "${profile.name}" \u5DF2\u5220\u9664`);
1259
+ } catch (error) {
1260
+ showError(`\u5220\u9664\u5931\u8D25: ${error.message}`);
1261
+ }
1262
+ await waitForEnter();
1263
+ }
1264
+ }
1265
+ function maskApiKey(apiKey) {
1266
+ if (apiKey.length <= 8) {
1267
+ return "*".repeat(apiKey.length);
1268
+ }
1269
+ return apiKey.substring(0, 4) + "****" + apiKey.substring(apiKey.length - 4);
1270
+ }
1271
+ function displaySavedConfig() {
1272
+ const settings = readClaudeSettings();
1273
+ console.log();
1274
+ console.log(theme.dim("\u914D\u7F6E\u5DF2\u540C\u6B65\uFF1A"));
1275
+ console.log(JSON.stringify(settings, null, 2));
1276
+ }
1277
+ async function waitForEnter() {
1278
+ console.log();
1279
+ await import_inquirer.default.prompt([
1280
+ { type: "input", name: "continue", message: "\u6309\u56DE\u8F66\u952E\u7EE7\u7EED..." }
1281
+ ]);
1282
+ }
1283
+
1284
+ // src/cli/menus/manage.ts
1285
+ var import_inquirer4 = __toESM(require("inquirer"));
1286
+ var import_ora4 = __toESM(require("ora"));
1287
+
1288
+ // src/cli/menus/install.ts
1289
+ var import_child_process2 = require("child_process");
1290
+ var import_inquirer2 = __toESM(require("inquirer"));
1291
+ var import_net = __toESM(require("net"));
1292
+ var import_ora2 = __toESM(require("ora"));
1293
+ init_exec();
1294
+
1295
+ // src/cli/utils/platform.ts
1296
+ var import_os3 = __toESM(require("os"));
1297
+ function getOsName(platform) {
1298
+ switch (platform) {
1299
+ case "darwin":
1300
+ return "macOS";
1301
+ case "win32":
1302
+ return "Windows";
1303
+ case "linux":
1304
+ return "Linux";
1305
+ default:
1306
+ return platform;
1307
+ }
1308
+ }
1309
+ function getArchName(arch) {
1310
+ switch (arch) {
1311
+ case "x64":
1312
+ return "x64";
1313
+ case "arm64":
1314
+ return "arm64";
1315
+ case "ia32":
1316
+ return "x86";
1317
+ default:
1318
+ return arch;
1319
+ }
1320
+ }
1321
+ function detectPlatform() {
1322
+ const platform = import_os3.default.platform();
1323
+ const arch = import_os3.default.arch();
1324
+ return {
1325
+ os: platform,
1326
+ osName: getOsName(platform),
1327
+ arch: getArchName(arch),
1328
+ isWindows: platform === "win32",
1329
+ isMac: platform === "darwin",
1330
+ isLinux: platform === "linux"
1331
+ };
1332
+ }
1333
+
1334
+ // src/cli/menus/install.ts
1335
+ var COMMON_PROXY_PORTS = [
1336
+ { port: 7890, name: "Clash" },
1337
+ { port: 7891, name: "Clash (SOCKS)" },
1338
+ { port: 1087, name: "V2RayU" },
1339
+ { port: 1086, name: "V2RayU (SOCKS)" },
1340
+ { port: 8118, name: "Privoxy" },
1341
+ { port: 1080, name: "SOCKS5" },
1342
+ { port: 8080, name: "HTTP Proxy" },
1343
+ { port: 9090, name: "Clash Dashboard" }
1344
+ ];
1345
+ var INSTALL_METHODS = [
1346
+ {
1347
+ name: "\u5B98\u65B9\u811A\u672C\u5B89\u88C5",
1348
+ command: "curl -fsSL https://claude.ai/install.sh | bash",
1349
+ description: "\u9700\u8981\u4EE3\u7406\u6216\u5916\u7F51\u8BBF\u95EE",
1350
+ platforms: ["darwin", "linux"],
1351
+ recommended: true
1352
+ },
1353
+ {
1354
+ name: "npm \u5B89\u88C5",
1355
+ command: "npm install -g @anthropic-ai/claude-code",
1356
+ description: "\u65E0\u9700\u7FFB\u5899",
1357
+ platforms: ["darwin", "linux", "win32"]
1358
+ },
1359
+ {
1360
+ name: "\u5B98\u65B9\u811A\u672C\u5B89\u88C5 (Windows)",
1361
+ command: "irm https://claude.ai/install.ps1 | iex",
1362
+ description: "\u9700\u8981\u4EE3\u7406\u6216\u5916\u7F51\u8BBF\u95EE",
1363
+ platforms: ["win32"],
1364
+ recommended: true
1365
+ },
1366
+ {
1367
+ name: "WinGet \u5B89\u88C5",
1368
+ command: "winget install Anthropic.ClaudeCode",
1369
+ description: "\u9002\u7528\u4E8E Windows",
1370
+ platforms: ["win32"]
1371
+ }
1372
+ ];
1373
+ function getAvailableMethods(platform) {
1374
+ return INSTALL_METHODS.filter(
1375
+ (method) => method.platforms.includes(platform.os)
1376
+ );
1377
+ }
1378
+ function checkPort(port, host = "127.0.0.1") {
1379
+ return new Promise((resolve) => {
1380
+ const socket = new import_net.default.Socket();
1381
+ socket.setTimeout(500);
1382
+ socket.on("connect", () => {
1383
+ socket.destroy();
1384
+ resolve(true);
1385
+ });
1386
+ socket.on("timeout", () => {
1387
+ socket.destroy();
1388
+ resolve(false);
1389
+ });
1390
+ socket.on("error", () => {
1391
+ socket.destroy();
1392
+ resolve(false);
1393
+ });
1394
+ socket.connect(port, host);
1395
+ });
1396
+ }
1397
+ function getSystemProxy() {
1398
+ const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY;
1399
+ const httpsProxy = process.env.https_proxy || process.env.HTTPS_PROXY;
1400
+ const proxy = httpsProxy || httpProxy;
1401
+ if (proxy) {
1402
+ try {
1403
+ const url = new URL(proxy);
1404
+ return { host: url.hostname, port: parseInt(url.port) || 80 };
1405
+ } catch {
1406
+ }
1407
+ }
1408
+ if (process.platform === "darwin") {
1409
+ try {
1410
+ const output = (0, import_child_process2.execSync)('networksetup -getwebproxy "Wi-Fi"', {
1411
+ encoding: "utf-8",
1412
+ timeout: 3e3
1413
+ });
1414
+ const enabledMatch = output.match(/Enabled:\s*(Yes|No)/i);
1415
+ const serverMatch = output.match(/Server:\s*(\S+)/);
1416
+ const portMatch = output.match(/Port:\s*(\d+)/);
1417
+ if (enabledMatch?.[1].toLowerCase() === "yes" && serverMatch && portMatch) {
1418
+ return { host: serverMatch[1], port: parseInt(portMatch[1]) };
1419
+ }
1420
+ } catch {
1421
+ }
1422
+ }
1423
+ return null;
1424
+ }
1425
+ async function detectProxyPorts() {
1426
+ const availablePorts = [];
1427
+ const results = await Promise.all(
1428
+ COMMON_PROXY_PORTS.map(async ({ port, name }) => {
1429
+ const isOpen = await checkPort(port);
1430
+ return { port, name, isOpen };
1431
+ })
1432
+ );
1433
+ for (const result of results) {
1434
+ if (result.isOpen) {
1435
+ availablePorts.push({ port: result.port, name: result.name });
1436
+ }
1437
+ }
1438
+ return availablePorts;
1439
+ }
1440
+ function isNetworkError(errorMessage) {
1441
+ const networkErrorPatterns = [
1442
+ "syntax error",
1443
+ "<!DOCTYPE",
1444
+ "<html",
1445
+ "Could not resolve host",
1446
+ "Connection refused",
1447
+ "Network is unreachable",
1448
+ "Operation timed out",
1449
+ "SSL",
1450
+ "SSL_connect",
1451
+ "SSL_ERROR",
1452
+ "LibreSSL",
1453
+ "certificate",
1454
+ "ENOTFOUND",
1455
+ "ECONNREFUSED",
1456
+ "ETIMEDOUT",
1457
+ "ECONNRESET"
1458
+ ];
1459
+ return networkErrorPatterns.some(
1460
+ (pattern) => errorMessage.toLowerCase().includes(pattern.toLowerCase())
1461
+ );
1462
+ }
1463
+ function formatErrorMessage(error) {
1464
+ const errorMsg = error.message;
1465
+ if (isNetworkError(errorMsg)) {
1466
+ return "\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BE5\u5B89\u88C5\u65B9\u5F0F\u9700\u8981\u80FD\u591F\u8BBF\u95EE\u5916\u7F51";
1467
+ }
1468
+ const lines = errorMsg.split("\n").filter((line) => line.trim());
1469
+ if (lines.length > 2) {
1470
+ return lines.slice(0, 2).join("\n") + `
1471
+ ${theme.dim(`... \u7701\u7565 ${lines.length - 2} \u884C`)}`;
1472
+ }
1473
+ return errorMsg;
1474
+ }
1475
+ function needsExternalNetwork(command) {
1476
+ return command.includes("claude.ai");
1477
+ }
1478
+ async function showInstallMenu() {
1479
+ showHeader();
1480
+ const platform = detectPlatform();
1481
+ console.log(createBoxTitle("\u5B89\u88C5 Claude Code"));
1482
+ console.log();
1483
+ showInfo(`\u68C0\u6D4B\u5230\u60A8\u7684\u7CFB\u7EDF\uFF1A${platform.osName} ${platform.arch}`);
1484
+ console.log();
1485
+ const availableMethods = getAvailableMethods(platform);
1486
+ const choices = availableMethods.map((method2) => ({
1487
+ name: `${method2.name}${method2.recommended ? theme.success(" (\u63A8\u8350)") : ""} - ${theme.dim(method2.description)}`,
1488
+ value: method2
1489
+ }));
1490
+ choices.push(new import_inquirer2.default.Separator());
1491
+ choices.push({
1492
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
1493
+ value: null
1494
+ });
1495
+ choices.push({
1496
+ name: `${theme.dim("X")} \u9000\u51FA`,
1497
+ value: "exit"
1498
+ });
1499
+ const { method } = await import_inquirer2.default.prompt([
1500
+ {
1501
+ type: "list",
1502
+ name: "method",
1503
+ message: "\u8BF7\u9009\u62E9\u5B89\u88C5\u65B9\u5F0F\uFF1A",
1504
+ choices
1505
+ }
1506
+ ]);
1507
+ if (!method) {
1508
+ return;
1509
+ }
1510
+ if (method === "exit") {
1511
+ process.exit(0);
1512
+ }
1513
+ let proxyUrl = null;
1514
+ let finalMethod = method;
1515
+ if (needsExternalNetwork(method.command)) {
1516
+ console.log();
1517
+ const spinner2 = (0, import_ora2.default)("\u68C0\u6D4B\u672C\u673A\u4EE3\u7406...").start();
1518
+ const systemProxy = getSystemProxy();
1519
+ const detectedPorts = await detectProxyPorts();
1520
+ spinner2.stop();
1521
+ const proxyChoices = [];
1522
+ if (systemProxy) {
1523
+ proxyChoices.push({
1524
+ name: `${theme.success("\u2713")} \u7CFB\u7EDF\u4EE3\u7406 ${theme.dim(
1525
+ `(${systemProxy.host}:${systemProxy.port})`
1526
+ )}`,
1527
+ value: `http://${systemProxy.host}:${systemProxy.port}`
1528
+ });
1529
+ }
1530
+ for (const { port, name } of detectedPorts) {
1531
+ if (systemProxy && systemProxy.port === port) continue;
1532
+ proxyChoices.push({
1533
+ name: `${theme.success("\u2713")} ${name} ${theme.dim(
1534
+ `(127.0.0.1:${port})`
1535
+ )}`,
1536
+ value: `http://127.0.0.1:${port}`
1537
+ });
1538
+ }
1539
+ const hasDetectedProxy = proxyChoices.length > 0;
1540
+ if (hasDetectedProxy) {
1541
+ showInfo("\u68C0\u6D4B\u5230\u672C\u673A\u4EE3\u7406\uFF1A");
1542
+ for (const choice of proxyChoices) {
1543
+ console.log(` ${choice.name}`);
1544
+ }
1545
+ console.log();
1546
+ const { useProxy } = await import_inquirer2.default.prompt([
1547
+ {
1548
+ type: "confirm",
1549
+ name: "useProxy",
1550
+ message: "\u662F\u5426\u4F7F\u7528\u4EE3\u7406\uFF1F\uFF08\u5EFA\u8BAE\u5F00\u542F\uFF09",
1551
+ default: true
1552
+ }
1553
+ ]);
1554
+ if (useProxy) {
1555
+ if (proxyChoices.length === 1) {
1556
+ proxyUrl = proxyChoices[0].value;
1557
+ } else {
1558
+ proxyChoices.push(new import_inquirer2.default.Separator());
1559
+ proxyChoices.push({
1560
+ name: `${theme.dim("\u2715")} \u4E0D\u4F7F\u7528\u4EE3\u7406`,
1561
+ value: null
1562
+ });
1563
+ const { selectedProxy } = await import_inquirer2.default.prompt([
1564
+ {
1565
+ type: "list",
1566
+ name: "selectedProxy",
1567
+ message: "\u8BF7\u9009\u62E9\u4EE3\u7406\uFF1A",
1568
+ choices: proxyChoices
1569
+ }
1570
+ ]);
1571
+ if (selectedProxy) {
1572
+ proxyUrl = selectedProxy;
1573
+ }
1574
+ }
1575
+ }
1576
+ } else {
1577
+ showWarning("\u672A\u68C0\u6D4B\u5230\u672C\u673A\u4EE3\u7406");
1578
+ showInfo("\u81EA\u52A8\u5207\u6362\u5230 npm \u5B89\u88C5\u65B9\u5F0F\uFF08\u65E0\u9700\u7FFB\u5899\uFF09");
1579
+ console.log();
1580
+ const npmMethod = availableMethods.find(
1581
+ (m) => m.command.includes("npm install")
1582
+ );
1583
+ if (npmMethod) {
1584
+ finalMethod = npmMethod;
1585
+ }
1586
+ }
1587
+ }
1588
+ let finalCommand = finalMethod.command;
1589
+ let envVars = {};
1590
+ if (proxyUrl) {
1591
+ if (finalCommand.includes("curl")) {
1592
+ finalCommand = finalCommand.replace("curl ", `curl --proxy ${proxyUrl} `);
1593
+ } else {
1594
+ envVars = {
1595
+ http_proxy: proxyUrl,
1596
+ https_proxy: proxyUrl,
1597
+ HTTP_PROXY: proxyUrl,
1598
+ HTTPS_PROXY: proxyUrl
1599
+ };
1600
+ }
1601
+ showInfo(`\u4F7F\u7528\u4EE3\u7406: ${proxyUrl}`);
1602
+ }
1603
+ console.log();
1604
+ showInfo(`\u5C06\u6267\u884C\u547D\u4EE4: ${theme.secondary(finalCommand)}`);
1605
+ console.log();
1606
+ const { confirm } = await import_inquirer2.default.prompt([
1607
+ {
1608
+ type: "confirm",
1609
+ name: "confirm",
1610
+ message: "\u786E\u8BA4\u6267\u884C\u5B89\u88C5\uFF1F",
1611
+ default: true
1612
+ }
1613
+ ]);
1614
+ if (!confirm) {
1615
+ return;
1616
+ }
1617
+ const spinner = (0, import_ora2.default)("\u6B63\u5728\u5B89\u88C5 Claude Code...").start();
1618
+ try {
1619
+ await executeCommand(finalCommand, envVars);
1620
+ spinner.text = "\u9A8C\u8BC1\u5B89\u88C5...";
1621
+ const installed = await commandExists("claude");
1622
+ if (installed) {
1623
+ spinner.succeed("Claude Code \u5B89\u88C5\u6210\u529F\uFF01");
1624
+ showSuccess("\u60A8\u73B0\u5728\u53EF\u4EE5\u5728\u7EC8\u7AEF\u4E2D\u8FD0\u884C claude \u547D\u4EE4");
1625
+ console.log();
1626
+ showInfo("\u4E0B\u4E00\u6B65\uFF1A\u914D\u7F6E API \u5BC6\u94A5");
1627
+ console.log(
1628
+ theme.dim(' \u8FD4\u56DE\u4E3B\u83DC\u5355 -> \u9009\u62E9 "\u6388\u6743\u767B\u5F55" -> \u914D\u7F6E\u60A8\u7684 API Key')
1629
+ );
1630
+ console.log(theme.dim(" \u914D\u7F6E\u5B8C\u6210\u540E\u5373\u53EF\u5F00\u59CB\u4F7F\u7528 Claude Code"));
1631
+ } else {
1632
+ spinner.fail("\u5B89\u88C5\u5931\u8D25");
1633
+ showError("\u5B89\u88C5\u547D\u4EE4\u6267\u884C\u5B8C\u6210\uFF0C\u4F46\u672A\u627E\u5230 claude \u547D\u4EE4");
1634
+ console.log();
1635
+ showInfo("\u53EF\u80FD\u7684\u539F\u56E0\uFF1A");
1636
+ console.log(theme.dim(" 1. \u5B89\u88C5\u8FC7\u7A0B\u4E2D\u51FA\u73B0\u7F51\u7EDC\u9519\u8BEF"));
1637
+ console.log(theme.dim(" 2. \u9700\u8981\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u624D\u80FD\u4F7F\u7528 claude \u547D\u4EE4"));
1638
+ console.log(theme.dim(" 3. \u73AF\u5883\u53D8\u91CF PATH \u672A\u6B63\u786E\u8BBE\u7F6E"));
1639
+ console.log();
1640
+ showInfo("\u5EFA\u8BAE\uFF1A");
1641
+ if (proxyUrl) {
1642
+ console.log(
1643
+ theme.dim(
1644
+ " 1. \u68C0\u67E5\u4EE3\u7406\u8F6F\u4EF6\u662F\u5426\u8BBE\u7F6E\u4E3A\u3010\u5168\u5C40\u6A21\u5F0F\u3011\uFF08\u89C4\u5219\u6A21\u5F0F\u53EF\u80FD\u62E6\u622A claude.ai\uFF09"
1645
+ )
1646
+ );
1647
+ console.log(theme.dim(' 2. \u6362\u7528 "npm \u5B89\u88C5" \u65B9\u5F0F\uFF08\u65E0\u9700\u7FFB\u5899\uFF09'));
1648
+ } else {
1649
+ console.log(
1650
+ theme.dim(' 1. \u4F7F\u7528\u4EE3\u7406\u91CD\u8BD5\uFF08\u9009\u62E9"\u5B98\u65B9\u811A\u672C\u5B89\u88C5"\u540E\u5F00\u542F\u4EE3\u7406\u9009\u9879\uFF09')
1651
+ );
1652
+ console.log(theme.dim(' 2. \u6362\u7528 "npm \u5B89\u88C5" \u65B9\u5F0F\uFF08\u65E0\u9700\u7FFB\u5899\uFF09'));
1653
+ }
1654
+ }
1655
+ } catch (error) {
1656
+ spinner.fail("\u5B89\u88C5\u5931\u8D25");
1657
+ const friendlyError = formatErrorMessage(error);
1658
+ showError(friendlyError);
1659
+ if (isNetworkError(error.message)) {
1660
+ console.log();
1661
+ showInfo("\u5EFA\u8BAE\uFF1A");
1662
+ if (proxyUrl) {
1663
+ console.log(
1664
+ theme.dim(
1665
+ " 1. \u68C0\u67E5\u4EE3\u7406\u8F6F\u4EF6\u662F\u5426\u8BBE\u7F6E\u4E3A\u3010\u5168\u5C40\u6A21\u5F0F\u3011\uFF08\u89C4\u5219\u6A21\u5F0F\u53EF\u80FD\u62E6\u622A claude.ai\uFF09"
1666
+ )
1667
+ );
1668
+ console.log(theme.dim(" 2. \u5C1D\u8BD5\u66F4\u6362\u4EE3\u7406\u7AEF\u53E3\u6216\u4EE3\u7406\u8F6F\u4EF6"));
1669
+ console.log(theme.dim(' 3. \u6362\u7528 "npm \u5B89\u88C5" \u65B9\u5F0F\uFF08\u65E0\u9700\u7FFB\u5899\uFF09'));
1670
+ } else {
1671
+ console.log(
1672
+ theme.dim(' 1. \u4F7F\u7528\u4EE3\u7406\u91CD\u8BD5\uFF08\u9009\u62E9"\u5B98\u65B9\u811A\u672C\u5B89\u88C5"\u540E\u5F00\u542F\u4EE3\u7406\u9009\u9879\uFF09')
1673
+ );
1674
+ console.log(theme.dim(' 2. \u6362\u7528 "npm \u5B89\u88C5" \u65B9\u5F0F\uFF08\u65E0\u9700\u7FFB\u5899\uFF09'));
1675
+ }
1676
+ }
1677
+ }
1678
+ await import_inquirer2.default.prompt([
1679
+ {
1680
+ type: "input",
1681
+ name: "continue",
1682
+ message: "\u6309\u56DE\u8F66\u952E\u8FD4\u56DE\u4E3B\u83DC\u5355..."
1683
+ }
1684
+ ]);
1685
+ }
1686
+
1687
+ // src/cli/menus/uninstall.ts
1688
+ var import_fs3 = __toESM(require("fs"));
1689
+ var import_inquirer3 = __toESM(require("inquirer"));
1690
+ var import_ora3 = __toESM(require("ora"));
1691
+ var import_os4 = __toESM(require("os"));
1692
+ var import_path3 = __toESM(require("path"));
1693
+ init_exec();
1694
+ async function showUninstallMenu() {
1695
+ showHeader();
1696
+ console.log(createBoxTitle("\u5378\u8F7D Claude Code"));
1697
+ console.log();
1698
+ const { choice } = await import_inquirer3.default.prompt([
1699
+ {
1700
+ type: "list",
1701
+ name: "choice",
1702
+ message: "\u8BF7\u9009\u62E9\u5378\u8F7D\u65B9\u5F0F\uFF1A",
1703
+ choices: [
1704
+ {
1705
+ name: `\u4EC5\u5378\u8F7D\u7A0B\u5E8F ${theme.dim("(\u4FDD\u7559\u914D\u7F6E\u3001\u4F1A\u8BDD\u548C\u63D2\u4EF6)")}`,
1706
+ value: "program_only" /* PROGRAM_ONLY */
1707
+ },
1708
+ {
1709
+ name: `${theme.error("\u5B8C\u6574\u5378\u8F7D")} ${theme.dim(
1710
+ "(\u5220\u9664\u7A0B\u5E8F\u3001\u914D\u7F6E\u3001\u4F1A\u8BDD\u548C\u63D2\u4EF6)"
1711
+ )}`,
1712
+ value: "complete" /* COMPLETE */
1713
+ },
1714
+ new import_inquirer3.default.Separator(),
1715
+ {
1716
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
1717
+ value: "back" /* BACK */
1718
+ },
1719
+ {
1720
+ name: `${theme.dim("X")} \u9000\u51FA`,
1721
+ value: "exit" /* EXIT */
1722
+ }
1723
+ ]
1724
+ }
1725
+ ]);
1726
+ switch (choice) {
1727
+ case "program_only" /* PROGRAM_ONLY */:
1728
+ await handleProgramOnlyUninstall();
1729
+ break;
1730
+ case "complete" /* COMPLETE */:
1731
+ await handleCompleteUninstall();
1732
+ break;
1733
+ case "back" /* BACK */:
1734
+ return;
1735
+ case "exit" /* EXIT */:
1736
+ process.exit(0);
1737
+ }
1738
+ }
1739
+ async function handleProgramOnlyUninstall() {
1740
+ console.log();
1741
+ showInfo("\u5C06\u4EC5\u5378\u8F7D Claude Code \u7A0B\u5E8F\uFF0C\u4FDD\u7559\u4EE5\u4E0B\u5185\u5BB9\uFF1A");
1742
+ console.log(theme.dim(" - ~/.claude/ \u76EE\u5F55\uFF08\u914D\u7F6E\u548C\u4F1A\u8BDD\uFF09"));
1743
+ console.log(theme.dim(" - ~/.claude.json\uFF08MCP \u914D\u7F6E\uFF09"));
1744
+ console.log(theme.dim(" - \u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6"));
1745
+ console.log();
1746
+ const { confirm } = await import_inquirer3.default.prompt([
1747
+ {
1748
+ type: "confirm",
1749
+ name: "confirm",
1750
+ message: "\u786E\u8BA4\u5378\u8F7D Claude Code \u7A0B\u5E8F\uFF1F",
1751
+ default: false
1752
+ }
1753
+ ]);
1754
+ if (!confirm) {
1755
+ return;
1756
+ }
1757
+ const spinner = (0, import_ora3.default)("\u6B63\u5728\u5378\u8F7D Claude Code...").start();
1758
+ try {
1759
+ const platform = detectPlatform();
1760
+ let uninstalled = false;
1761
+ try {
1762
+ await executeCommand("npm uninstall -g @anthropic-ai/claude-code");
1763
+ uninstalled = true;
1764
+ } catch {
1765
+ }
1766
+ if (platform.isMac && !uninstalled) {
1767
+ try {
1768
+ await executeCommand("brew uninstall --cask claude 2>/dev/null");
1769
+ uninstalled = true;
1770
+ } catch {
1771
+ }
1772
+ }
1773
+ const binaryPaths = [
1774
+ "/usr/local/bin/claude",
1775
+ import_path3.default.join(import_os4.default.homedir(), ".local/bin/claude"),
1776
+ import_path3.default.join(import_os4.default.homedir(), ".claude/bin/claude")
1777
+ ];
1778
+ for (const binPath of binaryPaths) {
1779
+ if (import_fs3.default.existsSync(binPath)) {
1780
+ try {
1781
+ import_fs3.default.unlinkSync(binPath);
1782
+ uninstalled = true;
1783
+ } catch {
1784
+ }
1785
+ }
1786
+ }
1787
+ if (uninstalled) {
1788
+ spinner.succeed("Claude Code \u7A0B\u5E8F\u5DF2\u5378\u8F7D");
1789
+ showSuccess("\u914D\u7F6E\u548C\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u91CD\u65B0\u5B89\u88C5\u540E\u53EF\u7EE7\u7EED\u4F7F\u7528");
1790
+ } else {
1791
+ spinner.warn("\u672A\u627E\u5230\u5DF2\u5B89\u88C5\u7684 Claude Code");
1792
+ showInfo("\u53EF\u80FD\u5DF2\u7ECF\u5378\u8F7D\u6216\u4F7F\u7528\u4E86\u5176\u4ED6\u5B89\u88C5\u65B9\u5F0F");
1793
+ }
1794
+ } catch (error) {
1795
+ spinner.fail("\u5378\u8F7D\u5931\u8D25");
1796
+ showError(error.message);
1797
+ }
1798
+ console.log();
1799
+ await import_inquirer3.default.prompt([
1800
+ {
1801
+ type: "input",
1802
+ name: "continue",
1803
+ message: "\u6309\u56DE\u8F66\u952E\u8FD4\u56DE..."
1804
+ }
1805
+ ]);
1806
+ }
1807
+ async function handleCompleteUninstall() {
1808
+ console.log();
1809
+ showWarning("\u26A0\uFE0F \u5B8C\u6574\u5378\u8F7D\u5C06\u5220\u9664\u4EE5\u4E0B\u6240\u6709\u5185\u5BB9\uFF1A");
1810
+ console.log(theme.error(" - Claude Code \u7A0B\u5E8F"));
1811
+ console.log(theme.error(" - ~/.claude/ \u76EE\u5F55\uFF08\u914D\u7F6E\u548C\u4F1A\u8BDD\uFF09"));
1812
+ console.log(theme.error(" - ~/.claude.json\uFF08MCP \u914D\u7F6E\uFF09"));
1813
+ console.log(theme.error(" - \u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6"));
1814
+ console.log();
1815
+ showWarning("\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF01");
1816
+ console.log();
1817
+ const { confirmFirst } = await import_inquirer3.default.prompt([
1818
+ {
1819
+ type: "confirm",
1820
+ name: "confirmFirst",
1821
+ message: "\u786E\u8BA4\u8981\u5B8C\u6574\u5378\u8F7D Claude Code\uFF1F",
1822
+ default: false
1823
+ }
1824
+ ]);
1825
+ if (!confirmFirst) {
1826
+ return;
1827
+ }
1828
+ const { confirmSecond } = await import_inquirer3.default.prompt([
1829
+ {
1830
+ type: "input",
1831
+ name: "confirmSecond",
1832
+ message: '\u8BF7\u8F93\u5165 "DELETE" \u786E\u8BA4\u5220\u9664\uFF1A'
1833
+ }
1834
+ ]);
1835
+ if (confirmSecond !== "DELETE") {
1836
+ showInfo("\u5DF2\u53D6\u6D88\u5378\u8F7D");
1837
+ return;
1838
+ }
1839
+ const spinner = (0, import_ora3.default)("\u6B63\u5728\u5B8C\u6574\u5378\u8F7D Claude Code...").start();
1840
+ try {
1841
+ const platform = detectPlatform();
1842
+ spinner.text = "\u5378\u8F7D\u7A0B\u5E8F...";
1843
+ try {
1844
+ await executeCommand(
1845
+ "npm uninstall -g @anthropic-ai/claude-code 2>/dev/null || true"
1846
+ );
1847
+ } catch {
1848
+ }
1849
+ if (platform.isMac) {
1850
+ try {
1851
+ await executeCommand(
1852
+ "brew uninstall --cask claude 2>/dev/null || true"
1853
+ );
1854
+ } catch {
1855
+ }
1856
+ }
1857
+ const binaryPaths = [
1858
+ "/usr/local/bin/claude",
1859
+ import_path3.default.join(import_os4.default.homedir(), ".local/bin/claude"),
1860
+ import_path3.default.join(import_os4.default.homedir(), ".claude/bin/claude")
1861
+ ];
1862
+ for (const binPath of binaryPaths) {
1863
+ if (import_fs3.default.existsSync(binPath)) {
1864
+ try {
1865
+ import_fs3.default.unlinkSync(binPath);
1866
+ } catch {
1867
+ }
1868
+ }
1869
+ }
1870
+ spinner.text = "\u5220\u9664\u914D\u7F6E\u548C\u4F1A\u8BDD...";
1871
+ const claudeDir = import_path3.default.join(import_os4.default.homedir(), ".claude");
1872
+ if (import_fs3.default.existsSync(claudeDir)) {
1873
+ import_fs3.default.rmSync(claudeDir, { recursive: true, force: true });
1874
+ }
1875
+ spinner.text = "\u5220\u9664 MCP \u914D\u7F6E...";
1876
+ const claudeJson = import_path3.default.join(import_os4.default.homedir(), ".claude.json");
1877
+ if (import_fs3.default.existsSync(claudeJson)) {
1878
+ import_fs3.default.unlinkSync(claudeJson);
1879
+ }
1880
+ spinner.succeed("Claude Code \u5DF2\u5B8C\u6574\u5378\u8F7D");
1881
+ showSuccess("\u6240\u6709\u7A0B\u5E8F\u3001\u914D\u7F6E\u548C\u6570\u636E\u5DF2\u5220\u9664");
1882
+ } catch (error) {
1883
+ spinner.fail("\u5378\u8F7D\u8FC7\u7A0B\u4E2D\u51FA\u73B0\u9519\u8BEF");
1884
+ showError(error.message);
1885
+ }
1886
+ console.log();
1887
+ await import_inquirer3.default.prompt([
1888
+ {
1889
+ type: "input",
1890
+ name: "continue",
1891
+ message: "\u6309\u56DE\u8F66\u952E\u8FD4\u56DE..."
1892
+ }
1893
+ ]);
1894
+ }
1895
+
1896
+ // src/cli/menus/manage.ts
1897
+ async function showManageMenu() {
1898
+ let claudeInfo = getCachedClaudeInfo();
1899
+ if (!claudeInfo) {
1900
+ const spinner = (0, import_ora4.default)("\u6B63\u5728\u68C0\u6D4B Claude Code...").start();
1901
+ claudeInfo = detectClaudeInstallation();
1902
+ spinner.stop();
1903
+ }
1904
+ while (true) {
1905
+ showHeader();
1906
+ console.log(createBoxTitle("Claude Code \u7BA1\u7406"));
1907
+ console.log();
1908
+ console.log(theme.primary("\u5F53\u524D\u72B6\u6001\uFF1A"));
1909
+ console.log();
1910
+ if (claudeInfo.installed) {
1911
+ showInfo(`\u2713 \u5DF2\u5B89\u88C5`);
1912
+ if (claudeInfo.version) {
1913
+ console.log(` \u7248\u672C\uFF1A${theme.success(claudeInfo.version)}`);
1914
+ }
1915
+ if (claudeInfo.installMethod) {
1916
+ console.log(
1917
+ ` \u5B89\u88C5\u65B9\u5F0F\uFF1A${theme.info(
1918
+ formatInstallMethod(claudeInfo.installMethod)
1919
+ )}`
1920
+ );
1921
+ }
1922
+ if (claudeInfo.binaryPath) {
1923
+ console.log(` \u8DEF\u5F84\uFF1A${theme.dim(claudeInfo.binaryPath)}`);
1924
+ }
1925
+ } else {
1926
+ showInfo(`\u2717 \u672A\u5B89\u88C5`);
1927
+ }
1928
+ console.log();
1929
+ const { choice } = await import_inquirer4.default.prompt([
1930
+ {
1931
+ type: "list",
1932
+ name: "choice",
1933
+ message: "\u8BF7\u9009\u62E9\u64CD\u4F5C\uFF1A",
1934
+ choices: [
1935
+ {
1936
+ name: `${theme.primary(">")} \u5B89\u88C5 Claude Code`,
1937
+ value: "install" /* INSTALL */
1938
+ },
1939
+ {
1940
+ name: `${theme.error("*")} \u5378\u8F7D Claude Code`,
1941
+ value: "uninstall" /* UNINSTALL */,
1942
+ disabled: !claudeInfo.installed ? "\u672A\u5B89\u88C5" : false
1943
+ },
1944
+ {
1945
+ name: `${theme.info("\u21BB")} \u5237\u65B0\u72B6\u6001`,
1946
+ value: "refresh" /* REFRESH */
1947
+ },
1948
+ new import_inquirer4.default.Separator(),
1949
+ {
1950
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
1951
+ value: "back" /* BACK */
1952
+ },
1953
+ {
1954
+ name: `${theme.dim("X")} \u9000\u51FA`,
1955
+ value: "exit" /* EXIT */
1956
+ }
1957
+ ]
1958
+ }
1959
+ ]);
1960
+ switch (choice) {
1961
+ case "install" /* INSTALL */:
1962
+ await showInstallMenu();
1963
+ clearClaudeCache();
1964
+ claudeInfo = detectClaudeInstallation();
1965
+ break;
1966
+ case "uninstall" /* UNINSTALL */:
1967
+ await showUninstallMenu();
1968
+ clearClaudeCache();
1969
+ claudeInfo = detectClaudeInstallation();
1970
+ break;
1971
+ case "refresh" /* REFRESH */: {
1972
+ const spinner = (0, import_ora4.default)("\u6B63\u5728\u5237\u65B0\u72B6\u6001...").start();
1973
+ clearClaudeCache();
1974
+ claudeInfo = detectClaudeInstallation();
1975
+ spinner.succeed("\u72B6\u6001\u5DF2\u5237\u65B0");
1976
+ await new Promise((resolve) => {
1977
+ setTimeout(resolve, 500);
1978
+ });
1979
+ break;
1980
+ }
1981
+ case "back" /* BACK */:
1982
+ return;
1983
+ case "exit" /* EXIT */:
1984
+ process.exit(0);
1985
+ }
1986
+ }
1987
+ }
1988
+
1989
+ // src/cli/menus/mcp.ts
1990
+ var import_inquirer5 = __toESM(require("inquirer"));
1991
+ var import_ora5 = __toESM(require("ora"));
1992
+
1993
+ // src/cli/services/mcp.ts
1994
+ var import_fs5 = __toESM(require("fs"));
1995
+ var import_os6 = __toESM(require("os"));
1996
+ var import_path6 = __toESM(require("path"));
1997
+
1998
+ // src/cli/config/constants.ts
1999
+ var import_path4 = __toESM(require("path"));
2000
+ var CONFIG_DIR = import_path4.default.resolve(__dirname, "../../../config");
2001
+ var MARKETS_CONFIG_FILE = import_path4.default.join(CONFIG_DIR, "markets.json");
2002
+ var MCP_SERVERS_CONFIG_FILE = import_path4.default.join(CONFIG_DIR, "mcpServers.json");
2003
+ var CACHE_TTL = 6 * 60 * 60 * 1e3;
2004
+ var BUILTIN_DEFAULT_MARKETS = [
2005
+ {
2006
+ name: "macopowers",
2007
+ source: "https://github.com/macopowers-dev/macopowers.git",
2008
+ description: "MacoPowers Official Plugin Marketplace",
2009
+ category: "official",
2010
+ recommended: true,
2011
+ default: true
2012
+ }
2013
+ ];
2014
+ var BUILTIN_DEFAULT_MCPS = [
2015
+ {
2016
+ id: "context7",
2017
+ name: "Context7",
2018
+ description: "Get real-time documentation and code examples for popular libraries like React, Next.js, Node.js",
2019
+ usage: 'Query the latest API docs, usage examples and best practices for any library in Claude. Example: "How to use Next.js 14 Server Actions?", "React useEffect latest usage".',
2020
+ transport: "http",
2021
+ url: "https://mcp.context7.com/mcp",
2022
+ headers: {
2023
+ CONTEXT7_API_KEY: "${CONTEXT7_API_KEY}"
2024
+ },
2025
+ requiredEnv: ["CONTEXT7_API_KEY"],
2026
+ apiKeyUrl: "https://context7.com/dashboard",
2027
+ category: "builtin",
2028
+ recommended: true,
2029
+ source: "local"
2030
+ }
2031
+ ];
2032
+
2033
+ // src/cli/utils/cache.ts
2034
+ var import_fs4 = __toESM(require("fs"));
2035
+ var import_os5 = __toESM(require("os"));
2036
+ var import_path5 = __toESM(require("path"));
2037
+ var CacheManager = class {
2038
+ cacheDir;
2039
+ cacheFile;
2040
+ constructor(cacheName) {
2041
+ this.cacheDir = import_path5.default.join(import_os5.default.homedir(), ".code-helper", "cache");
2042
+ this.cacheFile = import_path5.default.join(this.cacheDir, `${cacheName}.json`);
2043
+ this.ensureCacheDir();
2044
+ }
2045
+ /**
2046
+ * 加载缓存
2047
+ */
2048
+ load() {
2049
+ try {
2050
+ if (!import_fs4.default.existsSync(this.cacheFile)) {
2051
+ return null;
2052
+ }
2053
+ const content = import_fs4.default.readFileSync(this.cacheFile, "utf-8");
2054
+ return JSON.parse(content);
2055
+ } catch (error) {
2056
+ return null;
2057
+ }
2058
+ }
2059
+ /**
2060
+ * 保存缓存
2061
+ */
2062
+ save(data) {
2063
+ const cacheData = {
2064
+ data,
2065
+ timestamp: Date.now()
2066
+ };
2067
+ import_fs4.default.writeFileSync(this.cacheFile, JSON.stringify(cacheData, null, 2));
2068
+ }
2069
+ /**
2070
+ * 检查缓存是否过期
2071
+ */
2072
+ isExpired(ttl) {
2073
+ try {
2074
+ if (!import_fs4.default.existsSync(this.cacheFile)) {
2075
+ return true;
2076
+ }
2077
+ const content = import_fs4.default.readFileSync(this.cacheFile, "utf-8");
2078
+ const { timestamp } = JSON.parse(content);
2079
+ return Date.now() - timestamp > ttl;
2080
+ } catch (error) {
2081
+ return true;
2082
+ }
2083
+ }
2084
+ /**
2085
+ * 清除缓存
2086
+ */
2087
+ clear() {
2088
+ if (import_fs4.default.existsSync(this.cacheFile)) {
2089
+ import_fs4.default.unlinkSync(this.cacheFile);
2090
+ }
2091
+ }
2092
+ /**
2093
+ * 确保缓存目录存在
2094
+ */
2095
+ ensureCacheDir() {
2096
+ if (!import_fs4.default.existsSync(this.cacheDir)) {
2097
+ import_fs4.default.mkdirSync(this.cacheDir, { recursive: true });
2098
+ }
2099
+ }
2100
+ };
2101
+
2102
+ // src/cli/services/mcp.ts
2103
+ var CLAUDE_JSON_FILE = import_path6.default.join(import_os6.default.homedir(), ".claude.json");
2104
+ var McpService = class {
2105
+ cacheManager;
2106
+ constructor() {
2107
+ this.cacheManager = new CacheManager("mcp-servers");
2108
+ }
2109
+ /**
2110
+ * 获取所有 MCP 推荐列表(从本地配置文件读取)
2111
+ */
2112
+ async fetchMcpServers() {
2113
+ try {
2114
+ if (import_fs5.default.existsSync(MCP_SERVERS_CONFIG_FILE)) {
2115
+ const content = import_fs5.default.readFileSync(MCP_SERVERS_CONFIG_FILE, "utf-8");
2116
+ const data = JSON.parse(content);
2117
+ if (data.mcpServers && Array.isArray(data.mcpServers)) {
2118
+ const mcpServers = this.normalizeServers(data.mcpServers);
2119
+ return this.mergeServers(BUILTIN_DEFAULT_MCPS, mcpServers);
2120
+ }
2121
+ }
2122
+ showWarning("\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4 MCP \u914D\u7F6E");
2123
+ return BUILTIN_DEFAULT_MCPS;
2124
+ } catch (error) {
2125
+ showWarning("\u8BFB\u53D6 MCP \u914D\u7F6E\u6587\u4EF6\u5931\u8D25\uFF0C\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u914D\u7F6E");
2126
+ return BUILTIN_DEFAULT_MCPS;
2127
+ }
2128
+ }
2129
+ /**
2130
+ * 刷新 MCP 列表(清除缓存并重新获取)
2131
+ */
2132
+ async refreshMcpServers() {
2133
+ this.cacheManager.clear();
2134
+ return this.fetchMcpServers();
2135
+ }
2136
+ /**
2137
+ * 标准化 MCP 服务器数据
2138
+ */
2139
+ normalizeServers(rawServers) {
2140
+ return rawServers.map((server) => ({
2141
+ id: server.id,
2142
+ name: server.name,
2143
+ description: server.description,
2144
+ usage: server.usage,
2145
+ transport: server.transport || "stdio",
2146
+ // 默认 stdio 传输
2147
+ package: server.package,
2148
+ command: server.command,
2149
+ args: server.args || [],
2150
+ url: server.url,
2151
+ headers: server.headers,
2152
+ env: server.env,
2153
+ requiredEnv: server.requiredEnv,
2154
+ apiKeyUrl: server.apiKeyUrl,
2155
+ category: server.category || "remote",
2156
+ recommended: server.recommended || false,
2157
+ source: server.source || "marketplace"
2158
+ }));
2159
+ }
2160
+ /**
2161
+ * 合并本地和远程 MCP 列表(去重)
2162
+ */
2163
+ mergeServers(localServers, remoteServers) {
2164
+ const serverMap = /* @__PURE__ */ new Map();
2165
+ for (const server of localServers) {
2166
+ serverMap.set(server.id, server);
2167
+ }
2168
+ for (const server of remoteServers) {
2169
+ if (!serverMap.has(server.id)) {
2170
+ serverMap.set(server.id, server);
2171
+ }
2172
+ }
2173
+ return Array.from(serverMap.values());
2174
+ }
2175
+ /**
2176
+ * 降级处理
2177
+ */
2178
+ handleFallback(cached) {
2179
+ if (cached) {
2180
+ showWarning("\u4F7F\u7528\u7F13\u5B58\u7684 MCP \u5217\u8868\uFF08API \u6682\u65F6\u4E0D\u53EF\u7528\uFF09");
2181
+ return this.mergeServers(BUILTIN_DEFAULT_MCPS, cached.data.mcpServers);
2182
+ }
2183
+ showWarning("\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4 MCP \u914D\u7F6E");
2184
+ return BUILTIN_DEFAULT_MCPS;
2185
+ }
2186
+ /**
2187
+ * 读取 MCP 配置
2188
+ */
2189
+ readMcpConfig() {
2190
+ try {
2191
+ if (import_fs5.default.existsSync(CLAUDE_JSON_FILE)) {
2192
+ const content = import_fs5.default.readFileSync(CLAUDE_JSON_FILE, "utf-8");
2193
+ return JSON.parse(content);
2194
+ }
2195
+ } catch {
2196
+ }
2197
+ return { mcpServers: {} };
2198
+ }
2199
+ /**
2200
+ * 写入 MCP 配置
2201
+ */
2202
+ writeMcpConfig(config) {
2203
+ import_fs5.default.writeFileSync(
2204
+ CLAUDE_JSON_FILE,
2205
+ JSON.stringify(config, null, 2),
2206
+ "utf-8"
2207
+ );
2208
+ }
2209
+ /**
2210
+ * 获取已安装的 MCP 服务列表
2211
+ */
2212
+ getInstalledServers() {
2213
+ const config = this.readMcpConfig();
2214
+ return Object.keys(config.mcpServers || {});
2215
+ }
2216
+ /**
2217
+ * 检查 MCP 服务器是否已安装
2218
+ */
2219
+ isServerInstalled(serverId) {
2220
+ return this.getInstalledServers().includes(serverId);
2221
+ }
2222
+ /**
2223
+ * 安装单个 MCP 服务器
2224
+ * @param server MCP 服务器配置
2225
+ * @param userEnv 用户提供的环境变量(如 API Key)
2226
+ */
2227
+ installServer(server, userEnv) {
2228
+ const config = this.readMcpConfig();
2229
+ if (!config.mcpServers) {
2230
+ config.mcpServers = {};
2231
+ }
2232
+ if (server.transport === "http" || server.transport === "sse") {
2233
+ const headers = {};
2234
+ if (server.headers) {
2235
+ for (const [key, value] of Object.entries(server.headers)) {
2236
+ const match = value.match(/^\$\{(.+)\}$/);
2237
+ if (match && userEnv) {
2238
+ const varName = match[1];
2239
+ headers[key] = userEnv[varName] || value;
2240
+ } else {
2241
+ headers[key] = value;
2242
+ }
2243
+ }
2244
+ }
2245
+ config.mcpServers[server.id] = {
2246
+ transport: server.transport,
2247
+ url: server.url,
2248
+ ...Object.keys(headers).length > 0 ? { headers } : {}
2249
+ };
2250
+ } else {
2251
+ config.mcpServers[server.id] = {
2252
+ command: server.command,
2253
+ args: server.args,
2254
+ ...server.env || userEnv ? { env: { ...server.env, ...userEnv } } : {}
2255
+ };
2256
+ }
2257
+ this.writeMcpConfig(config);
2258
+ }
2259
+ /**
2260
+ * 卸载单个 MCP 服务器
2261
+ */
2262
+ uninstallServer(serverId) {
2263
+ const config = this.readMcpConfig();
2264
+ delete config.mcpServers[serverId];
2265
+ this.writeMcpConfig(config);
2266
+ }
2267
+ /**
2268
+ * 批量安装 MCP 服务器(不提示输入 API Key)
2269
+ */
2270
+ installServers(servers) {
2271
+ const config = this.readMcpConfig();
2272
+ if (!config.mcpServers) {
2273
+ config.mcpServers = {};
2274
+ }
2275
+ for (const server of servers) {
2276
+ if (server.transport === "http" || server.transport === "sse") {
2277
+ config.mcpServers[server.id] = {
2278
+ transport: server.transport,
2279
+ url: server.url,
2280
+ ...server.headers ? { headers: server.headers } : {}
2281
+ };
2282
+ } else {
2283
+ config.mcpServers[server.id] = {
2284
+ command: server.command,
2285
+ args: server.args,
2286
+ ...server.env ? { env: server.env } : {}
2287
+ };
2288
+ }
2289
+ }
2290
+ this.writeMcpConfig(config);
2291
+ }
2292
+ /**
2293
+ * 批量卸载 MCP 服务器
2294
+ */
2295
+ uninstallServers(serverIds) {
2296
+ const config = this.readMcpConfig();
2297
+ for (const serverId of serverIds) {
2298
+ delete config.mcpServers[serverId];
2299
+ }
2300
+ this.writeMcpConfig(config);
2301
+ }
2302
+ };
2303
+
2304
+ // src/cli/menus/mcp.ts
2305
+ var mcpService = new McpService();
2306
+ async function showMcpMenu() {
2307
+ showHeader();
2308
+ console.log(createBoxTitle("MCP \u670D\u52A1\u7BA1\u7406"));
2309
+ console.log();
2310
+ console.log();
2311
+ console.log(theme.info(" \u{1F680} \u656C\u8BF7\u671F\u5F85 \u{1F680}"));
2312
+ console.log();
2313
+ console.log(theme.dim(" MCP \u670D\u52A1\u7BA1\u7406\u529F\u80FD\u5373\u5C06\u4E0A\u7EBF"));
2314
+ console.log(theme.dim(" \u652F\u6301\u672C\u5730+\u4E91\u7AEF MCP \u670D\u52A1\u7BA1\u7406"));
2315
+ console.log(theme.dim(" \u656C\u8BF7\u671F\u5F85..."));
2316
+ console.log();
2317
+ console.log();
2318
+ await import_inquirer5.default.prompt([
2319
+ { type: "input", name: "continue", message: "\u6309\u56DE\u8F66\u952E\u8FD4\u56DE..." }
2320
+ ]);
2321
+ return;
2322
+ }
2323
+
2324
+ // src/cli/menus/plugins.ts
2325
+ var import_child_process4 = require("child_process");
2326
+ var import_fs7 = __toESM(require("fs"));
2327
+ var import_inquirer6 = __toESM(require("inquirer"));
2328
+ var import_ora6 = __toESM(require("ora"));
2329
+ var import_os8 = __toESM(require("os"));
2330
+ var import_path8 = __toESM(require("path"));
2331
+
2332
+ // src/cli/services/marketplace.ts
2333
+ var import_child_process3 = require("child_process");
2334
+ var import_fs6 = __toESM(require("fs"));
2335
+ var import_os7 = __toESM(require("os"));
2336
+ var import_path7 = __toESM(require("path"));
2337
+ var MarketplaceService = class {
2338
+ cacheManager;
2339
+ constructor() {
2340
+ this.cacheManager = new CacheManager("markets");
2341
+ }
2342
+ /**
2343
+ * 获取市场列表(从本地配置文件读取)
2344
+ */
2345
+ async fetchMarkets() {
2346
+ try {
2347
+ if (import_fs6.default.existsSync(MARKETS_CONFIG_FILE)) {
2348
+ const content = import_fs6.default.readFileSync(MARKETS_CONFIG_FILE, "utf-8");
2349
+ const data = JSON.parse(content);
2350
+ if (data.markets && Array.isArray(data.markets)) {
2351
+ return this.normalizeMarkets(data.markets);
2352
+ }
2353
+ }
2354
+ showWarning("\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u5E02\u573A\u914D\u7F6E");
2355
+ return BUILTIN_DEFAULT_MARKETS;
2356
+ } catch (error) {
2357
+ showWarning("\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25\uFF0C\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u5E02\u573A\u914D\u7F6E");
2358
+ return BUILTIN_DEFAULT_MARKETS;
2359
+ }
2360
+ }
2361
+ /**
2362
+ * 标准化市场数据(移除内部字段)
2363
+ */
2364
+ normalizeMarkets(rawMarkets) {
2365
+ return rawMarkets.map((market) => ({
2366
+ name: market.name,
2367
+ source: market.source,
2368
+ description: market.description,
2369
+ category: market.category,
2370
+ recommended: market.recommended || false,
2371
+ default: market.default || false
2372
+ }));
2373
+ }
2374
+ /**
2375
+ * 获取已安装的市场列表
2376
+ */
2377
+ async getInstalledMarkets() {
2378
+ try {
2379
+ const output = this.execClaude("plugin marketplace list");
2380
+ return this.parseMarketplaceList(output);
2381
+ } catch (error) {
2382
+ return [];
2383
+ }
2384
+ }
2385
+ /**
2386
+ * 检查市场是否已安装(通过源地址或名称匹配)
2387
+ */
2388
+ async isMarketInstalled(marketSource, marketName) {
2389
+ const installed = await this.getInstalledMarkets();
2390
+ const normalizedSource = marketSource.replace(/\.git$/, "");
2391
+ return installed.some((m) => {
2392
+ if (m.source) {
2393
+ const normalizedInstalled = m.source.replace(/\.git$/, "");
2394
+ if (normalizedInstalled === normalizedSource) {
2395
+ return true;
2396
+ }
2397
+ if (marketName && normalizedInstalled.includes(marketName)) {
2398
+ return true;
2399
+ }
2400
+ }
2401
+ if (marketName) {
2402
+ const baseMarketName = marketName.replace(/-dev$/, "");
2403
+ const baseInstalledName = m.name.replace(/-dev$/, "");
2404
+ if (baseMarketName === baseInstalledName) {
2405
+ return true;
2406
+ }
2407
+ }
2408
+ return false;
2409
+ });
2410
+ }
2411
+ /**
2412
+ * 根据源地址或名称获取已安装市场的名称
2413
+ */
2414
+ async getInstalledMarketName(marketSource, marketName) {
2415
+ const installed = await this.getInstalledMarkets();
2416
+ const normalizedSource = marketSource.replace(/\.git$/, "");
2417
+ const found = installed.find((m) => {
2418
+ if (m.source) {
2419
+ const normalizedInstalled = m.source.replace(/\.git$/, "");
2420
+ if (normalizedInstalled === normalizedSource) {
2421
+ return true;
2422
+ }
2423
+ if (marketName && normalizedInstalled.includes(marketName)) {
2424
+ return true;
2425
+ }
2426
+ }
2427
+ if (marketName) {
2428
+ const baseMarketName = marketName.replace(/-dev$/, "");
2429
+ const baseInstalledName = m.name.replace(/-dev$/, "");
2430
+ if (baseMarketName === baseInstalledName) {
2431
+ return true;
2432
+ }
2433
+ }
2434
+ return false;
2435
+ });
2436
+ return found ? found.name : null;
2437
+ }
2438
+ /**
2439
+ * 添加市场
2440
+ */
2441
+ async addMarket(market) {
2442
+ try {
2443
+ this.execClaude(`plugin marketplace add "${market.source}"`);
2444
+ return true;
2445
+ } catch (error) {
2446
+ if (error.message.includes("already exists") || error.message.includes("already configured") || error.message.includes("already installed")) {
2447
+ return true;
2448
+ }
2449
+ throw error;
2450
+ }
2451
+ }
2452
+ /**
2453
+ * 从市场获取插件列表(带版本和更新检测)
2454
+ */
2455
+ async getMarketPlugins(marketName) {
2456
+ try {
2457
+ const marketplacePath = this.getMarketplacePath(marketName);
2458
+ const manifestPath = import_path7.default.join(
2459
+ marketplacePath,
2460
+ ".claude-plugin",
2461
+ "marketplace.json"
2462
+ );
2463
+ if (!import_fs6.default.existsSync(manifestPath)) {
2464
+ return [];
2465
+ }
2466
+ const manifest = JSON.parse(import_fs6.default.readFileSync(manifestPath, "utf-8"));
2467
+ if (!manifest.plugins || !Array.isArray(manifest.plugins)) {
2468
+ return [];
2469
+ }
2470
+ const installedVersions = await this.getInstalledPluginVersions();
2471
+ return manifest.plugins.map((plugin) => {
2472
+ const pluginFullId = `${plugin.name}@${marketName}`;
2473
+ const installedVersion = installedVersions.get(pluginFullId);
2474
+ const marketVersion = plugin.version || "1.0.0";
2475
+ return {
2476
+ id: plugin.name,
2477
+ name: plugin.name.charAt(0).toUpperCase() + plugin.name.slice(1),
2478
+ description: plugin.description,
2479
+ marketplace: marketName,
2480
+ category: plugin.category || "development",
2481
+ recommended: true,
2482
+ version: marketVersion,
2483
+ installedVersion,
2484
+ hasUpdate: installedVersion ? this.compareVersions(marketVersion, installedVersion) > 0 : false
2485
+ };
2486
+ });
2487
+ } catch (error) {
2488
+ console.error("\u8BFB\u53D6\u5E02\u573A\u63D2\u4EF6\u5217\u8868\u5931\u8D25:", error);
2489
+ return [];
2490
+ }
2491
+ }
2492
+ /**
2493
+ * 获取已安装插件的版本信息
2494
+ */
2495
+ async getInstalledPluginVersions() {
2496
+ const versions = /* @__PURE__ */ new Map();
2497
+ try {
2498
+ const output = this.execClaude("plugin list --json");
2499
+ const data = JSON.parse(output);
2500
+ if (data.installed && Array.isArray(data.installed)) {
2501
+ for (const plugin of data.installed) {
2502
+ versions.set(plugin.id, plugin.version);
2503
+ }
2504
+ }
2505
+ } catch (error) {
2506
+ }
2507
+ return versions;
2508
+ }
2509
+ /**
2510
+ * 比较版本号
2511
+ * @returns >0 如果 v1 > v2, =0 如果相等, <0 如果 v1 < v2
2512
+ */
2513
+ compareVersions(v1, v2) {
2514
+ const parts1 = v1.split(".").map(Number);
2515
+ const parts2 = v2.split(".").map(Number);
2516
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
2517
+ const num1 = parts1[i] || 0;
2518
+ const num2 = parts2[i] || 0;
2519
+ if (num1 > num2) return 1;
2520
+ if (num1 < num2) return -1;
2521
+ }
2522
+ return 0;
2523
+ }
2524
+ /**
2525
+ * 刷新市场列表(清除缓存并重新获取)
2526
+ */
2527
+ async refreshMarkets() {
2528
+ this.cacheManager.clear();
2529
+ return this.fetchMarkets();
2530
+ }
2531
+ /**
2532
+ * 更新单个市场
2533
+ */
2534
+ async updateMarket(marketName) {
2535
+ try {
2536
+ this.execClaude(`plugin marketplace update "${marketName}"`);
2537
+ return true;
2538
+ } catch (error) {
2539
+ throw new Error(`\u66F4\u65B0\u5E02\u573A\u5931\u8D25: ${error.message}`);
2540
+ }
2541
+ }
2542
+ /**
2543
+ * 更新所有市场
2544
+ */
2545
+ async updateAllMarkets() {
2546
+ try {
2547
+ this.execClaude("plugin marketplace update");
2548
+ return true;
2549
+ } catch (error) {
2550
+ throw new Error(`\u66F4\u65B0\u6240\u6709\u5E02\u573A\u5931\u8D25: ${error.message}`);
2551
+ }
2552
+ }
2553
+ /**
2554
+ * 更新单个插件
2555
+ */
2556
+ async updatePlugin(pluginName) {
2557
+ try {
2558
+ this.execClaude(`plugin update "${pluginName}"`);
2559
+ return true;
2560
+ } catch (error) {
2561
+ throw new Error(`\u66F4\u65B0\u63D2\u4EF6\u5931\u8D25: ${error.message}`);
2562
+ }
2563
+ }
2564
+ /**
2565
+ * 降级处理
2566
+ */
2567
+ handleFallback(cached) {
2568
+ if (cached) {
2569
+ showWarning("\u4F7F\u7528\u7F13\u5B58\u7684\u5E02\u573A\u5217\u8868\uFF08API \u6682\u65F6\u4E0D\u53EF\u7528\uFF09");
2570
+ return cached.data.markets;
2571
+ }
2572
+ showWarning("\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u5E02\u573A\u914D\u7F6E");
2573
+ return BUILTIN_DEFAULT_MARKETS;
2574
+ }
2575
+ /**
2576
+ * 解析 marketplace list 输出
2577
+ */
2578
+ parseMarketplaceList(output) {
2579
+ const markets = [];
2580
+ const lines = output.split("\n");
2581
+ let currentMarket = null;
2582
+ for (const line of lines) {
2583
+ const trimmed = line.trim();
2584
+ if (trimmed.startsWith("\u276F ")) {
2585
+ if (currentMarket) {
2586
+ markets.push(currentMarket);
2587
+ }
2588
+ const name = trimmed.substring(2).trim();
2589
+ currentMarket = { name };
2590
+ } else if (currentMarket && trimmed.startsWith("Source:")) {
2591
+ const match = trimmed.match(/Source:\s+\w+\s+\((.+)\)/);
2592
+ if (match) {
2593
+ currentMarket.source = match[1];
2594
+ }
2595
+ }
2596
+ }
2597
+ if (currentMarket) {
2598
+ markets.push(currentMarket);
2599
+ }
2600
+ return markets;
2601
+ }
2602
+ /**
2603
+ * 获取市场仓库路径
2604
+ */
2605
+ getMarketplacePath(marketName) {
2606
+ return import_path7.default.join(
2607
+ import_os7.default.homedir(),
2608
+ ".claude",
2609
+ "plugins",
2610
+ "marketplaces",
2611
+ marketName
2612
+ );
2613
+ }
2614
+ /**
2615
+ * 执行 Claude 命令
2616
+ */
2617
+ execClaude(command) {
2618
+ try {
2619
+ return (0, import_child_process3.execSync)(`claude ${command}`, {
2620
+ encoding: "utf-8",
2621
+ stdio: ["pipe", "pipe", "pipe"]
2622
+ });
2623
+ } catch (error) {
2624
+ throw new Error(`\u6267\u884C\u547D\u4EE4\u5931\u8D25: ${error.message}
2625
+ ${error.stderr || ""}`);
2626
+ }
2627
+ }
2628
+ };
2629
+
2630
+ // src/cli/menus/plugins.ts
2631
+ function execClaude(command) {
2632
+ try {
2633
+ return (0, import_child_process4.execSync)(`claude ${command}`, {
2634
+ encoding: "utf-8",
2635
+ stdio: ["pipe", "pipe", "pipe"]
2636
+ });
2637
+ } catch (error) {
2638
+ throw new Error(`\u6267\u884C\u547D\u4EE4\u5931\u8D25: ${error.message}
2639
+ ${error.stderr || ""}`);
2640
+ }
2641
+ }
2642
+ var marketplaceService = new MarketplaceService();
2643
+ function getInstalledPlugins() {
2644
+ try {
2645
+ const output = execClaude("plugin list");
2646
+ const plugins = [];
2647
+ const lines = output.split("\n");
2648
+ let currentPlugin = {};
2649
+ for (const line of lines) {
2650
+ const trimmed = line.trim();
2651
+ if (trimmed.startsWith("\u276F ")) {
2652
+ if (currentPlugin.name) {
2653
+ plugins.push(currentPlugin);
2654
+ }
2655
+ currentPlugin = { name: trimmed.substring(2).trim() };
2656
+ } else if (trimmed.startsWith("Version:")) {
2657
+ currentPlugin.version = trimmed.substring(8).trim();
2658
+ } else if (trimmed.startsWith("Status:")) {
2659
+ currentPlugin.enabled = trimmed.includes("enabled");
2660
+ }
2661
+ }
2662
+ if (currentPlugin.name) {
2663
+ plugins.push(currentPlugin);
2664
+ }
2665
+ return plugins;
2666
+ } catch (error) {
2667
+ return [];
2668
+ }
2669
+ }
2670
+ function getPluginStatus(pluginFullName, installedPlugins) {
2671
+ const installed = installedPlugins.find((p) => p.name === pluginFullName);
2672
+ if (!installed) return "not_installed";
2673
+ return installed.enabled ? "enabled" : "disabled";
2674
+ }
2675
+ function getStatusText(status) {
2676
+ switch (status) {
2677
+ case "not_installed":
2678
+ return theme.dim("[\u672A\u5B89\u88C5]");
2679
+ case "enabled":
2680
+ return theme.success("[\u5DF2\u542F\u7528]");
2681
+ case "disabled":
2682
+ return theme.warning("[\u5DF2\u7981\u7528]");
2683
+ }
2684
+ }
2685
+ async function ensureDefaultMarkets(markets) {
2686
+ for (const market of markets) {
2687
+ if (market.default) {
2688
+ const isInstalled = await marketplaceService.isMarketInstalled(
2689
+ market.source,
2690
+ market.name
2691
+ );
2692
+ if (!isInstalled) {
2693
+ try {
2694
+ await marketplaceService.addMarket(market);
2695
+ } catch (error) {
2696
+ }
2697
+ }
2698
+ }
2699
+ }
2700
+ }
2701
+ async function showPluginsMenu() {
2702
+ const spinner = (0, import_ora6.default)("\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6\u5E02\u573A...").start();
2703
+ const markets = await marketplaceService.fetchMarkets();
2704
+ await ensureDefaultMarkets(markets);
2705
+ const installedMarkets = await marketplaceService.getInstalledMarkets();
2706
+ spinner.stop();
2707
+ while (true) {
2708
+ showHeader();
2709
+ console.log(createBoxTitle("\u63D2\u4EF6\u5E02\u573A"));
2710
+ console.log();
2711
+ console.log(theme.primary("\u{1F4E6} \u53EF\u7528\u5E02\u573A\uFF1A"));
2712
+ console.log();
2713
+ console.log(theme.dim("\u2191\u2193 \u9009\u62E9 | Enter \u786E\u8BA4"));
2714
+ console.log();
2715
+ const marketChoices = markets.map((market) => {
2716
+ const isInstalled = installedMarkets.some((m) => {
2717
+ if (m.source) {
2718
+ const normalizedSource = market.source.replace(/\.git$/, "");
2719
+ const normalizedInstalled = m.source.replace(/\.git$/, "");
2720
+ if (normalizedInstalled === normalizedSource) {
2721
+ return true;
2722
+ }
2723
+ if (normalizedInstalled.includes(market.name)) {
2724
+ return true;
2725
+ }
2726
+ }
2727
+ const baseMarketName = market.name.replace(/-dev$/, "");
2728
+ const baseInstalledName = m.name.replace(/-dev$/, "");
2729
+ return baseMarketName === baseInstalledName;
2730
+ });
2731
+ const statusIcon = isInstalled ? theme.success("\u2713") : theme.dim("\u2022");
2732
+ const categoryLabel = getCategoryLabel(market.category);
2733
+ return {
2734
+ name: ` ${statusIcon} [${categoryLabel}] ${market.name} - ${theme.dim(
2735
+ market.description
2736
+ )}`,
2737
+ value: { type: "market", market }
2738
+ };
2739
+ });
2740
+ const choices = [
2741
+ ...marketChoices,
2742
+ new import_inquirer6.default.Separator(),
2743
+ {
2744
+ name: ` ${theme.info("\u{1F504}")} \u5237\u65B0\u5E02\u573A\u5217\u8868`,
2745
+ value: { type: "refresh" }
2746
+ },
2747
+ {
2748
+ name: ` ${theme.info("\u2B06\uFE0F")} \u66F4\u65B0\u6240\u6709\u5E02\u573A`,
2749
+ value: { type: "update_all_markets" }
2750
+ },
2751
+ new import_inquirer6.default.Separator(),
2752
+ {
2753
+ name: ` ${theme.dim("<-")} \u8FD4\u56DE`,
2754
+ value: { type: "back" }
2755
+ },
2756
+ {
2757
+ name: ` ${theme.dim("X")} \u9000\u51FA`,
2758
+ value: { type: "exit" }
2759
+ }
2760
+ ];
2761
+ const { selection } = await import_inquirer6.default.prompt([
2762
+ {
2763
+ type: "list",
2764
+ name: "selection",
2765
+ message: "\u8BF7\u9009\u62E9\u5E02\u573A\uFF1A",
2766
+ pageSize: 15,
2767
+ choices
2768
+ }
2769
+ ]);
2770
+ if (selection.type === "back") {
2771
+ return;
2772
+ }
2773
+ if (selection.type === "exit") {
2774
+ process.exit(0);
2775
+ }
2776
+ if (selection.type === "refresh") {
2777
+ const refreshSpinner = (0, import_ora6.default)("\u6B63\u5728\u5237\u65B0\u5E02\u573A\u5217\u8868...").start();
2778
+ const newMarkets = await marketplaceService.refreshMarkets();
2779
+ markets.length = 0;
2780
+ markets.push(...newMarkets);
2781
+ refreshSpinner.succeed("\u5E02\u573A\u5217\u8868\u5DF2\u5237\u65B0");
2782
+ await new Promise((resolve) => {
2783
+ setTimeout(() => resolve(), 800);
2784
+ });
2785
+ continue;
2786
+ }
2787
+ if (selection.type === "update_all_markets") {
2788
+ const updateSpinner = (0, import_ora6.default)("\u6B63\u5728\u66F4\u65B0\u6240\u6709\u5E02\u573A...").start();
2789
+ try {
2790
+ await marketplaceService.updateAllMarkets();
2791
+ updateSpinner.succeed("\u6240\u6709\u5E02\u573A\u5DF2\u66F4\u65B0");
2792
+ await new Promise((resolve) => {
2793
+ setTimeout(() => resolve(), 1e3);
2794
+ });
2795
+ } catch (error) {
2796
+ updateSpinner.fail(`\u66F4\u65B0\u5931\u8D25: ${error.message}`);
2797
+ await new Promise((resolve) => {
2798
+ setTimeout(() => resolve(), 1500);
2799
+ });
2800
+ }
2801
+ continue;
2802
+ }
2803
+ if (selection.type === "market") {
2804
+ await showMarketPlugins(selection.market);
2805
+ }
2806
+ }
2807
+ }
2808
+ function getCategoryLabel(category) {
2809
+ switch (category) {
2810
+ case "official":
2811
+ return theme.success("\u5B98\u65B9");
2812
+ case "team":
2813
+ return theme.info("\u56E2\u961F");
2814
+ case "experimental":
2815
+ return theme.warning("\u5B9E\u9A8C");
2816
+ default:
2817
+ return theme.dim("\u5176\u4ED6");
2818
+ }
2819
+ }
2820
+ async function showMarketPlugins(market) {
2821
+ const isInstalled = await marketplaceService.isMarketInstalled(
2822
+ market.source,
2823
+ market.name
2824
+ );
2825
+ if (!isInstalled) {
2826
+ const addSpinner = (0, import_ora6.default)("\u6B63\u5728\u6DFB\u52A0\u5E02\u573A...").start();
2827
+ try {
2828
+ await marketplaceService.addMarket(market);
2829
+ addSpinner.succeed("\u5E02\u573A\u6DFB\u52A0\u6210\u529F");
2830
+ } catch (error) {
2831
+ addSpinner.fail(`\u5E02\u573A\u6DFB\u52A0\u5931\u8D25: ${error.message}`);
2832
+ await new Promise((resolve) => {
2833
+ setTimeout(() => resolve(), 2e3);
2834
+ });
2835
+ return;
2836
+ }
2837
+ await new Promise((resolve) => {
2838
+ setTimeout(() => resolve(), 800);
2839
+ });
2840
+ }
2841
+ const installedMarketName = await marketplaceService.getInstalledMarketName(
2842
+ market.source,
2843
+ market.name
2844
+ );
2845
+ if (!installedMarketName) {
2846
+ showWarning("\u65E0\u6CD5\u627E\u5230\u5DF2\u5B89\u88C5\u7684\u5E02\u573A");
2847
+ return;
2848
+ }
2849
+ const loadingSpinner = (0, import_ora6.default)("\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6\u5217\u8868...").start();
2850
+ const marketplacePlugins = await marketplaceService.getMarketPlugins(
2851
+ installedMarketName
2852
+ );
2853
+ let installedPlugins = getInstalledPlugins();
2854
+ loadingSpinner.stop();
2855
+ while (true) {
2856
+ showHeader();
2857
+ console.log(createBoxTitle(`${market.name} \u63D2\u4EF6\u5E02\u573A`));
2858
+ console.log();
2859
+ console.log(`${theme.dim("\u63CF\u8FF0:")} ${market.description}`);
2860
+ console.log(`${theme.dim("\u6E90\u5730\u5740:")} ${market.source}`);
2861
+ console.log();
2862
+ console.log(theme.primary("\u{1F4E6} \u53EF\u7528\u63D2\u4EF6\uFF1A"));
2863
+ console.log();
2864
+ console.log(theme.dim("\u2191\u2193 \u9009\u62E9 | Enter \u786E\u8BA4"));
2865
+ console.log();
2866
+ const pluginStatuses = /* @__PURE__ */ new Map();
2867
+ for (const p of marketplacePlugins) {
2868
+ const pluginFullName = `${p.id}@${p.marketplace}`;
2869
+ pluginStatuses.set(
2870
+ pluginFullName,
2871
+ getPluginStatus(pluginFullName, installedPlugins)
2872
+ );
2873
+ }
2874
+ const pluginChoices = marketplacePlugins.map((p) => {
2875
+ const pluginFullName = `${p.id}@${p.marketplace}`;
2876
+ const status = pluginStatuses.get(pluginFullName);
2877
+ const statusText = getStatusText(status);
2878
+ const updateBadge = p.hasUpdate ? theme.warning(" (\u6709\u66F4\u65B0)") : "";
2879
+ return {
2880
+ name: ` ${statusText} ${p.name}${updateBadge} - ${theme.dim(
2881
+ p.description
2882
+ )}`,
2883
+ value: { type: "plugin", plugin: p, status }
2884
+ };
2885
+ });
2886
+ const hasUpdatablePlugins = marketplacePlugins.some(
2887
+ (p) => p.hasUpdate && pluginStatuses.get(`${p.id}@${p.marketplace}`) !== "not_installed"
2888
+ );
2889
+ const choices = [
2890
+ ...pluginChoices,
2891
+ new import_inquirer6.default.Separator(),
2892
+ {
2893
+ name: ` ${theme.success("\u26A1")} \u4E00\u952E\u5B89\u88C5\u5168\u90E8`,
2894
+ value: { type: "install_all" }
2895
+ },
2896
+ ...hasUpdatablePlugins ? [
2897
+ {
2898
+ name: ` ${theme.info("\u2B06\uFE0F")} \u66F4\u65B0\u6240\u6709\u5DF2\u5B89\u88C5\u63D2\u4EF6`,
2899
+ value: { type: "update_all_plugins" }
2900
+ }
2901
+ ] : [],
2902
+ {
2903
+ name: ` ${theme.info("\u{1F504}")} \u66F4\u65B0\u6B64\u5E02\u573A`,
2904
+ value: { type: "update_market" }
2905
+ },
2906
+ new import_inquirer6.default.Separator(),
2907
+ {
2908
+ name: ` ${theme.dim("<-")} \u8FD4\u56DE`,
2909
+ value: { type: "back" }
2910
+ },
2911
+ {
2912
+ name: ` ${theme.dim("X")} \u9000\u51FA`,
2913
+ value: { type: "exit" }
2914
+ }
2915
+ ];
2916
+ const { selection } = await import_inquirer6.default.prompt([
2917
+ {
2918
+ type: "list",
2919
+ name: "selection",
2920
+ message: "\u8BF7\u9009\u62E9\u63D2\u4EF6\uFF1A",
2921
+ pageSize: 15,
2922
+ choices
2923
+ }
2924
+ ]);
2925
+ if (selection.type === "back") {
2926
+ return;
2927
+ }
2928
+ if (selection.type === "exit") {
2929
+ process.exit(0);
2930
+ }
2931
+ if (selection.type === "install_all") {
2932
+ await handleInstallAll(marketplacePlugins);
2933
+ installedPlugins = getInstalledPlugins();
2934
+ continue;
2935
+ }
2936
+ if (selection.type === "update_all_plugins") {
2937
+ const updateSpinner = (0, import_ora6.default)("\u6B63\u5728\u66F4\u65B0\u6240\u6709\u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6...").start();
2938
+ try {
2939
+ const pluginsToUpdate = marketplacePlugins.filter(
2940
+ (p) => p.hasUpdate && pluginStatuses.get(`${p.id}@${p.marketplace}`) !== "not_installed"
2941
+ );
2942
+ for (const plugin of pluginsToUpdate) {
2943
+ const pluginFullName = `${plugin.id}@${plugin.marketplace}`;
2944
+ updateSpinner.text = `\u6B63\u5728\u66F4\u65B0 ${plugin.name}...`;
2945
+ await marketplaceService.updatePlugin(pluginFullName);
2946
+ }
2947
+ updateSpinner.succeed("\u6240\u6709\u63D2\u4EF6\u5DF2\u66F4\u65B0");
2948
+ await new Promise((resolve) => {
2949
+ setTimeout(() => resolve(), 1e3);
2950
+ });
2951
+ installedPlugins = getInstalledPlugins();
2952
+ } catch (error) {
2953
+ updateSpinner.fail(`\u66F4\u65B0\u5931\u8D25: ${error.message}`);
2954
+ await new Promise((resolve) => {
2955
+ setTimeout(() => resolve(), 1500);
2956
+ });
2957
+ }
2958
+ continue;
2959
+ }
2960
+ if (selection.type === "update_market") {
2961
+ const updateSpinner = (0, import_ora6.default)(`\u6B63\u5728\u66F4\u65B0\u5E02\u573A ${market.name}...`).start();
2962
+ try {
2963
+ await marketplaceService.updateMarket(installedMarketName);
2964
+ updateSpinner.succeed("\u5E02\u573A\u5DF2\u66F4\u65B0");
2965
+ await new Promise((resolve) => {
2966
+ setTimeout(() => resolve(), 1e3);
2967
+ });
2968
+ const updatedPlugins = await marketplaceService.getMarketPlugins(
2969
+ installedMarketName
2970
+ );
2971
+ marketplacePlugins.length = 0;
2972
+ marketplacePlugins.push(...updatedPlugins);
2973
+ installedPlugins = getInstalledPlugins();
2974
+ } catch (error) {
2975
+ updateSpinner.fail(`\u66F4\u65B0\u5931\u8D25: ${error.message}`);
2976
+ await new Promise((resolve) => {
2977
+ setTimeout(() => resolve(), 1500);
2978
+ });
2979
+ }
2980
+ continue;
2981
+ }
2982
+ if (selection.type === "plugin") {
2983
+ await showPluginDetail(selection.plugin, selection.status);
2984
+ installedPlugins = getInstalledPlugins();
2985
+ }
2986
+ }
2987
+ }
2988
+ async function showPluginDetail(plugin, initialStatus) {
2989
+ const pluginFullName = `${plugin.id}@${plugin.marketplace}`;
2990
+ let needRefresh = true;
2991
+ let currentStatus = initialStatus;
2992
+ while (true) {
2993
+ showHeader();
2994
+ console.log(createBoxTitle(`\u63D2\u4EF6\u8BE6\u60C5\uFF1A${plugin.id}`));
2995
+ console.log();
2996
+ console.log(` ${theme.primary("\u540D\u79F0\uFF1A")} ${plugin.name}`);
2997
+ console.log(
2998
+ ` ${theme.primary("\u5206\u7C7B\uFF1A")} ${theme.info(
2999
+ plugin.category || "development"
3000
+ )}`
3001
+ );
3002
+ console.log(` ${theme.primary("\u63CF\u8FF0\uFF1A")} ${plugin.description}`);
3003
+ console.log();
3004
+ if (needRefresh) {
3005
+ const spinner = (0, import_ora6.default)("\u6B63\u5728\u83B7\u53D6\u63D2\u4EF6\u72B6\u6001...").start();
3006
+ const installedPlugins = getInstalledPlugins();
3007
+ currentStatus = getPluginStatus(pluginFullName, installedPlugins);
3008
+ spinner.stop();
3009
+ needRefresh = false;
3010
+ }
3011
+ const status = currentStatus;
3012
+ if (status === "not_installed") {
3013
+ console.log(` ${theme.primary("\u72B6\u6001\uFF1A")} ${theme.dim("[\u672A\u5B89\u88C5]")}`);
3014
+ } else {
3015
+ console.log(` ${theme.primary("\u72B6\u6001\uFF1A")} ${theme.success("[\u5DF2\u5B89\u88C5]")}`);
3016
+ if (plugin.installedVersion) {
3017
+ console.log(
3018
+ ` ${theme.primary("\u5F53\u524D\u7248\u672C\uFF1A")} ${plugin.installedVersion}`
3019
+ );
3020
+ }
3021
+ if (plugin.version) {
3022
+ console.log(` ${theme.primary("\u5E02\u573A\u7248\u672C\uFF1A")} ${plugin.version}`);
3023
+ }
3024
+ if (plugin.hasUpdate) {
3025
+ console.log(` ${theme.warning("\u2B06\uFE0F \u6709\u65B0\u7248\u672C\u53EF\u7528")}`);
3026
+ }
3027
+ console.log(
3028
+ ` ${theme.primary("\u542F\u7528\u72B6\u6001\uFF1A")} ${status === "enabled" ? theme.success("[\u5DF2\u542F\u7528]") : theme.warning("[\u5DF2\u7981\u7528]")}`
3029
+ );
3030
+ }
3031
+ console.log();
3032
+ console.log(theme.dim("\u2191\u2193 \u9009\u62E9 | Enter \u786E\u8BA4"));
3033
+ console.log();
3034
+ let actionChoices = [];
3035
+ if (status === "not_installed") {
3036
+ actionChoices = [
3037
+ {
3038
+ name: ` ${theme.success(">")} \u5B89\u88C5\u63D2\u4EF6`,
3039
+ value: "install"
3040
+ }
3041
+ ];
3042
+ } else if (status === "enabled") {
3043
+ actionChoices = [
3044
+ ...plugin.hasUpdate ? [
3045
+ {
3046
+ name: ` ${theme.info("\u2B06\uFE0F")} \u66F4\u65B0\u63D2\u4EF6`,
3047
+ value: "update"
3048
+ }
3049
+ ] : [],
3050
+ {
3051
+ name: ` ${theme.warning(">")} \u7981\u7528\u63D2\u4EF6`,
3052
+ value: "disable"
3053
+ },
3054
+ {
3055
+ name: ` ${theme.error("*")} \u5378\u8F7D\u63D2\u4EF6`,
3056
+ value: "uninstall"
3057
+ }
3058
+ ];
3059
+ } else if (status === "disabled") {
3060
+ actionChoices = [
3061
+ ...plugin.hasUpdate ? [
3062
+ {
3063
+ name: ` ${theme.info("\u2B06\uFE0F")} \u66F4\u65B0\u63D2\u4EF6`,
3064
+ value: "update"
3065
+ }
3066
+ ] : [],
3067
+ {
3068
+ name: ` ${theme.success(">")} \u542F\u7528\u63D2\u4EF6`,
3069
+ value: "enable"
3070
+ },
3071
+ {
3072
+ name: ` ${theme.error("*")} \u5378\u8F7D\u63D2\u4EF6`,
3073
+ value: "uninstall"
3074
+ }
3075
+ ];
3076
+ }
3077
+ const choices = [
3078
+ ...actionChoices,
3079
+ new import_inquirer6.default.Separator(),
3080
+ {
3081
+ name: ` ${theme.dim("<-")} \u8FD4\u56DE`,
3082
+ value: "back"
3083
+ },
3084
+ {
3085
+ name: ` ${theme.dim("X")} \u9000\u51FA`,
3086
+ value: "exit"
3087
+ }
3088
+ ];
3089
+ const { action } = await import_inquirer6.default.prompt([
3090
+ {
3091
+ type: "list",
3092
+ name: "action",
3093
+ message: "\u8BF7\u9009\u62E9\u64CD\u4F5C\uFF1A",
3094
+ pageSize: 10,
3095
+ choices
3096
+ }
3097
+ ]);
3098
+ if (action === "back") {
3099
+ return;
3100
+ }
3101
+ if (action === "exit") {
3102
+ process.exit(0);
3103
+ }
3104
+ await executePluginAction(action, plugin, pluginFullName);
3105
+ needRefresh = true;
3106
+ }
3107
+ }
3108
+ async function executePluginAction(action, plugin, pluginFullName) {
3109
+ const spinner = (0, import_ora6.default)();
3110
+ try {
3111
+ switch (action) {
3112
+ case "install":
3113
+ console.log();
3114
+ console.log(`$ claude plugin install ${pluginFullName}`);
3115
+ spinner.start(`${theme.success("+")} \u6B63\u5728\u5B89\u88C5\u63D2\u4EF6...`);
3116
+ execClaude(`plugin install ${pluginFullName}`);
3117
+ spinner.succeed(`${theme.success("+")} \u63D2\u4EF6\u5B89\u88C5\u6210\u529F`);
3118
+ break;
3119
+ case "enable":
3120
+ console.log();
3121
+ console.log(`$ claude plugin enable ${pluginFullName}`);
3122
+ spinner.start(`${theme.success("+")} \u6B63\u5728\u542F\u7528\u63D2\u4EF6...`);
3123
+ execClaude(`plugin enable ${pluginFullName}`);
3124
+ spinner.succeed(`${theme.success("+")} \u63D2\u4EF6\u5DF2\u542F\u7528`);
3125
+ break;
3126
+ case "disable":
3127
+ console.log();
3128
+ console.log(`$ claude plugin disable ${pluginFullName}`);
3129
+ spinner.start(`${theme.warning("*")} \u6B63\u5728\u7981\u7528\u63D2\u4EF6...`);
3130
+ execClaude(`plugin disable ${pluginFullName}`);
3131
+ spinner.succeed(`${theme.warning("*")} \u63D2\u4EF6\u5DF2\u7981\u7528`);
3132
+ break;
3133
+ case "update":
3134
+ console.log();
3135
+ console.log(`$ claude plugin update ${pluginFullName}`);
3136
+ spinner.start(`${theme.info("\u2B06\uFE0F")} \u6B63\u5728\u66F4\u65B0\u63D2\u4EF6...`);
3137
+ await marketplaceService.updatePlugin(pluginFullName);
3138
+ spinner.succeed(`${theme.success("\u2B06\uFE0F")} \u63D2\u4EF6\u5DF2\u66F4\u65B0`);
3139
+ break;
3140
+ case "uninstall": {
3141
+ console.log();
3142
+ const { confirm } = await import_inquirer6.default.prompt([
3143
+ {
3144
+ type: "confirm",
3145
+ name: "confirm",
3146
+ message: `\u786E\u5B9A\u8981\u5378\u8F7D\u63D2\u4EF6 "${plugin.name}" \u5417\uFF1F`,
3147
+ default: false
3148
+ }
3149
+ ]);
3150
+ if (confirm) {
3151
+ console.log(`$ claude plugin uninstall ${pluginFullName}`);
3152
+ spinner.start(`${theme.error("-")} \u6B63\u5728\u5378\u8F7D\u63D2\u4EF6...`);
3153
+ let uninstalled = false;
3154
+ const scopes = ["user", "project", "local"];
3155
+ for (const scope of scopes) {
3156
+ try {
3157
+ execClaude(`plugin uninstall ${pluginFullName} --scope ${scope}`);
3158
+ uninstalled = true;
3159
+ break;
3160
+ } catch (e) {
3161
+ if (!e.message.includes("scope")) {
3162
+ throw e;
3163
+ }
3164
+ }
3165
+ }
3166
+ if (uninstalled) {
3167
+ spinner.succeed(`${theme.error("-")} \u63D2\u4EF6\u5DF2\u5378\u8F7D`);
3168
+ } else {
3169
+ spinner.fail("CLI \u5378\u8F7D\u5931\u8D25");
3170
+ console.log();
3171
+ showWarning("Claude CLI \u65E0\u6CD5\u5378\u8F7D\u6B64\u63D2\u4EF6\uFF08\u5DF2\u77E5 bug\uFF09");
3172
+ const { manualClean } = await import_inquirer6.default.prompt([
3173
+ {
3174
+ type: "confirm",
3175
+ name: "manualClean",
3176
+ message: "\u662F\u5426\u624B\u52A8\u6E05\u7406\u914D\u7F6E\u6587\u4EF6\u6765\u5B8C\u6210\u5378\u8F7D\uFF1F",
3177
+ default: true
3178
+ }
3179
+ ]);
3180
+ if (manualClean) {
3181
+ try {
3182
+ const settingsPath = import_path8.default.join(
3183
+ import_os8.default.homedir(),
3184
+ ".claude",
3185
+ "settings.json"
3186
+ );
3187
+ const settings = JSON.parse(
3188
+ import_fs7.default.readFileSync(settingsPath, "utf-8")
3189
+ );
3190
+ if (settings.enabledPlugins) {
3191
+ const keysToRemove = Object.keys(
3192
+ settings.enabledPlugins
3193
+ ).filter((key) => key.startsWith(`${plugin.id}@`));
3194
+ for (const key of keysToRemove) {
3195
+ delete settings.enabledPlugins[key];
3196
+ }
3197
+ }
3198
+ import_fs7.default.writeFileSync(
3199
+ settingsPath,
3200
+ JSON.stringify(settings, null, 2)
3201
+ );
3202
+ console.log(theme.success("\u2713 \u5DF2\u4ECE\u914D\u7F6E\u4E2D\u79FB\u9664\u63D2\u4EF6"));
3203
+ showInfo("\u91CD\u542F Claude Code \u540E\u751F\u6548");
3204
+ } catch (e) {
3205
+ showWarning("\u624B\u52A8\u6E05\u7406\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u7F16\u8F91 ~/.claude/settings.json");
3206
+ }
3207
+ } else {
3208
+ showInfo('\u5EFA\u8BAE\uFF1A\u4F7F\u7528"\u7981\u7528\u63D2\u4EF6"\u6765\u505C\u7528\u6B64\u63D2\u4EF6');
3209
+ }
3210
+ }
3211
+ }
3212
+ break;
3213
+ }
3214
+ }
3215
+ } catch (error) {
3216
+ spinner.fail(`\u64CD\u4F5C\u5931\u8D25: ${error.message}`);
3217
+ }
3218
+ await new Promise((resolve) => {
3219
+ setTimeout(() => resolve(), 800);
3220
+ });
3221
+ }
3222
+ async function handleInstallAll(marketplacePlugins) {
3223
+ console.log();
3224
+ const recommendedPlugins = marketplacePlugins.filter((p) => p.recommended);
3225
+ const { confirm } = await import_inquirer6.default.prompt([
3226
+ {
3227
+ type: "confirm",
3228
+ name: "confirm",
3229
+ message: `\u786E\u5B9A\u8981\u5B89\u88C5\u5168\u90E8 ${recommendedPlugins.length} \u4E2A\u63A8\u8350\u63D2\u4EF6\u5417\uFF1F`,
3230
+ default: true
3231
+ }
3232
+ ]);
3233
+ if (!confirm) return;
3234
+ const spinner = (0, import_ora6.default)("\u6B63\u5728\u5B89\u88C5\u63D2\u4EF6...").start();
3235
+ try {
3236
+ for (const plugin of recommendedPlugins) {
3237
+ const pluginFullName = `${plugin.id}@${plugin.marketplace}`;
3238
+ spinner.text = `\u6B63\u5728\u5B89\u88C5 ${plugin.name}...`;
3239
+ const installedPlugins = getInstalledPlugins();
3240
+ const installed = installedPlugins.find((p) => p.name === pluginFullName);
3241
+ if (installed) {
3242
+ if (!installed.enabled) {
3243
+ execClaude(`plugin enable ${pluginFullName}`);
3244
+ }
3245
+ } else {
3246
+ execClaude(`plugin install ${pluginFullName}`);
3247
+ }
3248
+ }
3249
+ spinner.succeed(`\u6210\u529F\u5B89\u88C5 ${recommendedPlugins.length} \u4E2A\u63A8\u8350\u63D2\u4EF6`);
3250
+ console.log();
3251
+ showInfo("\u63D2\u4EF6\u5DF2\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F Claude Code");
3252
+ } catch (error) {
3253
+ spinner.fail(`\u5B89\u88C5\u5931\u8D25: ${error.message}`);
3254
+ }
3255
+ console.log();
3256
+ await import_inquirer6.default.prompt([
3257
+ { type: "input", name: "continue", message: "\u6309\u56DE\u8F66\u952E\u7EE7\u7EED..." }
3258
+ ]);
3259
+ }
3260
+
3261
+ // src/cli/menus/settings.ts
3262
+ var import_fs8 = __toESM(require("fs"));
3263
+ var import_inquirer7 = __toESM(require("inquirer"));
3264
+ var import_os9 = __toESM(require("os"));
3265
+ var import_path9 = __toESM(require("path"));
3266
+ var SETTINGS_FILE2 = import_path9.default.join(import_os9.default.homedir(), ".claude", "settings.json");
3267
+ var LANGUAGE_OPTIONS = [
3268
+ { name: "\u4E2D\u6587 (chinese)", value: "chinese" },
3269
+ { name: "English", value: "english" },
3270
+ { name: "\u65E5\u672C\u8A9E (japanese)", value: "japanese" },
3271
+ { name: "\uD55C\uAD6D\uC5B4 (korean)", value: "korean" },
3272
+ { name: "Espa\xF1ol (spanish)", value: "spanish" },
3273
+ { name: "Fran\xE7ais (french)", value: "french" },
3274
+ { name: "Deutsch (german)", value: "german" },
3275
+ { name: "\u5176\u4ED6\uFF08\u624B\u52A8\u8F93\u5165\uFF09", value: "__custom__" }
3276
+ ];
3277
+ async function showSettingsMenu() {
3278
+ while (true) {
3279
+ showHeader();
3280
+ console.log(createBoxTitle("Claude Code \u914D\u7F6E"));
3281
+ console.log();
3282
+ const { choice } = await import_inquirer7.default.prompt([
3283
+ {
3284
+ type: "list",
3285
+ name: "choice",
3286
+ message: "\u8BF7\u9009\u62E9\u914D\u7F6E\u7C7B\u522B\uFF1A",
3287
+ choices: [
3288
+ {
3289
+ name: `\u57FA\u7840\u8BBE\u7F6E`,
3290
+ value: "basic" /* BASIC */
3291
+ },
3292
+ {
3293
+ name: `\u67E5\u770B\u914D\u7F6E\u6587\u4EF6`,
3294
+ value: "view_config" /* VIEW_CONFIG */
3295
+ },
3296
+ new import_inquirer7.default.Separator(),
3297
+ {
3298
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
3299
+ value: "back" /* BACK */
3300
+ },
3301
+ {
3302
+ name: `${theme.dim("X")} \u9000\u51FA`,
3303
+ value: "exit" /* EXIT */
3304
+ }
3305
+ ]
3306
+ }
3307
+ ]);
3308
+ switch (choice) {
3309
+ case "basic" /* BASIC */:
3310
+ await showBasicSettings();
3311
+ break;
3312
+ case "view_config" /* VIEW_CONFIG */:
3313
+ await handleViewConfig();
3314
+ break;
3315
+ case "back" /* BACK */:
3316
+ return;
3317
+ case "exit" /* EXIT */:
3318
+ process.exit(0);
3319
+ }
3320
+ }
3321
+ }
3322
+ async function showBasicSettings() {
3323
+ while (true) {
3324
+ showHeader();
3325
+ console.log(createBoxTitle("\u57FA\u7840\u8BBE\u7F6E"));
3326
+ console.log();
3327
+ const settings = readClaudeSettings();
3328
+ const currentLanguage = settings.language || "\u672A\u8BBE\u7F6E";
3329
+ const currentCleanupDays = settings.cleanupPeriodDays ?? 30;
3330
+ const currentPlansDir = settings.plansDirectory || "./plans";
3331
+ const currentShowDuration = settings.showTurnDuration ?? false;
3332
+ const currentSpinnerTips = settings.spinnerTipsEnabled ?? true;
3333
+ const { choice } = await import_inquirer7.default.prompt([
3334
+ {
3335
+ type: "list",
3336
+ name: "choice",
3337
+ message: "\u8BF7\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\uFF1A",
3338
+ choices: [
3339
+ {
3340
+ name: `\u54CD\u5E94\u8BED\u8A00 ${theme.dim(`[\u5F53\u524D: ${currentLanguage}]`)}`,
3341
+ value: "language" /* LANGUAGE */
3342
+ },
3343
+ {
3344
+ name: `\u4F1A\u8BDD\u6E05\u7406\u5468\u671F ${theme.dim(
3345
+ `[\u5F53\u524D: ${currentCleanupDays}\u5929]`
3346
+ )}`,
3347
+ value: "cleanupPeriodDays" /* CLEANUP_DAYS */
3348
+ },
3349
+ {
3350
+ name: `\u8BA1\u5212\u6587\u4EF6\u76EE\u5F55 ${theme.dim(`[\u5F53\u524D: ${currentPlansDir}]`)}`,
3351
+ value: "plansDirectory" /* PLANS_DIR */
3352
+ },
3353
+ {
3354
+ name: `\u663E\u793A\u54CD\u5E94\u8017\u65F6 ${theme.dim(
3355
+ `[\u5F53\u524D: ${currentShowDuration ? "\u5F00\u542F" : "\u5173\u95ED"}]`
3356
+ )}`,
3357
+ value: "showTurnDuration" /* SHOW_DURATION */
3358
+ },
3359
+ {
3360
+ name: `\u663E\u793A\u52A0\u8F7D\u63D0\u793A ${theme.dim(
3361
+ `[\u5F53\u524D: ${currentSpinnerTips ? "\u5F00\u542F" : "\u5173\u95ED"}]`
3362
+ )}`,
3363
+ value: "spinnerTipsEnabled" /* SPINNER_TIPS */
3364
+ },
3365
+ new import_inquirer7.default.Separator(),
3366
+ {
3367
+ name: `${theme.dim("<-")} \u8FD4\u56DE`,
3368
+ value: "back" /* BACK */
3369
+ },
3370
+ {
3371
+ name: `${theme.dim("X")} \u9000\u51FA`,
3372
+ value: "exit" /* EXIT */
3373
+ }
3374
+ ]
3375
+ }
3376
+ ]);
3377
+ switch (choice) {
3378
+ case "language" /* LANGUAGE */:
3379
+ await handleLanguageSetting();
3380
+ break;
3381
+ case "cleanupPeriodDays" /* CLEANUP_DAYS */:
3382
+ await handleCleanupDaysSetting();
3383
+ break;
3384
+ case "plansDirectory" /* PLANS_DIR */:
3385
+ await handlePlansDirSetting();
3386
+ break;
3387
+ case "showTurnDuration" /* SHOW_DURATION */:
3388
+ await handleBooleanSetting("showTurnDuration", "\u663E\u793A\u54CD\u5E94\u8017\u65F6");
3389
+ break;
3390
+ case "spinnerTipsEnabled" /* SPINNER_TIPS */:
3391
+ await handleBooleanSetting("spinnerTipsEnabled", "\u663E\u793A\u52A0\u8F7D\u63D0\u793A");
3392
+ break;
3393
+ case "back" /* BACK */:
3394
+ return;
3395
+ case "exit" /* EXIT */:
3396
+ process.exit(0);
3397
+ }
3398
+ }
3399
+ }
3400
+ async function handleLanguageSetting() {
3401
+ console.log();
3402
+ const { language } = await import_inquirer7.default.prompt([
3403
+ {
3404
+ type: "list",
3405
+ name: "language",
3406
+ message: "\u8BF7\u9009\u62E9\u54CD\u5E94\u8BED\u8A00\uFF1A",
3407
+ choices: LANGUAGE_OPTIONS
3408
+ }
3409
+ ]);
3410
+ let finalLanguage = language;
3411
+ if (language === "__custom__") {
3412
+ const { customLanguage } = await import_inquirer7.default.prompt([
3413
+ {
3414
+ type: "input",
3415
+ name: "customLanguage",
3416
+ message: "\u8BF7\u8F93\u5165\u8BED\u8A00\u540D\u79F0\uFF08\u82F1\u6587\uFF09\uFF1A",
3417
+ validate: (input) => {
3418
+ if (!input || input.trim().length === 0) {
3419
+ return "\u8BED\u8A00\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
3420
+ }
3421
+ return true;
3422
+ }
3423
+ }
3424
+ ]);
3425
+ finalLanguage = customLanguage;
3426
+ }
3427
+ try {
3428
+ const settings = readClaudeSettings();
3429
+ settings.language = finalLanguage;
3430
+ writeClaudeSettings(settings);
3431
+ showSuccess(`\u54CD\u5E94\u8BED\u8A00\u5DF2\u8BBE\u7F6E\u4E3A: ${finalLanguage}`);
3432
+ } catch (error) {
3433
+ showError(`\u4FDD\u5B58\u5931\u8D25: ${error.message}`);
3434
+ }
3435
+ }
3436
+ async function handleCleanupDaysSetting() {
3437
+ console.log();
3438
+ showInfo("\u8BBE\u7F6E\u4E3A 0 \u8868\u793A\u6BCF\u6B21\u542F\u52A8\u90FD\u6E05\u7406\u6240\u6709\u5386\u53F2\u4F1A\u8BDD");
3439
+ console.log();
3440
+ const { days } = await import_inquirer7.default.prompt([
3441
+ {
3442
+ type: "number",
3443
+ name: "days",
3444
+ message: "\u8BF7\u8F93\u5165\u4F1A\u8BDD\u6E05\u7406\u5468\u671F\uFF08\u5929\uFF09\uFF1A",
3445
+ default: 30,
3446
+ validate: (input) => {
3447
+ if (isNaN(input) || input < 0) {
3448
+ return "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u5929\u6570\uFF08>=0\uFF09";
3449
+ }
3450
+ return true;
3451
+ }
3452
+ }
3453
+ ]);
3454
+ try {
3455
+ const settings = readClaudeSettings();
3456
+ settings.cleanupPeriodDays = days;
3457
+ writeClaudeSettings(settings);
3458
+ showSuccess(`\u4F1A\u8BDD\u6E05\u7406\u5468\u671F\u5DF2\u8BBE\u7F6E\u4E3A: ${days}\u5929`);
3459
+ } catch (error) {
3460
+ showError(`\u4FDD\u5B58\u5931\u8D25: ${error.message}`);
3461
+ }
3462
+ }
3463
+ async function handlePlansDirSetting() {
3464
+ console.log();
3465
+ showInfo("\u53EF\u4F7F\u7528\u76F8\u5BF9\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u9879\u76EE\u6839\u76EE\u5F55\uFF09\u6216\u7EDD\u5BF9\u8DEF\u5F84");
3466
+ console.log();
3467
+ const { dir } = await import_inquirer7.default.prompt([
3468
+ {
3469
+ type: "input",
3470
+ name: "dir",
3471
+ message: "\u8BF7\u8F93\u5165\u8BA1\u5212\u6587\u4EF6\u76EE\u5F55\uFF1A",
3472
+ default: "./plans"
3473
+ }
3474
+ ]);
3475
+ try {
3476
+ const settings = readClaudeSettings();
3477
+ settings.plansDirectory = dir;
3478
+ writeClaudeSettings(settings);
3479
+ showSuccess(`\u8BA1\u5212\u6587\u4EF6\u76EE\u5F55\u5DF2\u8BBE\u7F6E\u4E3A: ${dir}`);
3480
+ } catch (error) {
3481
+ showError(`\u4FDD\u5B58\u5931\u8D25: ${error.message}`);
3482
+ }
3483
+ }
3484
+ async function handleBooleanSetting(key, label) {
3485
+ console.log();
3486
+ const settings = readClaudeSettings();
3487
+ const currentValue = settings[key] ?? key === "spinnerTipsEnabled";
3488
+ const { value } = await import_inquirer7.default.prompt([
3489
+ {
3490
+ type: "list",
3491
+ name: "value",
3492
+ message: `${label}\uFF1A`,
3493
+ choices: [
3494
+ { name: "\u5F00\u542F", value: true },
3495
+ { name: "\u5173\u95ED", value: false }
3496
+ ],
3497
+ default: currentValue
3498
+ }
3499
+ ]);
3500
+ try {
3501
+ settings[key] = value;
3502
+ writeClaudeSettings(settings);
3503
+ showSuccess(`${label}\u5DF2${value ? "\u5F00\u542F" : "\u5173\u95ED"}`);
3504
+ } catch (error) {
3505
+ showError(`\u4FDD\u5B58\u5931\u8D25: ${error.message}`);
3506
+ }
3507
+ }
3508
+ async function handleViewConfig() {
3509
+ console.log();
3510
+ console.log(theme.primary(`\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${SETTINGS_FILE2}`));
3511
+ console.log();
3512
+ try {
3513
+ if (import_fs8.default.existsSync(SETTINGS_FILE2)) {
3514
+ const content = import_fs8.default.readFileSync(SETTINGS_FILE2, "utf-8");
3515
+ console.log(theme.dim("\u2500".repeat(50)));
3516
+ console.log(content);
3517
+ console.log(theme.dim("\u2500".repeat(50)));
3518
+ } else {
3519
+ showWarning("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728");
3520
+ }
3521
+ } catch (error) {
3522
+ showError(`\u8BFB\u53D6\u5931\u8D25: ${error.message}`);
3523
+ }
3524
+ console.log();
3525
+ await import_inquirer7.default.prompt([
3526
+ { type: "input", name: "continue", message: "\u6309\u56DE\u8F66\u952E\u7EE7\u7EED..." }
3527
+ ]);
3528
+ }
3529
+
3530
+ // src/cli/menus/main.ts
3531
+ async function showMainMenu() {
3532
+ let claudeInfo = detectClaudeInstallation();
3533
+ while (true) {
3534
+ showHeader();
3535
+ const claudeStatus = formatClaudeStatus(claudeInfo);
3536
+ console.log(
3537
+ `Claude Code: ${claudeInfo.installed ? theme.success(claudeStatus) : theme.dim(claudeStatus)}`
3538
+ );
3539
+ const profileStatus = getCurrentProfileStatus();
3540
+ const apiKeyStatus = getApiKeyStatus();
3541
+ const baseUrlStatus = getBaseUrlStatus();
3542
+ console.log(`\u5F53\u524D\u914D\u7F6E: ${profileStatus}`);
3543
+ console.log(`Base URL: ${baseUrlStatus}`);
3544
+ console.log(`API Key: ${apiKeyStatus}
3545
+ `);
3546
+ console.log(createBoxTitle("\u4E3B\u83DC\u5355"));
3547
+ console.log();
3548
+ const { choice } = await import_inquirer9.default.prompt([
3549
+ {
3550
+ type: "list",
3551
+ name: "choice",
3552
+ message: "\u8BF7\u9009\u62E9\u64CD\u4F5C\uFF1A",
3553
+ pageSize: 10,
3554
+ choices: [
3555
+ {
3556
+ name: `${theme.primary("1.")} Claude Code \u7BA1\u7406 ${theme.dim(
3557
+ "(\u5B89\u88C5/\u5378\u8F7D)"
3558
+ )}`,
3559
+ value: "manage" /* MANAGE */
3560
+ },
3561
+ {
3562
+ name: `${theme.primary("2.")} \u6388\u6743\u767B\u5F55`,
3563
+ value: "auth" /* AUTH */
3564
+ },
3565
+ {
3566
+ name: `${theme.primary("3.")} Claude Code \u914D\u7F6E`,
3567
+ value: "settings" /* SETTINGS */
3568
+ },
3569
+ {
3570
+ name: `${theme.primary("4.")} MCP \u670D\u52A1\u7BA1\u7406`,
3571
+ value: "mcp" /* MCP */
3572
+ },
3573
+ {
3574
+ name: `${theme.primary("5.")} \u63D2\u4EF6\u5E02\u573A`,
3575
+ value: "plugins" /* PLUGINS */
3576
+ },
3577
+ {
3578
+ name: `${theme.primary("6.")} \u542F\u52A8 Web UI ${theme.dim(
3579
+ "(\u56FE\u5F62\u5316\u754C\u9762)"
3580
+ )}`,
3581
+ value: "webui" /* WEBUI */
3582
+ },
3583
+ new import_inquirer9.default.Separator(),
3584
+ {
3585
+ name: `${theme.dim("0.")} \u9000\u51FA`,
3586
+ value: "exit" /* EXIT */
3587
+ }
3588
+ ]
3589
+ }
3590
+ ]);
3591
+ switch (choice) {
3592
+ case "manage" /* MANAGE */:
3593
+ await showManageMenu();
3594
+ claudeInfo = detectClaudeInstallation();
3595
+ break;
3596
+ case "auth" /* AUTH */:
3597
+ await showAuthMenu();
3598
+ break;
3599
+ case "settings" /* SETTINGS */:
3600
+ await showSettingsMenu();
3601
+ break;
3602
+ case "mcp" /* MCP */:
3603
+ await showMcpMenu();
3604
+ break;
3605
+ case "plugins" /* PLUGINS */:
3606
+ await showPluginsMenu();
3607
+ break;
3608
+ case "webui" /* WEBUI */: {
3609
+ const { launchWebUI: launchWebUI2 } = (init_webui(), __toCommonJS(webui_exports));
3610
+ await launchWebUI2();
3611
+ break;
3612
+ }
3613
+ case "exit" /* EXIT */:
3614
+ console.log("\n\u518D\u89C1\uFF01");
3615
+ process.exit(0);
3616
+ }
3617
+ }
3618
+ }
3619
+
3620
+ // src/cli/index.ts
3621
+ init_version();
3622
+ var pkg2 = require_package();
3623
+ async function main() {
3624
+ try {
3625
+ const args = process.argv.slice(2);
3626
+ if (args.includes("--version") || args.includes("-v")) {
3627
+ console.log(`v${pkg2.version}`);
3628
+ process.exit(0);
3629
+ }
3630
+ if (args.includes("--test-update")) {
3631
+ const { testUpdate: testUpdate2 } = (init_version(), __toCommonJS(version_exports));
3632
+ await testUpdate2();
3633
+ process.exit(0);
3634
+ }
3635
+ if (args.includes("ui")) {
3636
+ const { launchWebUI: launchWebUI2 } = (init_webui(), __toCommonJS(webui_exports));
3637
+ await launchWebUI2();
3638
+ process.exit(0);
3639
+ }
3640
+ if (args.includes("--help") || args.includes("-h")) {
3641
+ console.log(`
3642
+ Code Helper v${pkg2.version}
3643
+ A unified tool to manage your Claude Code
3644
+
3645
+ Usage:
3646
+ code-helper Launch interactive menu
3647
+ code-helper ui Launch Web UI interface
3648
+ code-helper --version Show version number
3649
+ code-helper --help Show help information
3650
+ code-helper --test-update Test version update functionality
3651
+
3652
+ You can also use these command aliases:
3653
+ - ch
3654
+ - maco
3655
+
3656
+ Options:
3657
+ -v, --version Show version number
3658
+ -h, --help Show help information
3659
+ --test-update Test version update functionality
3660
+ ui Launch Web UI interface
3661
+
3662
+ Installation:
3663
+ Recommended global installation for better experience:
3664
+ npm install -g code-helper
3665
+
3666
+ Global installation will automatically check for updates
3667
+
3668
+ Web UI Launch:
3669
+ 1. code-helper ui Launch via code-helper command
3670
+ 2. npx @siteboon/claude-code-ui Launch UI directly
3671
+ `);
3672
+ process.exit(0);
3673
+ }
3674
+ await checkAndUpdate();
3675
+ showHeader();
3676
+ await showMainMenu();
3677
+ } catch (error) {
3678
+ if (error?.message === "User force closed the prompt") {
3679
+ console.log("\n\u518D\u89C1\uFF01");
3680
+ process.exit(0);
3681
+ }
3682
+ console.error("\u53D1\u751F\u9519\u8BEF:", error);
3683
+ process.exit(1);
3684
+ }
3685
+ }
3686
+ main();
3687
+ //# sourceMappingURL=index.js.map