@tkpdx01/ccc 1.3.7 → 1.6.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.
package/README.md CHANGED
@@ -4,15 +4,6 @@ Claude Code Settings Launcher - Launch Claude Code with different settings profi
4
4
 
5
5
  Claude Code 设置启动器 - 使用不同的 settings profile 文件启动 Claude Code,可同时运行多个使用不同 API 配置的 Claude 实例。
6
6
 
7
- ## Compatibility / 兼容性
8
-
9
- Tested export file versions / 已测试的导出文件版本:
10
-
11
- | Tool | Version | Export Format |
12
- |------|---------|---------------|
13
- | [cc-switch](https://github.com/farion1231/cc-switch) | 3.8.2 | SQL |
14
- | [All API Hub](https://github.com/qixing-jk/all-api-hub) | v2.26.1 | JSON |
15
-
16
7
  ## Installation / 安装
17
8
 
18
9
  ```bash
@@ -38,7 +29,6 @@ ccc list -v # List with URLs / 显示 API URLs
38
29
  ccc show [profile] # Show config / 显示完整配置
39
30
  ccc use <profile> # Set default / 设置默认
40
31
  ccc new [name] # Create from template / 从模板创建
41
- ccc import # Import from cc-switch SQL or All API Hub JSON / 导入 cc-switch SQL 或 All API Hub JSON
42
32
  ccc sync [profile] # Sync from template / 从模板同步
43
33
  ccc sync -a # Sync all / 同步所有
44
34
  ccc edit [profile] # Edit profile / 编辑配置
@@ -58,9 +48,8 @@ ccc webdav status # View sync status / 查看同步状态
58
48
 
59
49
  - **Multiple Profiles / 多配置**: Manage different API configurations
60
50
  - **Template Support / 模板**: Based on `~/.claude/settings.json`
61
- - **Smart Import / 智能导入**: Auto-detect API URL and token
62
51
  - **Sync Settings / 同步**: Update from template, preserve credentials
63
- - **Claude Env Defaults / Claude 环境变量默认值**: Auto-ensure these values in the `env` section of both `~/.claude/settings.json` and each profile: `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, `CLAUDE_CODE_ATTRIBUTION_HEADER=0`, `DISABLE_INSTALLATION_CHECKS=1`
52
+ - **Claude Env Defaults / Claude 环境变量默认值**: Auto-ensure these values in the `env` section of both `~/.claude/settings.json` and each profile: `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, `CLAUDE_CODE_ATTRIBUTION_HEADER=0`, `DISABLE_INSTALLATION_CHECKS=1`, `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`
64
53
  - **WebDAV Cloud Sync / 云同步**: Encrypted sync across devices
65
54
 
66
55
  ## Sync Command / 同步命令
package/index.js CHANGED
@@ -2,21 +2,21 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
- import {
6
- getDefaultProfile,
7
- profileExists,
8
- resolveProfile
5
+ import {
6
+ getDefaultProfile,
7
+ anyProfileExists,
8
+ resolveAnyProfile
9
9
  } from './src/profiles.js';
10
- import { launchClaude, selectProfile } from './src/launch.js';
10
+ import { launchProfile, selectProfile } from './src/launch.js';
11
11
  import {
12
12
  listCommand,
13
13
  useCommand,
14
14
  showCommand,
15
- importCommand,
16
15
  newCommand,
17
16
  editCommand,
18
17
  deleteCommand,
19
18
  syncCommand,
19
+ applyCommand,
20
20
  webdavCommand,
21
21
  helpCommand
22
22
  } from './src/commands/index.js';
@@ -26,39 +26,39 @@ const program = new Command();
26
26
  // 主程序
27
27
  program
28
28
  .name('ccc')
29
- .description('Claude Code Settings Launcher - 管理多个 Claude Code 配置文件')
30
- .version('1.3.7');
29
+ .description('Claude Code / Codex Settings Launcher - 管理多个 Claude Code 和 Codex 配置文件')
30
+ .version('1.6.0');
31
31
 
32
32
  // 注册所有命令
33
33
  listCommand(program);
34
34
  useCommand(program);
35
35
  showCommand(program);
36
- importCommand(program);
37
36
  newCommand(program);
38
37
  editCommand(program);
39
38
  deleteCommand(program);
40
39
  syncCommand(program);
40
+ applyCommand(program);
41
41
  webdavCommand(program);
42
42
  helpCommand(program);
43
43
 
44
44
  // ccc <profile> 或 ccc (无参数)
45
- // 使用 -d 或 --ddd 启用 dangerously-skip-permissions
45
+ // 使用 -d 或 --ddd 启用 dangerously-skip-permissions / full-auto
46
46
  program
47
47
  .argument('[profile]', '要使用的 profile 名称或序号')
48
- .option('-d, --ddd', '启用 --dangerously-skip-permissions 参数')
48
+ .option('-d, --ddd', '启用 --dangerously-skip-permissions (Claude) 或 --full-auto (Codex)')
49
49
  .action(async (profile, options) => {
50
50
  const dangerouslySkipPermissions = options.ddd || false;
51
51
 
52
52
  if (profile) {
53
53
  // 检查是否是子命令
54
- if (['list', 'ls', 'use', 'show', 'import', 'if', 'new', 'edit', 'delete', 'rm', 'sync', 'webdav', 'help'].includes(profile)) {
54
+ if (['list', 'ls', 'use', 'show', 'new', 'edit', 'delete', 'rm', 'sync', 'apply', 'webdav', 'help'].includes(profile)) {
55
55
  return; // 让子命令处理
56
56
  }
57
57
 
58
- // 解析序号或名称
59
- const resolvedProfile = resolveProfile(profile);
60
- if (resolvedProfile) {
61
- launchClaude(resolvedProfile, dangerouslySkipPermissions);
58
+ // 解析序号或名称(统一)
59
+ const resolved = resolveAnyProfile(profile);
60
+ if (resolved) {
61
+ launchProfile(resolved.name, resolved.type, dangerouslySkipPermissions);
62
62
  } else {
63
63
  console.log(chalk.red(`Profile "${profile}" 不存在`));
64
64
  console.log(chalk.yellow(`使用 "ccc list" 查看可用的 profiles`));
@@ -67,8 +67,13 @@ program
67
67
  } else {
68
68
  // 无参数,检查默认或交互选择
69
69
  const defaultProfile = getDefaultProfile();
70
- if (defaultProfile && profileExists(defaultProfile)) {
71
- launchClaude(defaultProfile, dangerouslySkipPermissions);
70
+ if (defaultProfile) {
71
+ const check = anyProfileExists(defaultProfile);
72
+ if (check.exists) {
73
+ launchProfile(defaultProfile, check.type, dangerouslySkipPermissions);
74
+ } else {
75
+ await selectProfile(dangerouslySkipPermissions);
76
+ }
72
77
  } else {
73
78
  await selectProfile(dangerouslySkipPermissions);
74
79
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tkpdx01/ccc",
3
- "version": "1.3.7",
4
- "description": "Claude Code Settings Launcher - Manage multiple Claude Code profiles",
3
+ "version": "1.6.0",
4
+ "description": "Claude Code / Codex Settings Launcher - Manage multiple Claude Code and Codex profiles",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "ccc": "./index.js"
@@ -14,6 +14,8 @@
14
14
  "keywords": [
15
15
  "claude",
16
16
  "claude-code",
17
+ "codex",
18
+ "openai",
17
19
  "cli",
18
20
  "settings",
19
21
  "launcher",
@@ -0,0 +1,79 @@
1
+ import chalk from 'chalk';
2
+ import inquirer from 'inquirer';
3
+ import {
4
+ getAllProfiles,
5
+ resolveAnyProfile,
6
+ applyClaudeProfile,
7
+ applyCodexProfile
8
+ } from '../profiles.js';
9
+
10
+ export function applyCommand(program) {
11
+ program
12
+ .command('apply [profile]')
13
+ .description('将 profile 的配置应用到默认目录(~/.claude 或 ~/.codex)')
14
+ .action(async (profile) => {
15
+ const allProfiles = getAllProfiles();
16
+
17
+ if (allProfiles.length === 0) {
18
+ console.log(chalk.yellow('没有可用的 profiles'));
19
+ console.log(chalk.gray('使用 "ccc new" 创建配置'));
20
+ process.exit(0);
21
+ }
22
+
23
+ let profileInfo;
24
+
25
+ if (!profile) {
26
+ const choices = allProfiles.map(p => {
27
+ const typeTag = p.type === 'codex' ? chalk.blue('[Codex]') : chalk.magenta('[Claude]');
28
+ return { name: `${typeTag} ${p.name}`, value: p };
29
+ });
30
+
31
+ const { selected } = await inquirer.prompt([
32
+ {
33
+ type: 'list',
34
+ name: 'selected',
35
+ message: '选择要应用的配置:',
36
+ choices
37
+ }
38
+ ]);
39
+ profileInfo = selected;
40
+ } else {
41
+ profileInfo = resolveAnyProfile(profile);
42
+ if (!profileInfo) {
43
+ console.log(chalk.red(`Profile "${profile}" 不存在`));
44
+ process.exit(1);
45
+ }
46
+ }
47
+
48
+ const typeLabel = profileInfo.type === 'codex' ? 'Codex' : 'Claude';
49
+ const targetDir = profileInfo.type === 'codex' ? '~/.codex/' : '~/.claude/settings.json';
50
+
51
+ const { confirm } = await inquirer.prompt([
52
+ {
53
+ type: 'confirm',
54
+ name: 'confirm',
55
+ message: `将 ${typeLabel} 配置 "${profileInfo.name}" 应用到 ${targetDir}?(会覆盖当前配置)`,
56
+ default: false
57
+ }
58
+ ]);
59
+
60
+ if (!confirm) {
61
+ console.log(chalk.yellow('已取消'));
62
+ process.exit(0);
63
+ }
64
+
65
+ let result;
66
+ if (profileInfo.type === 'codex') {
67
+ result = applyCodexProfile(profileInfo.name);
68
+ } else {
69
+ result = applyClaudeProfile(profileInfo.name);
70
+ }
71
+
72
+ if (result) {
73
+ console.log(chalk.green(`\n✓ ${typeLabel} 配置 "${profileInfo.name}" 已应用到 ${targetDir}`));
74
+ } else {
75
+ console.log(chalk.red(`\n✗ 应用失败`));
76
+ process.exit(1);
77
+ }
78
+ });
79
+ }
@@ -1,11 +1,12 @@
1
1
  import chalk from 'chalk';
2
2
  import inquirer from 'inquirer';
3
- import {
4
- getProfiles,
5
- getDefaultProfile,
6
- profileExists,
7
- deleteProfile,
8
- clearDefaultProfile
3
+ import {
4
+ getAllProfiles,
5
+ getDefaultProfile,
6
+ resolveAnyProfile,
7
+ deleteProfile,
8
+ deleteCodexProfile,
9
+ clearDefaultProfile
9
10
  } from '../profiles.js';
10
11
 
11
12
  export function deleteCommand(program) {
@@ -14,36 +15,45 @@ export function deleteCommand(program) {
14
15
  .alias('rm')
15
16
  .description('删除 profile')
16
17
  .action(async (profile) => {
17
- const profiles = getProfiles();
18
+ const allProfiles = getAllProfiles();
18
19
 
19
- if (profiles.length === 0) {
20
+ if (allProfiles.length === 0) {
20
21
  console.log(chalk.yellow('没有可用的 profiles'));
21
22
  process.exit(0);
22
23
  }
23
24
 
24
- // 如果没有指定 profile,交互选择
25
+ let profileInfo;
26
+
25
27
  if (!profile) {
26
- const { selectedProfile } = await inquirer.prompt([
28
+ const choices = allProfiles.map(p => {
29
+ const typeTag = p.type === 'codex' ? chalk.blue('[Codex]') : chalk.magenta('[Claude]');
30
+ return { name: `${typeTag} ${p.name}`, value: p };
31
+ });
32
+
33
+ const { selected } = await inquirer.prompt([
27
34
  {
28
35
  type: 'list',
29
- name: 'selectedProfile',
36
+ name: 'selected',
30
37
  message: '选择要删除的配置:',
31
- choices: profiles
38
+ choices
32
39
  }
33
40
  ]);
34
- profile = selectedProfile;
41
+ profileInfo = selected;
42
+ } else {
43
+ profileInfo = resolveAnyProfile(profile);
44
+ if (!profileInfo) {
45
+ console.log(chalk.red(`Profile "${profile}" 不存在`));
46
+ process.exit(1);
47
+ }
35
48
  }
36
49
 
37
- if (!profileExists(profile)) {
38
- console.log(chalk.red(`Profile "${profile}" 不存在`));
39
- process.exit(1);
40
- }
50
+ const typeLabel = profileInfo.type === 'codex' ? 'Codex' : 'Claude';
41
51
 
42
52
  const { confirm } = await inquirer.prompt([
43
53
  {
44
54
  type: 'confirm',
45
55
  name: 'confirm',
46
- message: `确定要删除 "${profile}" 吗?`,
56
+ message: `确定要删除 ${typeLabel} 配置 "${profileInfo.name}" 吗?`,
47
57
  default: false
48
58
  }
49
59
  ]);
@@ -53,14 +63,16 @@ export function deleteCommand(program) {
53
63
  process.exit(0);
54
64
  }
55
65
 
56
- deleteProfile(profile);
66
+ if (profileInfo.type === 'codex') {
67
+ deleteCodexProfile(profileInfo.name);
68
+ } else {
69
+ deleteProfile(profileInfo.name);
70
+ }
57
71
 
58
- // 如果删除的是默认 profile,清除默认设置
59
- if (getDefaultProfile() === profile) {
72
+ if (getDefaultProfile() === profileInfo.name) {
60
73
  clearDefaultProfile();
61
74
  }
62
75
 
63
- console.log(chalk.green(`✓ Profile "${profile}" 已删除`));
76
+ console.log(chalk.green(`✓ ${typeLabel} Profile "${profileInfo.name}" 已删除`));
64
77
  });
65
78
  }
66
-
@@ -2,20 +2,25 @@ import fs from 'fs';
2
2
  import chalk from 'chalk';
3
3
  import inquirer from 'inquirer';
4
4
  import {
5
- getProfiles,
5
+ getAllProfiles,
6
6
  getDefaultProfile,
7
7
  profileExists,
8
+ codexProfileExists,
9
+ anyProfileExists,
8
10
  getProfilePath,
9
11
  readProfile,
10
12
  saveProfile,
11
13
  setDefaultProfile,
12
14
  deleteProfile,
13
- resolveProfile,
15
+ resolveAnyProfile,
14
16
  getProfileCredentials,
17
+ getCodexProfileCredentials,
15
18
  getClaudeSettingsTemplate,
16
19
  ensureRequiredClaudeEnvSettings,
17
20
  ensureClaudeSettingsExtras,
18
- applyClaudeSettingsExtras
21
+ applyClaudeSettingsExtras,
22
+ createCodexProfile,
23
+ deleteCodexProfile
19
24
  } from '../profiles.js';
20
25
 
21
26
  export function editCommand(program) {
@@ -23,108 +28,162 @@ export function editCommand(program) {
23
28
  .command('edit [profile]')
24
29
  .description('编辑 profile 配置')
25
30
  .action(async (profile) => {
26
- const profiles = getProfiles();
31
+ const allProfiles = getAllProfiles();
27
32
 
28
- if (profiles.length === 0) {
33
+ if (allProfiles.length === 0) {
29
34
  console.log(chalk.yellow('没有可用的 profiles'));
30
- console.log(chalk.gray('使用 "ccc import" 导入配置'));
35
+ console.log(chalk.gray('使用 "ccc new" 创建配置'));
31
36
  process.exit(0);
32
37
  }
33
38
 
39
+ let profileInfo;
40
+
34
41
  // 如果没有指定 profile,交互选择
35
42
  if (!profile) {
36
- const { selectedProfile } = await inquirer.prompt([
43
+ const choices = allProfiles.map(p => {
44
+ const typeTag = p.type === 'codex' ? chalk.blue('[Codex]') : chalk.magenta('[Claude]');
45
+ return { name: `${typeTag} ${p.name}`, value: p };
46
+ });
47
+
48
+ const { selected } = await inquirer.prompt([
37
49
  {
38
50
  type: 'list',
39
- name: 'selectedProfile',
51
+ name: 'selected',
40
52
  message: '选择要编辑的配置:',
41
- choices: profiles
53
+ choices
42
54
  }
43
55
  ]);
44
- profile = selectedProfile;
56
+ profileInfo = selected;
45
57
  } else {
46
- // 支持序号或名称
47
- const resolved = resolveProfile(profile);
48
- if (!resolved) {
58
+ profileInfo = resolveAnyProfile(profile);
59
+ if (!profileInfo) {
49
60
  console.log(chalk.red(`Profile "${profile}" 不存在`));
50
61
  process.exit(1);
51
62
  }
52
- profile = resolved;
53
63
  }
54
64
 
55
- // 使用新的 getProfileCredentials 函数获取凭证(支持新旧格式)
56
- const { apiKey: currentApiKey, apiUrl: currentApiUrl } = getProfileCredentials(profile);
57
-
58
- console.log(chalk.cyan(`\n当前配置 (${profile}):`));
59
- console.log(chalk.gray(` ANTHROPIC_BASE_URL: ${currentApiUrl || '未设置'}`));
60
- console.log(chalk.gray(` ANTHROPIC_AUTH_TOKEN: ${currentApiKey ? currentApiKey.substring(0, 10) + '...' : '未设置'}`));
61
- console.log();
62
-
63
- const { apiUrl, apiKey, newName } = await inquirer.prompt([
64
- {
65
- type: 'input',
66
- name: 'apiUrl',
67
- message: 'ANTHROPIC_BASE_URL:',
68
- default: currentApiUrl || ''
69
- },
70
- {
71
- type: 'input',
72
- name: 'apiKey',
73
- message: 'ANTHROPIC_AUTH_TOKEN:',
74
- default: currentApiKey || ''
75
- },
76
- {
77
- type: 'input',
78
- name: 'newName',
79
- message: 'Profile 名称:',
80
- default: profile
65
+ if (profileInfo.type === 'codex') {
66
+ // 编辑 Codex profile
67
+ const { apiKey: currentApiKey, baseUrl: currentBaseUrl, model: currentModel } = getCodexProfileCredentials(profileInfo.name);
68
+
69
+ console.log(chalk.cyan(`\n当前配置 (${profileInfo.name}) ${chalk.blue('[Codex]')}:`));
70
+ console.log(chalk.gray(` OPENAI_API_KEY: ${currentApiKey ? currentApiKey.substring(0, 10) + '...' : '未设置'}`));
71
+ console.log(chalk.gray(` Base URL: ${currentBaseUrl || '未设置'}`));
72
+ console.log(chalk.gray(` Model: ${currentModel || '(默认)'}`));
73
+ console.log();
74
+
75
+ const { apiKey, baseUrl, model, newName } = await inquirer.prompt([
76
+ {
77
+ type: 'input',
78
+ name: 'apiKey',
79
+ message: 'OPENAI_API_KEY:',
80
+ default: currentApiKey || ''
81
+ },
82
+ {
83
+ type: 'input',
84
+ name: 'baseUrl',
85
+ message: 'Base URL:',
86
+ default: currentBaseUrl || 'https://api.openai.com/v1'
87
+ },
88
+ {
89
+ type: 'input',
90
+ name: 'model',
91
+ message: 'Model (留空使用默认):',
92
+ default: currentModel || ''
93
+ },
94
+ {
95
+ type: 'input',
96
+ name: 'newName',
97
+ message: 'Profile 名称:',
98
+ default: profileInfo.name
99
+ }
100
+ ]);
101
+
102
+ if (newName && newName !== profileInfo.name) {
103
+ const check = anyProfileExists(newName);
104
+ if (check.exists) {
105
+ console.log(chalk.red(`Profile "${newName}" 已存在`));
106
+ process.exit(1);
107
+ }
108
+ createCodexProfile(newName, apiKey, baseUrl, model);
109
+ deleteCodexProfile(profileInfo.name);
110
+
111
+ if (getDefaultProfile() === profileInfo.name) {
112
+ setDefaultProfile(newName);
113
+ }
114
+ console.log(chalk.green(`\n✓ Codex Profile 已重命名为 "${newName}" 并保存`));
115
+ } else {
116
+ createCodexProfile(profileInfo.name, apiKey, baseUrl, model);
117
+ console.log(chalk.green(`\n✓ Codex Profile "${profileInfo.name}" 已更新`));
81
118
  }
82
- ]);
83
-
84
- // 读取当前 profile 或使用主配置模板
85
- let currentProfile = readProfile(profile);
86
- if (!currentProfile || !currentProfile.env) {
87
- // 如果是旧格式或空配置,基于主配置模板创建
88
- const template = getClaudeSettingsTemplate() || {};
89
- currentProfile = { ...template };
90
- }
119
+ } else {
120
+ // 编辑 Claude profile(保持原逻辑)
121
+ const { apiKey: currentApiKey, apiUrl: currentApiUrl } = getProfileCredentials(profileInfo.name);
91
122
 
92
- // 确保 env 对象存在
93
- if (!currentProfile.env) {
94
- currentProfile.env = {};
95
- }
123
+ console.log(chalk.cyan(`\n当前配置 (${profileInfo.name}) ${chalk.magenta('[Claude]')}:`));
124
+ console.log(chalk.gray(` ANTHROPIC_BASE_URL: ${currentApiUrl || '未设置'}`));
125
+ console.log(chalk.gray(` ANTHROPIC_AUTH_TOKEN: ${currentApiKey ? currentApiKey.substring(0, 10) + '...' : '未设置'}`));
126
+ console.log();
96
127
 
97
- // 更新 env 中的 API 凭证
98
- currentProfile.env.ANTHROPIC_AUTH_TOKEN = apiKey;
99
- currentProfile.env.ANTHROPIC_BASE_URL = apiUrl;
100
-
101
- // 确保主配置(~/.claude/settings.json)与 profile 都包含必要 env 设置
102
- ensureRequiredClaudeEnvSettings();
103
- ensureClaudeSettingsExtras();
104
- currentProfile.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
105
- currentProfile.env.CLAUDE_CODE_ATTRIBUTION_HEADER = '0';
106
- currentProfile.env.DISABLE_INSTALLATION_CHECKS = '1';
107
- applyClaudeSettingsExtras(currentProfile);
108
-
109
- // 如果重命名
110
- if (newName && newName !== profile) {
111
- const newPath = getProfilePath(newName);
112
- if (fs.existsSync(newPath)) {
113
- console.log(chalk.red(`Profile "${newName}" 已存在`));
114
- process.exit(1);
128
+ const { apiUrl, apiKey, newName } = await inquirer.prompt([
129
+ {
130
+ type: 'input',
131
+ name: 'apiUrl',
132
+ message: 'ANTHROPIC_BASE_URL:',
133
+ default: currentApiUrl || ''
134
+ },
135
+ {
136
+ type: 'input',
137
+ name: 'apiKey',
138
+ message: 'ANTHROPIC_AUTH_TOKEN:',
139
+ default: currentApiKey || ''
140
+ },
141
+ {
142
+ type: 'input',
143
+ name: 'newName',
144
+ message: 'Profile 名称:',
145
+ default: profileInfo.name
146
+ }
147
+ ]);
148
+
149
+ let currentProfile = readProfile(profileInfo.name);
150
+ if (!currentProfile || !currentProfile.env) {
151
+ const template = getClaudeSettingsTemplate() || {};
152
+ currentProfile = { ...template };
115
153
  }
116
- saveProfile(newName, currentProfile);
117
- deleteProfile(profile);
118
154
 
119
- // 更新默认 profile
120
- if (getDefaultProfile() === profile) {
121
- setDefaultProfile(newName);
155
+ if (!currentProfile.env) {
156
+ currentProfile.env = {};
122
157
  }
123
158
 
124
- console.log(chalk.green(`\n✓ Profile 已重命名为 "${newName}" 并保存`));
125
- } else {
126
- saveProfile(profile, currentProfile);
127
- console.log(chalk.green(`\n✓ Profile "${profile}" 已更新`));
159
+ currentProfile.env.ANTHROPIC_AUTH_TOKEN = apiKey;
160
+ currentProfile.env.ANTHROPIC_BASE_URL = apiUrl;
161
+
162
+ ensureRequiredClaudeEnvSettings();
163
+ ensureClaudeSettingsExtras();
164
+ currentProfile.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
165
+ currentProfile.env.CLAUDE_CODE_ATTRIBUTION_HEADER = '0';
166
+ currentProfile.env.DISABLE_INSTALLATION_CHECKS = '1';
167
+ applyClaudeSettingsExtras(currentProfile);
168
+
169
+ if (newName && newName !== profileInfo.name) {
170
+ const newPath = getProfilePath(newName);
171
+ if (fs.existsSync(newPath)) {
172
+ console.log(chalk.red(`Profile "${newName}" 已存在`));
173
+ process.exit(1);
174
+ }
175
+ saveProfile(newName, currentProfile);
176
+ deleteProfile(profileInfo.name);
177
+
178
+ if (getDefaultProfile() === profileInfo.name) {
179
+ setDefaultProfile(newName);
180
+ }
181
+
182
+ console.log(chalk.green(`\n✓ Claude Profile 已重命名为 "${newName}" 并保存`));
183
+ } else {
184
+ saveProfile(profileInfo.name, currentProfile);
185
+ console.log(chalk.green(`\n✓ Claude Profile "${profileInfo.name}" 已更新`));
186
+ }
128
187
  }
129
188
  });
130
189
  }
@@ -1,24 +1,24 @@
1
1
  import chalk from 'chalk';
2
2
 
3
3
  export function showHelp() {
4
- console.log(chalk.cyan.bold('\n CCC - Claude Code Settings Launcher\n'));
5
- console.log(chalk.white(' 管理多个 Claude Code 配置文件,快速切换不同的 API 设置\n'));
4
+ console.log(chalk.cyan.bold('\n CCC - Claude Code / Codex Settings Launcher\n'));
5
+ console.log(chalk.white(' 管理多个 Claude Code 和 OpenAI Codex 配置文件,快速切换不同的 API 设置\n'));
6
6
 
7
7
  console.log(chalk.yellow(' 启动命令:'));
8
8
  console.log(chalk.gray(' ccc ') + '使用默认配置启动,无默认则交互选择');
9
- console.log(chalk.gray(' ccc <profile> ') + '使用指定配置启动(支持名称或序号)');
9
+ console.log(chalk.gray(' ccc <profile> ') + '使用指定配置启动(支持名称或序号,自动识别类型)');
10
10
  console.log(chalk.gray(' ccc <序号> ') + '使用序号启动(如 ccc 1)');
11
- console.log(chalk.gray(' ccc -d, --ddd ') + '启动时添加 --dangerously-skip-permissions');
11
+ console.log(chalk.gray(' ccc -d, --ddd ') + 'Claude: --dangerously-skip-permissions / Codex: --full-auto');
12
12
  console.log();
13
13
 
14
14
  console.log(chalk.yellow(' 管理命令:'));
15
- console.log(chalk.gray(' ccc list, ls ') + '列出所有配置(带序号,按 a-z 排序)');
15
+ console.log(chalk.gray(' ccc list, ls ') + '列出所有配置(Claude + Codex 混合,带序号)');
16
16
  console.log(chalk.gray(' ccc show [profile] ') + '显示完整配置');
17
17
  console.log(chalk.gray(' ccc use <profile> ') + '设置默认配置');
18
- console.log(chalk.gray(' ccc new [name] ') + '创建新的影子配置');
19
- console.log(chalk.gray(' ccc import <file> ') + '从文件导入(自动识别格式)');
18
+ console.log(chalk.gray(' ccc new [name] ') + '创建新配置(可选 Claude 或 Codex)');
20
19
  console.log(chalk.gray(' ccc sync [profile] ') + '从模板同步配置(保留 API 凭证)');
21
20
  console.log(chalk.gray(' ccc sync --all ') + '同步所有配置');
21
+ console.log(chalk.gray(' ccc apply [profile] ') + '将配置应用到默认目录(~/.claude 或 ~/.codex)');
22
22
  console.log(chalk.gray(' ccc edit [profile] ') + '编辑配置');
23
23
  console.log(chalk.gray(' ccc delete, rm [name] ') + '删除配置');
24
24
  console.log(chalk.gray(' ccc help ') + '显示此帮助信息');
@@ -32,22 +32,17 @@ export function showHelp() {
32
32
  console.log();
33
33
 
34
34
  console.log(chalk.yellow(' 配置存储:'));
35
- console.log(chalk.gray(' ~/.ccc/profiles/ ') + '影子配置文件目录');
35
+ console.log(chalk.gray(' ~/.ccc/profiles/ ') + 'Claude 影子配置文件目录');
36
+ console.log(chalk.gray(' ~/.ccc/codex-profiles/ ') + 'Codex 配置目录(auth.json + config.toml)');
36
37
  console.log(chalk.gray(' ~/.ccc/webdav.json ') + 'WebDAV 连接配置');
37
38
  console.log(chalk.gray(' ~/.ccc/.sync_key ') + '本地密码缓存(机器指纹加密)');
38
39
  console.log();
39
40
 
40
- console.log(chalk.yellow(' 支持的导入格式:'));
41
- console.log(chalk.gray(' CC-Switch SQL ') + '自动识别 INSERT INTO providers 语句');
42
- console.log(chalk.gray(' All API Hub JSON ') + '自动识别 accounts.accounts 结构');
43
- console.log();
44
-
45
41
  console.log(chalk.yellow(' 示例:'));
46
42
  console.log(chalk.gray(' ccc ls ') + '查看配置列表和序号');
47
- console.log(chalk.gray(' ccc 3 ') + '启动第 3 个配置');
48
- console.log(chalk.gray(' ccc 3 -d ') + '启动第 3 个配置 + 跳过权限');
49
- console.log(chalk.gray(' ccc kfc ') + '使用名称启动');
50
- console.log(chalk.gray(' ccc import export.sql ') + '从文件导入配置');
43
+ console.log(chalk.gray(' ccc 3 ') + '启动第 3 个配置(自动识别 Claude/Codex)');
44
+ console.log(chalk.gray(' ccc 3 -d ') + '启动第 3 个配置 + 跳过权限/全自动');
45
+ console.log(chalk.gray(' ccc apply myprofile ') + '将 myprofile 的配置应用到默认目录');
51
46
  console.log(chalk.gray(' ccc webdav push ') + '推送配置到云端');
52
47
  console.log();
53
48
  }
@@ -58,4 +53,3 @@ export function helpCommand(program) {
58
53
  .description('显示帮助信息')
59
54
  .action(showHelp);
60
55
  }
61
-