yymaxapi 1.0.96 → 1.0.98
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
CHANGED
|
@@ -23,6 +23,8 @@ $env:OPENCLAW_CLAUDE_KEY="你的Key"; npx yymaxapi@latest preset-claude
|
|
|
23
23
|
set OPENCLAW_CLAUDE_KEY=你的Key && npx yymaxapi@latest preset-claude
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
说明:`preset-claude` 现在只写 Claude Code CLI 自身配置,不会改动 OpenClaw、Codex CLI、Opencode。
|
|
27
|
+
|
|
26
28
|
**方式三:一键配置 Codex**
|
|
27
29
|
```bash
|
|
28
30
|
# macOS/Linux
|
|
@@ -38,22 +40,22 @@ set OPENCLAW_CODEX_KEY=你的Key && npx yymaxapi@latest preset-codex
|
|
|
38
40
|
**方式四:完全自动化(无交互)**
|
|
39
41
|
```bash
|
|
40
42
|
# macOS/Linux
|
|
41
|
-
OPENCLAW_CLAUDE_KEY="你的Key" npx yymaxapi@latest preset-claude --model claude-opus-4-
|
|
43
|
+
OPENCLAW_CLAUDE_KEY="你的Key" npx yymaxapi@latest preset-claude --model claude-opus-4-6 --set-primary true --force --test true
|
|
42
44
|
|
|
43
45
|
# Windows PowerShell
|
|
44
|
-
$env:OPENCLAW_CLAUDE_KEY="你的Key"; npx yymaxapi@latest preset-claude --model claude-opus-4-
|
|
46
|
+
$env:OPENCLAW_CLAUDE_KEY="你的Key"; npx yymaxapi@latest preset-claude --model claude-opus-4-6 --set-primary true --force --test true
|
|
45
47
|
|
|
46
48
|
# Windows CMD
|
|
47
|
-
set OPENCLAW_CLAUDE_KEY=你的Key && npx yymaxapi@latest preset-claude --model claude-opus-4-
|
|
49
|
+
set OPENCLAW_CLAUDE_KEY=你的Key && npx yymaxapi@latest preset-claude --model claude-opus-4-6 --set-primary true --force --test true
|
|
48
50
|
|
|
49
51
|
# macOS/Linux
|
|
50
|
-
OPENCLAW_CODEX_KEY="你的Key" npx yymaxapi@latest preset-codex --model gpt-5.
|
|
52
|
+
OPENCLAW_CODEX_KEY="你的Key" npx yymaxapi@latest preset-codex --model gpt-5.4 --set-primary true --force --test true
|
|
51
53
|
|
|
52
54
|
# Windows PowerShell
|
|
53
|
-
$env:OPENCLAW_CODEX_KEY="你的Key"; npx yymaxapi@latest preset-codex --model gpt-5.
|
|
55
|
+
$env:OPENCLAW_CODEX_KEY="你的Key"; npx yymaxapi@latest preset-codex --model gpt-5.4 --set-primary true --force --test true
|
|
54
56
|
|
|
55
57
|
# Windows CMD
|
|
56
|
-
set OPENCLAW_CODEX_KEY=你的Key && npx yymaxapi@latest preset-codex --model gpt-5.
|
|
58
|
+
set OPENCLAW_CODEX_KEY=你的Key && npx yymaxapi@latest preset-codex --model gpt-5.4 --set-primary true --force --test true
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
## 重要说明
|
package/bin/yymaxapi.js
CHANGED
|
@@ -829,82 +829,23 @@ function writeConfig(configPath, config) {
|
|
|
829
829
|
// ============ 多工具配置同步 ============
|
|
830
830
|
|
|
831
831
|
function writeClaudeCodeSettings(baseUrl, apiKey, modelId = getDefaultClaudeModel().id) {
|
|
832
|
-
const home = os.homedir();
|
|
833
832
|
// ~/.claude/settings.json
|
|
834
|
-
const
|
|
835
|
-
const
|
|
833
|
+
const settingsPath = getClaudeCodeSettingsPath();
|
|
834
|
+
const claudeDir = path.dirname(settingsPath);
|
|
836
835
|
try {
|
|
837
836
|
let settings = {};
|
|
838
837
|
if (fs.existsSync(settingsPath)) {
|
|
839
838
|
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch { settings = {}; }
|
|
840
839
|
}
|
|
841
840
|
settings.apiBaseUrl = baseUrl.replace(/\/+$/, '');
|
|
842
|
-
settings.model = modelId;
|
|
843
|
-
settings.availableModels = CLAUDE_MODELS.map(model => model.id);
|
|
844
841
|
if (!settings.env) settings.env = {};
|
|
845
|
-
settings.env.ANTHROPIC_BASE_URL = baseUrl.replace(/\/+$/, '');
|
|
846
842
|
settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
847
|
-
settings.
|
|
843
|
+
delete settings.availableModels;
|
|
844
|
+
delete settings.env.ANTHROPIC_BASE_URL;
|
|
845
|
+
delete settings.env.ANTHROPIC_MODEL;
|
|
848
846
|
if (!fs.existsSync(claudeDir)) fs.mkdirSync(claudeDir, { recursive: true });
|
|
849
847
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
850
848
|
} catch { /* 非关键,静默失败 */ }
|
|
851
|
-
|
|
852
|
-
// ~/.claude.json — 跳过 onboarding
|
|
853
|
-
const claudeJsonPath = path.join(home, '.claude.json');
|
|
854
|
-
try {
|
|
855
|
-
let claudeJson = {};
|
|
856
|
-
if (fs.existsSync(claudeJsonPath)) {
|
|
857
|
-
try { claudeJson = JSON.parse(fs.readFileSync(claudeJsonPath, 'utf8')); } catch { claudeJson = {}; }
|
|
858
|
-
}
|
|
859
|
-
if (!claudeJson.hasCompletedOnboarding) {
|
|
860
|
-
claudeJson.hasCompletedOnboarding = true;
|
|
861
|
-
fs.writeFileSync(claudeJsonPath, JSON.stringify(claudeJson, null, 2), 'utf8');
|
|
862
|
-
}
|
|
863
|
-
} catch { /* 非关键,静默失败 */ }
|
|
864
|
-
|
|
865
|
-
// 写入 shell 环境变量
|
|
866
|
-
if (process.platform === 'win32') {
|
|
867
|
-
try {
|
|
868
|
-
const cleanUrl = baseUrl.replace(/\/+$/, '');
|
|
869
|
-
execSync(
|
|
870
|
-
`powershell -NoProfile -Command "[Environment]::SetEnvironmentVariable('ANTHROPIC_BASE_URL','${cleanUrl}','User'); [Environment]::SetEnvironmentVariable('ANTHROPIC_AUTH_TOKEN','${apiKey}','User'); [Environment]::SetEnvironmentVariable('ANTHROPIC_MODEL','${modelId}','User')"`,
|
|
871
|
-
{ stdio: 'pipe' }
|
|
872
|
-
);
|
|
873
|
-
} catch { /* best-effort */ }
|
|
874
|
-
} else {
|
|
875
|
-
const marker = '# >>> yymaxapi claude >>>';
|
|
876
|
-
const markerEnd = '# <<< yymaxapi claude <<<';
|
|
877
|
-
const cleanUrl = baseUrl.replace(/\/+$/, '');
|
|
878
|
-
// 只持久化工具本身需要的 Claude 变量,TLS 放宽只能留在进程内临时使用。
|
|
879
|
-
const block = [
|
|
880
|
-
marker,
|
|
881
|
-
`export ANTHROPIC_BASE_URL="${cleanUrl}"`,
|
|
882
|
-
`export ANTHROPIC_AUTH_TOKEN="${apiKey}"`,
|
|
883
|
-
`export ANTHROPIC_MODEL="${modelId}"`,
|
|
884
|
-
markerEnd
|
|
885
|
-
].join('\n');
|
|
886
|
-
|
|
887
|
-
const shellEnv = process.env.SHELL || '';
|
|
888
|
-
const rcFiles = [];
|
|
889
|
-
if (shellEnv.includes('zsh') || !shellEnv) rcFiles.push(path.join(home, '.zshrc'));
|
|
890
|
-
if (shellEnv.includes('bash') || !shellEnv) rcFiles.push(path.join(home, '.bashrc'));
|
|
891
|
-
if (rcFiles.length === 0) rcFiles.push(path.join(home, '.profile'));
|
|
892
|
-
|
|
893
|
-
for (const rcFile of rcFiles) {
|
|
894
|
-
try {
|
|
895
|
-
let content = '';
|
|
896
|
-
if (fs.existsSync(rcFile)) {
|
|
897
|
-
content = fs.readFileSync(rcFile, 'utf8');
|
|
898
|
-
const re = new RegExp(
|
|
899
|
-
`${marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${markerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`,
|
|
900
|
-
'g'
|
|
901
|
-
);
|
|
902
|
-
content = content.replace(re, '').trimEnd();
|
|
903
|
-
}
|
|
904
|
-
fs.writeFileSync(rcFile, content ? `${content}\n\n${block}\n` : `${block}\n`, 'utf8');
|
|
905
|
-
} catch { /* best-effort */ }
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
849
|
}
|
|
909
850
|
|
|
910
851
|
function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
@@ -2834,6 +2775,88 @@ function syncMirroredAuthStores(paths) {
|
|
|
2834
2775
|
}
|
|
2835
2776
|
}
|
|
2836
2777
|
|
|
2778
|
+
function getManagedAgentSessionDirs(paths, agentId) {
|
|
2779
|
+
if (!paths?.configDir || !agentId) return [];
|
|
2780
|
+
const dirs = [path.join(paths.configDir, 'agents', agentId, 'sessions')];
|
|
2781
|
+
|
|
2782
|
+
for (const target of paths.syncTargets || []) {
|
|
2783
|
+
const baseDir = path.dirname(target);
|
|
2784
|
+
dirs.push(path.join(baseDir, 'agents', agentId, 'sessions'));
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
return [...new Set(dirs.filter(Boolean))];
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
function archiveManagedSessionFile(sessionDir, sessionId) {
|
|
2791
|
+
if (!sessionDir || !sessionId) return false;
|
|
2792
|
+
const sessionFile = path.join(sessionDir, `${sessionId}.jsonl`);
|
|
2793
|
+
if (!fs.existsSync(sessionFile)) return false;
|
|
2794
|
+
|
|
2795
|
+
const archiveDir = path.join(sessionDir, 'archive');
|
|
2796
|
+
if (!fs.existsSync(archiveDir)) {
|
|
2797
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
const archiveName = `${sessionId}-${Date.now()}.jsonl`;
|
|
2801
|
+
fs.renameSync(sessionFile, path.join(archiveDir, archiveName));
|
|
2802
|
+
return true;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
function resetManagedAgentSessionStore(sessionDir, agentId) {
|
|
2806
|
+
if (!sessionDir || !agentId) return { changed: false, archived: 0 };
|
|
2807
|
+
const sessionsPath = path.join(sessionDir, 'sessions.json');
|
|
2808
|
+
if (!fs.existsSync(sessionsPath)) return { changed: false, archived: 0 };
|
|
2809
|
+
|
|
2810
|
+
let store;
|
|
2811
|
+
try {
|
|
2812
|
+
store = JSON.parse(fs.readFileSync(sessionsPath, 'utf8'));
|
|
2813
|
+
} catch {
|
|
2814
|
+
return { changed: false, archived: 0 };
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
if (!store || typeof store !== 'object' || Array.isArray(store)) {
|
|
2818
|
+
return { changed: false, archived: 0 };
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
const keyPrefix = `agent:${agentId}:`;
|
|
2822
|
+
const keysToRemove = Object.keys(store).filter(key => key.startsWith(keyPrefix));
|
|
2823
|
+
if (keysToRemove.length === 0) return { changed: false, archived: 0 };
|
|
2824
|
+
|
|
2825
|
+
const remaining = { ...store };
|
|
2826
|
+
const removedSessionIds = new Set();
|
|
2827
|
+
for (const key of keysToRemove) {
|
|
2828
|
+
const sessionId = String(store[key]?.sessionId || '').trim();
|
|
2829
|
+
if (sessionId) removedSessionIds.add(sessionId);
|
|
2830
|
+
delete remaining[key];
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
let archived = 0;
|
|
2834
|
+
for (const sessionId of removedSessionIds) {
|
|
2835
|
+
const stillReferenced = Object.values(remaining).some(entry => String(entry?.sessionId || '').trim() === sessionId);
|
|
2836
|
+
if (stillReferenced) continue;
|
|
2837
|
+
if (archiveManagedSessionFile(sessionDir, sessionId)) archived += 1;
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
fs.writeFileSync(sessionsPath, JSON.stringify(remaining, null, 2), 'utf8');
|
|
2841
|
+
return { changed: true, archived };
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
function resetManagedAgentSessionsWithSync(paths, agentId) {
|
|
2845
|
+
const dirs = getManagedAgentSessionDirs(paths, agentId);
|
|
2846
|
+
let changed = false;
|
|
2847
|
+
let archived = 0;
|
|
2848
|
+
|
|
2849
|
+
for (const sessionDir of dirs) {
|
|
2850
|
+
try {
|
|
2851
|
+
const result = resetManagedAgentSessionStore(sessionDir, agentId);
|
|
2852
|
+
if (result.changed) changed = true;
|
|
2853
|
+
archived += result.archived || 0;
|
|
2854
|
+
} catch { /* best-effort */ }
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
return { changed, archived };
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2837
2860
|
function renameProviderInAuthStore(paths, oldProvider, newProvider) {
|
|
2838
2861
|
if (!paths?.authProfiles || !oldProvider || !newProvider || oldProvider === newProvider) return false;
|
|
2839
2862
|
const store = readAuthStore(paths.authProfiles);
|
|
@@ -4616,6 +4639,12 @@ async function autoActivate(paths, args = {}) {
|
|
|
4616
4639
|
if (yunyiLayoutResult.applied) {
|
|
4617
4640
|
syncManagedYunyiAuthProfiles(paths, config);
|
|
4618
4641
|
}
|
|
4642
|
+
if (!isClaudePrimary) {
|
|
4643
|
+
const resetResult = resetManagedAgentSessionsWithSync(paths, YYMAXAPI_OPENCLAW_GPT_AGENT_ID);
|
|
4644
|
+
if (resetResult.changed) {
|
|
4645
|
+
console.log(chalk.gray(` 已重置 ${YYMAXAPI_OPENCLAW_GPT_AGENT_ID} 的活动会话映射`));
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4619
4648
|
const opencodeDefaultModelKey = isClaudePrimary ? `yunyi-claude/${claudeModelId}` : `yunyi-codex/${codexModelId}`;
|
|
4620
4649
|
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey }); } catch { /* ignore */ }
|
|
4621
4650
|
try { syncExternalTools('codex', codexBaseUrl, apiKey, { modelId: codexModelId }); } catch { /* ignore */ }
|
|
@@ -4729,9 +4758,8 @@ async function activateClaudeCode(paths, args = {}) {
|
|
|
4729
4758
|
console.log(chalk.gray(' API Key: 已设置'));
|
|
4730
4759
|
console.log(chalk.gray('\n 已写入:'));
|
|
4731
4760
|
console.log(chalk.gray(' • ~/.claude/settings.json'));
|
|
4732
|
-
console.log(chalk.gray(' •
|
|
4733
|
-
console.log(chalk.
|
|
4734
|
-
console.log(chalk.yellow('\n 提示: 请重新打开终端或执行 source ~/.zshrc 使环境变量生效'));
|
|
4761
|
+
console.log(chalk.gray(' • 最小字段: apiBaseUrl + env.ANTHROPIC_AUTH_TOKEN'));
|
|
4762
|
+
console.log(chalk.yellow('\n 提示: 如果 Claude Code 已在运行,重新打开一个会话即可读取新配置'));
|
|
4735
4763
|
|
|
4736
4764
|
if (await confirmImmediateTest(args, '是否立即测试 Claude Code CLI 连接?')) {
|
|
4737
4765
|
await testAdditionalCliConnections(args, { only: ['claude'] });
|
|
@@ -5112,7 +5140,7 @@ async function main() {
|
|
|
5112
5140
|
return;
|
|
5113
5141
|
}
|
|
5114
5142
|
if (args.preset === 'claude' || args._.includes('preset-claude') || args._.includes('claude-preset')) {
|
|
5115
|
-
await
|
|
5143
|
+
await activateClaudeCode(paths, args);
|
|
5116
5144
|
return;
|
|
5117
5145
|
}
|
|
5118
5146
|
if (args.preset === 'codex' || args._.includes('preset-codex') || args._.includes('codex-preset')) {
|
|
@@ -5589,6 +5617,12 @@ async function switchModel(paths) {
|
|
|
5589
5617
|
primary = finalSelected;
|
|
5590
5618
|
ensureGatewaySettings(config);
|
|
5591
5619
|
writeConfigWithSync(paths, config);
|
|
5620
|
+
if (selectedAgentId === YYMAXAPI_OPENCLAW_GPT_AGENT_ID) {
|
|
5621
|
+
const resetResult = resetManagedAgentSessionsWithSync(paths, selectedAgentId);
|
|
5622
|
+
if (resetResult.changed) {
|
|
5623
|
+
console.log(chalk.gray(` 已重置 ${selectedAgentId} 的活动会话映射`));
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5592
5626
|
|
|
5593
5627
|
const selectedProviderKey = finalSelected.split('/')[0];
|
|
5594
5628
|
const selectedProviderConfig = providers[selectedProviderKey];
|
|
@@ -148,21 +148,20 @@ npx yymaxapi@latest
|
|
|
148
148
|
|
|
149
149
|
**2. Claude Code CLI(本机终端)**
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
推荐直接写 `settings.json` 最小配置:
|
|
152
152
|
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"apiBaseUrl": "https://yunyi.rdzhvip.com/claude",
|
|
156
|
+
"env": {
|
|
157
|
+
"ANTHROPIC_AUTH_TOKEN": "<你的云翼 API Key>"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
158
160
|
```
|
|
159
161
|
|
|
160
|
-
|
|
162
|
+
文件位置:
|
|
161
163
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
[Environment]::SetEnvironmentVariable('ANTHROPIC_AUTH_TOKEN', '<你的云翼 API Key>', 'User')
|
|
165
|
-
[Environment]::SetEnvironmentVariable('NODE_TLS_REJECT_UNAUTHORIZED', '0', 'User')
|
|
166
|
-
```
|
|
164
|
+
- macOS / Linux:`~/.claude/settings.json`
|
|
165
|
+
- Windows:`%USERPROFILE%\\.claude\\settings.json`
|
|
167
166
|
|
|
168
167
|
完成后:腾讯云 OpenClaw 里可选 Claude 或 GPT;本机 Claude Code CLI 使用同一 Key 走云翼 Claude。
|