ccman 3.1.0 → 3.1.1

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 +227 -165
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "../core/package.json"() {
16
16
  package_default = {
17
17
  name: "@ccman/core",
18
- version: "3.1.0",
18
+ version: "3.1.1",
19
19
  type: "module",
20
20
  description: "Core business logic for ccman",
21
21
  main: "./dist/index.js",
@@ -65,6 +65,59 @@ var init_package = __esm({
65
65
  }
66
66
  });
67
67
 
68
+ // ../core/dist/constants.js
69
+ var TOOL_TYPES, MAIN_TOOL_TYPES, TOOL_CONFIG;
70
+ var init_constants = __esm({
71
+ "../core/dist/constants.js"() {
72
+ "use strict";
73
+ TOOL_TYPES = {
74
+ CODEX: "codex",
75
+ CLAUDE: "claude",
76
+ MCP: "mcp",
77
+ GEMINI: "gemini"
78
+ };
79
+ MAIN_TOOL_TYPES = {
80
+ CODEX: TOOL_TYPES.CODEX,
81
+ CLAUDE: TOOL_TYPES.CLAUDE,
82
+ GEMINI: TOOL_TYPES.GEMINI
83
+ };
84
+ TOOL_CONFIG = {
85
+ [TOOL_TYPES.CODEX]: {
86
+ displayName: "Codex",
87
+ color: "blue",
88
+ textColorClass: "text-blue-600",
89
+ bgColorClass: "bg-blue-50",
90
+ hoverBgColorClass: "hover:bg-blue-100",
91
+ description: "Codex AI \u52A9\u624B"
92
+ },
93
+ [TOOL_TYPES.CLAUDE]: {
94
+ displayName: "Claude Code",
95
+ color: "purple",
96
+ textColorClass: "text-purple-600",
97
+ bgColorClass: "bg-purple-50",
98
+ hoverBgColorClass: "hover:bg-purple-100",
99
+ description: "Claude Code AI \u52A9\u624B"
100
+ },
101
+ [TOOL_TYPES.MCP]: {
102
+ displayName: "MCP",
103
+ color: "gray",
104
+ textColorClass: "text-gray-600",
105
+ bgColorClass: "bg-gray-50",
106
+ hoverBgColorClass: "hover:bg-gray-100",
107
+ description: "MCP \u670D\u52A1"
108
+ },
109
+ [TOOL_TYPES.GEMINI]: {
110
+ displayName: "Gemini CLI",
111
+ color: "green",
112
+ textColorClass: "text-green-600",
113
+ bgColorClass: "bg-green-50",
114
+ hoverBgColorClass: "hover:bg-green-100",
115
+ description: "Gemini CLI AI \u52A9\u624B"
116
+ }
117
+ };
118
+ }
119
+ });
120
+
68
121
  // ../core/dist/paths.js
69
122
  import * as os from "os";
70
123
  import * as path from "path";
@@ -1510,87 +1563,77 @@ import fs8 from "fs";
1510
1563
  import path8 from "path";
1511
1564
  async function uploadToCloud(config, password) {
1512
1565
  const ccmanDir2 = getCcmanDir();
1513
- const codexConfigPath = path8.join(ccmanDir2, "codex.json");
1514
- const claudeConfigPath = path8.join(ccmanDir2, "claude.json");
1515
- const codexConfig = readJSON(codexConfigPath);
1516
- const claudeConfig = readJSON(claudeConfigPath);
1517
- const encryptedCodexProviders = encryptProviders(codexConfig.providers, password);
1518
- const encryptedClaudeProviders = encryptProviders(claudeConfig.providers, password);
1519
- const encryptedCodexConfig = {
1520
- ...codexConfig,
1521
- // 保留所有字段
1522
- providers: encryptedCodexProviders
1523
- // 只替换 providers(加密后的)
1524
- };
1525
- const encryptedClaudeConfig = {
1526
- ...claudeConfig,
1527
- // 保留所有字段
1528
- providers: encryptedClaudeProviders
1529
- // 只替换 providers(加密后的)
1530
- };
1531
- const codexJson = JSON.stringify(encryptedCodexConfig, null, 2);
1532
- const claudeJson = JSON.stringify(encryptedClaudeConfig, null, 2);
1533
- await uploadToWebDAV(config, CODEX_REMOTE_PATH, codexJson);
1534
- await uploadToWebDAV(config, CLAUDE_REMOTE_PATH, claudeJson);
1566
+ const toolKeys = Object.keys(TOOL_SYNC_CONFIG);
1567
+ for (const tool of toolKeys) {
1568
+ const { remotePath, configFilename } = TOOL_SYNC_CONFIG[tool];
1569
+ const configPath = path8.join(ccmanDir2, configFilename);
1570
+ const localConfig = readJSON(configPath);
1571
+ const encryptedProviders = encryptProviders(localConfig.providers, password);
1572
+ const encryptedConfig = {
1573
+ ...localConfig,
1574
+ // 保留所有字段
1575
+ providers: encryptedProviders
1576
+ // 只替换 providers(加密后的)
1577
+ };
1578
+ const jsonContent = JSON.stringify(encryptedConfig, null, 2);
1579
+ await uploadToWebDAV(config, remotePath, jsonContent);
1580
+ }
1535
1581
  updateLastSyncTime();
1536
1582
  console.log("\u2705 \u914D\u7F6E\u5DF2\u4E0A\u4F20\u5230\u4E91\u7AEF");
1537
1583
  }
1538
1584
  async function downloadFromCloud(config, password) {
1539
- const codexExists = await existsOnWebDAV(config, CODEX_REMOTE_PATH);
1540
- const claudeExists = await existsOnWebDAV(config, CLAUDE_REMOTE_PATH);
1541
- if (!codexExists && !claudeExists) {
1585
+ const ccmanDir2 = getCcmanDir();
1586
+ const toolKeys = Object.keys(TOOL_SYNC_CONFIG);
1587
+ const existsChecks = await Promise.all(toolKeys.map(async (tool) => {
1588
+ const { remotePath } = TOOL_SYNC_CONFIG[tool];
1589
+ return existsOnWebDAV(config, remotePath);
1590
+ }));
1591
+ if (!existsChecks.some((exists) => exists)) {
1542
1592
  throw new Error("\u8FDC\u7A0B\u914D\u7F6E\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u4E0A\u4F20\u914D\u7F6E");
1543
1593
  }
1544
- const codexJson = codexExists ? await downloadFromWebDAV(config, CODEX_REMOTE_PATH) : null;
1545
- const claudeJson = claudeExists ? await downloadFromWebDAV(config, CLAUDE_REMOTE_PATH) : null;
1546
- const remoteCodexConfig = codexJson ? JSON.parse(codexJson) : null;
1547
- const remoteClaudeConfig = claudeJson ? JSON.parse(claudeJson) : null;
1548
- let decryptedCodexProviders = null;
1549
- let decryptedClaudeProviders = null;
1550
- try {
1551
- if (remoteCodexConfig) {
1552
- decryptedCodexProviders = decryptProviders(remoteCodexConfig.providers, password);
1553
- }
1554
- if (remoteClaudeConfig) {
1555
- decryptedClaudeProviders = decryptProviders(remoteClaudeConfig.providers, password);
1594
+ const remoteConfigs = [];
1595
+ for (let i = 0; i < toolKeys.length; i++) {
1596
+ const tool = toolKeys[i];
1597
+ const { remotePath } = TOOL_SYNC_CONFIG[tool];
1598
+ if (existsChecks[i]) {
1599
+ const jsonContent = await downloadFromWebDAV(config, remotePath);
1600
+ const remoteConfig = JSON.parse(jsonContent);
1601
+ try {
1602
+ const decryptedProviders = decryptProviders(remoteConfig.providers, password);
1603
+ remoteConfigs.push({ tool, config: remoteConfig, decryptedProviders });
1604
+ } catch (error) {
1605
+ throw new Error("\u89E3\u5BC6\u5931\u8D25\uFF1A\u5BC6\u7801\u9519\u8BEF\u6216\u6570\u636E\u635F\u574F");
1606
+ }
1607
+ } else {
1608
+ remoteConfigs.push({ tool, config: null, decryptedProviders: null });
1556
1609
  }
1557
- } catch (error) {
1558
- throw new Error("\u89E3\u5BC6\u5931\u8D25\uFF1A\u5BC6\u7801\u9519\u8BEF\u6216\u6570\u636E\u635F\u574F");
1559
1610
  }
1560
1611
  const backupPaths = [];
1561
- const ccmanDir2 = getCcmanDir();
1562
- const codexConfigPath = path8.join(ccmanDir2, "codex.json");
1563
- const claudeConfigPath = path8.join(ccmanDir2, "claude.json");
1564
1612
  try {
1565
- if (fs8.existsSync(codexConfigPath)) {
1566
- backupPaths.push(backupConfig(codexConfigPath));
1567
- }
1568
- if (fs8.existsSync(claudeConfigPath)) {
1569
- backupPaths.push(backupConfig(claudeConfigPath));
1613
+ for (const tool of toolKeys) {
1614
+ const { configFilename } = TOOL_SYNC_CONFIG[tool];
1615
+ const configPath = path8.join(ccmanDir2, configFilename);
1616
+ if (fs8.existsSync(configPath)) {
1617
+ backupPaths.push(backupConfig(configPath));
1618
+ }
1570
1619
  }
1571
1620
  } catch (error) {
1572
1621
  throw new Error(`\u5907\u4EFD\u5931\u8D25: ${error.message}`);
1573
1622
  }
1574
1623
  try {
1575
- if (remoteCodexConfig && decryptedCodexProviders) {
1576
- const newCodexConfig = {
1577
- ...remoteCodexConfig,
1578
- // 使用云端配置的所有字段
1579
- providers: decryptedCodexProviders
1580
- // 只替换 providers(解密后的)
1581
- };
1582
- writeJSON(codexConfigPath, newCodexConfig);
1583
- applyCurrentProvider("codex", newCodexConfig);
1584
- }
1585
- if (remoteClaudeConfig && decryptedClaudeProviders) {
1586
- const newClaudeConfig = {
1587
- ...remoteClaudeConfig,
1624
+ for (const { tool, config: remoteConfig, decryptedProviders } of remoteConfigs) {
1625
+ if (!remoteConfig || !decryptedProviders)
1626
+ continue;
1627
+ const { configFilename } = TOOL_SYNC_CONFIG[tool];
1628
+ const configPath = path8.join(ccmanDir2, configFilename);
1629
+ const newConfig = {
1630
+ ...remoteConfig,
1588
1631
  // 使用云端配置的所有字段
1589
- providers: decryptedClaudeProviders
1632
+ providers: decryptedProviders
1590
1633
  // 只替换 providers(解密后的)
1591
1634
  };
1592
- writeJSON(claudeConfigPath, newClaudeConfig);
1593
- applyCurrentProvider("claude", newClaudeConfig);
1635
+ writeJSON(configPath, newConfig);
1636
+ applyCurrentProvider(tool, newConfig);
1594
1637
  }
1595
1638
  updateLastSyncTime();
1596
1639
  console.log("\u2705 \u914D\u7F6E\u5DF2\u4ECE\u4E91\u7AEF\u4E0B\u8F7D\u5E76\u5E94\u7528");
@@ -1606,9 +1649,13 @@ async function downloadFromCloud(config, password) {
1606
1649
  }
1607
1650
  }
1608
1651
  async function mergeSync(config, password) {
1609
- const codexExists = await existsOnWebDAV(config, CODEX_REMOTE_PATH);
1610
- const claudeExists = await existsOnWebDAV(config, CLAUDE_REMOTE_PATH);
1611
- if (!codexExists && !claudeExists) {
1652
+ const ccmanDir2 = getCcmanDir();
1653
+ const toolKeys = Object.keys(TOOL_SYNC_CONFIG);
1654
+ const existsChecks = await Promise.all(toolKeys.map(async (tool) => {
1655
+ const { remotePath } = TOOL_SYNC_CONFIG[tool];
1656
+ return existsOnWebDAV(config, remotePath);
1657
+ }));
1658
+ if (!existsChecks.some((exists) => exists)) {
1612
1659
  console.log("\u8FDC\u7A0B\u914D\u7F6E\u4E0D\u5B58\u5728\uFF0C\u6267\u884C\u4E0A\u4F20\u64CD\u4F5C");
1613
1660
  await uploadToCloud(config, password);
1614
1661
  return {
@@ -1616,30 +1663,31 @@ async function mergeSync(config, password) {
1616
1663
  backupPaths: []
1617
1664
  };
1618
1665
  }
1619
- const codexJson = codexExists ? await downloadFromWebDAV(config, CODEX_REMOTE_PATH) : null;
1620
- const claudeJson = claudeExists ? await downloadFromWebDAV(config, CLAUDE_REMOTE_PATH) : null;
1621
- const remoteCodexConfig = codexJson ? JSON.parse(codexJson) : null;
1622
- const remoteClaudeConfig = claudeJson ? JSON.parse(claudeJson) : null;
1623
- let remoteCodexProviders = [];
1624
- let remoteClaudeProviders = [];
1625
- try {
1626
- if (remoteCodexConfig) {
1627
- remoteCodexProviders = decryptProviders(remoteCodexConfig.providers, password);
1628
- }
1629
- if (remoteClaudeConfig) {
1630
- remoteClaudeProviders = decryptProviders(remoteClaudeConfig.providers, password);
1666
+ const mergeDataList = [];
1667
+ for (let i = 0; i < toolKeys.length; i++) {
1668
+ const tool = toolKeys[i];
1669
+ const { remotePath, configFilename } = TOOL_SYNC_CONFIG[tool];
1670
+ const configPath = path8.join(ccmanDir2, configFilename);
1671
+ const localConfig = readJSON(configPath);
1672
+ let remoteProviders = [];
1673
+ if (existsChecks[i]) {
1674
+ try {
1675
+ const jsonContent = await downloadFromWebDAV(config, remotePath);
1676
+ const remoteConfig = JSON.parse(jsonContent);
1677
+ remoteProviders = decryptProviders(remoteConfig.providers, password);
1678
+ } catch (error) {
1679
+ throw new Error("\u89E3\u5BC6\u5931\u8D25\uFF1A\u5BC6\u7801\u9519\u8BEF\u6216\u6570\u636E\u635F\u574F");
1680
+ }
1631
1681
  }
1632
- } catch (error) {
1633
- throw new Error("\u89E3\u5BC6\u5931\u8D25\uFF1A\u5BC6\u7801\u9519\u8BEF\u6216\u6570\u636E\u635F\u574F");
1682
+ const mergeResult = mergeProviders(localConfig.providers, remoteProviders);
1683
+ mergeDataList.push({
1684
+ tool,
1685
+ localConfig,
1686
+ remoteProviders,
1687
+ mergeResult
1688
+ });
1634
1689
  }
1635
- const ccmanDir2 = getCcmanDir();
1636
- const codexConfigPath = path8.join(ccmanDir2, "codex.json");
1637
- const claudeConfigPath = path8.join(ccmanDir2, "claude.json");
1638
- const localCodexConfig = readJSON(codexConfigPath);
1639
- const localClaudeConfig = readJSON(claudeConfigPath);
1640
- const codexMergeResult = mergeProviders(localCodexConfig.providers, remoteCodexProviders);
1641
- const claudeMergeResult = mergeProviders(localClaudeConfig.providers, remoteClaudeProviders);
1642
- const hasChanges = codexMergeResult.hasChanges || claudeMergeResult.hasChanges;
1690
+ const hasChanges = mergeDataList.some((data) => data.mergeResult.hasChanges);
1643
1691
  if (!hasChanges) {
1644
1692
  console.log("\u2139\uFE0F \u914D\u7F6E\u5DF2\u540C\u6B65\uFF0C\u65E0\u9700\u64CD\u4F5C");
1645
1693
  return {
@@ -1649,56 +1697,47 @@ async function mergeSync(config, password) {
1649
1697
  }
1650
1698
  const backupPaths = [];
1651
1699
  try {
1652
- if (fs8.existsSync(codexConfigPath)) {
1653
- backupPaths.push(backupConfig(codexConfigPath));
1654
- }
1655
- if (fs8.existsSync(claudeConfigPath)) {
1656
- backupPaths.push(backupConfig(claudeConfigPath));
1700
+ for (const tool of toolKeys) {
1701
+ const { configFilename } = TOOL_SYNC_CONFIG[tool];
1702
+ const configPath = path8.join(ccmanDir2, configFilename);
1703
+ if (fs8.existsSync(configPath)) {
1704
+ backupPaths.push(backupConfig(configPath));
1705
+ }
1657
1706
  }
1658
1707
  } catch (error) {
1659
1708
  throw new Error(`\u5907\u4EFD\u5931\u8D25: ${error.message}`);
1660
1709
  }
1661
- const mergedCodexPresets = mergePresets(localCodexConfig.presets, remoteCodexConfig?.presets);
1662
- const mergedClaudePresets = mergePresets(localClaudeConfig.presets, remoteClaudeConfig?.presets);
1663
1710
  try {
1664
- const mergedCodexConfig = {
1665
- ...localCodexConfig,
1666
- // 保留本地配置的所有字段
1667
- providers: codexMergeResult.merged,
1668
- // 替换为合并后的 providers
1669
- presets: mergedCodexPresets
1670
- // 替换为合并后的 presets
1671
- };
1672
- const mergedClaudeConfig = {
1673
- ...localClaudeConfig,
1674
- // 保留本地配置的所有字段
1675
- providers: claudeMergeResult.merged,
1676
- // 替换为合并后的 providers
1677
- presets: mergedClaudePresets
1678
- // 替换为合并后的 presets
1679
- };
1680
- writeJSON(codexConfigPath, mergedCodexConfig);
1681
- writeJSON(claudeConfigPath, mergedClaudeConfig);
1682
- applyCurrentProvider("codex", mergedCodexConfig);
1683
- applyCurrentProvider("claude", mergedClaudeConfig);
1684
- const encryptedCodexProviders = encryptProviders(codexMergeResult.merged, password);
1685
- const encryptedClaudeProviders = encryptProviders(claudeMergeResult.merged, password);
1686
- const encryptedCodexConfig = {
1687
- ...mergedCodexConfig,
1688
- // 保留合并后配置的所有字段
1689
- providers: encryptedCodexProviders
1690
- // 只替换 providers(加密后的)
1691
- };
1692
- const encryptedClaudeConfig = {
1693
- ...mergedClaudeConfig,
1694
- // 保留合并后配置的所有字段
1695
- providers: encryptedClaudeProviders
1696
- // 只替换 providers(加密后的)
1697
- };
1698
- const codexJson2 = JSON.stringify(encryptedCodexConfig, null, 2);
1699
- const claudeJson2 = JSON.stringify(encryptedClaudeConfig, null, 2);
1700
- await uploadToWebDAV(config, CODEX_REMOTE_PATH, codexJson2);
1701
- await uploadToWebDAV(config, CLAUDE_REMOTE_PATH, claudeJson2);
1711
+ for (let i = 0; i < mergeDataList.length; i++) {
1712
+ const { tool, localConfig, mergeResult } = mergeDataList[i];
1713
+ const { remotePath, configFilename } = TOOL_SYNC_CONFIG[tool];
1714
+ const configPath = path8.join(ccmanDir2, configFilename);
1715
+ let remoteConfig = null;
1716
+ if (existsChecks[i]) {
1717
+ const jsonContent2 = await downloadFromWebDAV(config, remotePath);
1718
+ remoteConfig = JSON.parse(jsonContent2);
1719
+ }
1720
+ const mergedPresets = mergePresets(localConfig.presets, remoteConfig?.presets);
1721
+ const mergedConfig = {
1722
+ ...localConfig,
1723
+ // 保留本地配置的所有字段
1724
+ providers: mergeResult.merged,
1725
+ // 替换为合并后的 providers
1726
+ presets: mergedPresets
1727
+ // 替换为合并后的 presets
1728
+ };
1729
+ writeJSON(configPath, mergedConfig);
1730
+ applyCurrentProvider(tool, mergedConfig);
1731
+ const encryptedProviders = encryptProviders(mergeResult.merged, password);
1732
+ const encryptedConfig = {
1733
+ ...mergedConfig,
1734
+ // 保留合并后配置的所有字段
1735
+ providers: encryptedProviders
1736
+ // 只替换 providers(加密后的)
1737
+ };
1738
+ const jsonContent = JSON.stringify(encryptedConfig, null, 2);
1739
+ await uploadToWebDAV(config, remotePath, jsonContent);
1740
+ }
1702
1741
  updateLastSyncTime();
1703
1742
  console.log("\u2705 \u914D\u7F6E\u5DF2\u5408\u5E76\u5E76\u540C\u6B65\u5230\u4E91\u7AEF");
1704
1743
  return {
@@ -1723,13 +1762,10 @@ function applyCurrentProvider(tool, config) {
1723
1762
  if (!provider) {
1724
1763
  return;
1725
1764
  }
1726
- if (tool === "codex") {
1727
- writeCodexConfig(provider);
1728
- } else {
1729
- writeClaudeConfig(provider);
1730
- }
1765
+ const { writerFunc } = TOOL_SYNC_CONFIG[tool];
1766
+ writerFunc(provider);
1731
1767
  }
1732
- var CODEX_REMOTE_PATH, CLAUDE_REMOTE_PATH;
1768
+ var TOOL_SYNC_CONFIG;
1733
1769
  var init_sync_v2 = __esm({
1734
1770
  "../core/dist/sync/sync-v2.js"() {
1735
1771
  "use strict";
@@ -1742,8 +1778,25 @@ var init_sync_v2 = __esm({
1742
1778
  init_file();
1743
1779
  init_codex();
1744
1780
  init_claude();
1745
- CODEX_REMOTE_PATH = ".ccman/codex.json";
1746
- CLAUDE_REMOTE_PATH = ".ccman/claude.json";
1781
+ init_gemini2();
1782
+ init_constants();
1783
+ TOOL_SYNC_CONFIG = {
1784
+ [MAIN_TOOL_TYPES.CODEX]: {
1785
+ remotePath: ".ccman/codex.json",
1786
+ configFilename: "codex.json",
1787
+ writerFunc: writeCodexConfig
1788
+ },
1789
+ [MAIN_TOOL_TYPES.CLAUDE]: {
1790
+ remotePath: ".ccman/claude.json",
1791
+ configFilename: "claude.json",
1792
+ writerFunc: writeClaudeConfig
1793
+ },
1794
+ [MAIN_TOOL_TYPES.GEMINI]: {
1795
+ remotePath: ".ccman/gemini.json",
1796
+ configFilename: "gemini.json",
1797
+ writerFunc: writeGeminiConfig
1798
+ }
1799
+ };
1747
1800
  }
1748
1801
  });
1749
1802
 
@@ -2057,6 +2110,7 @@ var init_dist = __esm({
2057
2110
  "../core/dist/index.js"() {
2058
2111
  "use strict";
2059
2112
  init_package();
2113
+ init_constants();
2060
2114
  init_tool_manager();
2061
2115
  init_codex2();
2062
2116
  init_claude2();
@@ -2844,11 +2898,21 @@ function formatProviderTable(providers, currentId) {
2844
2898
  }
2845
2899
 
2846
2900
  // src/interactive.ts
2847
- var TOOL_CONFIG = {
2848
- codex: { name: "Codex", emoji: "\u{1F536}", cmd: "cx" },
2849
- claude: { name: "Claude", emoji: "\u{1F537}", cmd: "cc" },
2850
- gemini: { name: "Gemini", emoji: "\u{1F48E}", cmd: "gm" }
2901
+ var CLI_TOOL_CONFIG = {
2902
+ [TOOL_TYPES.CODEX]: { name: "Codex", emoji: "\u{1F536}", cmd: "cx" },
2903
+ [TOOL_TYPES.CLAUDE]: { name: "Claude", emoji: "\u{1F537}", cmd: "cc" },
2904
+ [TOOL_TYPES.GEMINI]: { name: "Gemini", emoji: "\u{1F48E}", cmd: "gm" }
2851
2905
  };
2906
+ function getManager(tool) {
2907
+ switch (tool) {
2908
+ case TOOL_TYPES.CODEX:
2909
+ return createCodexManager();
2910
+ case TOOL_TYPES.CLAUDE:
2911
+ return createClaudeManager();
2912
+ case TOOL_TYPES.GEMINI:
2913
+ return createGeminiManager();
2914
+ }
2915
+ }
2852
2916
  async function promptProviderForm(defaults) {
2853
2917
  const answers = await inquirer7.prompt([
2854
2918
  {
@@ -2936,16 +3000,16 @@ async function startMainMenu() {
2936
3000
  }
2937
3001
  }
2938
3002
  async function startClaudeMenu() {
2939
- await showToolMenu("claude");
3003
+ await showToolMenu(TOOL_TYPES.CLAUDE);
2940
3004
  }
2941
3005
  async function startCodexMenu() {
2942
- await showToolMenu("codex");
3006
+ await showToolMenu(TOOL_TYPES.CODEX);
2943
3007
  }
2944
3008
  async function startGeminiMenu() {
2945
- await showToolMenu("gemini");
3009
+ await showToolMenu(TOOL_TYPES.GEMINI);
2946
3010
  }
2947
3011
  async function showToolMenu(tool) {
2948
- const { name: toolName, emoji: toolEmoji } = TOOL_CONFIG[tool];
3012
+ const { name: toolName, emoji: toolEmoji } = CLI_TOOL_CONFIG[tool];
2949
3013
  while (true) {
2950
3014
  console.log();
2951
3015
  const { action } = await inquirer7.prompt([
@@ -2959,7 +3023,7 @@ async function showToolMenu(tool) {
2959
3023
  { name: "\u{1F4CB} \u5217\u51FA\u6240\u6709\u670D\u52A1\u5546", value: "list" },
2960
3024
  { name: "\u{1F441}\uFE0F \u67E5\u770B\u5F53\u524D\u670D\u52A1\u5546", value: "current" },
2961
3025
  { name: "\u270F\uFE0F \u7F16\u8F91\u670D\u52A1\u5546", value: "edit" },
2962
- { name: "\u{1F4CB} \u514B\u9686\u670D\u52A1\u5546", value: "clone" },
3026
+ { name: "\u{1F501} \u514B\u9686\u670D\u52A1\u5546", value: "clone" },
2963
3027
  { name: "\u{1F5D1}\uFE0F \u5220\u9664\u670D\u52A1\u5546", value: "remove" },
2964
3028
  { name: "\u2B05\uFE0F \u8FD4\u56DE\u4E0A\u7EA7", value: "back" }
2965
3029
  ]
@@ -3010,8 +3074,8 @@ async function showPresetsMenu() {
3010
3074
  console.log(chalk11.yellow("\n\u26A0\uFE0F \u9884\u7F6E\u670D\u52A1\u5546\u7BA1\u7406\u529F\u80FD\u5373\u5C06\u63A8\u51FA\n"));
3011
3075
  }
3012
3076
  async function handleAdd(tool) {
3013
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3014
- const { name: toolName, cmd } = TOOL_CONFIG[tool];
3077
+ const manager = getManager(tool);
3078
+ const { name: toolName, cmd } = CLI_TOOL_CONFIG[tool];
3015
3079
  const presets = manager.listPresets();
3016
3080
  console.log(chalk11.bold(`
3017
3081
  \u{1F4DD} \u6DFB\u52A0 ${toolName} \u670D\u52A1\u5546
@@ -3109,14 +3173,12 @@ async function handleAdd(tool) {
3109
3173
  manager.switch(provider.id);
3110
3174
  console.log(chalk11.green("\u2705 \u5DF2\u5207\u6362\u5230\u65B0\u670D\u52A1\u5546\n"));
3111
3175
  } else {
3112
- console.log(
3113
- chalk11.blue("\u{1F4A1} \u7A0D\u540E\u5207\u6362:") + chalk11.white(` ccman ${cmd} use "${provider.name}"
3114
- `)
3115
- );
3176
+ console.log(chalk11.blue("\u{1F4A1} \u7A0D\u540E\u5207\u6362:") + chalk11.white(` ccman ${cmd} use "${provider.name}"
3177
+ `));
3116
3178
  }
3117
3179
  }
3118
3180
  async function handleSwitch(tool) {
3119
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3181
+ const manager = getManager(tool);
3120
3182
  const providers = manager.list();
3121
3183
  const current = manager.getCurrent();
3122
3184
  if (providers.length === 0) {
@@ -3141,10 +3203,10 @@ async function handleSwitch(tool) {
3141
3203
  `));
3142
3204
  }
3143
3205
  async function handleList(tool) {
3144
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3206
+ const manager = getManager(tool);
3145
3207
  const providers = manager.list();
3146
3208
  const current = manager.getCurrent();
3147
- const { name: toolName } = TOOL_CONFIG[tool];
3209
+ const { name: toolName } = CLI_TOOL_CONFIG[tool];
3148
3210
  if (providers.length === 0) {
3149
3211
  console.log(chalk11.yellow(`
3150
3212
  \u26A0\uFE0F \u6682\u65E0 ${toolName} \u670D\u52A1\u5546
@@ -3156,9 +3218,9 @@ async function handleList(tool) {
3156
3218
  console.log(formatProviderTable(providers, current?.id));
3157
3219
  }
3158
3220
  async function handleCurrent(tool) {
3159
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3221
+ const manager = getManager(tool);
3160
3222
  const current = manager.getCurrent();
3161
- const { name: toolName } = TOOL_CONFIG[tool];
3223
+ const { name: toolName } = CLI_TOOL_CONFIG[tool];
3162
3224
  if (!current) {
3163
3225
  console.log(chalk11.yellow(`
3164
3226
  \u26A0\uFE0F \u672A\u9009\u62E9\u4EFB\u4F55 ${toolName} \u670D\u52A1\u5546
@@ -3177,7 +3239,7 @@ async function handleCurrent(tool) {
3177
3239
  console.log();
3178
3240
  }
3179
3241
  async function handleEdit(tool) {
3180
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3242
+ const manager = getManager(tool);
3181
3243
  const providers = manager.list();
3182
3244
  if (providers.length === 0) {
3183
3245
  console.log(chalk11.yellow("\n\u26A0\uFE0F \u6682\u65E0\u670D\u52A1\u5546\n"));
@@ -3238,7 +3300,7 @@ async function handleEdit(tool) {
3238
3300
  console.log(chalk11.green("\n\u2705 \u7F16\u8F91\u6210\u529F\n"));
3239
3301
  }
3240
3302
  async function handleClone(tool) {
3241
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3303
+ const manager = getManager(tool);
3242
3304
  const providers = manager.list();
3243
3305
  if (providers.length === 0) {
3244
3306
  console.log(chalk11.yellow("\n\u26A0\uFE0F \u6682\u65E0\u670D\u52A1\u5546\n"));
@@ -3285,7 +3347,7 @@ async function handleClone(tool) {
3285
3347
  console.log();
3286
3348
  }
3287
3349
  async function handleRemove(tool) {
3288
- const manager = tool === "codex" ? createCodexManager() : tool === "claude" ? createClaudeManager() : createGeminiManager();
3350
+ const manager = getManager(tool);
3289
3351
  const providers = manager.list();
3290
3352
  if (providers.length === 0) {
3291
3353
  console.log(chalk11.yellow("\n\u26A0\uFE0F \u6682\u65E0\u670D\u52A1\u5546\n"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccman",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "type": "module",
5
5
  "description": "Manage Codex and Claude Code API service provider configurations",
6
6
  "main": "./dist/index.js",