@pikecode/api-key-manager 1.0.4 → 1.0.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/README.md +58 -10
- package/package.json +1 -1
- package/src/commands/add.js +69 -12
- package/src/config.js +1 -0
- package/src/utils/env-launcher.js +46 -20
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- 🎯 **灵活配置** - 支持多种认证模式(API Key、Auth Token、OAuth)
|
|
11
11
|
- 🚀 **开箱即用** - 无需复杂配置
|
|
12
12
|
- 💾 **环境变量管理** - 自动设置和管理环境变量
|
|
13
|
+
- 🛠️ **多 IDE 支持** - 支持 Claude Code 和 Codex
|
|
13
14
|
|
|
14
15
|
## 安装
|
|
15
16
|
|
|
@@ -54,29 +55,76 @@ akm list
|
|
|
54
55
|
示例配置结构:
|
|
55
56
|
```json
|
|
56
57
|
{
|
|
57
|
-
"version": "
|
|
58
|
+
"version": "1.0.0",
|
|
58
59
|
"currentProvider": "provider-name",
|
|
59
60
|
"providers": {
|
|
60
|
-
"provider
|
|
61
|
-
"name": "provider
|
|
62
|
-
"displayName": "Provider
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
61
|
+
"claude-provider": {
|
|
62
|
+
"name": "claude-provider",
|
|
63
|
+
"displayName": "Claude Code Provider",
|
|
64
|
+
"ideName": "claude",
|
|
65
|
+
"authMode": "oauth_token",
|
|
66
|
+
"authToken": "sk-ant-oat01-...",
|
|
67
|
+
"baseUrl": null,
|
|
68
|
+
"tokenType": null,
|
|
66
69
|
"models": {
|
|
67
70
|
"primary": "claude-sonnet-4",
|
|
68
71
|
"smallFast": "claude-haiku-4"
|
|
69
72
|
}
|
|
73
|
+
},
|
|
74
|
+
"codex-provider": {
|
|
75
|
+
"name": "codex-provider",
|
|
76
|
+
"displayName": "Codex Provider",
|
|
77
|
+
"ideName": "codex",
|
|
78
|
+
"authMode": "api_key",
|
|
79
|
+
"authToken": "sk-...",
|
|
80
|
+
"baseUrl": null,
|
|
81
|
+
"tokenType": null,
|
|
82
|
+
"models": {
|
|
83
|
+
"primary": null,
|
|
84
|
+
"smallFast": null
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"codex-chatgpt": {
|
|
88
|
+
"name": "codex-chatgpt",
|
|
89
|
+
"displayName": "Codex ChatGPT Login",
|
|
90
|
+
"ideName": "codex",
|
|
91
|
+
"authMode": "chatgpt_login",
|
|
92
|
+
"authToken": null,
|
|
93
|
+
"baseUrl": null,
|
|
94
|
+
"tokenType": null,
|
|
95
|
+
"models": {
|
|
96
|
+
"primary": null,
|
|
97
|
+
"smallFast": null
|
|
98
|
+
}
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
}
|
|
73
102
|
```
|
|
74
103
|
|
|
104
|
+
## 支持的 IDE
|
|
105
|
+
|
|
106
|
+
### Claude Code - Anthropic 官方代码编辑器
|
|
107
|
+
- 认证模式:
|
|
108
|
+
- `oauth_token` - OAuth 令牌模式(推荐官方用户)
|
|
109
|
+
- `api_key` - 通用 API 密钥模式(支持 ANTHROPIC_API_KEY 和 ANTHROPIC_AUTH_TOKEN)
|
|
110
|
+
- `auth_token` - 认证令牌模式(仅 ANTHROPIC_AUTH_TOKEN)
|
|
111
|
+
- 环境变量:CLAUDE_CODE_OAUTH_TOKEN、ANTHROPIC_API_KEY、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_BASE_URL
|
|
112
|
+
|
|
113
|
+
### Codex - OpenAI Codex 代码生成工具
|
|
114
|
+
- 认证模式:
|
|
115
|
+
- `chatgpt_login` - ChatGPT 登录模式(推荐,使用 ChatGPT 账户登录)
|
|
116
|
+
- `api_key` - OpenAI API 密钥模式
|
|
117
|
+
- 环境变量:OPENAI_API_KEY、OPENAI_API_BASE(可选)
|
|
118
|
+
- 官方包:`npm install -g @openai/codex`
|
|
119
|
+
|
|
75
120
|
## 支持的认证模式
|
|
76
121
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
122
|
+
| 模式 | IDE | 说明 |
|
|
123
|
+
|------|-----|------|
|
|
124
|
+
| **oauth_token** | Claude Code | OAuth 令牌模式 |
|
|
125
|
+
| **api_key** | Claude Code / Codex | 标准 API 密钥模式 |
|
|
126
|
+
| **auth_token** | Claude Code | 认证令牌模式 |
|
|
127
|
+
| **chatgpt_login** | Codex | ChatGPT 登录模式(推荐) |
|
|
80
128
|
|
|
81
129
|
## 快捷键
|
|
82
130
|
|
package/package.json
CHANGED
package/src/commands/add.js
CHANGED
|
@@ -196,13 +196,39 @@ class ProviderAdder extends BaseCommand {
|
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
type: 'list',
|
|
199
|
-
name: '
|
|
200
|
-
message: '
|
|
199
|
+
name: 'ideName',
|
|
200
|
+
message: '选择要使用的 IDE:',
|
|
201
201
|
choices: [
|
|
202
|
-
{ name: '
|
|
203
|
-
{ name: '
|
|
204
|
-
{ name: '🌐 OAuth令牌模式 (CLAUDE_CODE_OAUTH_TOKEN) - 适用于官方Claude Code', value: 'oauth_token' }
|
|
202
|
+
{ name: '🚀 Claude Code - Anthropic 官方代码编辑器', value: 'claude' },
|
|
203
|
+
{ name: '⚙️ Codex - 代码生成和编辑工具', value: 'codex' }
|
|
205
204
|
],
|
|
205
|
+
default: 'claude'
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
type: 'list',
|
|
209
|
+
name: 'authMode',
|
|
210
|
+
message: (answers) => {
|
|
211
|
+
if (answers.ideName === 'codex') {
|
|
212
|
+
return '选择 Codex 认证模式:';
|
|
213
|
+
}
|
|
214
|
+
return '选择 Claude Code 认证模式:';
|
|
215
|
+
},
|
|
216
|
+
choices: (answers) => {
|
|
217
|
+
if (answers.ideName === 'codex') {
|
|
218
|
+
// Codex 的认证模式选择
|
|
219
|
+
// @openai/codex 支持两种方式:ChatGPT 登录 (推荐) 或 OpenAI API Key
|
|
220
|
+
return [
|
|
221
|
+
{ name: '🔐 ChatGPT 登录 (推荐) - 使用 ChatGPT 账户登录', value: 'chatgpt_login' },
|
|
222
|
+
{ name: '🔑 OpenAI API Key - 使用 OPENAI_API_KEY', value: 'api_key' }
|
|
223
|
+
];
|
|
224
|
+
}
|
|
225
|
+
// Claude Code 的认证模式选择
|
|
226
|
+
return [
|
|
227
|
+
{ name: '🔑 通用API密钥模式 - 支持 ANTHROPIC_API_KEY 和 ANTHROPIC_AUTH_TOKEN', value: 'api_key' },
|
|
228
|
+
{ name: '🔐 认证令牌模式 (仅 ANTHROPIC_AUTH_TOKEN) - 适用于某些服务商', value: 'auth_token' },
|
|
229
|
+
{ name: '🌐 OAuth令牌模式 (CLAUDE_CODE_OAUTH_TOKEN) - 适用于官方Claude Code', value: 'oauth_token' }
|
|
230
|
+
];
|
|
231
|
+
},
|
|
206
232
|
default: 'api_key'
|
|
207
233
|
},
|
|
208
234
|
{
|
|
@@ -214,13 +240,18 @@ class ProviderAdder extends BaseCommand {
|
|
|
214
240
|
{ name: '🔐 ANTHROPIC_AUTH_TOKEN - 认证令牌', value: 'auth_token' }
|
|
215
241
|
],
|
|
216
242
|
default: 'api_key',
|
|
217
|
-
|
|
243
|
+
// 只对 Claude Code 的 api_key 模式显示 tokenType 选择
|
|
244
|
+
// Codex 的 api_key 模式固定使用 OPENAI_API_KEY
|
|
245
|
+
when: (answers) => answers.ideName === 'claude' && answers.authMode === 'api_key'
|
|
218
246
|
},
|
|
219
247
|
{
|
|
220
248
|
type: 'input',
|
|
221
249
|
name: 'baseUrl',
|
|
222
250
|
message: (answers) => {
|
|
223
251
|
// 根据认证模式显示不同的提示
|
|
252
|
+
if (answers.ideName === 'codex' && answers.authMode === 'api_key') {
|
|
253
|
+
return '请输入OpenAI API基础URL (可选,默认为官方API):';
|
|
254
|
+
}
|
|
224
255
|
if (answers.authMode === 'auth_token') {
|
|
225
256
|
return '请输入API基础URL (如使用官方API可留空):';
|
|
226
257
|
}
|
|
@@ -231,20 +262,43 @@ class ProviderAdder extends BaseCommand {
|
|
|
231
262
|
if (input === '' && answers.authMode === 'auth_token') {
|
|
232
263
|
return true;
|
|
233
264
|
}
|
|
234
|
-
//
|
|
235
|
-
if (
|
|
265
|
+
// Codex 的 api_key 模式也允许空值(使用官方 OpenAI API)
|
|
266
|
+
if (input === '' && answers.ideName === 'codex' && answers.authMode === 'api_key') {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
// Claude Code 的 api_key 模式需要有效的 URL
|
|
270
|
+
if (!input && answers.ideName === 'claude' && answers.authMode === 'api_key') {
|
|
236
271
|
return 'API基础URL不能为空';
|
|
237
272
|
}
|
|
238
|
-
|
|
239
|
-
if (
|
|
273
|
+
// 如果提供了 URL,验证格式
|
|
274
|
+
if (input) {
|
|
275
|
+
const error = validator.validateUrl(input);
|
|
276
|
+
if (error) return error;
|
|
277
|
+
}
|
|
240
278
|
return true;
|
|
241
279
|
},
|
|
242
|
-
|
|
280
|
+
// Codex 只在 api_key 模式时询问 baseUrl,Claude Code 在 api_key 和 auth_token 时询问
|
|
281
|
+
when: (answers) => {
|
|
282
|
+
if (answers.ideName === 'codex') {
|
|
283
|
+
return answers.authMode === 'api_key';
|
|
284
|
+
}
|
|
285
|
+
return answers.authMode === 'api_key' || answers.authMode === 'auth_token';
|
|
286
|
+
}
|
|
243
287
|
},
|
|
244
288
|
{
|
|
245
289
|
type: 'input',
|
|
246
290
|
name: 'authToken',
|
|
247
291
|
message: (answers) => {
|
|
292
|
+
// Codex 的特殊处理
|
|
293
|
+
if (answers.ideName === 'codex') {
|
|
294
|
+
if (answers.authMode === 'api_key') {
|
|
295
|
+
return '请输入OpenAI API Key (OPENAI_API_KEY):';
|
|
296
|
+
}
|
|
297
|
+
// chatgpt_login 模式不需要输入 Token
|
|
298
|
+
return '请输入认证令牌:';
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Claude Code 的处理
|
|
248
302
|
switch (answers.authMode) {
|
|
249
303
|
case 'api_key':
|
|
250
304
|
const tokenTypeLabel = answers.tokenType === 'auth_token' ? 'ANTHROPIC_AUTH_TOKEN' : 'ANTHROPIC_API_KEY';
|
|
@@ -261,7 +315,9 @@ class ProviderAdder extends BaseCommand {
|
|
|
261
315
|
const error = validator.validateToken(input);
|
|
262
316
|
if (error) return error;
|
|
263
317
|
return true;
|
|
264
|
-
}
|
|
318
|
+
},
|
|
319
|
+
// Codex 的 chatgpt_login 模式不需要输入 Token
|
|
320
|
+
when: (answers) => !(answers.ideName === 'codex' && answers.authMode === 'chatgpt_login')
|
|
265
321
|
},
|
|
266
322
|
{
|
|
267
323
|
type: 'confirm',
|
|
@@ -316,6 +372,7 @@ class ProviderAdder extends BaseCommand {
|
|
|
316
372
|
|
|
317
373
|
await this.configManager.addProvider(answers.name, {
|
|
318
374
|
displayName: answers.displayName || answers.name,
|
|
375
|
+
ideName: answers.ideName, // 'claude' 或 'codex'
|
|
319
376
|
baseUrl: answers.baseUrl,
|
|
320
377
|
authToken: answers.authToken,
|
|
321
378
|
authMode: answers.authMode,
|
package/src/config.js
CHANGED
|
@@ -143,6 +143,7 @@ class ConfigManager {
|
|
|
143
143
|
this.config.providers[name] = {
|
|
144
144
|
name,
|
|
145
145
|
displayName: providerConfig.displayName || name,
|
|
146
|
+
ideName: providerConfig.ideName || 'claude', // 'claude' 或 'codex'
|
|
146
147
|
baseUrl: providerConfig.baseUrl,
|
|
147
148
|
authToken: providerConfig.authToken,
|
|
148
149
|
authMode: providerConfig.authMode || 'api_key',
|
|
@@ -24,29 +24,51 @@ function clearTerminal() {
|
|
|
24
24
|
function buildEnvVariables(config) {
|
|
25
25
|
const env = { ...process.env };
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
// Claude Code 配置
|
|
28
|
+
if (config.ideName === 'claude' || !config.ideName) {
|
|
29
|
+
if (config.authMode === 'oauth_token') {
|
|
30
|
+
env.CLAUDE_CODE_OAUTH_TOKEN = config.authToken;
|
|
31
|
+
} else if (config.authMode === 'api_key') {
|
|
32
|
+
env.ANTHROPIC_BASE_URL = config.baseUrl;
|
|
33
|
+
// 根据 tokenType 选择设置哪种 token
|
|
34
|
+
if (config.tokenType === 'auth_token') {
|
|
35
|
+
env.ANTHROPIC_AUTH_TOKEN = config.authToken;
|
|
36
|
+
} else {
|
|
37
|
+
// 默认使用 ANTHROPIC_API_KEY
|
|
38
|
+
env.ANTHROPIC_API_KEY = config.authToken;
|
|
39
|
+
}
|
|
34
40
|
} else {
|
|
35
|
-
//
|
|
36
|
-
env.
|
|
41
|
+
// auth_token 模式
|
|
42
|
+
env.ANTHROPIC_BASE_URL = config.baseUrl;
|
|
43
|
+
env.ANTHROPIC_AUTH_TOKEN = config.authToken;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (config.models && config.models.primary) {
|
|
47
|
+
env.ANTHROPIC_MODEL = config.models.primary;
|
|
37
48
|
}
|
|
38
|
-
} else {
|
|
39
|
-
// auth_token 模式
|
|
40
|
-
env.ANTHROPIC_BASE_URL = config.baseUrl;
|
|
41
|
-
env.ANTHROPIC_AUTH_TOKEN = config.authToken;
|
|
42
|
-
}
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
if (config.models && config.models.smallFast) {
|
|
51
|
+
env.ANTHROPIC_SMALL_FAST_MODEL = config.models.smallFast;
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
// Codex 配置
|
|
56
|
+
// @openai/codex 支持两种认证方式:
|
|
57
|
+
// 1. ChatGPT 登录(推荐)- 无需环境变量,使用交互式登录
|
|
58
|
+
// 2. OpenAI API Key - 通过 OPENAI_API_KEY 环境变量
|
|
59
|
+
if (config.ideName === 'codex') {
|
|
60
|
+
if (config.authMode === 'api_key' && config.authToken) {
|
|
61
|
+
// 使用 OpenAI API Key 方式
|
|
62
|
+
// Codex 通过 OPENAI_API_KEY 环境变量读取 API 密钥
|
|
63
|
+
env.OPENAI_API_KEY = config.authToken;
|
|
64
|
+
|
|
65
|
+
// 如果指定了基础 URL(用于自定义 OpenAI 兼容的 API 端点)
|
|
66
|
+
if (config.baseUrl) {
|
|
67
|
+
env.OPENAI_API_BASE = config.baseUrl;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// 如果是 chatgpt_login 模式,不需要设置环境变量
|
|
71
|
+
// Codex 会启动交互式登录流程
|
|
50
72
|
}
|
|
51
73
|
|
|
52
74
|
return env;
|
|
@@ -58,8 +80,12 @@ async function executeWithEnv(config, launchArgs = []) {
|
|
|
58
80
|
|
|
59
81
|
clearTerminal();
|
|
60
82
|
|
|
83
|
+
// 确定要启动的命令(claude 或 codex)
|
|
84
|
+
const command = config.ideName === 'codex' ? 'codex' : 'claude';
|
|
85
|
+
const description = config.ideName === 'codex' ? 'Codex' : 'Claude Code';
|
|
86
|
+
|
|
61
87
|
return new Promise((resolve, reject) => {
|
|
62
|
-
const child = spawn(
|
|
88
|
+
const child = spawn(command, args, {
|
|
63
89
|
stdio: 'inherit',
|
|
64
90
|
env,
|
|
65
91
|
shell: true
|
|
@@ -69,7 +95,7 @@ async function executeWithEnv(config, launchArgs = []) {
|
|
|
69
95
|
if (code === 0) {
|
|
70
96
|
resolve();
|
|
71
97
|
} else {
|
|
72
|
-
reject(new Error(
|
|
98
|
+
reject(new Error(`${description} 退出,代码: ${code}`));
|
|
73
99
|
}
|
|
74
100
|
});
|
|
75
101
|
|