ccman 3.0.26 → 3.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +113 -50
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ var init_package = __esm({
39
39
  "../core/package.json"() {
40
40
  package_default = {
41
41
  name: "@ccman/core",
42
- version: "3.0.26",
42
+ version: "3.0.28",
43
43
  type: "module",
44
44
  description: "Core business logic for ccman",
45
45
  main: "./dist/index.js",
@@ -2323,6 +2323,8 @@ function migrateMCPConfig(config) {
2323
2323
  server.enabledApps = ["claude"];
2324
2324
  }
2325
2325
  }
2326
+ } else {
2327
+ config.servers = [];
2326
2328
  }
2327
2329
  return config;
2328
2330
  }
@@ -2656,6 +2658,7 @@ function createToolManager(tool) {
2656
2658
  const provider = {
2657
2659
  id: generateId(),
2658
2660
  name: input.name,
2661
+ desc: input.desc,
2659
2662
  baseUrl: input.baseUrl,
2660
2663
  apiKey: input.apiKey,
2661
2664
  model: input.model,
@@ -2722,6 +2725,8 @@ function createToolManager(tool) {
2722
2725
  }
2723
2726
  if (updates.name !== void 0)
2724
2727
  provider.name = updates.name;
2728
+ if (updates.desc !== void 0)
2729
+ provider.desc = updates.desc;
2725
2730
  if (updates.baseUrl !== void 0)
2726
2731
  provider.baseUrl = updates.baseUrl;
2727
2732
  if (updates.apiKey !== void 0)
@@ -2765,6 +2770,7 @@ function createToolManager(tool) {
2765
2770
  ...source,
2766
2771
  id: generateId(),
2767
2772
  name: newName,
2773
+ desc: void 0,
2768
2774
  createdAt: timestamp,
2769
2775
  lastModified: timestamp,
2770
2776
  lastUsedAt: void 0
@@ -16228,7 +16234,7 @@ function normalizePath(dir) {
16228
16234
  if (!dir || dir === "/") {
16229
16235
  return "/";
16230
16236
  }
16231
- let normalized = dir.trim().replace(/^\/+/, "").replace(/\/+$/, "");
16237
+ const normalized = dir.trim().replace(/^\/+/, "").replace(/\/+$/, "");
16232
16238
  return `/${normalized}`;
16233
16239
  }
16234
16240
  function joinPath(baseDir, filename) {
@@ -16358,6 +16364,12 @@ function deriveKey(password, salt) {
16358
16364
  return crypto.pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, KEY_LENGTH, "sha256");
16359
16365
  }
16360
16366
  function encryptApiKey(apiKey, password) {
16367
+ if (typeof apiKey !== "string") {
16368
+ throw new Error("API Key \u7F3A\u5931\u6216\u7C7B\u578B\u9519\u8BEF\uFF0C\u65E0\u6CD5\u52A0\u5BC6");
16369
+ }
16370
+ if (!password) {
16371
+ throw new Error("\u540C\u6B65\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A");
16372
+ }
16361
16373
  const salt = crypto.randomBytes(SALT_LENGTH);
16362
16374
  const iv = crypto.randomBytes(IV_LENGTH);
16363
16375
  const key = deriveKey(password, salt);
@@ -16386,10 +16398,15 @@ function decryptApiKey(encryptedApiKey, password) {
16386
16398
  }
16387
16399
  }
16388
16400
  function encryptProviders(providers, password) {
16389
- return providers.map((provider) => ({
16390
- ...provider,
16391
- apiKey: encryptApiKey(provider.apiKey, password)
16392
- }));
16401
+ return providers.map((provider) => {
16402
+ if (typeof provider.apiKey !== "string" || provider.apiKey.length === 0) {
16403
+ throw new Error(`\u670D\u52A1\u5546 "${provider.name}" \u7684 API Key \u4E3A\u7A7A\u6216\u7F3A\u5931\uFF0C\u8BF7\u5148\u5728 ccman \u4E2D\u8865\u5168\u540E\u518D\u8FDB\u884C\u540C\u6B65`);
16404
+ }
16405
+ return {
16406
+ ...provider,
16407
+ apiKey: encryptApiKey(provider.apiKey, password)
16408
+ };
16409
+ });
16393
16410
  }
16394
16411
  function decryptProviders(encryptedProviders, password) {
16395
16412
  return encryptedProviders.map((provider) => ({
@@ -17240,55 +17257,63 @@ function configCommand(program2) {
17240
17257
  return;
17241
17258
  }
17242
17259
  }
17243
- const newConfig = { ...existingConfig };
17260
+ let newConfig;
17261
+ if (existingConfig) {
17262
+ newConfig = { ...existingConfig };
17263
+ } else {
17264
+ if (!trimmedAnswers.webdavUrl) {
17265
+ throw new Error("WebDAV \u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A");
17266
+ }
17267
+ if (!trimmedAnswers.username) {
17268
+ throw new Error("\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A");
17269
+ }
17270
+ if (!trimmedAnswers.password) {
17271
+ throw new Error("\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A");
17272
+ }
17273
+ if (!trimmedAnswers.syncPassword) {
17274
+ throw new Error("\u540C\u6B65\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A");
17275
+ }
17276
+ newConfig = {
17277
+ webdavUrl: trimmedAnswers.webdavUrl,
17278
+ username: trimmedAnswers.username,
17279
+ password: trimmedAnswers.password,
17280
+ authType: trimmedAnswers.authType,
17281
+ remoteDir: trimmedAnswers.remoteDir || "/",
17282
+ syncPassword: trimmedAnswers.syncPassword,
17283
+ rememberSyncPassword: trimmedAnswers.rememberSyncPassword,
17284
+ lastSync: void 0
17285
+ };
17286
+ }
17244
17287
  let hasChanges = false;
17245
- if (trimmedAnswers.webdavUrl) {
17246
- if (trimmedAnswers.webdavUrl !== existingConfig?.webdavUrl) {
17288
+ if (existingConfig) {
17289
+ if (trimmedAnswers.webdavUrl && trimmedAnswers.webdavUrl !== existingConfig.webdavUrl) {
17247
17290
  newConfig.webdavUrl = trimmedAnswers.webdavUrl;
17248
17291
  hasChanges = true;
17249
17292
  }
17250
- } else if (!existingConfig) {
17251
- throw new Error("WebDAV \u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A");
17252
- }
17253
- if (trimmedAnswers.username) {
17254
- if (trimmedAnswers.username !== existingConfig?.username) {
17293
+ if (trimmedAnswers.username && trimmedAnswers.username !== existingConfig.username) {
17255
17294
  newConfig.username = trimmedAnswers.username;
17256
17295
  hasChanges = true;
17257
17296
  }
17258
- } else if (!existingConfig) {
17259
- throw new Error("\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A");
17260
- }
17261
- if (trimmedAnswers.password) {
17262
- if (trimmedAnswers.password !== existingConfig?.password) {
17297
+ if (trimmedAnswers.password && trimmedAnswers.password !== existingConfig.password) {
17263
17298
  newConfig.password = trimmedAnswers.password;
17264
17299
  hasChanges = true;
17265
17300
  }
17266
- } else if (!existingConfig) {
17267
- throw new Error("\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A");
17268
- }
17269
- if (trimmedAnswers.authType !== existingConfig?.authType) {
17270
- newConfig.authType = trimmedAnswers.authType;
17271
- hasChanges = true;
17272
- }
17273
- if (trimmedAnswers.remoteDir) {
17274
- if (trimmedAnswers.remoteDir !== existingConfig?.remoteDir) {
17301
+ if (trimmedAnswers.authType !== existingConfig.authType) {
17302
+ newConfig.authType = trimmedAnswers.authType;
17303
+ hasChanges = true;
17304
+ }
17305
+ if (trimmedAnswers.remoteDir && trimmedAnswers.remoteDir !== existingConfig.remoteDir) {
17275
17306
  newConfig.remoteDir = trimmedAnswers.remoteDir;
17276
17307
  hasChanges = true;
17277
17308
  }
17278
- } else if (!existingConfig) {
17279
- newConfig.remoteDir = "/";
17280
- }
17281
- if (trimmedAnswers.syncPassword) {
17282
- if (trimmedAnswers.syncPassword !== existingConfig?.syncPassword) {
17309
+ if (trimmedAnswers.syncPassword && trimmedAnswers.syncPassword !== existingConfig.syncPassword) {
17283
17310
  newConfig.syncPassword = trimmedAnswers.syncPassword;
17284
17311
  hasChanges = true;
17285
17312
  }
17286
- } else if (!existingConfig) {
17287
- throw new Error("\u540C\u6B65\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A");
17288
- }
17289
- if (trimmedAnswers.rememberSyncPassword !== existingConfig?.rememberSyncPassword) {
17290
- newConfig.rememberSyncPassword = trimmedAnswers.rememberSyncPassword;
17291
- hasChanges = true;
17313
+ if (trimmedAnswers.rememberSyncPassword !== existingConfig.rememberSyncPassword) {
17314
+ newConfig.rememberSyncPassword = trimmedAnswers.rememberSyncPassword;
17315
+ hasChanges = true;
17316
+ }
17292
17317
  }
17293
17318
  if (!hasChanges && existingConfig) {
17294
17319
  console.log();
@@ -17446,7 +17471,7 @@ function uploadCommand(program2) {
17446
17471
  console.log(import_chalk6.default.gray("\n\u5DF2\u53D6\u6D88\n"));
17447
17472
  return;
17448
17473
  }
17449
- let syncPassword = config.syncPassword;
17474
+ let syncPassword = config.syncPassword || "";
17450
17475
  if (!syncPassword) {
17451
17476
  const { password } = await import_inquirer3.default.prompt([
17452
17477
  {
@@ -17525,7 +17550,7 @@ function downloadCommand(program2) {
17525
17550
  console.log(import_chalk7.default.gray("\n\u5DF2\u53D6\u6D88\n"));
17526
17551
  return;
17527
17552
  }
17528
- let syncPassword = config.syncPassword;
17553
+ let syncPassword = config.syncPassword || "";
17529
17554
  if (!syncPassword) {
17530
17555
  const { password } = await import_inquirer4.default.prompt([
17531
17556
  {
@@ -17600,7 +17625,7 @@ function mergeCommand(program2) {
17600
17625
  console.log(import_chalk8.default.gray("\n\u5DF2\u53D6\u6D88\n"));
17601
17626
  return;
17602
17627
  }
17603
- let syncPassword = config.syncPassword;
17628
+ let syncPassword = config.syncPassword || "";
17604
17629
  if (!syncPassword) {
17605
17630
  const { password } = await import_inquirer5.default.prompt([
17606
17631
  {
@@ -17870,6 +17895,10 @@ function formatProviderTable(providers, currentId) {
17870
17895
  lines.push(` ${marker} ${name}${tag}`);
17871
17896
  const url = isCurrent ? import_chalk2.default.green(p.baseUrl) : import_chalk2.default.gray(p.baseUrl);
17872
17897
  lines.push(` ${url}`);
17898
+ if (p.desc) {
17899
+ const desc = isCurrent ? import_chalk2.default.green(p.desc) : import_chalk2.default.gray(p.desc);
17900
+ lines.push(` ${desc}`);
17901
+ }
17873
17902
  if (index < providers.length - 1) {
17874
17903
  lines.push("");
17875
17904
  }
@@ -17891,6 +17920,12 @@ async function promptProviderForm(defaults2) {
17891
17920
  return true;
17892
17921
  }
17893
17922
  },
17923
+ {
17924
+ type: "input",
17925
+ name: "desc",
17926
+ message: "\u63CF\u8FF0(\u53EF\u9009):",
17927
+ default: defaults2?.desc || void 0
17928
+ },
17894
17929
  {
17895
17930
  type: "input",
17896
17931
  name: "baseUrl",
@@ -17918,6 +17953,7 @@ async function promptProviderForm(defaults2) {
17918
17953
  ]);
17919
17954
  return {
17920
17955
  name: answers.name,
17956
+ desc: answers.desc || void 0,
17921
17957
  baseUrl: answers.baseUrl,
17922
17958
  apiKey: answers.apiKey
17923
17959
  };
@@ -18046,6 +18082,7 @@ async function handleAdd(tool) {
18046
18082
  }
18047
18083
  ]);
18048
18084
  let name;
18085
+ let desc;
18049
18086
  let baseUrl;
18050
18087
  let apiKey;
18051
18088
  if (usePreset) {
@@ -18066,10 +18103,12 @@ async function handleAdd(tool) {
18066
18103
  `));
18067
18104
  const input = await promptProviderForm({
18068
18105
  name: preset.name,
18106
+ desc: "",
18069
18107
  baseUrl: preset.baseUrl,
18070
18108
  apiKey: ""
18071
18109
  });
18072
18110
  name = input.name;
18111
+ desc = input.desc;
18073
18112
  baseUrl = input.baseUrl;
18074
18113
  apiKey = input.apiKey;
18075
18114
  } else {
@@ -18101,10 +18140,11 @@ async function handleAdd(tool) {
18101
18140
  }
18102
18141
  ]);
18103
18142
  name = answers.name;
18143
+ desc = void 0;
18104
18144
  baseUrl = answers.baseUrl;
18105
18145
  apiKey = answers.apiKey;
18106
18146
  }
18107
- const provider = manager.add({ name, baseUrl, apiKey });
18147
+ const provider = manager.add({ name, desc, baseUrl, apiKey });
18108
18148
  console.log();
18109
18149
  console.log(import_chalk11.default.green("\u2705 \u6DFB\u52A0\u6210\u529F"));
18110
18150
  console.log();
@@ -18123,8 +18163,10 @@ async function handleAdd(tool) {
18123
18163
  manager.switch(provider.id);
18124
18164
  console.log(import_chalk11.default.green("\u2705 \u5DF2\u5207\u6362\u5230\u65B0\u670D\u52A1\u5546\n"));
18125
18165
  } else {
18126
- console.log(import_chalk11.default.blue("\u{1F4A1} \u7A0D\u540E\u5207\u6362:") + import_chalk11.default.white(` ccman ${tool === "codex" ? "cx" : "cc"} use "${provider.name}"
18127
- `));
18166
+ console.log(
18167
+ import_chalk11.default.blue("\u{1F4A1} \u7A0D\u540E\u5207\u6362:") + import_chalk11.default.white(` ccman ${tool === "codex" ? "cx" : "cc"} use "${provider.name}"
18168
+ `)
18169
+ );
18128
18170
  }
18129
18171
  }
18130
18172
  async function handleSwitch(tool) {
@@ -18165,7 +18207,7 @@ async function handleList(tool) {
18165
18207
  }
18166
18208
  console.log(import_chalk11.default.bold(`
18167
18209
  \u{1F4CB} ${toolName} \u670D\u52A1\u5546 (${providers.length} \u4E2A)`));
18168
- console.log(formatProviderTable(providers, current?.id, toolName));
18210
+ console.log(formatProviderTable(providers, current?.id));
18169
18211
  }
18170
18212
  async function handleCurrent(tool) {
18171
18213
  const manager = tool === "codex" ? createCodexManager() : createClaudeManager();
@@ -18228,6 +18270,12 @@ async function handleEdit(tool) {
18228
18270
  return true;
18229
18271
  }
18230
18272
  },
18273
+ {
18274
+ type: "input",
18275
+ name: "desc",
18276
+ message: "\u63CF\u8FF0(\u53EF\u9009):",
18277
+ default: provider.desc || ""
18278
+ },
18231
18279
  {
18232
18280
  type: "password",
18233
18281
  name: "apiKey",
@@ -18237,6 +18285,7 @@ async function handleEdit(tool) {
18237
18285
  ]);
18238
18286
  manager.edit(providerId, {
18239
18287
  name: answers.name,
18288
+ desc: answers.desc || void 0,
18240
18289
  baseUrl: answers.baseUrl,
18241
18290
  apiKey: answers.apiKey || void 0
18242
18291
  });
@@ -18279,6 +18328,8 @@ async function handleClone(tool) {
18279
18328
  ]);
18280
18329
  const newProvider = manager.add({
18281
18330
  name: answers.name,
18331
+ // 克隆时不继承描述,留空让用户后续编辑
18332
+ desc: void 0,
18282
18333
  baseUrl: provider.baseUrl,
18283
18334
  apiKey: answers.apiKey
18284
18335
  });
@@ -18342,6 +18393,7 @@ function addCommand(program2) {
18342
18393
  }
18343
18394
  ]);
18344
18395
  let name;
18396
+ let desc;
18345
18397
  let baseUrl;
18346
18398
  let apiKey;
18347
18399
  if (usePreset) {
@@ -18362,10 +18414,12 @@ function addCommand(program2) {
18362
18414
  `));
18363
18415
  const input = await promptProviderForm({
18364
18416
  name: preset.name,
18417
+ desc: "",
18365
18418
  baseUrl: preset.baseUrl,
18366
18419
  apiKey: ""
18367
18420
  });
18368
18421
  name = input.name;
18422
+ desc = input.desc;
18369
18423
  baseUrl = input.baseUrl;
18370
18424
  apiKey = input.apiKey;
18371
18425
  } else {
@@ -18403,10 +18457,11 @@ function addCommand(program2) {
18403
18457
  }
18404
18458
  ]);
18405
18459
  name = answers.name;
18460
+ desc = void 0;
18406
18461
  baseUrl = answers.baseUrl;
18407
18462
  apiKey = answers.apiKey;
18408
18463
  }
18409
- const provider = manager.add({ name, baseUrl, apiKey });
18464
+ const provider = manager.add({ name, desc, baseUrl, apiKey });
18410
18465
  console.log();
18411
18466
  console.log(import_chalk12.default.green("\u2705 \u6DFB\u52A0\u6210\u529F"));
18412
18467
  console.log();
@@ -18456,7 +18511,7 @@ function listCommand(program2) {
18456
18511
  }
18457
18512
  console.log(import_chalk13.default.bold(`
18458
18513
  \u{1F4CB} Codex \u670D\u52A1\u5546 (${providers.length} \u4E2A)`));
18459
- console.log(formatProviderTable(providers, current?.id, "Codex"));
18514
+ console.log(formatProviderTable(providers, current?.id));
18460
18515
  } catch (error) {
18461
18516
  console.error(import_chalk13.default.red(`
18462
18517
  \u274C ${error.message}
@@ -18762,6 +18817,8 @@ function cloneCommand(program2) {
18762
18817
  `));
18763
18818
  const input = await promptProviderForm({
18764
18819
  name: `${source.name}\uFF08\u526F\u672C\uFF09`,
18820
+ // 克隆时不继承描述
18821
+ desc: "",
18765
18822
  baseUrl: source.baseUrl,
18766
18823
  apiKey: source.apiKey
18767
18824
  });
@@ -18815,6 +18872,7 @@ function addCommand2(program2) {
18815
18872
  }
18816
18873
  ]);
18817
18874
  let name;
18875
+ let desc;
18818
18876
  let baseUrl;
18819
18877
  let apiKey;
18820
18878
  if (usePreset) {
@@ -18835,10 +18893,12 @@ function addCommand2(program2) {
18835
18893
  `));
18836
18894
  const input = await promptProviderForm({
18837
18895
  name: preset.name,
18896
+ desc: "",
18838
18897
  baseUrl: preset.baseUrl,
18839
18898
  apiKey: ""
18840
18899
  });
18841
18900
  name = input.name;
18901
+ desc = input.desc;
18842
18902
  baseUrl = input.baseUrl;
18843
18903
  apiKey = input.apiKey;
18844
18904
  } else {
@@ -18876,10 +18936,11 @@ function addCommand2(program2) {
18876
18936
  }
18877
18937
  ]);
18878
18938
  name = answers.name;
18939
+ desc = void 0;
18879
18940
  baseUrl = answers.baseUrl;
18880
18941
  apiKey = answers.apiKey;
18881
18942
  }
18882
- const provider = manager.add({ name, baseUrl, apiKey });
18943
+ const provider = manager.add({ name, desc, baseUrl, apiKey });
18883
18944
  console.log();
18884
18945
  console.log(import_chalk19.default.green("\u2705 \u6DFB\u52A0\u6210\u529F"));
18885
18946
  console.log();
@@ -18928,7 +18989,7 @@ function listCommand2(program2) {
18928
18989
  }
18929
18990
  console.log(import_chalk20.default.bold(`
18930
18991
  \u{1F4CB} Claude Code \u670D\u52A1\u5546 (${providers.length} \u4E2A)`));
18931
- console.log(formatProviderTable(providers, current?.id, "Claude Code"));
18992
+ console.log(formatProviderTable(providers, current?.id));
18932
18993
  } catch (error) {
18933
18994
  console.error(import_chalk20.default.red(`
18934
18995
  \u274C ${error.message}
@@ -19233,6 +19294,8 @@ function cloneCommand2(program2) {
19233
19294
  `));
19234
19295
  const input = await promptProviderForm({
19235
19296
  name: `${source.name}\uFF08\u526F\u672C\uFF09`,
19297
+ // 克隆时不继承描述
19298
+ desc: "",
19236
19299
  baseUrl: source.baseUrl,
19237
19300
  apiKey: source.apiKey
19238
19301
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccman",
3
- "version": "3.0.26",
3
+ "version": "3.0.28",
4
4
  "description": "Manage Codex and Claude Code API service provider configurations",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {