yymaxapi 1.0.43 → 1.0.45
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/bin/yymaxapi.js +196 -6
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -723,6 +723,31 @@ function writeCodexConfig(baseUrl, apiKey) {
|
|
|
723
723
|
} catch { /* 非关键,静默失败 */ }
|
|
724
724
|
}
|
|
725
725
|
|
|
726
|
+
function writeOpencodeConfig(baseUrl, apiKey, modelId) {
|
|
727
|
+
const home = os.homedir();
|
|
728
|
+
const configDir = process.platform === 'win32'
|
|
729
|
+
? path.join(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'opencode')
|
|
730
|
+
: path.join(home, '.config', 'opencode');
|
|
731
|
+
const configPath = path.join(configDir, 'config.json');
|
|
732
|
+
try {
|
|
733
|
+
if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
|
|
734
|
+
const cleanUrl = baseUrl.replace(/\/+$/, '');
|
|
735
|
+
const config = {
|
|
736
|
+
provider: {
|
|
737
|
+
anthropic: {
|
|
738
|
+
apiKey: apiKey,
|
|
739
|
+
baseURL: cleanUrl
|
|
740
|
+
}
|
|
741
|
+
},
|
|
742
|
+
model: modelId || 'claude-sonnet-4-6'
|
|
743
|
+
};
|
|
744
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
745
|
+
return configPath;
|
|
746
|
+
} catch {
|
|
747
|
+
return null;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
726
751
|
function syncExternalTools(type, baseUrl, apiKey) {
|
|
727
752
|
const synced = [];
|
|
728
753
|
try {
|
|
@@ -2699,7 +2724,7 @@ async function autoActivate(paths, args = {}) {
|
|
|
2699
2724
|
config.agents.defaults.models[codexModelKey] = { alias: codexProviderName };
|
|
2700
2725
|
|
|
2701
2726
|
// ---- 选择主力 ----
|
|
2702
|
-
let primaryType = '
|
|
2727
|
+
let primaryType = 'claude';
|
|
2703
2728
|
if (args.primary === 'claude') {
|
|
2704
2729
|
primaryType = 'claude';
|
|
2705
2730
|
} else if (args.primary === 'codex') {
|
|
@@ -2710,8 +2735,8 @@ async function autoActivate(paths, args = {}) {
|
|
|
2710
2735
|
name: 'picked',
|
|
2711
2736
|
message: '选择主力工具(默认启动哪个):',
|
|
2712
2737
|
choices: [
|
|
2713
|
-
{ name: '
|
|
2714
|
-
{ name: '
|
|
2738
|
+
{ name: 'Claude Code', value: 'claude' },
|
|
2739
|
+
{ name: 'Codex (GPT)', value: 'codex' }
|
|
2715
2740
|
]
|
|
2716
2741
|
}]);
|
|
2717
2742
|
primaryType = picked;
|
|
@@ -2767,6 +2792,163 @@ async function autoActivate(paths, args = {}) {
|
|
|
2767
2792
|
}
|
|
2768
2793
|
}
|
|
2769
2794
|
|
|
2795
|
+
// ============ 单独配置 Claude Code CLI ============
|
|
2796
|
+
async function activateClaudeCode(paths, args = {}) {
|
|
2797
|
+
console.log(chalk.cyan.bold('\n🔧 配置 Claude Code CLI\n'));
|
|
2798
|
+
|
|
2799
|
+
const claudeApiConfig = API_CONFIG.claude;
|
|
2800
|
+
|
|
2801
|
+
// ---- 测速选节点 ----
|
|
2802
|
+
const shouldTest = !(args['no-test'] || args.noTest);
|
|
2803
|
+
let selectedEndpoint = ENDPOINTS[0];
|
|
2804
|
+
|
|
2805
|
+
if (shouldTest) {
|
|
2806
|
+
console.log(chalk.cyan('📡 开始测速节点...\n'));
|
|
2807
|
+
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
2808
|
+
const sorted = speedResult.ranked || [];
|
|
2809
|
+
if (sorted.length > 0) {
|
|
2810
|
+
const defaultEp = ENDPOINTS[0];
|
|
2811
|
+
const { selectedIndex } = await inquirer.prompt([{
|
|
2812
|
+
type: 'list',
|
|
2813
|
+
name: 'selectedIndex',
|
|
2814
|
+
message: '选择节点:',
|
|
2815
|
+
choices: [
|
|
2816
|
+
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
2817
|
+
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
2818
|
+
...sorted.map((e, i) => ({
|
|
2819
|
+
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
2820
|
+
value: i
|
|
2821
|
+
}))
|
|
2822
|
+
]
|
|
2823
|
+
}]);
|
|
2824
|
+
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
2825
|
+
} else {
|
|
2826
|
+
console.log(chalk.red('\n⚠️ 所有节点均不可达'));
|
|
2827
|
+
const { proceed } = await inquirer.prompt([{
|
|
2828
|
+
type: 'confirm', name: 'proceed',
|
|
2829
|
+
message: '仍要使用默认节点配置吗?', default: false
|
|
2830
|
+
}]);
|
|
2831
|
+
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
// ---- API Key ----
|
|
2836
|
+
const directKey = (args['api-key'] || args.apiKey || args.key || '').toString().trim();
|
|
2837
|
+
let apiKey;
|
|
2838
|
+
if (directKey) {
|
|
2839
|
+
apiKey = directKey;
|
|
2840
|
+
} else {
|
|
2841
|
+
const envKey = process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '';
|
|
2842
|
+
apiKey = await promptApiKey('请输入 API Key:', envKey);
|
|
2843
|
+
}
|
|
2844
|
+
if (!apiKey) { console.log(chalk.gray('已取消')); return; }
|
|
2845
|
+
|
|
2846
|
+
// ---- 验证 ----
|
|
2847
|
+
console.log('');
|
|
2848
|
+
const validation = await validateApiKey(selectedEndpoint.url, apiKey);
|
|
2849
|
+
if (!validation.valid) {
|
|
2850
|
+
const { continueAnyway } = await inquirer.prompt([{
|
|
2851
|
+
type: 'confirm', name: 'continueAnyway',
|
|
2852
|
+
message: 'API Key 验证失败,是否仍然继续写入配置?', default: false
|
|
2853
|
+
}]);
|
|
2854
|
+
if (!continueAnyway) { console.log(chalk.gray('已取消')); return; }
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
// ---- 写入配置 ----
|
|
2858
|
+
const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
|
|
2859
|
+
const writeSpinner = ora({ text: '正在写入 Claude Code 配置...', spinner: 'dots' }).start();
|
|
2860
|
+
writeClaudeCodeSettings(claudeBaseUrl, apiKey);
|
|
2861
|
+
writeSpinner.succeed('Claude Code 配置写入完成');
|
|
2862
|
+
|
|
2863
|
+
console.log(chalk.green('\n✅ Claude Code CLI 配置完成!'));
|
|
2864
|
+
console.log(chalk.cyan(` Base URL: ${claudeBaseUrl}`));
|
|
2865
|
+
console.log(chalk.gray(` 模型: claude-sonnet-4-6`));
|
|
2866
|
+
console.log(chalk.gray(' API Key: 已设置'));
|
|
2867
|
+
console.log(chalk.gray('\n 已写入:'));
|
|
2868
|
+
console.log(chalk.gray(' • ~/.claude/settings.json'));
|
|
2869
|
+
console.log(chalk.gray(' • ~/.claude.json (跳过 onboarding)'));
|
|
2870
|
+
console.log(chalk.gray(' • shell 环境变量 (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN)'));
|
|
2871
|
+
console.log(chalk.yellow('\n 提示: 请重新打开终端或执行 source ~/.zshrc 使环境变量生效'));
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
// ============ 单独配置 Opencode ============
|
|
2875
|
+
async function activateOpencode(paths, args = {}) {
|
|
2876
|
+
console.log(chalk.cyan.bold('\n🔧 配置 Opencode\n'));
|
|
2877
|
+
|
|
2878
|
+
const claudeApiConfig = API_CONFIG.claude;
|
|
2879
|
+
|
|
2880
|
+
// ---- 测速选节点 ----
|
|
2881
|
+
const shouldTest = !(args['no-test'] || args.noTest);
|
|
2882
|
+
let selectedEndpoint = ENDPOINTS[0];
|
|
2883
|
+
|
|
2884
|
+
if (shouldTest) {
|
|
2885
|
+
console.log(chalk.cyan('📡 开始测速节点...\n'));
|
|
2886
|
+
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
2887
|
+
const sorted = speedResult.ranked || [];
|
|
2888
|
+
if (sorted.length > 0) {
|
|
2889
|
+
const defaultEp = ENDPOINTS[0];
|
|
2890
|
+
const { selectedIndex } = await inquirer.prompt([{
|
|
2891
|
+
type: 'list',
|
|
2892
|
+
name: 'selectedIndex',
|
|
2893
|
+
message: '选择节点:',
|
|
2894
|
+
choices: [
|
|
2895
|
+
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
2896
|
+
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
2897
|
+
...sorted.map((e, i) => ({
|
|
2898
|
+
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
2899
|
+
value: i
|
|
2900
|
+
}))
|
|
2901
|
+
]
|
|
2902
|
+
}]);
|
|
2903
|
+
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
2904
|
+
} else {
|
|
2905
|
+
console.log(chalk.red('\n⚠️ 所有节点均不可达'));
|
|
2906
|
+
const { proceed } = await inquirer.prompt([{
|
|
2907
|
+
type: 'confirm', name: 'proceed',
|
|
2908
|
+
message: '仍要使用默认节点配置吗?', default: false
|
|
2909
|
+
}]);
|
|
2910
|
+
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2914
|
+
// ---- API Key ----
|
|
2915
|
+
const directKey = (args['api-key'] || args.apiKey || args.key || '').toString().trim();
|
|
2916
|
+
let apiKey;
|
|
2917
|
+
if (directKey) {
|
|
2918
|
+
apiKey = directKey;
|
|
2919
|
+
} else {
|
|
2920
|
+
const envKey = process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '';
|
|
2921
|
+
apiKey = await promptApiKey('请输入 API Key:', envKey);
|
|
2922
|
+
}
|
|
2923
|
+
if (!apiKey) { console.log(chalk.gray('已取消')); return; }
|
|
2924
|
+
|
|
2925
|
+
// ---- 验证 ----
|
|
2926
|
+
console.log('');
|
|
2927
|
+
const validation = await validateApiKey(selectedEndpoint.url, apiKey);
|
|
2928
|
+
if (!validation.valid) {
|
|
2929
|
+
const { continueAnyway } = await inquirer.prompt([{
|
|
2930
|
+
type: 'confirm', name: 'continueAnyway',
|
|
2931
|
+
message: 'API Key 验证失败,是否仍然继续写入配置?', default: false
|
|
2932
|
+
}]);
|
|
2933
|
+
if (!continueAnyway) { console.log(chalk.gray('已取消')); return; }
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
// ---- 写入配置 ----
|
|
2937
|
+
const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
|
|
2938
|
+
const modelId = 'claude-sonnet-4-6';
|
|
2939
|
+
const writeSpinner = ora({ text: '正在写入 Opencode 配置...', spinner: 'dots' }).start();
|
|
2940
|
+
const configPath = writeOpencodeConfig(claudeBaseUrl, apiKey, modelId);
|
|
2941
|
+
writeSpinner.succeed('Opencode 配置写入完成');
|
|
2942
|
+
|
|
2943
|
+
console.log(chalk.green('\n✅ Opencode 配置完成!'));
|
|
2944
|
+
console.log(chalk.cyan(` Base URL: ${claudeBaseUrl}`));
|
|
2945
|
+
console.log(chalk.gray(` 模型: ${modelId}`));
|
|
2946
|
+
console.log(chalk.gray(' API Key: 已设置'));
|
|
2947
|
+
if (configPath) {
|
|
2948
|
+
console.log(chalk.gray(` 配置文件: ${configPath}`));
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2770
2952
|
// ============ yycode 精简模式(零交互一键配置) ============
|
|
2771
2953
|
async function yycodeQuickSetup(paths) {
|
|
2772
2954
|
console.log(chalk.cyan.bold('\n⚡ yycode 一键配置\n'));
|
|
@@ -2985,11 +3167,13 @@ async function main() {
|
|
|
2985
3167
|
type: 'list',
|
|
2986
3168
|
name: 'action',
|
|
2987
3169
|
message: '请选择操作:',
|
|
2988
|
-
pageSize:
|
|
3170
|
+
pageSize: 15,
|
|
2989
3171
|
loop: false,
|
|
2990
3172
|
choices: [
|
|
2991
|
-
new inquirer.Separator(' --
|
|
2992
|
-
{ name: '
|
|
3173
|
+
new inquirer.Separator(' -- 一键配置 --'),
|
|
3174
|
+
{ name: ' 配置 OpenClaw(Claude + Codex)', value: 'auto_activate' },
|
|
3175
|
+
{ name: ' 配置 Claude Code', value: 'activate_claude_code' },
|
|
3176
|
+
{ name: ' 配置 Opencode', value: 'activate_opencode' },
|
|
2993
3177
|
new inquirer.Separator(' -- 工具 --'),
|
|
2994
3178
|
{ name: ' 切换模型', value: 'switch_model' },
|
|
2995
3179
|
{ name: ' 测试连接', value: 'test_connection' },
|
|
@@ -3029,6 +3213,12 @@ async function main() {
|
|
|
3029
3213
|
case 'install_openclaw':
|
|
3030
3214
|
await installOrUpdateOpenClaw();
|
|
3031
3215
|
break;
|
|
3216
|
+
case 'activate_claude_code':
|
|
3217
|
+
await activateClaudeCode(paths);
|
|
3218
|
+
break;
|
|
3219
|
+
case 'activate_opencode':
|
|
3220
|
+
await activateOpencode(paths);
|
|
3221
|
+
break;
|
|
3032
3222
|
}
|
|
3033
3223
|
} catch (error) {
|
|
3034
3224
|
console.log(chalk.red(`\n错误: ${error.message}\n`));
|