aihezu 2.8.1 → 2.8.3
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 +1 -1
- package/bin/aihezu.js +1 -1
- package/commands/check.js +3 -3
- package/commands/config.js +24 -10
- package/commands/install.js +28 -14
- package/commands/usage.js +2 -2
- package/docs/TROUBLESHOOTING.md +1 -1
- package/package.json +1 -1
- package/services/codex.js +20 -71
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
- `ccinstall` / `install`:交互式配置 Claude(默认)或 Codex
|
|
18
18
|
- Claude:默认 `https://cc.aihezu.dev/api`,企业可用 `--api` / `--api-url` 指定独立域名
|
|
19
|
-
- Codex:默认 `https://cc.aihezu.dev/openai`,企业可用 `--api` / `--api-url` 指定独立域名;写入 `~/.codex/config.toml` 和 `auth.json`,使用 `
|
|
19
|
+
- Codex:默认 `https://cc.aihezu.dev/openai`,企业可用 `--api` / `--api-url` 指定独立域名;写入 `~/.codex/config.toml` 和 `auth.json`,使用 `OPENAI_API_KEY`
|
|
20
20
|
- `ccclear`:清理 Claude Code 缓存和配置
|
|
21
21
|
- `usage`:查看 Claude Code / Codex / Gemini 用量统计(支持 `--key` 指定 API Key)
|
|
22
22
|
|
package/bin/aihezu.js
CHANGED
|
@@ -52,7 +52,7 @@ function showHelp() {
|
|
|
52
52
|
console.log(' 环境变量: ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL');
|
|
53
53
|
console.log(' Codex:');
|
|
54
54
|
console.log(' 配置文件: ~/.codex/config.toml, ~/.codex/auth.json');
|
|
55
|
-
console.log(' 环境变量:
|
|
55
|
+
console.log(' 环境变量: OPENAI_API_KEY');
|
|
56
56
|
console.log(' Google Gemini:');
|
|
57
57
|
console.log(' 配置文件: ~/.gemini/.env, ~/.gemini/settings.json (可选)');
|
|
58
58
|
console.log(' 环境变量: GEMINI_API_KEY, GOOGLE_GEMINI_BASE_URL');
|
package/commands/check.js
CHANGED
|
@@ -113,7 +113,7 @@ function checkCodex() {
|
|
|
113
113
|
try {
|
|
114
114
|
const authData = JSON.parse(fs.readFileSync(authPath, 'utf8'));
|
|
115
115
|
console.log(' ✅ 文件存在');
|
|
116
|
-
console.log(' 📝
|
|
116
|
+
console.log(' 📝 OPENAI_API_KEY:', maskSensitive(authData.OPENAI_API_KEY));
|
|
117
117
|
} catch (e) {
|
|
118
118
|
console.log(' ❌ 文件存在但格式错误:', e.message);
|
|
119
119
|
}
|
|
@@ -123,8 +123,8 @@ function checkCodex() {
|
|
|
123
123
|
|
|
124
124
|
// Check environment variables
|
|
125
125
|
console.log('\n3️⃣ 环境变量:');
|
|
126
|
-
const envKey = process.env.
|
|
127
|
-
console.log(' 📝
|
|
126
|
+
const envKey = process.env.OPENAI_API_KEY;
|
|
127
|
+
console.log(' 📝 OPENAI_API_KEY:', maskSensitive(envKey));
|
|
128
128
|
|
|
129
129
|
// Priority explanation
|
|
130
130
|
console.log('\n4️⃣ 优先级说明:');
|
package/commands/config.js
CHANGED
|
@@ -101,27 +101,40 @@ async function configCommand(service, args = []) {
|
|
|
101
101
|
// 3. Extra Options (Service specific)
|
|
102
102
|
const options = {};
|
|
103
103
|
if (service.name === 'codex') {
|
|
104
|
+
const knownModels = ['gpt-5-codex', 'gpt-5.3-codex', 'claude-sonnet-4.5'];
|
|
104
105
|
let defaultModel = cliModel || 'gpt-5-codex';
|
|
105
106
|
|
|
106
107
|
console.log('请选择模型:');
|
|
107
108
|
console.log(' [1] gpt-5-codex' + (defaultModel === 'gpt-5-codex' ? ' (默认)' : ''));
|
|
108
|
-
console.log(' [2]
|
|
109
|
-
console.log(' [3]
|
|
109
|
+
console.log(' [2] gpt-5.3-codex' + (defaultModel === 'gpt-5.3-codex' ? ' (默认)' : ''));
|
|
110
|
+
console.log(' [3] claude-sonnet-4.5' + (defaultModel === 'claude-sonnet-4.5' ? ' (默认)' : ''));
|
|
111
|
+
console.log(' [4] 自定义模型名称' + (!knownModels.includes(defaultModel) ? ' (默认: ' + defaultModel + ')' : ''));
|
|
110
112
|
|
|
111
|
-
const choice = await askQuestion(rl, '请选择 [1/2/3]: ');
|
|
113
|
+
const choice = await askQuestion(rl, '请选择 [1/2/3/4]: ');
|
|
112
114
|
|
|
113
115
|
if (choice === '2') {
|
|
114
|
-
options.modelName = '
|
|
116
|
+
options.modelName = 'gpt-5.3-codex';
|
|
115
117
|
} else if (choice === '3') {
|
|
118
|
+
options.modelName = 'claude-sonnet-4.5';
|
|
119
|
+
} else if (choice === '4') {
|
|
116
120
|
const customModel = await askQuestion(rl, '请输入自定义模型名称: ');
|
|
117
121
|
options.modelName = customModel || defaultModel;
|
|
118
122
|
} else if (choice === '1' || choice === '') {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
options.modelName = (choice === '') ? defaultModel : 'gpt-5-codex';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Reasoning effort selection
|
|
127
|
+
console.log('');
|
|
128
|
+
console.log('请选择推理能力:');
|
|
129
|
+
console.log(' [1] high (默认)');
|
|
130
|
+
console.log(' [2] xhigh (Extra High)');
|
|
131
|
+
|
|
132
|
+
const effortChoice = await askQuestion(rl, '请选择 [1/2]: ');
|
|
133
|
+
|
|
134
|
+
if (effortChoice === '2') {
|
|
135
|
+
options.reasoningEffort = 'xhigh';
|
|
136
|
+
} else {
|
|
137
|
+
options.reasoningEffort = 'high';
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
140
|
|
|
@@ -131,6 +144,7 @@ async function configCommand(service, args = []) {
|
|
|
131
144
|
console.log('服务类型: ' + service.displayName);
|
|
132
145
|
console.log('API 地址: ' + apiUrl);
|
|
133
146
|
if (options.modelName) console.log('模型: ' + options.modelName);
|
|
147
|
+
if (options.reasoningEffort) console.log('推理能力: ' + options.reasoningEffort);
|
|
134
148
|
console.log('API Key: ' + apiKey.substring(0, 5) + '...');
|
|
135
149
|
|
|
136
150
|
console.log('');
|
package/commands/install.js
CHANGED
|
@@ -102,27 +102,40 @@ async function installCommand(service, args = []) {
|
|
|
102
102
|
// 3. Extra Options (Service specific)
|
|
103
103
|
const options = {};
|
|
104
104
|
if (service.name === 'codex') {
|
|
105
|
+
const knownModels = ['gpt-5-codex', 'gpt-5.3-codex', 'claude-sonnet-4.5'];
|
|
105
106
|
let defaultModel = cliModel || 'gpt-5-codex';
|
|
106
|
-
|
|
107
|
+
|
|
107
108
|
console.log('请选择模型:');
|
|
108
109
|
console.log(' [1] gpt-5-codex' + (defaultModel === 'gpt-5-codex' ? ' (默认)' : ''));
|
|
109
|
-
console.log(' [2]
|
|
110
|
-
console.log(' [3]
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
console.log(' [2] gpt-5.3-codex' + (defaultModel === 'gpt-5.3-codex' ? ' (默认)' : ''));
|
|
111
|
+
console.log(' [3] claude-sonnet-4.5' + (defaultModel === 'claude-sonnet-4.5' ? ' (默认)' : ''));
|
|
112
|
+
console.log(' [4] 自定义模型名称' + (!knownModels.includes(defaultModel) ? ' (默认: ' + defaultModel + ')' : ''));
|
|
113
|
+
|
|
114
|
+
const choice = await askQuestion(rl, '请选择 [1/2/3/4]: ');
|
|
115
|
+
|
|
114
116
|
if (choice === '2') {
|
|
115
|
-
options.modelName = '
|
|
117
|
+
options.modelName = 'gpt-5.3-codex';
|
|
116
118
|
} else if (choice === '3') {
|
|
119
|
+
options.modelName = 'claude-sonnet-4.5';
|
|
120
|
+
} else if (choice === '4') {
|
|
117
121
|
const customModel = await askQuestion(rl, '请输入自定义模型名称: ');
|
|
118
|
-
options.modelName = customModel || defaultModel;
|
|
122
|
+
options.modelName = customModel || defaultModel;
|
|
119
123
|
} else if (choice === '1' || choice === '') {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
options.modelName = (choice === '') ? defaultModel : 'gpt-5-codex';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Reasoning effort selection
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log('请选择推理能力:');
|
|
130
|
+
console.log(' [1] high (默认)');
|
|
131
|
+
console.log(' [2] xhigh (Extra High)');
|
|
132
|
+
|
|
133
|
+
const effortChoice = await askQuestion(rl, '请选择 [1/2]: ');
|
|
134
|
+
|
|
135
|
+
if (effortChoice === '2') {
|
|
136
|
+
options.reasoningEffort = 'xhigh';
|
|
137
|
+
} else {
|
|
138
|
+
options.reasoningEffort = 'high';
|
|
126
139
|
}
|
|
127
140
|
}
|
|
128
141
|
|
|
@@ -132,6 +145,7 @@ async function installCommand(service, args = []) {
|
|
|
132
145
|
console.log('服务类型: ' + service.displayName);
|
|
133
146
|
console.log('API 地址: ' + apiUrl);
|
|
134
147
|
if (options.modelName) console.log('模型: ' + options.modelName);
|
|
148
|
+
if (options.reasoningEffort) console.log('推理能力: ' + options.reasoningEffort);
|
|
135
149
|
console.log('API Key: ' + apiKey.substring(0, 5) + '...');
|
|
136
150
|
|
|
137
151
|
console.log('');
|
package/commands/usage.js
CHANGED
|
@@ -133,7 +133,7 @@ function readCodexConfig() {
|
|
|
133
133
|
const configs = [];
|
|
134
134
|
|
|
135
135
|
// 读取环境变量
|
|
136
|
-
const envAuthToken = process.env.
|
|
136
|
+
const envAuthToken = process.env.OPENAI_API_KEY || '';
|
|
137
137
|
|
|
138
138
|
// 读取配置文件中的 base_url
|
|
139
139
|
let fileBaseUrl = '';
|
|
@@ -159,7 +159,7 @@ function readCodexConfig() {
|
|
|
159
159
|
try {
|
|
160
160
|
const content = fs.readFileSync(authPath, 'utf8');
|
|
161
161
|
const authData = JSON.parse(content);
|
|
162
|
-
fileAuthToken = authData.
|
|
162
|
+
fileAuthToken = authData.OPENAI_API_KEY || '';
|
|
163
163
|
} catch (error) {
|
|
164
164
|
// 忽略错误
|
|
165
165
|
}
|
package/docs/TROUBLESHOOTING.md
CHANGED
package/package.json
CHANGED
package/services/codex.js
CHANGED
|
@@ -25,82 +25,29 @@ module.exports = {
|
|
|
25
25
|
|
|
26
26
|
// Configuration setup logic
|
|
27
27
|
setupConfig: async (apiKey, apiUrl, options = {}) => {
|
|
28
|
-
const { modelName = 'gpt-5-codex' } = options;
|
|
28
|
+
const { modelName = 'gpt-5-codex', reasoningEffort = 'high' } = options;
|
|
29
29
|
|
|
30
30
|
if (!fs.existsSync(configDir)) {
|
|
31
31
|
console.log('📁 创建 ~/.codex 目录...');
|
|
32
32
|
fs.mkdirSync(configDir, { recursive: true });
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Handle config.toml
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Update model
|
|
52
|
-
const modelPattern = /^model\s*=\s*"[^"]*"/m;
|
|
53
|
-
if (modelPattern.test(newConfig)) {
|
|
54
|
-
newConfig = newConfig.replace(modelPattern, `model = "${modelName}"`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Update base_url
|
|
58
|
-
const baseUrlPattern = new RegExp(
|
|
59
|
-
`(\[model_providers\.${providerName}\][\s\S]*?base_url\s*=\s*)"[^"]*"`,
|
|
60
|
-
'm'
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (baseUrlPattern.test(newConfig)) {
|
|
64
|
-
newConfig = newConfig.replace(baseUrlPattern, `$1"${apiUrl}"`);
|
|
65
|
-
} else {
|
|
66
|
-
// If provider block exists but no base_url (rare), or provider block missing
|
|
67
|
-
const providerSectionPattern = new RegExp(`\[model_providers\.${providerName}\]`, 'm');
|
|
68
|
-
if (providerSectionPattern.test(newConfig)) {
|
|
69
|
-
newConfig = newConfig.replace(
|
|
70
|
-
providerSectionPattern,
|
|
71
|
-
`[model_providers.${providerName}]\nbase_url = "${apiUrl}"`
|
|
72
|
-
);
|
|
73
|
-
} else {
|
|
74
|
-
// Append new provider
|
|
75
|
-
newConfig = newConfig.trim() + '\n\n' +
|
|
76
|
-
`[model_providers.${providerName}]\n` +
|
|
77
|
-
`name = "${providerName}"\n` +
|
|
78
|
-
`base_url = "${apiUrl}"\n` +
|
|
79
|
-
`wire_api = "responses"\n` +
|
|
80
|
-
`requires_openai_auth = true\n` +
|
|
81
|
-
`env_key = "AIHEZU_OAI_KEY"\n`;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
configContent = newConfig;
|
|
85
|
-
|
|
86
|
-
} else {
|
|
87
|
-
// New Config
|
|
88
|
-
configContent = [
|
|
89
|
-
'model_provider = "aihezu"',
|
|
90
|
-
`model = "${modelName}"`,
|
|
91
|
-
'model_reasoning_effort = "high"',
|
|
92
|
-
'disable_response_storage = true',
|
|
93
|
-
'preferred_auth_method = "apikey"',
|
|
94
|
-
'',
|
|
95
|
-
'[model_providers.aihezu]',
|
|
96
|
-
'name = "aihezu"',
|
|
97
|
-
`base_url = "${apiUrl}"`,
|
|
98
|
-
'wire_api = "responses"',
|
|
99
|
-
'requires_openai_auth = true',
|
|
100
|
-
'env_key = "AIHEZU_OAI_KEY"',
|
|
101
|
-
''
|
|
102
|
-
].join('\n');
|
|
103
|
-
}
|
|
35
|
+
// Handle config.toml - always regenerate to avoid duplication issues
|
|
36
|
+
const providerName = 'aihezu';
|
|
37
|
+
const configContent = [
|
|
38
|
+
`model_provider = "${providerName}"`,
|
|
39
|
+
`model = "${modelName}"`,
|
|
40
|
+
`model_reasoning_effort = "${reasoningEffort}"`,
|
|
41
|
+
'disable_response_storage = true',
|
|
42
|
+
'preferred_auth_method = "apikey"',
|
|
43
|
+
'',
|
|
44
|
+
`[model_providers.${providerName}]`,
|
|
45
|
+
`name = "${providerName}"`,
|
|
46
|
+
`base_url = "${apiUrl}"`,
|
|
47
|
+
'wire_api = "responses"',
|
|
48
|
+
'requires_openai_auth = true',
|
|
49
|
+
''
|
|
50
|
+
].join('\n');
|
|
104
51
|
|
|
105
52
|
fs.writeFileSync(configPath, configContent, 'utf8');
|
|
106
53
|
|
|
@@ -113,7 +60,9 @@ module.exports = {
|
|
|
113
60
|
authData = {};
|
|
114
61
|
}
|
|
115
62
|
}
|
|
116
|
-
|
|
63
|
+
// Remove legacy key if present
|
|
64
|
+
delete authData.AIHEZU_OAI_KEY;
|
|
65
|
+
authData.OPENAI_API_KEY = apiKey;
|
|
117
66
|
fs.writeFileSync(authPath, JSON.stringify(authData, null, 2), 'utf8');
|
|
118
67
|
|
|
119
68
|
// Fix permissions if running with sudo
|