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-5 --set-primary true --force --test true
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-5 --set-primary true --force --test true
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-5 --set-primary true --force --test true
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.2 --set-primary true --force --test true
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.2 --set-primary true --force --test true
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.2 --set-primary true --force --test true
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 claudeDir = path.join(home, '.claude');
835
- const settingsPath = path.join(claudeDir, 'settings.json');
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.env.ANTHROPIC_MODEL = modelId;
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(' • ~/.claude.json (跳过 onboarding)'));
4733
- console.log(chalk.gray(' shell 环境变量 (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_MODEL)'));
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 autoActivate(paths, { ...args, primary: 'claude' });
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
- 在终端执行一次,或写入 `~/.zshrc` / `~/.bashrc` 后 `source`,Claude Code 即走云翼 Claude:
151
+ 推荐直接写 `settings.json` 最小配置:
152
152
 
153
- ```bash
154
- export ANTHROPIC_BASE_URL="https://yunyi.rdzhvip.com/claude"
155
- export ANTHROPIC_AUTH_TOKEN="<你的云翼 API Key>"
156
- # 若遇证书报错可加:
157
- export NODE_TLS_REJECT_UNAUTHORIZED=0
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
- Windows(PowerShell,用户级环境变量):
162
+ 文件位置:
161
163
 
162
- ```powershell
163
- [Environment]::SetEnvironmentVariable('ANTHROPIC_BASE_URL', 'https://yunyi.rdzhvip.com/claude', 'User')
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。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.96",
3
+ "version": "1.0.98",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {