@tkpdx01/ccc 1.2.3 → 1.2.6
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/index.js +2 -4
- package/package.json +1 -1
- package/settings-sample.json +4 -0
- package/src/commands/edit.js +9 -9
- package/src/commands/help.js +3 -5
- package/src/commands/import.js +11 -20
- package/src/commands/index.js +0 -1
- package/src/commands/list.js +15 -26
- package/src/commands/new.js +14 -42
- package/src/commands/show.js +1 -1
- package/src/utils.js +6 -21
- package/src/commands/sync.js +0 -168
package/index.js
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
showCommand,
|
|
15
15
|
importCommand,
|
|
16
16
|
newCommand,
|
|
17
|
-
syncCommand,
|
|
18
17
|
editCommand,
|
|
19
18
|
deleteCommand,
|
|
20
19
|
helpCommand
|
|
@@ -26,7 +25,7 @@ const program = new Command();
|
|
|
26
25
|
program
|
|
27
26
|
.name('ccc')
|
|
28
27
|
.description('Claude Code Settings Launcher - 管理多个 Claude Code 配置文件')
|
|
29
|
-
.version('
|
|
28
|
+
.version('1.2.6');
|
|
30
29
|
|
|
31
30
|
// 注册所有命令
|
|
32
31
|
listCommand(program);
|
|
@@ -34,7 +33,6 @@ useCommand(program);
|
|
|
34
33
|
showCommand(program);
|
|
35
34
|
importCommand(program);
|
|
36
35
|
newCommand(program);
|
|
37
|
-
syncCommand(program);
|
|
38
36
|
editCommand(program);
|
|
39
37
|
deleteCommand(program);
|
|
40
38
|
helpCommand(program);
|
|
@@ -49,7 +47,7 @@ program
|
|
|
49
47
|
|
|
50
48
|
if (profile) {
|
|
51
49
|
// 检查是否是子命令
|
|
52
|
-
if (['list', 'ls', 'use', 'show', 'import', 'if', 'new', '
|
|
50
|
+
if (['list', 'ls', 'use', 'show', 'import', 'if', 'new', 'edit', 'delete', 'rm', 'help'].includes(profile)) {
|
|
53
51
|
return; // 让子命令处理
|
|
54
52
|
}
|
|
55
53
|
|
package/package.json
CHANGED
package/src/commands/edit.js
CHANGED
|
@@ -50,22 +50,22 @@ export function editCommand(program) {
|
|
|
50
50
|
const currentSettings = readProfile(profile);
|
|
51
51
|
|
|
52
52
|
console.log(chalk.cyan(`\n当前配置 (${profile}):`));
|
|
53
|
-
console.log(chalk.gray(`
|
|
54
|
-
console.log(chalk.gray(`
|
|
53
|
+
console.log(chalk.gray(` ANTHROPIC_BASE_URL: ${currentSettings.ANTHROPIC_BASE_URL || '未设置'}`));
|
|
54
|
+
console.log(chalk.gray(` ANTHROPIC_AUTH_TOKEN: ${currentSettings.ANTHROPIC_AUTH_TOKEN ? currentSettings.ANTHROPIC_AUTH_TOKEN.substring(0, 10) + '...' : '未设置'}`));
|
|
55
55
|
console.log();
|
|
56
56
|
|
|
57
57
|
const { apiUrl, apiKey, newName } = await inquirer.prompt([
|
|
58
58
|
{
|
|
59
59
|
type: 'input',
|
|
60
60
|
name: 'apiUrl',
|
|
61
|
-
message: '
|
|
62
|
-
default: currentSettings.
|
|
61
|
+
message: 'ANTHROPIC_BASE_URL:',
|
|
62
|
+
default: currentSettings.ANTHROPIC_BASE_URL || ''
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
type: 'input',
|
|
66
66
|
name: 'apiKey',
|
|
67
|
-
message: '
|
|
68
|
-
default: currentSettings.
|
|
67
|
+
message: 'ANTHROPIC_AUTH_TOKEN:',
|
|
68
|
+
default: currentSettings.ANTHROPIC_AUTH_TOKEN || ''
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
type: 'input',
|
|
@@ -75,10 +75,10 @@ export function editCommand(program) {
|
|
|
75
75
|
}
|
|
76
76
|
]);
|
|
77
77
|
|
|
78
|
+
// 影子配置只存储 API 凭证
|
|
78
79
|
const newSettings = {
|
|
79
|
-
|
|
80
|
-
apiUrl
|
|
81
|
-
apiKey
|
|
80
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
81
|
+
ANTHROPIC_BASE_URL: apiUrl
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
// 如果重命名
|
package/src/commands/help.js
CHANGED
|
@@ -15,18 +15,16 @@ export function showHelp() {
|
|
|
15
15
|
console.log(chalk.gray(' ccc list, ls ') + '列出所有配置(带序号,按 a-z 排序)');
|
|
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] ') + '
|
|
18
|
+
console.log(chalk.gray(' ccc new [name] ') + '创建新的影子配置');
|
|
19
19
|
console.log(chalk.gray(' ccc import <file> ') + '从文件导入(自动识别格式)');
|
|
20
|
-
console.log(chalk.gray(' ccc sync [profile] ') + '同步模板设置(保留 API 配置)');
|
|
21
|
-
console.log(chalk.gray(' ccc sync -a, --all ') + '同步所有配置');
|
|
22
20
|
console.log(chalk.gray(' ccc edit [profile] ') + '编辑配置');
|
|
23
21
|
console.log(chalk.gray(' ccc delete, rm [name] ') + '删除配置');
|
|
24
22
|
console.log(chalk.gray(' ccc help ') + '显示此帮助信息');
|
|
25
23
|
console.log();
|
|
26
24
|
|
|
27
25
|
console.log(chalk.yellow(' 配置存储:'));
|
|
28
|
-
console.log(chalk.gray(' ~/.ccc/profiles/ ') + '
|
|
29
|
-
console.log(chalk.gray('
|
|
26
|
+
console.log(chalk.gray(' ~/.ccc/profiles/ ') + '影子配置文件目录');
|
|
27
|
+
console.log(chalk.gray(' 影子配置只存储 ') + 'ANTHROPIC_AUTH_TOKEN 和 ANTHROPIC_BASE_URL');
|
|
30
28
|
console.log();
|
|
31
29
|
|
|
32
30
|
console.log(chalk.yellow(' 支持的导入格式:'));
|
package/src/commands/import.js
CHANGED
|
@@ -4,13 +4,12 @@ import chalk from 'chalk';
|
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import readline from 'readline';
|
|
6
6
|
import Table from 'cli-table3';
|
|
7
|
-
import {
|
|
8
|
-
ensureDirs,
|
|
9
|
-
getProfiles,
|
|
10
|
-
getProfilePath,
|
|
11
|
-
setDefaultProfile,
|
|
12
|
-
profileExists
|
|
13
|
-
getClaudeSettingsTemplate
|
|
7
|
+
import {
|
|
8
|
+
ensureDirs,
|
|
9
|
+
getProfiles,
|
|
10
|
+
getProfilePath,
|
|
11
|
+
setDefaultProfile,
|
|
12
|
+
profileExists
|
|
14
13
|
} from '../profiles.js';
|
|
15
14
|
import { parseCCSwitchSQL, parseAllApiHubJSON, detectFileFormat } from '../parsers.js';
|
|
16
15
|
import { extractFromText, getDomainName, sanitizeProfileName, convertToClaudeSettings } from '../utils.js';
|
|
@@ -61,9 +60,6 @@ export function importCommand(program) {
|
|
|
61
60
|
process.exit(1);
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
// 获取模板
|
|
65
|
-
const template = getClaudeSettingsTemplate();
|
|
66
|
-
|
|
67
63
|
let providers = [];
|
|
68
64
|
let formatName = '';
|
|
69
65
|
|
|
@@ -83,11 +79,6 @@ export function importCommand(program) {
|
|
|
83
79
|
console.log(chalk.green(`✓ 识别到 ${formatName} 格式`));
|
|
84
80
|
console.log(chalk.green(`✓ 找到 ${providers.length} 个配置\n`));
|
|
85
81
|
|
|
86
|
-
// 显示模板状态
|
|
87
|
-
if (template) {
|
|
88
|
-
console.log(chalk.gray('将使用 ~/.claude/settings.json 作为模板合并设置\n'));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
82
|
// 显示找到的配置
|
|
92
83
|
const table = new Table({
|
|
93
84
|
head: [chalk.cyan('#'), chalk.cyan('Profile 名称'), chalk.cyan('API URL'), chalk.cyan('备注')],
|
|
@@ -200,8 +191,8 @@ export function importCommand(program) {
|
|
|
200
191
|
}
|
|
201
192
|
}
|
|
202
193
|
|
|
203
|
-
//
|
|
204
|
-
const settings = convertToClaudeSettings(provider
|
|
194
|
+
// 转换并保存配置(影子配置只包含 API 凭证)
|
|
195
|
+
const settings = convertToClaudeSettings(provider);
|
|
205
196
|
fs.writeFileSync(profilePath, JSON.stringify(settings, null, 2));
|
|
206
197
|
console.log(chalk.green(`✓ ${profileName}`));
|
|
207
198
|
imported++;
|
|
@@ -327,10 +318,10 @@ export async function interactiveImport() {
|
|
|
327
318
|
const finalApiUrl = apiUrl || 'https://api.anthropic.com';
|
|
328
319
|
const finalApiKey = apiKey || tokens[0] || '';
|
|
329
320
|
|
|
330
|
-
//
|
|
321
|
+
// 影子配置只存储 API 凭证
|
|
331
322
|
const settings = {
|
|
332
|
-
|
|
333
|
-
|
|
323
|
+
ANTHROPIC_AUTH_TOKEN: finalApiKey,
|
|
324
|
+
ANTHROPIC_BASE_URL: finalApiUrl
|
|
334
325
|
};
|
|
335
326
|
|
|
336
327
|
ensureDirs();
|
package/src/commands/index.js
CHANGED
|
@@ -3,7 +3,6 @@ export { useCommand } from './use.js';
|
|
|
3
3
|
export { showCommand } from './show.js';
|
|
4
4
|
export { importCommand } from './import.js';
|
|
5
5
|
export { newCommand } from './new.js';
|
|
6
|
-
export { syncCommand } from './sync.js';
|
|
7
6
|
export { editCommand } from './edit.js';
|
|
8
7
|
export { deleteCommand } from './delete.js';
|
|
9
8
|
export { helpCommand, showHelp } from './help.js';
|
package/src/commands/list.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import Table from 'cli-table3';
|
|
3
|
-
import { getProfiles, getDefaultProfile, getProfilePath
|
|
4
|
+
import { getProfiles, getDefaultProfile, getProfilePath } from '../profiles.js';
|
|
4
5
|
|
|
5
6
|
export function listCommand(program) {
|
|
6
7
|
program
|
|
@@ -18,7 +19,7 @@ export function listCommand(program) {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
const table = new Table({
|
|
21
|
-
head: [chalk.cyan('#'), chalk.cyan('Profile'), chalk.cyan('
|
|
22
|
+
head: [chalk.cyan('#'), chalk.cyan('Profile'), chalk.cyan('ANTHROPIC_BASE_URL')],
|
|
22
23
|
style: { head: [], border: [] },
|
|
23
24
|
chars: {
|
|
24
25
|
'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐',
|
|
@@ -30,35 +31,23 @@ export function listCommand(program) {
|
|
|
30
31
|
|
|
31
32
|
profiles.forEach((p, index) => {
|
|
32
33
|
const isDefault = p === defaultProfile;
|
|
33
|
-
const
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
apiUrl = settings.apiUrl;
|
|
43
|
-
} else if (settings.env) {
|
|
44
|
-
if (Array.isArray(settings.env)) {
|
|
45
|
-
// 数组格式,用正则提取
|
|
46
|
-
const envLine = settings.env.find(e => /^ANTHROPIC_BASE_URL=/.test(e));
|
|
47
|
-
if (envLine) {
|
|
48
|
-
apiUrl = envLine.replace(/^ANTHROPIC_BASE_URL=/, '');
|
|
49
|
-
}
|
|
50
|
-
} else if (typeof settings.env === 'object') {
|
|
51
|
-
// 对象格式
|
|
52
|
-
apiUrl = settings.env.ANTHROPIC_BASE_URL || chalk.gray('(未设置)');
|
|
53
|
-
}
|
|
34
|
+
const profilePath = getProfilePath(p);
|
|
35
|
+
let baseUrl = chalk.gray('(未设置)');
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const content = fs.readFileSync(profilePath, 'utf-8');
|
|
39
|
+
// 用正则从 JSON 文件内容中提取 ANTHROPIC_BASE_URL(新格式直接在顶层)
|
|
40
|
+
const match = content.match(/"ANTHROPIC_BASE_URL"\s*:\s*"([^"]+)"/);
|
|
41
|
+
if (match && match[1]) {
|
|
42
|
+
baseUrl = match[1];
|
|
54
43
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
44
|
+
} catch {
|
|
45
|
+
baseUrl = chalk.red('(读取失败)');
|
|
57
46
|
}
|
|
58
47
|
|
|
59
48
|
const num = isDefault ? chalk.green(`${index + 1}`) : chalk.gray(`${index + 1}`);
|
|
60
49
|
const name = isDefault ? chalk.green(`${p} *`) : p;
|
|
61
|
-
table.push([num, name,
|
|
50
|
+
table.push([num, name, baseUrl]);
|
|
62
51
|
});
|
|
63
52
|
|
|
64
53
|
console.log();
|
package/src/commands/new.js
CHANGED
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import {
|
|
4
|
-
ensureDirs,
|
|
5
|
-
getProfiles,
|
|
6
|
-
profileExists,
|
|
7
|
-
saveProfile,
|
|
8
|
-
setDefaultProfile
|
|
9
|
-
getClaudeSettingsTemplate
|
|
3
|
+
import {
|
|
4
|
+
ensureDirs,
|
|
5
|
+
getProfiles,
|
|
6
|
+
profileExists,
|
|
7
|
+
saveProfile,
|
|
8
|
+
setDefaultProfile
|
|
10
9
|
} from '../profiles.js';
|
|
11
10
|
import { launchClaude } from '../launch.js';
|
|
12
11
|
|
|
13
12
|
export function newCommand(program) {
|
|
14
13
|
program
|
|
15
14
|
.command('new [name]')
|
|
16
|
-
.description('
|
|
15
|
+
.description('创建新的影子配置(只包含 API 凭证)')
|
|
17
16
|
.action(async (name) => {
|
|
18
|
-
const template = getClaudeSettingsTemplate();
|
|
19
|
-
|
|
20
|
-
// 显示模板状态
|
|
21
|
-
if (template) {
|
|
22
|
-
console.log(chalk.green('✓ 检测到模板文件: ~/.claude/settings.json'));
|
|
23
|
-
console.log(chalk.gray(' 将基于此模板创建新配置\n'));
|
|
24
|
-
} else {
|
|
25
|
-
console.log(chalk.yellow('! 未找到模板文件: ~/.claude/settings.json'));
|
|
26
|
-
console.log(chalk.gray(' 将创建空白配置\n'));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
17
|
// 如果没有提供名称,询问
|
|
30
18
|
if (!name) {
|
|
31
19
|
const { profileName } = await inquirer.prompt([
|
|
@@ -55,33 +43,18 @@ export function newCommand(program) {
|
|
|
55
43
|
}
|
|
56
44
|
}
|
|
57
45
|
|
|
58
|
-
// 基于模板创建,但需要用户填写 API 信息
|
|
59
|
-
const baseSettings = template || {};
|
|
60
|
-
|
|
61
|
-
// 显示模板中已有的设置(如果有)
|
|
62
|
-
if (template) {
|
|
63
|
-
console.log(chalk.cyan('模板中的现有设置:'));
|
|
64
|
-
if (template.apiUrl) console.log(chalk.gray(` API URL: ${template.apiUrl}`));
|
|
65
|
-
if (template.apiKey) console.log(chalk.gray(` API Key: ${template.apiKey.substring(0, 10)}...`));
|
|
66
|
-
const otherKeys = Object.keys(template).filter(k => !['apiUrl', 'apiKey'].includes(k));
|
|
67
|
-
if (otherKeys.length > 0) {
|
|
68
|
-
console.log(chalk.gray(` 其他设置: ${otherKeys.join(', ')}`));
|
|
69
|
-
}
|
|
70
|
-
console.log();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
46
|
const { apiUrl, apiKey, finalName } = await inquirer.prompt([
|
|
74
47
|
{
|
|
75
48
|
type: 'input',
|
|
76
49
|
name: 'apiUrl',
|
|
77
|
-
message: '
|
|
78
|
-
default:
|
|
50
|
+
message: 'ANTHROPIC_BASE_URL:',
|
|
51
|
+
default: 'https://api.anthropic.com'
|
|
79
52
|
},
|
|
80
53
|
{
|
|
81
54
|
type: 'input',
|
|
82
55
|
name: 'apiKey',
|
|
83
|
-
message: '
|
|
84
|
-
default:
|
|
56
|
+
message: 'ANTHROPIC_AUTH_TOKEN:',
|
|
57
|
+
default: ''
|
|
85
58
|
},
|
|
86
59
|
{
|
|
87
60
|
type: 'input',
|
|
@@ -107,11 +80,10 @@ export function newCommand(program) {
|
|
|
107
80
|
}
|
|
108
81
|
}
|
|
109
82
|
|
|
110
|
-
//
|
|
83
|
+
// 影子配置只存储 API 凭证
|
|
111
84
|
const newSettings = {
|
|
112
|
-
|
|
113
|
-
apiUrl
|
|
114
|
-
apiKey
|
|
85
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
86
|
+
ANTHROPIC_BASE_URL: apiUrl
|
|
115
87
|
};
|
|
116
88
|
|
|
117
89
|
ensureDirs();
|
package/src/commands/show.js
CHANGED
|
@@ -51,7 +51,7 @@ export function showCommand(program) {
|
|
|
51
51
|
// 格式化显示配置
|
|
52
52
|
Object.entries(settings).forEach(([key, value]) => {
|
|
53
53
|
const formattedValue = formatValue(key, value);
|
|
54
|
-
if (key === 'apiKey' && value) {
|
|
54
|
+
if ((key === 'apiKey' || key === 'ANTHROPIC_AUTH_TOKEN') && value) {
|
|
55
55
|
console.log(` ${chalk.cyan(key)}: ${chalk.yellow(formattedValue)}`);
|
|
56
56
|
} else if (typeof value === 'boolean') {
|
|
57
57
|
console.log(` ${chalk.cyan(key)}: ${value ? chalk.green(formattedValue) : chalk.red(formattedValue)}`);
|
package/src/utils.js
CHANGED
|
@@ -35,9 +35,8 @@ export function sanitizeProfileName(name) {
|
|
|
35
35
|
.substring(0, 50); // 限制长度
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
//
|
|
38
|
+
// 将导入的配置转换为影子配置格式(只包含 API 凭证)
|
|
39
39
|
export function convertToClaudeSettings(provider, template) {
|
|
40
|
-
const baseSettings = template || {};
|
|
41
40
|
const config = provider.settingsConfig || {};
|
|
42
41
|
|
|
43
42
|
// 从 env 中提取 API 信息
|
|
@@ -45,30 +44,16 @@ export function convertToClaudeSettings(provider, template) {
|
|
|
45
44
|
const apiKey = env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_API_KEY || config.apiKey || '';
|
|
46
45
|
const apiUrl = env.ANTHROPIC_BASE_URL || config.apiUrl || provider.websiteUrl || '';
|
|
47
46
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const settings = {
|
|
53
|
-
...baseSettings,
|
|
54
|
-
env: {
|
|
55
|
-
...baseSettings.env,
|
|
56
|
-
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
57
|
-
ANTHROPIC_BASE_URL: apiUrl
|
|
58
|
-
}
|
|
47
|
+
// 影子配置只存储 API 凭证,不用 env 包裹
|
|
48
|
+
return {
|
|
49
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
50
|
+
ANTHROPIC_BASE_URL: apiUrl
|
|
59
51
|
};
|
|
60
|
-
|
|
61
|
-
// 如果有 model 设置,添加到配置中
|
|
62
|
-
if (model) {
|
|
63
|
-
settings.model = model;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return settings;
|
|
67
52
|
}
|
|
68
53
|
|
|
69
54
|
// 格式化显示配置值
|
|
70
55
|
export function formatValue(key, value) {
|
|
71
|
-
if (key === 'apiKey' && value) {
|
|
56
|
+
if ((key === 'apiKey' || key === 'ANTHROPIC_AUTH_TOKEN') && value) {
|
|
72
57
|
return value.substring(0, 15) + '...';
|
|
73
58
|
}
|
|
74
59
|
if (typeof value === 'boolean') {
|
package/src/commands/sync.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
|
-
import {
|
|
4
|
-
getProfiles,
|
|
5
|
-
profileExists,
|
|
6
|
-
getProfilePath,
|
|
7
|
-
readProfile,
|
|
8
|
-
saveProfile,
|
|
9
|
-
getClaudeSettingsTemplate
|
|
10
|
-
} from '../profiles.js';
|
|
11
|
-
|
|
12
|
-
export function syncCommand(program) {
|
|
13
|
-
program
|
|
14
|
-
.command('sync [profile]')
|
|
15
|
-
.description('从 ~/.claude/settings.json 同步设置(保留 API 配置)')
|
|
16
|
-
.option('-a, --all', '同步所有配置')
|
|
17
|
-
.action(async (profile, options) => {
|
|
18
|
-
const template = getClaudeSettingsTemplate();
|
|
19
|
-
|
|
20
|
-
if (!template) {
|
|
21
|
-
console.log(chalk.red('✗ 未找到模板文件: ~/.claude/settings.json'));
|
|
22
|
-
console.log(chalk.gray(' 请确保该文件存在'));
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const profiles = getProfiles();
|
|
27
|
-
if (profiles.length === 0) {
|
|
28
|
-
console.log(chalk.yellow('没有可用的配置'));
|
|
29
|
-
process.exit(0);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// 需要保留的字段(每个 profile 独立的设置)
|
|
33
|
-
const preserveKeys = ['apiUrl', 'apiKey', 'includeCoAuthoredBy', 'model'];
|
|
34
|
-
|
|
35
|
-
// 同步单个配置的函数
|
|
36
|
-
const syncProfile = (name) => {
|
|
37
|
-
const currentSettings = readProfile(name);
|
|
38
|
-
|
|
39
|
-
// 保留指定字段
|
|
40
|
-
const preserved = {};
|
|
41
|
-
preserveKeys.forEach(key => {
|
|
42
|
-
if (currentSettings[key] !== undefined) {
|
|
43
|
-
preserved[key] = currentSettings[key];
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// 确保 includeCoAuthoredBy 为 false
|
|
48
|
-
if (preserved.includeCoAuthoredBy === undefined) {
|
|
49
|
-
preserved.includeCoAuthoredBy = false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 合并:模板 + 保留的字段
|
|
53
|
-
const newSettings = {
|
|
54
|
-
...template,
|
|
55
|
-
...preserved
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
saveProfile(name, newSettings);
|
|
59
|
-
return { name, preserved };
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
if (options.all) {
|
|
63
|
-
// 同步所有配置
|
|
64
|
-
console.log(chalk.cyan(`同步所有配置 (${profiles.length} 个)...\n`));
|
|
65
|
-
|
|
66
|
-
const { confirm } = await inquirer.prompt([
|
|
67
|
-
{
|
|
68
|
-
type: 'confirm',
|
|
69
|
-
name: 'confirm',
|
|
70
|
-
message: `确定要同步所有 ${profiles.length} 个配置吗?`,
|
|
71
|
-
default: false
|
|
72
|
-
}
|
|
73
|
-
]);
|
|
74
|
-
|
|
75
|
-
if (!confirm) {
|
|
76
|
-
console.log(chalk.yellow('已取消'));
|
|
77
|
-
process.exit(0);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
profiles.forEach(name => {
|
|
81
|
-
const result = syncProfile(name);
|
|
82
|
-
console.log(chalk.green(`✓ ${name}`) + chalk.gray(` (保留: ${Object.keys(result.preserved).join(', ')})`));
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
console.log(chalk.green(`\n✓ 已同步 ${profiles.length} 个配置`));
|
|
86
|
-
} else {
|
|
87
|
-
// 同步单个配置
|
|
88
|
-
if (!profile) {
|
|
89
|
-
const { selectedProfile } = await inquirer.prompt([
|
|
90
|
-
{
|
|
91
|
-
type: 'list',
|
|
92
|
-
name: 'selectedProfile',
|
|
93
|
-
message: '选择要同步的配置:',
|
|
94
|
-
choices: [...profiles, new inquirer.Separator(), { name: '同步全部', value: '__all__' }]
|
|
95
|
-
}
|
|
96
|
-
]);
|
|
97
|
-
|
|
98
|
-
if (selectedProfile === '__all__') {
|
|
99
|
-
// 递归调用同步全部
|
|
100
|
-
const { confirm } = await inquirer.prompt([
|
|
101
|
-
{
|
|
102
|
-
type: 'confirm',
|
|
103
|
-
name: 'confirm',
|
|
104
|
-
message: `确定要同步所有 ${profiles.length} 个配置吗?`,
|
|
105
|
-
default: false
|
|
106
|
-
}
|
|
107
|
-
]);
|
|
108
|
-
|
|
109
|
-
if (!confirm) {
|
|
110
|
-
console.log(chalk.yellow('已取消'));
|
|
111
|
-
process.exit(0);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
profiles.forEach(name => {
|
|
115
|
-
const result = syncProfile(name);
|
|
116
|
-
console.log(chalk.green(`✓ ${name}`) + chalk.gray(` (保留: ${Object.keys(result.preserved).join(', ')})`));
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
console.log(chalk.green(`\n✓ 已同步 ${profiles.length} 个配置`));
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
profile = selectedProfile;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (!profileExists(profile)) {
|
|
127
|
-
console.log(chalk.red(`配置 "${profile}" 不存在`));
|
|
128
|
-
process.exit(1);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 显示将要进行的更改
|
|
132
|
-
const currentSettings = readProfile(profile);
|
|
133
|
-
|
|
134
|
-
console.log(chalk.cyan(`\n同步配置: ${profile}`));
|
|
135
|
-
console.log(chalk.gray('将保留以下字段:'));
|
|
136
|
-
preserveKeys.forEach(key => {
|
|
137
|
-
const value = currentSettings[key];
|
|
138
|
-
if (value !== undefined) {
|
|
139
|
-
const display = key === 'apiKey' ? value.substring(0, 10) + '...' : value;
|
|
140
|
-
console.log(chalk.gray(` ${key}: ${display}`));
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
const templateKeys = Object.keys(template).filter(k => !preserveKeys.includes(k));
|
|
145
|
-
console.log(chalk.gray('\n将从模板同步:'));
|
|
146
|
-
console.log(chalk.gray(` ${templateKeys.join(', ') || '(无)'}`));
|
|
147
|
-
console.log();
|
|
148
|
-
|
|
149
|
-
const { confirm } = await inquirer.prompt([
|
|
150
|
-
{
|
|
151
|
-
type: 'confirm',
|
|
152
|
-
name: 'confirm',
|
|
153
|
-
message: '确认同步?',
|
|
154
|
-
default: true
|
|
155
|
-
}
|
|
156
|
-
]);
|
|
157
|
-
|
|
158
|
-
if (!confirm) {
|
|
159
|
-
console.log(chalk.yellow('已取消'));
|
|
160
|
-
process.exit(0);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
syncProfile(profile);
|
|
164
|
-
console.log(chalk.green(`\n✓ 配置 "${profile}" 已同步`));
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|