aihezu 1.7.1 → 1.8.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/INSTALL_USAGE.md +152 -0
- package/bin/ccinstall.js +210 -72
- package/package.json +1 -1
package/INSTALL_USAGE.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# aihezu install 使用说明
|
|
2
|
+
|
|
3
|
+
## 功能概述
|
|
4
|
+
|
|
5
|
+
`npx aihezu install` 命令现在是完全交互式的,支持配置 Claude 和 Codex 服务。
|
|
6
|
+
|
|
7
|
+
## 使用方式
|
|
8
|
+
|
|
9
|
+
### 1. 基本用法(无参数)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx aihezu install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
交互流程:
|
|
16
|
+
1. 选择服务类型(Claude / Codex)
|
|
17
|
+
2. 输入 API 地址(显示系统默认值,可直接回车使用)
|
|
18
|
+
3. 选择模型(仅 Codex)
|
|
19
|
+
4. 输入 API Key
|
|
20
|
+
5. 查看配置摘要并确认
|
|
21
|
+
6. 自动备份现有配置
|
|
22
|
+
7. 自动清理缓存
|
|
23
|
+
8. 写入新配置
|
|
24
|
+
|
|
25
|
+
**示例输出:**
|
|
26
|
+
```
|
|
27
|
+
🔧 Claude / Codex API 配置工具
|
|
28
|
+
🌐 Powered by https://aihezu.dev
|
|
29
|
+
|
|
30
|
+
请选择服务类型 [1] Claude (默认) / [2] Codex: 1
|
|
31
|
+
|
|
32
|
+
✅ 已选择服务: Claude
|
|
33
|
+
|
|
34
|
+
💡 Claude 默认 API 地址: https://cc.aihezu.dev/api
|
|
35
|
+
请输入 API 地址(直接回车使用默认地址):
|
|
36
|
+
✅ API 地址: https://cc.aihezu.dev/api
|
|
37
|
+
...
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. 带参数用法(推荐)
|
|
41
|
+
|
|
42
|
+
#### Claude 企业域名
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx aihezu install --api hk.aihezu.dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**交互提示:**
|
|
49
|
+
```
|
|
50
|
+
✅ 已选择服务: Claude
|
|
51
|
+
|
|
52
|
+
💡 检测到命令行参数,默认 API 地址: https://hk.aihezu.dev/api
|
|
53
|
+
请输入 API 地址(直接回车使用默认地址):
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
此时用户可以:
|
|
57
|
+
- **直接回车**:使用命令行参数 `https://hk.aihezu.dev/api`
|
|
58
|
+
- **输入其他值**:覆盖命令行参数
|
|
59
|
+
|
|
60
|
+
#### Codex 企业域名
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx aihezu install --provider codex --api hk.aihezu.dev
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**交互提示:**
|
|
67
|
+
```
|
|
68
|
+
✅ 已选择服务: Codex
|
|
69
|
+
|
|
70
|
+
💡 检测到命令行参数,默认 API 地址: https://hk.aihezu.dev/openai
|
|
71
|
+
请输入 API 地址(直接回车使用默认地址):
|
|
72
|
+
|
|
73
|
+
请选择模型:
|
|
74
|
+
[1] gpt-5-codex (默认)
|
|
75
|
+
[2] claude-sonnet-4.5
|
|
76
|
+
[3] 自定义模型名称
|
|
77
|
+
请选择 [1/2/3]:
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## 参数优先级
|
|
81
|
+
|
|
82
|
+
对于 API 地址配置:
|
|
83
|
+
|
|
84
|
+
1. **用户交互输入** > 命令行参数 > 系统默认值
|
|
85
|
+
2. 如果带了 `--api` 参数,会将参数值作为默认值显示给用户
|
|
86
|
+
3. 用户可以直接回车使用这个默认值,也可以输入新值覆盖
|
|
87
|
+
|
|
88
|
+
## 配置摘要示例
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
=== 配置摘要 ===
|
|
92
|
+
服务类型: Claude
|
|
93
|
+
API 地址: https://hk.aihezu.dev/api
|
|
94
|
+
API Key: sk-ant-123...xyz
|
|
95
|
+
|
|
96
|
+
⚠️ 即将执行以下操作:
|
|
97
|
+
1. 备份现有配置文件
|
|
98
|
+
2. 清理缓存数据
|
|
99
|
+
3. 写入新的配置
|
|
100
|
+
4. 修改 hosts 文件
|
|
101
|
+
|
|
102
|
+
是否继续?(y/n):
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 自动备份
|
|
106
|
+
|
|
107
|
+
无论是否首次使用,每次运行都会:
|
|
108
|
+
- 自动备份现有配置文件(如果存在)
|
|
109
|
+
- 备份文件命名格式:`原文件名.backup-时间戳`
|
|
110
|
+
- 示例:`settings.json.backup-2024-12-10T08-30-45-123Z`
|
|
111
|
+
|
|
112
|
+
## 模型选择(Codex)
|
|
113
|
+
|
|
114
|
+
Codex 用户可以选择:
|
|
115
|
+
1. `gpt-5-codex`(默认)
|
|
116
|
+
2. `claude-sonnet-4.5`
|
|
117
|
+
3. 自定义模型名称
|
|
118
|
+
|
|
119
|
+
## 完整示例
|
|
120
|
+
|
|
121
|
+
### 场景 1:企业用户首次配置 Claude
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npx aihezu install --api company.aihezu.dev
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
只需要:
|
|
128
|
+
1. 直接回车确认企业域名
|
|
129
|
+
2. 输入 API Key
|
|
130
|
+
3. 确认配置摘要
|
|
131
|
+
4. 等待完成
|
|
132
|
+
|
|
133
|
+
### 场景 2:切换到 Codex 服务
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npx aihezu install --provider codex
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
1. 系统识别 Codex 服务
|
|
140
|
+
2. 显示默认地址 `https://cc.aihezu.dev/openai`
|
|
141
|
+
3. 选择模型
|
|
142
|
+
4. 输入 API Key
|
|
143
|
+
5. 自动备份 Claude 配置
|
|
144
|
+
6. 完成切换
|
|
145
|
+
|
|
146
|
+
### 场景 3:完全自定义配置
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npx aihezu install
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
交互式输入所有选项,完全自定义。
|
package/bin/ccinstall.js
CHANGED
|
@@ -147,11 +147,6 @@ function writeClaudeSettings(apiKey, apiBaseUrl) {
|
|
|
147
147
|
settings = JSON.parse(content);
|
|
148
148
|
} catch (e) {
|
|
149
149
|
console.log('⚠️ 现有配置文件格式错误,将创建新的配置');
|
|
150
|
-
// 备份错误的配置文件
|
|
151
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
152
|
-
const backupPath = `${claudeSettingsPath}.backup-${timestamp}`;
|
|
153
|
-
fs.writeFileSync(backupPath, content);
|
|
154
|
-
console.log(`📦 已备份原配置文件到: ${path.basename(backupPath)}`);
|
|
155
150
|
}
|
|
156
151
|
}
|
|
157
152
|
|
|
@@ -172,32 +167,87 @@ function writeClaudeSettings(apiKey, apiBaseUrl) {
|
|
|
172
167
|
console.log(' ANTHROPIC_BASE_URL:', apiBaseUrl);
|
|
173
168
|
}
|
|
174
169
|
|
|
175
|
-
function writeCodexConfig(apiKey, codexBaseUrl) {
|
|
170
|
+
function writeCodexConfig(apiKey, codexBaseUrl, modelName = 'gpt-5-codex') {
|
|
176
171
|
if (!fs.existsSync(codexDir)) {
|
|
177
172
|
console.log('📁 创建 ~/.codex 目录...');
|
|
178
173
|
fs.mkdirSync(codexDir, { recursive: true });
|
|
179
174
|
}
|
|
180
175
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
let configContent = '';
|
|
177
|
+
let existingConfig = '';
|
|
178
|
+
let providerName = 'aihezu'; // 默认 provider 名称
|
|
179
|
+
|
|
180
|
+
// 读取现有配置
|
|
181
|
+
if (fs.existsSync(codexConfigPath)) {
|
|
182
|
+
console.log('📖 读取现有 Codex 配置文件...');
|
|
183
|
+
existingConfig = fs.readFileSync(codexConfigPath, 'utf8');
|
|
184
|
+
|
|
185
|
+
// 提取现有的 provider 名称
|
|
186
|
+
const providerMatch = existingConfig.match(/model_provider\s*=\s*"([^"]+)"/);
|
|
187
|
+
if (providerMatch) {
|
|
188
|
+
providerName = providerMatch[1];
|
|
189
|
+
console.log(`ℹ️ 检测到现有 provider: ${providerName}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// 更新 model
|
|
193
|
+
const modelPattern = /^model\s*=\s*"[^"]*"/m;
|
|
194
|
+
if (modelPattern.test(existingConfig)) {
|
|
195
|
+
existingConfig = existingConfig.replace(modelPattern, `model = "${modelName}"`);
|
|
196
|
+
console.log('✏️ 已更新模型配置');
|
|
197
|
+
}
|
|
185
198
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
// 更新 base_url
|
|
200
|
+
const baseUrlPattern = new RegExp(
|
|
201
|
+
`(\\[model_providers\\.${providerName}\\][\\s\\S]*?base_url\\s*=\\s*)"[^"]*"`,
|
|
202
|
+
'm'
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
if (baseUrlPattern.test(existingConfig)) {
|
|
206
|
+
// 如果找到了 base_url,就替换它
|
|
207
|
+
configContent = existingConfig.replace(baseUrlPattern, `$1"${codexBaseUrl}"`);
|
|
208
|
+
console.log('✏️ 已更新现有配置中的 base_url');
|
|
209
|
+
} else {
|
|
210
|
+
// 如果没有找到完整的 provider 配置,尝试添加或创建
|
|
211
|
+
const providerSectionPattern = new RegExp(`\\[model_providers\\.${providerName}\\]`, 'm');
|
|
212
|
+
|
|
213
|
+
if (providerSectionPattern.test(existingConfig)) {
|
|
214
|
+
// provider section 存在但没有 base_url,添加 base_url
|
|
215
|
+
configContent = existingConfig.replace(
|
|
216
|
+
providerSectionPattern,
|
|
217
|
+
`[model_providers.${providerName}]\nbase_url = "${codexBaseUrl}"`
|
|
218
|
+
);
|
|
219
|
+
console.log('✏️ 已在现有 provider 配置中添加 base_url');
|
|
220
|
+
} else {
|
|
221
|
+
// 完全没有这个 provider,保留现有配置并追加新的
|
|
222
|
+
configContent = existingConfig.trim() + '\n\n' +
|
|
223
|
+
`[model_providers.${providerName}]\n` +
|
|
224
|
+
`name = "${providerName}"\n` +
|
|
225
|
+
`base_url = "${codexBaseUrl}"\n` +
|
|
226
|
+
`wire_api = "responses"\n` +
|
|
227
|
+
`requires_openai_auth = true\n` +
|
|
228
|
+
`env_key = "AIHEZU_OAI_KEY"\n`;
|
|
229
|
+
console.log('✏️ 已追加新的 provider 配置');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
// 文件不存在,创建新配置
|
|
234
|
+
console.log('📝 创建新的 Codex 配置文件...');
|
|
235
|
+
configContent = [
|
|
236
|
+
'model_provider = "aihezu"',
|
|
237
|
+
`model = "${modelName}"`,
|
|
238
|
+
'model_reasoning_effort = "high"',
|
|
239
|
+
'disable_response_storage = true',
|
|
240
|
+
'preferred_auth_method = "apikey"',
|
|
241
|
+
'',
|
|
242
|
+
'[model_providers.aihezu]',
|
|
243
|
+
'name = "aihezu"',
|
|
244
|
+
`base_url = "${codexBaseUrl}"`,
|
|
245
|
+
'wire_api = "responses"',
|
|
246
|
+
'requires_openai_auth = true',
|
|
247
|
+
'env_key = "AIHEZU_OAI_KEY"',
|
|
248
|
+
''
|
|
249
|
+
].join('\n');
|
|
250
|
+
}
|
|
201
251
|
|
|
202
252
|
fs.writeFileSync(codexConfigPath, configContent, 'utf8');
|
|
203
253
|
|
|
@@ -207,13 +257,12 @@ function writeCodexConfig(apiKey, codexBaseUrl) {
|
|
|
207
257
|
const content = fs.readFileSync(codexAuthPath, 'utf8');
|
|
208
258
|
authData = JSON.parse(content);
|
|
209
259
|
} catch (e) {
|
|
210
|
-
|
|
211
|
-
console.log('⚠️ 现有 auth.json 解析失败,已备份旧文件:', backupPath ? path.basename(backupPath) : '未备份');
|
|
260
|
+
console.log('⚠️ 现有 auth.json 解析失败,将创建新文件');
|
|
212
261
|
authData = {};
|
|
213
262
|
}
|
|
214
263
|
}
|
|
215
264
|
|
|
216
|
-
|
|
265
|
+
// 只设置 AIHEZU_OAI_KEY,不修改其他环境变量
|
|
217
266
|
authData.AIHEZU_OAI_KEY = apiKey;
|
|
218
267
|
|
|
219
268
|
fs.writeFileSync(codexAuthPath, JSON.stringify(authData, null, 2), 'utf8');
|
|
@@ -224,10 +273,13 @@ function writeCodexConfig(apiKey, codexBaseUrl) {
|
|
|
224
273
|
console.log(' -', codexConfigPath);
|
|
225
274
|
console.log(' -', codexAuthPath);
|
|
226
275
|
console.log('\n配置内容:');
|
|
227
|
-
console.log(' AIHEZU_OAI_KEY
|
|
228
|
-
console.log('
|
|
229
|
-
console.log('
|
|
230
|
-
console.log('
|
|
276
|
+
console.log(' 环境变量名: AIHEZU_OAI_KEY');
|
|
277
|
+
console.log(' API 密钥:', apiKey);
|
|
278
|
+
console.log(' API 地址:', codexBaseUrl);
|
|
279
|
+
console.log('\n💡 Codex 会自动从 auth.json 中读取 AIHEZU_OAI_KEY');
|
|
280
|
+
console.log(' 如果遇到认证问题,请确保:');
|
|
281
|
+
console.log(' 1. auth.json 文件存在且格式正确');
|
|
282
|
+
console.log(' 2. 或者在终端中手动设置: export AIHEZU_OAI_KEY="' + apiKey + '"');
|
|
231
283
|
}
|
|
232
284
|
|
|
233
285
|
async function main() {
|
|
@@ -240,6 +292,7 @@ async function main() {
|
|
|
240
292
|
});
|
|
241
293
|
|
|
242
294
|
try {
|
|
295
|
+
// 1. 选择服务类型
|
|
243
296
|
const cliProviderInput = parseProviderArg(cliArgs);
|
|
244
297
|
let provider = resolveProvider(cliProviderInput);
|
|
245
298
|
|
|
@@ -248,76 +301,161 @@ async function main() {
|
|
|
248
301
|
provider = resolveProvider(providerAnswer);
|
|
249
302
|
}
|
|
250
303
|
|
|
251
|
-
|
|
252
|
-
const codexBaseInput = provider === PROVIDERS.CODEX ? parseApiBaseInput(cliArgs) : '';
|
|
304
|
+
console.log(`\n✅ 已选择服务: ${provider === PROVIDERS.CLAUDE ? 'Claude' : 'Codex'}\n`);
|
|
253
305
|
|
|
306
|
+
// 2. 交互式询问 API 地址
|
|
254
307
|
let apiBaseUrl = DEFAULT_CLAUDE_API_BASE;
|
|
255
308
|
let codexBaseUrl = DEFAULT_CODEX_BASE_URL;
|
|
309
|
+
|
|
256
310
|
if (provider === PROVIDERS.CLAUDE) {
|
|
311
|
+
// 先检查命令行参数
|
|
312
|
+
const cliApiInput = parseApiBaseInput(cliArgs);
|
|
313
|
+
let defaultApiBase = DEFAULT_CLAUDE_API_BASE;
|
|
314
|
+
let promptMessage = '';
|
|
315
|
+
|
|
316
|
+
if (cliApiInput) {
|
|
317
|
+
// 如果用户传了参数,将参数作为默认值
|
|
318
|
+
try {
|
|
319
|
+
defaultApiBase = normalizeClaudeApiBaseUrl(cliApiInput);
|
|
320
|
+
promptMessage = `💡 检测到命令行参数,默认 API 地址: ${defaultApiBase}`;
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error(`❌ 命令行参数错误: ${error.message}`);
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
} else {
|
|
326
|
+
promptMessage = `💡 Claude 默认 API 地址: ${defaultApiBase}`;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
console.log(promptMessage);
|
|
330
|
+
const apiBaseInput = await askQuestion(rl, '请输入 API 地址(直接回车使用默认地址): ');
|
|
331
|
+
|
|
257
332
|
try {
|
|
258
|
-
apiBaseUrl = normalizeClaudeApiBaseUrl(apiBaseInput);
|
|
333
|
+
apiBaseUrl = normalizeClaudeApiBaseUrl(apiBaseInput || defaultApiBase);
|
|
334
|
+
console.log(`✅ API 地址: ${apiBaseUrl}\n`);
|
|
259
335
|
} catch (error) {
|
|
260
336
|
console.error(`❌ ${error.message}`);
|
|
261
337
|
process.exit(1);
|
|
262
338
|
}
|
|
263
339
|
} else {
|
|
340
|
+
// 先检查命令行参数
|
|
341
|
+
const cliCodexInput = parseApiBaseInput(cliArgs);
|
|
342
|
+
let defaultCodexBase = DEFAULT_CODEX_BASE_URL;
|
|
343
|
+
let promptMessage = '';
|
|
344
|
+
|
|
345
|
+
if (cliCodexInput) {
|
|
346
|
+
// 如果用户传了参数,将参数作为默认值
|
|
347
|
+
try {
|
|
348
|
+
defaultCodexBase = normalizeCodexBaseUrl(cliCodexInput);
|
|
349
|
+
promptMessage = `💡 检测到命令行参数,默认 API 地址: ${defaultCodexBase}`;
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error(`❌ 命令行参数错误: ${error.message}`);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
355
|
+
promptMessage = `💡 Codex 默认 API 地址: ${defaultCodexBase}`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
console.log(promptMessage);
|
|
359
|
+
const codexBaseInput = await askQuestion(rl, '请输入 API 地址(直接回车使用默认地址): ');
|
|
360
|
+
|
|
264
361
|
try {
|
|
265
|
-
codexBaseUrl = normalizeCodexBaseUrl(codexBaseInput);
|
|
362
|
+
codexBaseUrl = normalizeCodexBaseUrl(codexBaseInput || defaultCodexBase);
|
|
363
|
+
console.log(`✅ API 地址: ${codexBaseUrl}\n`);
|
|
266
364
|
} catch (error) {
|
|
267
365
|
console.error(`❌ ${error.message}`);
|
|
268
366
|
process.exit(1);
|
|
269
367
|
}
|
|
270
368
|
}
|
|
271
369
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
370
|
+
// 3. 交互式询问模型(Codex 专用)
|
|
371
|
+
let selectedModel = '';
|
|
372
|
+
if (provider === PROVIDERS.CODEX) {
|
|
373
|
+
console.log('请选择模型:');
|
|
374
|
+
console.log(' [1] gpt-5-codex (默认)');
|
|
375
|
+
console.log(' [2] claude-sonnet-4.5');
|
|
376
|
+
console.log(' [3] 自定义模型名称');
|
|
377
|
+
const modelChoice = await askQuestion(rl, '请选择 [1/2/3]: ');
|
|
378
|
+
|
|
379
|
+
if (modelChoice === '2') {
|
|
380
|
+
selectedModel = 'claude-sonnet-4.5';
|
|
381
|
+
} else if (modelChoice === '3') {
|
|
382
|
+
const customModel = await askQuestion(rl, '请输入自定义模型名称: ');
|
|
383
|
+
selectedModel = customModel.trim() || 'gpt-5-codex';
|
|
278
384
|
} else {
|
|
279
|
-
|
|
280
|
-
console.log(' 企业用户可使用 --api 或 --api-url 指定独立域名,例如:');
|
|
281
|
-
console.log(' sudo npx aihezu install --api your-org.aihezu.dev\n');
|
|
282
|
-
}
|
|
283
|
-
} else {
|
|
284
|
-
if (usingCustomCodexDomain) {
|
|
285
|
-
console.log(`🏢 Codex 已使用企业域名: ${codexBaseUrl}\n`);
|
|
286
|
-
} else {
|
|
287
|
-
console.log(`🤖 已选择 Codex,默认网关: ${DEFAULT_CODEX_BASE_URL}`);
|
|
288
|
-
console.log(' 企业用户可用 --api 或 --api-url 指定独立域名,例如:');
|
|
289
|
-
console.log(' npx aihezu install --provider codex --api your-org.aihezu.dev\n');
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const needCleanAnswer = await askQuestion(
|
|
294
|
-
rl,
|
|
295
|
-
'您是从其他服务切换过来的吗?(y/n,如果是首次使用请输入 n): '
|
|
296
|
-
);
|
|
297
|
-
const needClean = ['y', 'yes'].includes(needCleanAnswer.toLowerCase());
|
|
298
|
-
|
|
299
|
-
if (needClean) {
|
|
300
|
-
try {
|
|
301
|
-
console.log('\n=== 清理旧缓存 ===');
|
|
302
|
-
const count = cleanCache({ showHeader: false });
|
|
303
|
-
console.log(`\n✅ 缓存清理完成!(共处理 ${count} 项)`);
|
|
304
|
-
console.log('💡 配置文件已保留,即将配置新的 API Key\n');
|
|
305
|
-
} catch (error) {
|
|
306
|
-
console.error('⚠️ 清理缓存时出错:', error.message);
|
|
307
|
-
console.log('继续配置流程...\n');
|
|
385
|
+
selectedModel = 'gpt-5-codex';
|
|
308
386
|
}
|
|
387
|
+
console.log(`✅ 已选择模型: ${selectedModel}\n`);
|
|
309
388
|
}
|
|
310
389
|
|
|
390
|
+
// 4. 询问 API Key
|
|
311
391
|
const apiKey = await askQuestion(rl, '请输入您的 API Key: ');
|
|
312
392
|
if (!apiKey) {
|
|
313
393
|
console.error('❌ API Key 不能为空');
|
|
314
394
|
process.exit(1);
|
|
315
395
|
}
|
|
316
396
|
|
|
397
|
+
// 5. 显示配置摘要并确认
|
|
398
|
+
console.log('\n=== 配置摘要 ===');
|
|
399
|
+
console.log(`服务类型: ${provider === PROVIDERS.CLAUDE ? 'Claude' : 'Codex'}`);
|
|
400
|
+
if (provider === PROVIDERS.CLAUDE) {
|
|
401
|
+
console.log(`API 地址: ${apiBaseUrl}`);
|
|
402
|
+
} else {
|
|
403
|
+
console.log(`API 地址: ${codexBaseUrl}`);
|
|
404
|
+
console.log(`模型: ${selectedModel}`);
|
|
405
|
+
}
|
|
406
|
+
console.log(`API Key: ${apiKey.substring(0, 10)}...${apiKey.substring(apiKey.length - 4)}`);
|
|
407
|
+
console.log('\n⚠️ 即将执行以下操作:');
|
|
408
|
+
console.log(' 1. 备份现有配置文件');
|
|
409
|
+
console.log(' 2. 清理缓存数据');
|
|
410
|
+
console.log(' 3. 写入新的配置');
|
|
411
|
+
if (provider === PROVIDERS.CLAUDE) {
|
|
412
|
+
console.log(' 4. 修改 hosts 文件');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const confirmAnswer = await askQuestion(rl, '\n是否继续?(y/n): ');
|
|
416
|
+
if (!['y', 'yes'].includes(confirmAnswer.toLowerCase())) {
|
|
417
|
+
console.log('❌ 已取消配置');
|
|
418
|
+
process.exit(0);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// 6. 默认执行备份和清理缓存
|
|
422
|
+
try {
|
|
423
|
+
console.log('\n=== 备份与清理 ===');
|
|
424
|
+
|
|
425
|
+
// 备份现有配置文件
|
|
426
|
+
if (provider === PROVIDERS.CLAUDE && fs.existsSync(claudeSettingsPath)) {
|
|
427
|
+
const backup = backupFile(claudeSettingsPath);
|
|
428
|
+
if (backup) {
|
|
429
|
+
console.log(`📦 已备份 Claude 配置: ${path.basename(backup)}`);
|
|
430
|
+
}
|
|
431
|
+
} else if (provider === PROVIDERS.CODEX) {
|
|
432
|
+
if (fs.existsSync(codexConfigPath)) {
|
|
433
|
+
const backup = backupFile(codexConfigPath);
|
|
434
|
+
if (backup) {
|
|
435
|
+
console.log(`📦 已备份 Codex config.toml: ${path.basename(backup)}`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (fs.existsSync(codexAuthPath)) {
|
|
439
|
+
const backup = backupFile(codexAuthPath);
|
|
440
|
+
if (backup) {
|
|
441
|
+
console.log(`📦 已备份 Codex auth.json: ${path.basename(backup)}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// 清理缓存
|
|
447
|
+
const count = cleanCache({ showHeader: false });
|
|
448
|
+
console.log(`✅ 缓存清理完成!(共处理 ${count} 项)\n`);
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.error('⚠️ 备份或清理时出错:', error.message);
|
|
451
|
+
console.log('继续配置流程...\n');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// 7. 写入配置
|
|
317
455
|
if (provider === PROVIDERS.CLAUDE) {
|
|
318
456
|
writeClaudeSettings(apiKey.trim(), apiBaseUrl);
|
|
319
457
|
} else {
|
|
320
|
-
writeCodexConfig(apiKey.trim(), codexBaseUrl);
|
|
458
|
+
writeCodexConfig(apiKey.trim(), codexBaseUrl, selectedModel);
|
|
321
459
|
}
|
|
322
460
|
|
|
323
461
|
if (provider === PROVIDERS.CLAUDE) {
|