ccman 3.0.21 → 3.0.22

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 +319 -168
  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.21",
42
+ version: "3.0.22",
43
43
  type: "module",
44
44
  description: "Core business logic for ccman",
45
45
  main: "./dist/index.js",
@@ -2357,20 +2357,20 @@ var init_claude2 = __esm({
2357
2357
  });
2358
2358
 
2359
2359
  // ../core/dist/tool-manager.js
2360
- function createToolManager(tool) {
2361
- const toolConfig = TOOL_CONFIGS[tool];
2362
- const configPath = toolConfig.configPath;
2363
- function generateId() {
2364
- const timestamp = Date.now();
2365
- const random = Math.random().toString(36).substring(2, 8);
2366
- return `${tool}-${timestamp}-${random}`;
2367
- }
2360
+ function generateId(tool) {
2361
+ const timestamp = Date.now();
2362
+ const random = Math.random().toString(36).substring(2, 8);
2363
+ return `${tool}-${timestamp}-${random}`;
2364
+ }
2365
+ function createCodexManager() {
2366
+ const configPath = path3.join(getCcmanDir(), "codex.json");
2368
2367
  function loadConfig2() {
2369
2368
  if (!fileExists(configPath)) {
2370
2369
  ensureDir(getCcmanDir());
2371
2370
  const initialConfig = {
2372
2371
  providers: [],
2373
2372
  presets: []
2373
+ // 只存储用户自定义预置
2374
2374
  };
2375
2375
  writeJSON(configPath, initialConfig);
2376
2376
  return initialConfig;
@@ -2389,11 +2389,12 @@ function createToolManager(tool) {
2389
2389
  }
2390
2390
  const timestamp = Date.now();
2391
2391
  const provider = {
2392
- id: generateId(),
2392
+ id: generateId("codex"),
2393
2393
  name: input.name,
2394
2394
  baseUrl: input.baseUrl,
2395
2395
  apiKey: input.apiKey,
2396
2396
  model: input.model,
2397
+ // 保存 model 字段
2397
2398
  createdAt: timestamp,
2398
2399
  lastModified: timestamp
2399
2400
  };
@@ -2427,7 +2428,7 @@ function createToolManager(tool) {
2427
2428
  config.currentProviderId = id;
2428
2429
  provider.lastUsedAt = Date.now();
2429
2430
  saveConfig2(config);
2430
- toolConfig.writer(provider);
2431
+ writeCodexConfig(provider);
2431
2432
  },
2432
2433
  getCurrent() {
2433
2434
  const config = loadConfig2();
@@ -2460,7 +2461,7 @@ function createToolManager(tool) {
2460
2461
  provider.lastModified = Date.now();
2461
2462
  saveConfig2(config);
2462
2463
  if (config.currentProviderId === id) {
2463
- toolConfig.writer(provider);
2464
+ writeCodexConfig(provider);
2464
2465
  }
2465
2466
  return provider;
2466
2467
  },
@@ -2486,7 +2487,7 @@ function createToolManager(tool) {
2486
2487
  const timestamp = Date.now();
2487
2488
  const newProvider = {
2488
2489
  ...source,
2489
- id: generateId(),
2490
+ id: generateId("codex"),
2490
2491
  name: newName,
2491
2492
  createdAt: timestamp,
2492
2493
  lastModified: timestamp,
@@ -2501,7 +2502,7 @@ function createToolManager(tool) {
2501
2502
  if (!config.presets) {
2502
2503
  config.presets = [];
2503
2504
  }
2504
- const allPresets = [...toolConfig.builtinPresets, ...config.presets];
2505
+ const allPresets = [...CODEX_PRESETS, ...config.presets];
2505
2506
  const nameExists = allPresets.some((p) => p.name === input.name);
2506
2507
  if (nameExists) {
2507
2508
  throw new PresetNameConflictError(input.name);
@@ -2513,23 +2514,12 @@ function createToolManager(tool) {
2513
2514
  };
2514
2515
  config.presets.push(preset);
2515
2516
  saveConfig2(config);
2516
- return {
2517
- ...preset,
2518
- isBuiltIn: false
2519
- };
2517
+ return preset;
2520
2518
  },
2521
2519
  listPresets() {
2522
2520
  const config = loadConfig2();
2523
2521
  const userPresets = config.presets || [];
2524
- const builtinWithFlag = toolConfig.builtinPresets.map((p) => ({
2525
- ...p,
2526
- isBuiltIn: true
2527
- }));
2528
- const userWithFlag = userPresets.map((p) => ({
2529
- ...p,
2530
- isBuiltIn: false
2531
- }));
2532
- return [...builtinWithFlag, ...userWithFlag];
2522
+ return [...CODEX_PRESETS, ...userPresets];
2533
2523
  },
2534
2524
  editPreset(name, updates) {
2535
2525
  const config = loadConfig2();
@@ -2541,7 +2531,7 @@ function createToolManager(tool) {
2541
2531
  throw new Error(`\u9884\u7F6E\u4E0D\u5B58\u5728: ${name}`);
2542
2532
  }
2543
2533
  if (updates.name !== void 0 && updates.name !== preset.name) {
2544
- const allPresets = [...toolConfig.builtinPresets, ...config.presets];
2534
+ const allPresets = [...CODEX_PRESETS, ...config.presets];
2545
2535
  const nameConflict = allPresets.some((p) => p.name !== name && p.name === updates.name);
2546
2536
  if (nameConflict) {
2547
2537
  throw new PresetNameConflictError(updates.name);
@@ -2554,10 +2544,7 @@ function createToolManager(tool) {
2554
2544
  if (updates.description !== void 0)
2555
2545
  preset.description = updates.description;
2556
2546
  saveConfig2(config);
2557
- return {
2558
- ...preset,
2559
- isBuiltIn: false
2560
- };
2547
+ return preset;
2561
2548
  },
2562
2549
  removePreset(name) {
2563
2550
  const config = loadConfig2();
@@ -2573,13 +2560,201 @@ function createToolManager(tool) {
2573
2560
  }
2574
2561
  };
2575
2562
  }
2576
- function createCodexManager() {
2577
- return createToolManager("codex");
2578
- }
2579
2563
  function createClaudeManager() {
2580
- return createToolManager("claude");
2564
+ const configPath = path3.join(getCcmanDir(), "claude.json");
2565
+ function loadConfig2() {
2566
+ if (!fileExists(configPath)) {
2567
+ ensureDir(getCcmanDir());
2568
+ const initialConfig = {
2569
+ providers: [],
2570
+ presets: []
2571
+ // 只存储用户自定义预置
2572
+ };
2573
+ writeJSON(configPath, initialConfig);
2574
+ return initialConfig;
2575
+ }
2576
+ return readJSON(configPath);
2577
+ }
2578
+ function saveConfig2(config) {
2579
+ writeJSON(configPath, config);
2580
+ }
2581
+ return {
2582
+ add(input) {
2583
+ const config = loadConfig2();
2584
+ const nameExists = config.providers.some((p) => p.name === input.name);
2585
+ if (nameExists) {
2586
+ throw new ProviderNameConflictError(input.name);
2587
+ }
2588
+ const timestamp = Date.now();
2589
+ const provider = {
2590
+ id: generateId("claude"),
2591
+ name: input.name,
2592
+ baseUrl: input.baseUrl,
2593
+ apiKey: input.apiKey,
2594
+ createdAt: timestamp,
2595
+ lastModified: timestamp
2596
+ };
2597
+ config.providers.push(provider);
2598
+ saveConfig2(config);
2599
+ return provider;
2600
+ },
2601
+ list() {
2602
+ const config = loadConfig2();
2603
+ return config.providers;
2604
+ },
2605
+ get(id) {
2606
+ const config = loadConfig2();
2607
+ const provider = config.providers.find((p) => p.id === id);
2608
+ if (!provider) {
2609
+ throw new ProviderNotFoundError(id);
2610
+ }
2611
+ return provider;
2612
+ },
2613
+ findByName(name) {
2614
+ const config = loadConfig2();
2615
+ const lowerName = name.toLowerCase();
2616
+ return config.providers.find((p) => p.name.toLowerCase() === lowerName);
2617
+ },
2618
+ switch(id) {
2619
+ const config = loadConfig2();
2620
+ const provider = config.providers.find((p) => p.id === id);
2621
+ if (!provider) {
2622
+ throw new ProviderNotFoundError(id);
2623
+ }
2624
+ config.currentProviderId = id;
2625
+ provider.lastUsedAt = Date.now();
2626
+ saveConfig2(config);
2627
+ writeClaudeConfig(provider);
2628
+ },
2629
+ getCurrent() {
2630
+ const config = loadConfig2();
2631
+ if (!config.currentProviderId) {
2632
+ return null;
2633
+ }
2634
+ const provider = config.providers.find((p) => p.id === config.currentProviderId);
2635
+ return provider || null;
2636
+ },
2637
+ edit(id, updates) {
2638
+ const config = loadConfig2();
2639
+ const provider = config.providers.find((p) => p.id === id);
2640
+ if (!provider) {
2641
+ throw new ProviderNotFoundError(id);
2642
+ }
2643
+ if (updates.name !== void 0 && updates.name !== provider.name) {
2644
+ const nameConflict = config.providers.some((p) => p.id !== id && p.name === updates.name);
2645
+ if (nameConflict) {
2646
+ throw new ProviderNameConflictError(updates.name);
2647
+ }
2648
+ }
2649
+ if (updates.name !== void 0)
2650
+ provider.name = updates.name;
2651
+ if (updates.baseUrl !== void 0)
2652
+ provider.baseUrl = updates.baseUrl;
2653
+ if (updates.apiKey !== void 0)
2654
+ provider.apiKey = updates.apiKey;
2655
+ provider.lastModified = Date.now();
2656
+ saveConfig2(config);
2657
+ if (config.currentProviderId === id) {
2658
+ writeClaudeConfig(provider);
2659
+ }
2660
+ return provider;
2661
+ },
2662
+ remove(id) {
2663
+ const config = loadConfig2();
2664
+ const index = config.providers.findIndex((p) => p.id === id);
2665
+ if (index === -1) {
2666
+ throw new ProviderNotFoundError(id);
2667
+ }
2668
+ if (config.currentProviderId === id) {
2669
+ config.currentProviderId = void 0;
2670
+ }
2671
+ config.providers.splice(index, 1);
2672
+ saveConfig2(config);
2673
+ },
2674
+ clone(sourceId, newName) {
2675
+ const source = this.get(sourceId);
2676
+ const config = loadConfig2();
2677
+ const nameExists = config.providers.some((p) => p.name === newName);
2678
+ if (nameExists) {
2679
+ throw new ProviderNameConflictError(newName);
2680
+ }
2681
+ const timestamp = Date.now();
2682
+ const newProvider = {
2683
+ ...source,
2684
+ id: generateId("claude"),
2685
+ name: newName,
2686
+ createdAt: timestamp,
2687
+ lastModified: timestamp,
2688
+ lastUsedAt: void 0
2689
+ };
2690
+ config.providers.push(newProvider);
2691
+ saveConfig2(config);
2692
+ return newProvider;
2693
+ },
2694
+ addPreset(input) {
2695
+ const config = loadConfig2();
2696
+ if (!config.presets) {
2697
+ config.presets = [];
2698
+ }
2699
+ const allPresets = [...CC_PRESETS, ...config.presets];
2700
+ const nameExists = allPresets.some((p) => p.name === input.name);
2701
+ if (nameExists) {
2702
+ throw new PresetNameConflictError(input.name);
2703
+ }
2704
+ const preset = {
2705
+ name: input.name,
2706
+ baseUrl: input.baseUrl,
2707
+ description: input.description
2708
+ };
2709
+ config.presets.push(preset);
2710
+ saveConfig2(config);
2711
+ return preset;
2712
+ },
2713
+ listPresets() {
2714
+ const config = loadConfig2();
2715
+ const userPresets = config.presets || [];
2716
+ return [...CC_PRESETS, ...userPresets];
2717
+ },
2718
+ editPreset(name, updates) {
2719
+ const config = loadConfig2();
2720
+ if (!config.presets) {
2721
+ config.presets = [];
2722
+ }
2723
+ const preset = config.presets.find((p) => p.name === name);
2724
+ if (!preset) {
2725
+ throw new Error(`\u9884\u7F6E\u4E0D\u5B58\u5728: ${name}`);
2726
+ }
2727
+ if (updates.name !== void 0 && updates.name !== preset.name) {
2728
+ const allPresets = [...CC_PRESETS, ...config.presets];
2729
+ const nameConflict = allPresets.some((p) => p.name !== name && p.name === updates.name);
2730
+ if (nameConflict) {
2731
+ throw new PresetNameConflictError(updates.name);
2732
+ }
2733
+ }
2734
+ if (updates.name !== void 0)
2735
+ preset.name = updates.name;
2736
+ if (updates.baseUrl !== void 0)
2737
+ preset.baseUrl = updates.baseUrl;
2738
+ if (updates.description !== void 0)
2739
+ preset.description = updates.description;
2740
+ saveConfig2(config);
2741
+ return preset;
2742
+ },
2743
+ removePreset(name) {
2744
+ const config = loadConfig2();
2745
+ if (!config.presets) {
2746
+ return;
2747
+ }
2748
+ const index = config.presets.findIndex((p) => p.name === name);
2749
+ if (index === -1) {
2750
+ throw new Error(`Preset not found: ${name}`);
2751
+ }
2752
+ config.presets.splice(index, 1);
2753
+ saveConfig2(config);
2754
+ }
2755
+ };
2581
2756
  }
2582
- var path3, ProviderNotFoundError, ProviderNameConflictError, PresetNameConflictError, TOOL_CONFIGS;
2757
+ var path3, ProviderNotFoundError, ProviderNameConflictError, PresetNameConflictError;
2583
2758
  var init_tool_manager = __esm({
2584
2759
  "../core/dist/tool-manager.js"() {
2585
2760
  "use strict";
@@ -2608,18 +2783,6 @@ var init_tool_manager = __esm({
2608
2783
  this.name = "PresetNameConflictError";
2609
2784
  }
2610
2785
  };
2611
- TOOL_CONFIGS = {
2612
- codex: {
2613
- configPath: path3.join(getCcmanDir(), "codex.json"),
2614
- builtinPresets: CODEX_PRESETS,
2615
- writer: writeCodexConfig
2616
- },
2617
- claude: {
2618
- configPath: path3.join(getCcmanDir(), "claude.json"),
2619
- builtinPresets: CC_PRESETS,
2620
- writer: writeClaudeConfig
2621
- }
2622
- };
2623
2786
  }
2624
2787
  });
2625
2788
 
@@ -16146,24 +16309,14 @@ function decryptApiKey(encryptedApiKey, password) {
16146
16309
  }
16147
16310
  function encryptProviders(providers, password) {
16148
16311
  return providers.map((provider) => ({
16149
- id: provider.id,
16150
- name: provider.name,
16151
- baseUrl: provider.baseUrl,
16152
- encryptedApiKey: encryptApiKey(provider.apiKey, password),
16153
- createdAt: provider.createdAt,
16154
- lastModified: provider.lastModified,
16155
- lastUsedAt: provider.lastUsedAt
16312
+ ...provider,
16313
+ apiKey: encryptApiKey(provider.apiKey, password)
16156
16314
  }));
16157
16315
  }
16158
16316
  function decryptProviders(encryptedProviders, password) {
16159
16317
  return encryptedProviders.map((provider) => ({
16160
- id: provider.id,
16161
- name: provider.name,
16162
- baseUrl: provider.baseUrl,
16163
- apiKey: decryptApiKey(provider.encryptedApiKey, password),
16164
- createdAt: provider.createdAt,
16165
- lastModified: provider.lastModified,
16166
- lastUsedAt: provider.lastUsedAt
16318
+ ...provider,
16319
+ apiKey: decryptApiKey(provider.apiKey, password)
16167
16320
  }));
16168
16321
  }
16169
16322
  var crypto, ALGORITHM, KEY_LENGTH, IV_LENGTH, SALT_LENGTH, TAG_LENGTH, PBKDF2_ITERATIONS;
@@ -16181,15 +16334,6 @@ var init_crypto2 = __esm({
16181
16334
  });
16182
16335
 
16183
16336
  // ../core/dist/sync/merge-advanced.js
16184
- function ensureLastModified(provider) {
16185
- if (provider.lastModified === void 0) {
16186
- return {
16187
- ...provider,
16188
- lastModified: provider.createdAt
16189
- };
16190
- }
16191
- return provider;
16192
- }
16193
16337
  function isSameConfig(a, b) {
16194
16338
  return a.baseUrl === b.baseUrl && a.apiKey === b.apiKey;
16195
16339
  }
@@ -16214,49 +16358,26 @@ function resolveNameConflict(existingProviders, newProvider) {
16214
16358
  };
16215
16359
  }
16216
16360
  function mergeProviders(local, remote) {
16217
- const localProviders = local.map(ensureLastModified);
16218
- const remoteProviders = remote.map(ensureLastModified);
16219
16361
  const mergedMap = /* @__PURE__ */ new Map();
16220
16362
  let hasChanges = false;
16221
- for (const localProvider of localProviders) {
16363
+ for (const localProvider of local) {
16222
16364
  mergedMap.set(localProvider.id, localProvider);
16223
16365
  }
16224
- for (const remoteProvider of remoteProviders) {
16225
- if (mergedMap.has(remoteProvider.id)) {
16226
- const localProvider = mergedMap.get(remoteProvider.id);
16227
- if (remoteProvider.lastModified > localProvider.lastModified) {
16228
- console.log(`provider ${remoteProvider.id} \u8FDC\u7A0B\u66F4\u65B0\uFF0C\u4F7F\u7528\u8FDC\u7A0B\u7248\u672C`);
16229
- mergedMap.set(remoteProvider.id, remoteProvider);
16366
+ for (const remoteProvider of remote) {
16367
+ const existingLocal = Array.from(mergedMap.values()).find((p) => isSameConfig(p, remoteProvider));
16368
+ if (existingLocal) {
16369
+ mergedMap.delete(existingLocal.id);
16370
+ mergedMap.set(remoteProvider.id, remoteProvider);
16371
+ if (!isProviderEqual(existingLocal, remoteProvider)) {
16230
16372
  hasChanges = true;
16231
- } else if (remoteProvider.lastModified < localProvider.lastModified) {
16232
- console.log(`provider ${remoteProvider.id} \u672C\u5730\u66F4\u65B0\uFF0C\u4F7F\u7528\u672C\u5730\u7248\u672C`);
16233
- hasChanges = true;
16234
- } else {
16235
- if (!isProviderEqual(localProvider, remoteProvider)) {
16236
- console.log(`provider ${remoteProvider.id} \u65F6\u95F4\u6233\u76F8\u540C\u4F46\u5185\u5BB9\u4E0D\u540C\uFF0C\u4F7F\u7528\u8FDC\u7A0B\u7248\u672C`);
16237
- mergedMap.set(remoteProvider.id, remoteProvider);
16238
- hasChanges = true;
16239
- }
16373
+ console.log(`\u76F8\u540C\u914D\u7F6E (${remoteProvider.baseUrl})\uFF0C\u4F7F\u7528\u4E91\u7AEF\u6570\u636E`);
16240
16374
  }
16241
16375
  } else {
16242
- const existingWithSameConfig = Array.from(mergedMap.values()).find((p) => isSameConfig(p, remoteProvider));
16243
- if (existingWithSameConfig) {
16244
- if (remoteProvider.lastModified > existingWithSameConfig.lastModified) {
16245
- console.log(`\u76F8\u540C\u914D\u7F6E (${remoteProvider.baseUrl})\uFF0C\u8FDC\u7A0B\u66F4\u65B0\uFF0C\u66FF\u6362 ${existingWithSameConfig.id} \u4E3A ${remoteProvider.id}`);
16246
- mergedMap.delete(existingWithSameConfig.id);
16247
- mergedMap.set(remoteProvider.id, remoteProvider);
16248
- hasChanges = true;
16249
- } else {
16250
- console.log(`\u76F8\u540C\u914D\u7F6E (${remoteProvider.baseUrl})\uFF0C\u672C\u5730\u66F4\u65B0\uFF0C\u4FDD\u7559 ${existingWithSameConfig.id}`);
16251
- hasChanges = true;
16252
- }
16253
- } else {
16254
- console.log(`\u65B0 provider ${remoteProvider.id}\uFF0C\u6DFB\u52A0\u5230\u5408\u5E76\u5217\u8868`);
16255
- const existingProviders = Array.from(mergedMap.values());
16256
- const resolvedProvider = resolveNameConflict(existingProviders, remoteProvider);
16257
- mergedMap.set(resolvedProvider.id, resolvedProvider);
16258
- hasChanges = true;
16259
- }
16376
+ const existingProviders = Array.from(mergedMap.values());
16377
+ const resolvedProvider = resolveNameConflict(existingProviders, remoteProvider);
16378
+ mergedMap.set(resolvedProvider.id, resolvedProvider);
16379
+ hasChanges = true;
16380
+ console.log(`\u65B0 provider ${resolvedProvider.name}\uFF0C\u6DFB\u52A0\u5230\u5408\u5E76\u5217\u8868`);
16260
16381
  }
16261
16382
  }
16262
16383
  const merged = Array.from(mergedMap.values());
@@ -16265,6 +16386,43 @@ function mergeProviders(local, remote) {
16265
16386
  hasChanges
16266
16387
  };
16267
16388
  }
16389
+ function resolvePresetNameConflict(existingPresets, newPreset) {
16390
+ const existingNames = new Set(existingPresets.map((p) => p.name));
16391
+ if (!existingNames.has(newPreset.name)) {
16392
+ return newPreset;
16393
+ }
16394
+ let suffix = 2;
16395
+ let newName = `${newPreset.name}_${suffix}`;
16396
+ while (existingNames.has(newName)) {
16397
+ suffix++;
16398
+ newName = `${newPreset.name}_${suffix}`;
16399
+ }
16400
+ console.log(`preset name \u51B2\u7A81\uFF1A\u5C06 "${newPreset.name}" \u91CD\u547D\u540D\u4E3A "${newName}"`);
16401
+ return {
16402
+ ...newPreset,
16403
+ name: newName
16404
+ };
16405
+ }
16406
+ function mergePresets(local, remote) {
16407
+ const localPresets = local || [];
16408
+ const remotePresets = remote || [];
16409
+ const mergedMap = /* @__PURE__ */ new Map();
16410
+ for (const preset of localPresets) {
16411
+ mergedMap.set(preset.baseUrl, preset);
16412
+ }
16413
+ for (const remotePreset of remotePresets) {
16414
+ const existingLocal = mergedMap.get(remotePreset.baseUrl);
16415
+ if (existingLocal) {
16416
+ mergedMap.set(remotePreset.baseUrl, remotePreset);
16417
+ console.log(`preset ${remotePreset.name} (${remotePreset.baseUrl})\uFF0C\u4F7F\u7528\u4E91\u7AEF\u6570\u636E`);
16418
+ } else {
16419
+ const existingPresets = Array.from(mergedMap.values());
16420
+ const resolvedPreset = resolvePresetNameConflict(existingPresets, remotePreset);
16421
+ mergedMap.set(resolvedPreset.baseUrl, resolvedPreset);
16422
+ }
16423
+ }
16424
+ return Array.from(mergedMap.values());
16425
+ }
16268
16426
  var init_merge_advanced = __esm({
16269
16427
  "../core/dist/sync/merge-advanced.js"() {
16270
16428
  "use strict";
@@ -16281,12 +16439,16 @@ async function uploadToCloud(config, password) {
16281
16439
  const encryptedCodexProviders = encryptProviders(codexConfig.providers, password);
16282
16440
  const encryptedClaudeProviders = encryptProviders(claudeConfig.providers, password);
16283
16441
  const encryptedCodexConfig = {
16284
- currentProviderId: codexConfig.currentProviderId,
16442
+ ...codexConfig,
16443
+ // 保留所有字段
16285
16444
  providers: encryptedCodexProviders
16445
+ // 只替换 providers(加密后的)
16286
16446
  };
16287
16447
  const encryptedClaudeConfig = {
16288
- currentProviderId: claudeConfig.currentProviderId,
16448
+ ...claudeConfig,
16449
+ // 保留所有字段
16289
16450
  providers: encryptedClaudeProviders
16451
+ // 只替换 providers(加密后的)
16290
16452
  };
16291
16453
  const codexJson = JSON.stringify(encryptedCodexConfig, null, 2);
16292
16454
  const claudeJson = JSON.stringify(encryptedClaudeConfig, null, 2);
@@ -16331,24 +16493,22 @@ async function downloadFromCloud(config, password) {
16331
16493
  throw new Error(`\u5907\u4EFD\u5931\u8D25: ${error.message}`);
16332
16494
  }
16333
16495
  try {
16334
- const currentCodexConfig = readJSON(codexConfigPath);
16335
- const currentClaudeConfig = readJSON(claudeConfigPath);
16336
16496
  if (remoteCodexConfig && decryptedCodexProviders) {
16337
16497
  const newCodexConfig = {
16338
- currentProviderId: remoteCodexConfig.currentProviderId,
16339
- providers: decryptedCodexProviders,
16340
- presets: currentCodexConfig.presets
16341
- // 保留本地 presets
16498
+ ...remoteCodexConfig,
16499
+ // 使用云端配置的所有字段
16500
+ providers: decryptedCodexProviders
16501
+ // 只替换 providers(解密后的)
16342
16502
  };
16343
16503
  writeJSON(codexConfigPath, newCodexConfig);
16344
16504
  applyCurrentProvider("codex", newCodexConfig);
16345
16505
  }
16346
16506
  if (remoteClaudeConfig && decryptedClaudeProviders) {
16347
16507
  const newClaudeConfig = {
16348
- currentProviderId: remoteClaudeConfig.currentProviderId,
16349
- providers: decryptedClaudeProviders,
16350
- presets: currentClaudeConfig.presets
16351
- // 保留本地 presets
16508
+ ...remoteClaudeConfig,
16509
+ // 使用云端配置的所有字段
16510
+ providers: decryptedClaudeProviders
16511
+ // 只替换 providers(解密后的)
16352
16512
  };
16353
16513
  writeJSON(claudeConfigPath, newClaudeConfig);
16354
16514
  applyCurrentProvider("claude", newClaudeConfig);
@@ -16418,16 +16578,24 @@ async function mergeSync(config, password) {
16418
16578
  } catch (error) {
16419
16579
  throw new Error(`\u5907\u4EFD\u5931\u8D25: ${error.message}`);
16420
16580
  }
16581
+ const mergedCodexPresets = mergePresets(localCodexConfig.presets, remoteCodexConfig?.presets);
16582
+ const mergedClaudePresets = mergePresets(localClaudeConfig.presets, remoteClaudeConfig?.presets);
16421
16583
  try {
16422
16584
  const mergedCodexConfig = {
16423
- currentProviderId: localCodexConfig.currentProviderId,
16585
+ ...localCodexConfig,
16586
+ // 保留本地配置的所有字段
16424
16587
  providers: codexMergeResult.merged,
16425
- presets: localCodexConfig.presets
16588
+ // 替换为合并后的 providers
16589
+ presets: mergedCodexPresets
16590
+ // 替换为合并后的 presets
16426
16591
  };
16427
16592
  const mergedClaudeConfig = {
16428
- currentProviderId: localClaudeConfig.currentProviderId,
16593
+ ...localClaudeConfig,
16594
+ // 保留本地配置的所有字段
16429
16595
  providers: claudeMergeResult.merged,
16430
- presets: localClaudeConfig.presets
16596
+ // 替换为合并后的 providers
16597
+ presets: mergedClaudePresets
16598
+ // 替换为合并后的 presets
16431
16599
  };
16432
16600
  writeJSON(codexConfigPath, mergedCodexConfig);
16433
16601
  writeJSON(claudeConfigPath, mergedClaudeConfig);
@@ -16436,12 +16604,16 @@ async function mergeSync(config, password) {
16436
16604
  const encryptedCodexProviders = encryptProviders(codexMergeResult.merged, password);
16437
16605
  const encryptedClaudeProviders = encryptProviders(claudeMergeResult.merged, password);
16438
16606
  const encryptedCodexConfig = {
16439
- currentProviderId: mergedCodexConfig.currentProviderId,
16607
+ ...mergedCodexConfig,
16608
+ // 保留合并后配置的所有字段
16440
16609
  providers: encryptedCodexProviders
16610
+ // 只替换 providers(加密后的)
16441
16611
  };
16442
16612
  const encryptedClaudeConfig = {
16443
- currentProviderId: mergedClaudeConfig.currentProviderId,
16613
+ ...mergedClaudeConfig,
16614
+ // 保留合并后配置的所有字段
16444
16615
  providers: encryptedClaudeProviders
16616
+ // 只替换 providers(加密后的)
16445
16617
  };
16446
16618
  const codexJson2 = JSON.stringify(encryptedCodexConfig, null, 2);
16447
16619
  const claudeJson2 = JSON.stringify(encryptedClaudeConfig, null, 2);
@@ -16661,45 +16833,12 @@ var init_dist4 = __esm({
16661
16833
  });
16662
16834
 
16663
16835
  // src/utils/sync-config.ts
16664
- function getMachineId() {
16665
- return import_crypto4.default.createHash("sha256").update(import_os.default.hostname() + import_os.default.userInfo().username).digest();
16666
- }
16667
- function encrypt(text) {
16668
- const key = getMachineId();
16669
- const iv = import_crypto4.default.randomBytes(16);
16670
- const cipher = import_crypto4.default.createCipheriv("aes-256-cbc", key, iv);
16671
- let encrypted = cipher.update(text, "utf8", "hex");
16672
- encrypted += cipher.final("hex");
16673
- return iv.toString("hex") + ":" + encrypted;
16674
- }
16675
- function decrypt(encrypted) {
16676
- const parts = encrypted.split(":");
16677
- const iv = Buffer.from(parts[0], "hex");
16678
- const encryptedText = parts[1];
16679
- const key = getMachineId();
16680
- const decipher = import_crypto4.default.createDecipheriv("aes-256-cbc", key, iv);
16681
- let decrypted = decipher.update(encryptedText, "hex", "utf8");
16682
- decrypted += decipher.final("utf8");
16683
- return decrypted;
16684
- }
16685
16836
  function loadSyncConfig() {
16686
16837
  try {
16687
16838
  const config = getSyncConfig();
16688
16839
  if (!config) {
16689
16840
  return null;
16690
16841
  }
16691
- if (config.password && config.password.includes(":")) {
16692
- try {
16693
- config.password = decrypt(config.password);
16694
- } catch {
16695
- }
16696
- }
16697
- if (config.syncPassword && config.syncPassword.includes(":")) {
16698
- try {
16699
- config.syncPassword = decrypt(config.syncPassword);
16700
- } catch {
16701
- }
16702
- }
16703
16842
  return config;
16704
16843
  } catch (error) {
16705
16844
  throw new Error(`\u8BFB\u53D6\u540C\u6B65\u914D\u7F6E\u5931\u8D25: ${error.message}`);
@@ -16708,12 +16847,7 @@ function loadSyncConfig() {
16708
16847
  function saveSyncConfig2(config) {
16709
16848
  try {
16710
16849
  const configToSave = { ...config };
16711
- if (configToSave.password) {
16712
- configToSave.password = encrypt(configToSave.password);
16713
- }
16714
- if (configToSave.syncPassword && configToSave.rememberSyncPassword) {
16715
- configToSave.syncPassword = encrypt(configToSave.syncPassword);
16716
- } else {
16850
+ if (!configToSave.rememberSyncPassword) {
16717
16851
  delete configToSave.syncPassword;
16718
16852
  }
16719
16853
  configToSave.lastSync = Date.now();
@@ -16725,12 +16859,9 @@ function saveSyncConfig2(config) {
16725
16859
  function getSyncConfigPath() {
16726
16860
  return getConfigPath();
16727
16861
  }
16728
- var import_crypto4, import_os;
16729
16862
  var init_sync_config = __esm({
16730
16863
  "src/utils/sync-config.ts"() {
16731
16864
  "use strict";
16732
- import_crypto4 = __toESM(require("crypto"));
16733
- import_os = __toESM(require("os"));
16734
16865
  init_dist4();
16735
16866
  }
16736
16867
  });
@@ -18956,6 +19087,26 @@ program.name("ccman").description("Codex/Claude Code API \u670D\u52A1\u5546\u914
18956
19087
  }
18957
19088
  throw err;
18958
19089
  });
19090
+ program.on("command:*", (operands) => {
19091
+ const unknownCommand = operands[0];
19092
+ console.error(import_chalk27.default.red(`
19093
+ \u274C \u672A\u77E5\u547D\u4EE4: ${unknownCommand}
19094
+ `));
19095
+ const availableCommands = ["cx", "cc", "sync", "export", "import"];
19096
+ const suggestions = availableCommands.filter(
19097
+ (cmd) => cmd.includes(unknownCommand) || unknownCommand.includes(cmd)
19098
+ );
19099
+ if (suggestions.length > 0) {
19100
+ console.log(import_chalk27.default.yellow("\u{1F4A1} \u4F60\u662F\u4E0D\u662F\u60F3\u8F93\u5165:"));
19101
+ suggestions.forEach((cmd) => {
19102
+ console.log(import_chalk27.default.cyan(` ccman ${cmd}`));
19103
+ });
19104
+ console.log();
19105
+ }
19106
+ console.log(import_chalk27.default.gray("\u67E5\u770B\u6240\u6709\u53EF\u7528\u547D\u4EE4: ") + import_chalk27.default.cyan("ccman --help"));
19107
+ console.log();
19108
+ process.exit(1);
19109
+ });
18959
19110
  var cx = program.command("cx").description("\u7BA1\u7406 Codex \u670D\u52A1\u5546");
18960
19111
  createCodexCommands(cx);
18961
19112
  cx.action(async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccman",
3
- "version": "3.0.21",
3
+ "version": "3.0.22",
4
4
  "description": "Manage Codex and Claude Code API service provider configurations",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {