base_parts_ai 1.0.52 → 1.0.53

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
@@ -1,6 +1,36 @@
1
1
 
2
- ## 下载发布的包
3
- https://registry.npmjs.org/base_parts_ai/-/base_parts_ai-1.0.45.tgz
2
+ ## npx 运行
3
+
4
+ 已发布到 npm 仓库后,可以直接运行入口命令:
5
+
6
+ ```powershell
7
+ npx base_parts_ai
8
+ ```
9
+
10
+ 无参数时会让用户选择 `jcc`、`jcx` 或 `weds`,再继续执行对应配置流程。
11
+
12
+ 也可以明确指定工具,适合脚本或需要带参数的场景:
13
+
14
+ ```powershell
15
+ npx base_parts_ai jcc
16
+ npx base_parts_ai jcx
17
+ npx base_parts_ai weds
18
+ npx base_parts_ai jcc setapi
19
+ npx base_parts_ai jcx setapi
20
+ npx base_parts_ai weds setapi
21
+ ```
22
+
23
+ 入口级帮助和版本:
24
+
25
+ ```powershell
26
+ npx base_parts_ai --help
27
+ npx base_parts_ai --version
28
+ ```
29
+
30
+ 通过 `base_parts_ai` 入口执行时,会屏蔽 `base_parts_ai` 自身自动升级;`jcc`、`jcx`、`weds` 单独运行行为保持不变。
31
+
32
+ ## 下载发布的包
33
+ https://registry.npmjs.org/base_parts_ai/-/base_parts_ai-1.0.45.tgz
4
34
 
5
35
  ## 然后放在jdwfiles目录下
6
36
  https://jdwfiles.oss-cn-hangzhou.aliyuncs.com/npm_pkg/base_parts_ai-1.0.34.tgz
package/bin/jcc.js CHANGED
@@ -1,155 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- var fs = require('fs');
4
- var os = require('os');
5
- var path = require('path');
6
- // commander v14+ 改为具名导出,需用 Command 类实例化
7
- var { Command } = require('commander');
8
- var program = new Command();
3
+ 'use strict';
9
4
 
5
+ var claudeCli = require('../lib/claude_cli_common');
10
6
 
11
7
  /**
12
- * 获取配置文件
13
- * @param {string} cmd 命令行
14
- * @returns {*} 配置段
15
- */
16
- function getBuildCfg(cmd) {
17
- // 配置路径
18
- if (!cmd.config) {
19
- cmd.config = process.cwd() + "/jai_cfg.json";
20
- }
21
- cmd.config = path.resolve(cmd.config);
22
-
23
- // 读入配置
24
- // console.log("Read jai_cfg.json ...");
25
- var buildCfg = {}
26
- try {
27
- // console.log("[Config path] " + cmd.config);
28
- buildCfg = JSON.parse(jutils.jsonTrim(fs.readFileSync(cmd.config, "utf8")));
29
- } catch (error) {
30
- // console.log("[Notice] not found jai_cfg.json");
31
- }
32
-
33
- // 详情输出
34
- buildCfg.details = cmd.details;
35
-
36
- // 缺省路径
37
- if (!buildCfg.rootPath) {
38
- buildCfg.rootPath = process.cwd();
39
- }
40
- buildCfg.rootPath = path.resolve(buildCfg.rootPath);
41
- // console.log("[Root path] " + buildCfg.rootPath);
42
-
43
- // 从 npm 全局目录下的 @anthropic-ai/claude-code/package.json 提取 Claude 版本号
44
- try {
45
- // 通过子进程执行 npm root -g 获取全局包根目录,兼容不同系统安装位置
46
- var npmRootG = require('child_process').execSync('npm root -g', { encoding: 'utf8' }).trim();
47
- var claudePkgPath = path.join(npmRootG, '@anthropic-ai', 'claude-code', 'package.json');
48
- var claudePkg = JSON.parse(fs.readFileSync(claudePkgPath, 'utf8'));
49
- buildCfg.claudeVersion = claudePkg.version || '';
50
- } catch (e) {
51
- buildCfg.claudeVersion = '';
52
- }
53
- console.log("[Claude version] " + (buildCfg.claudeVersion || '(未找到)'));
54
-
55
- // Claude 配置文件路径(跨平台支持)
56
- // 支持环境变量 JCC_TEST_HOME 覆盖 homedir,方便测试时隔离环境
57
- var homeDir = process.env.JCC_TEST_HOME || os.homedir();
58
- // ~/.claude.json 全局配置
59
- buildCfg.claudeJsonPath = path.join(homeDir, '.claude.json');
60
- // ~/.claude/settings.json Claude Code 设置文件
61
- buildCfg.claudeSettingsPath = path.join(homeDir, '.claude', 'settings.json');
62
- // ~/.claude/jcc.json 自定义渠道Key存储文件
63
- buildCfg.jccJsonPath = path.join(homeDir, '.claude', 'jcc.json');
64
-
65
- // 确保 ~/.claude 目录存在,防止未安装 Claude 时崩溃
66
- var claudeDir = path.join(homeDir, '.claude');
67
- if (!fs.existsSync(claudeDir)) {
68
- fs.mkdirSync(claudeDir, { recursive: true });
69
- console.log('[Init] 已创建目录: ' + claudeDir);
70
- }
71
- // 确保 settings.json 存在(空对象兜底)
72
- if (!fs.existsSync(buildCfg.claudeSettingsPath)) {
73
- fs.writeFileSync(buildCfg.claudeSettingsPath, '{}', 'utf8');
74
- console.log('[Init] 已创建文件: ' + buildCfg.claudeSettingsPath);
75
- }
76
-
77
- return buildCfg;
78
- }
79
-
80
- /**
81
- * 动态加载 lib 下的命令模块(热更新)
82
- * @param {string} libName lib目录下的文件名(不含.js)
83
- * @returns {Function} 导出的模块函数
84
- */
85
- function loadLib(libName) {
86
- var libPath = path.resolve(__dirname, '../lib/' + libName + '.js');
87
- // 清除 require 缓存,实现热更新
88
- delete require.cache[require.resolve(libPath)];
89
- return require(libPath);
90
- }
91
-
92
- /**
93
- * 检查系统环境变量中是否存在会干扰 Claude 配置的变量
94
- * 若存在 ANTHROPIC_AUTH_TOKEN 或 ANTHROPIC_BASE_URL,则红色警告并等待用户确认
8
+ * 运行 jcc CLI,可供命令行直接执行或被 base_parts_ai require 调用
9
+ * @param {Array<string>} args 用户参数,不包含 node 和脚本路径
95
10
  * @returns {Promise<void>}
96
11
  */
97
- async function checkEnvConflict() {
98
- // 检查可能覆盖工具配置的系统环境变量
99
- var conflictVars = ['ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL'].filter(function (name) {
100
- return !!process.env[name];
101
- });
102
- if (!conflictVars.length) return;
103
-
104
- // 红色警告输出
105
- console.log('\x1b[31m');
106
- console.log('⚠️ 警告:检测到以下系统环境变量,可能导致工具配置无效!');
107
- conflictVars.forEach(function (name) {
108
- console.log(' ' + name + ' = ' + process.env[name]);
109
- });
110
- console.log('\x1b[0m');
111
-
112
- // 等待用户按回车确认后继续
113
- await new Promise(function (resolve) {
114
- var rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
115
- rl.question('按回车键继续...', function () {
116
- rl.close();
117
- resolve();
118
- });
12
+ async function runCli(args) {
13
+ await claudeCli.runClaudeCli(args, {
14
+ cliName: 'jcc',
15
+ cacheFileName: 'jcc.json',
16
+ noticeType: 'default',
17
+ getChannels: function (utils) {
18
+ return utils.API_CHANNELS;
19
+ },
119
20
  });
120
21
  }
121
22
 
122
- /**
123
- * 公共命令执行流程:拉取配置 → 显示公告 → 执行业务模块 → 完成提示
124
- * @param {string} libName lib 目录下的业务模块名(不含 .js)
125
- * @param {object} opts commander 解析出的选项
126
- */
127
- async function runCommand(libName, opts) {
128
- // 检查系统环境变量冲突,有冲突则红色警告并等待确认
129
- await checkEnvConflict();
130
- var buildCfg = getBuildCfg(opts);
131
- // 从服务端拉取渠道配置(含 jcc 自动升级检查)
132
- var utils = loadLib('ai_utils');
133
- await utils.fetchConfig(buildCfg);
134
- // 显示公告,有公告时等待用户按回车继续
135
- await utils.showNotice();
136
- // 执行业务模块
137
- await loadLib(libName)(opts, buildCfg);
138
- console.log('\n✅ 完成!重启 Claude 后生效。');
139
- }
140
-
141
- // 命令:setapi —— 选择 AI 渠道,修改 Claude settings.json 中的 ANTHROPIC_BASE_URL
142
- program
143
- .command('setapi')
144
- .action(async function () {
145
- await runCommand('setapi_cc', this.opts());
23
+ if (require.main === module) {
24
+ runCli(process.argv.slice(2)).catch(function (err) {
25
+ console.error('jcc 执行失败:', err.message);
26
+ process.exit(1);
146
27
  });
147
-
148
- // 若未传入任何子命令,默认执行 setapi
149
- if (process.argv.length <= 2) {
150
- process.argv.push('setapi');
151
28
  }
152
29
 
153
- // 开始解析
154
- program.parse(process.argv);
155
-
30
+ module.exports = runCli;
package/bin/jcx.js CHANGED
@@ -7,7 +7,6 @@ var os = require('os');
7
7
  var path = require('path');
8
8
  var { execSync } = require('child_process');
9
9
  var { Command } = require('commander');
10
- var program = new Command();
11
10
 
12
11
  /**
13
12
  * 构建 Codex 配置路径,并确保 ~/.codex 目录存在
@@ -70,20 +69,40 @@ async function runCommand(libName, opts) {
70
69
  console.log('\n✅ 完成!重启 Codex 后生效。');
71
70
  }
72
71
 
73
- program
74
- .command('setapi')
75
- .description('选择 Codex AI 渠道并写入 ~/.codex 配置')
76
- .action(async function () {
77
- await runCommand('setapi_cx', this.opts());
78
- });
72
+ /**
73
+ * 运行 jcx CLI,可供命令行直接执行或被 base_parts_ai require 调用
74
+ * @param {Array<string>} args 用户参数,不包含 node 和脚本路径
75
+ * @returns {Promise<void>}
76
+ */
77
+ async function runCli(args) {
78
+ var cliArgs = (args || []).slice();
79
+ var program = new Command();
79
80
 
80
- program
81
- .name('jcx')
82
- .description('Codex 配置工具');
81
+ program
82
+ .name('jcx')
83
+ .description('Codex 配置工具');
83
84
 
84
- // 若未传入任何子命令,默认执行 setapi
85
- if (process.argv.length <= 2) {
86
- process.argv.push('setapi');
85
+ program
86
+ .command('setapi')
87
+ .description('选择 Codex AI 渠道并写入 ~/.codex 配置')
88
+ .action(async function () {
89
+ await runCommand('setapi_cx', this.opts());
90
+ });
91
+
92
+ // 若未传入任何子命令,默认执行 setapi
93
+ if (cliArgs.length <= 0) {
94
+ cliArgs.push('setapi');
95
+ }
96
+
97
+ // 使用 from:user 避免读取或修改全局 process.argv,便于被主入口 require 调用
98
+ await program.parseAsync(cliArgs, { from: 'user' });
99
+ }
100
+
101
+ if (require.main === module) {
102
+ runCli(process.argv.slice(2)).catch(function (err) {
103
+ console.error('jcx 执行失败:', err.message);
104
+ process.exit(1);
105
+ });
87
106
  }
88
107
 
89
- program.parse(process.argv);
108
+ module.exports = runCli;
@@ -15,5 +15,6 @@ console.log('');
15
15
  console.log(c.cyan + ' ╔══════════════════════════════════════════╗' + c.reset);
16
16
  console.log(c.cyan + ' ║ ' + c.yellow + '安装完成!输入以下命令开始配置:' + c.reset);
17
17
  console.log(c.cyan + ' ║ ' + c.green + 'jcc' + c.white + ' 配置或安装 ClaudeCode' + c.reset);
18
+ console.log(c.cyan + ' ║ ' + c.green + 'weds' + c.white + ' 配置或安装 weds ClaudeCode' + c.reset);
18
19
  console.log(c.cyan + ' ╚══════════════════════════════════════════╝' + c.reset);
19
20
  console.log('');
package/bin/weds.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ var claudeCli = require('../lib/claude_cli_common');
6
+
7
+ /**
8
+ * 运行 weds CLI,可供命令行直接执行或被 base_parts_ai require 调用
9
+ * @param {Array<string>} args 用户参数,不包含 node 和脚本路径
10
+ * @returns {Promise<void>}
11
+ */
12
+ async function runCli(args) {
13
+ await claudeCli.runClaudeCli(args, {
14
+ cliName: 'weds',
15
+ cacheFileName: 'weds.json',
16
+ noticeType: 'weds',
17
+ getChannels: function (utils) {
18
+ return utils.WEDS_CHANNELS;
19
+ },
20
+ });
21
+ }
22
+
23
+ if (require.main === module) {
24
+ runCli(process.argv.slice(2)).catch(function (err) {
25
+ console.error('weds 执行失败:', err.message);
26
+ process.exit(1);
27
+ });
28
+ }
29
+
30
+ module.exports = runCli;
package/lib/ai_utils.js CHANGED
@@ -17,9 +17,15 @@ var API_CHANNELS = [];
17
17
  // Codex 渠道列表(运行时由 fetchConfig 从服务端 cxChannels 填充)
18
18
  var CX_CHANNELS = [];
19
19
 
20
+ // weds 渠道列表(运行时由 fetchConfig 从服务端 wedsChannels 填充)
21
+ var WEDS_CHANNELS = [];
22
+
20
23
  // 公告列表(运行时由 fetchConfig 从服务端拉取填充)
21
24
  var noticeList = [];
22
25
 
26
+ // weds 公告列表(运行时由 fetchConfig 从服务端 noticeWedsList 填充)
27
+ var noticeWedsList = [];
28
+
23
29
  // jcc.json 中保存最后一次手动输入 Token 的内部字段名
24
30
  var LAST_MANUAL_AUTH_TOKEN_KEY = '__lastManualAuthToken';
25
31
 
@@ -45,12 +51,13 @@ async function fetchRemoteText(url, timeoutMs) {
45
51
 
46
52
  /**
47
53
  * 从当前入口文件名推断正在运行的 CLI 命令名
48
- * @returns {string} jcc、jcx 或空字符串
54
+ * @returns {string} jcc、jcx、weds 或空字符串
49
55
  */
50
56
  function getCurrentCliName() {
51
57
  var entryName = path.basename(process.argv[1] || '').toLowerCase();
52
58
  if (entryName === 'jcx' || entryName === 'jcx.js') return 'jcx';
53
59
  if (entryName === 'jcc' || entryName === 'jcc.js') return 'jcc';
60
+ if (entryName === 'weds' || entryName === 'weds.js') return 'weds';
54
61
  return '';
55
62
  }
56
63
 
@@ -120,6 +127,14 @@ async function fetchConfig(buildCfg) {
120
127
  });
121
128
  console.log('[fetchConfig] 已拉取 ' + CX_CHANNELS.length + ' 个 Codex 渠道');
122
129
  }
130
+ // 将服务端返回的 weds 渠道列表填充到 WEDS_CHANNELS
131
+ if (Array.isArray(result.data.wedsChannels)) {
132
+ WEDS_CHANNELS.length = 0;
133
+ result.data.wedsChannels.forEach(function (ch) {
134
+ WEDS_CHANNELS.push(ch);
135
+ });
136
+ console.log('[fetchConfig] 已拉取 ' + WEDS_CHANNELS.length + ' 个 weds 渠道');
137
+ }
123
138
  // 解析公告列表
124
139
  if (Array.isArray(result.data.noticeList)) {
125
140
  noticeList.length = 0;
@@ -127,6 +142,13 @@ async function fetchConfig(buildCfg) {
127
142
  noticeList.push(item);
128
143
  });
129
144
  }
145
+ // 解析 weds 公告列表
146
+ if (Array.isArray(result.data.noticeWedsList)) {
147
+ noticeWedsList.length = 0;
148
+ result.data.noticeWedsList.forEach(function (item) {
149
+ noticeWedsList.push(item);
150
+ });
151
+ }
130
152
  // 检查 jcc 自身版本,若需要升级则询问用户确认后安装
131
153
  var currentVer = '';
132
154
  try { currentVer = require('../package.json').version; } catch (e) { }
@@ -338,14 +360,16 @@ function getManualAuthTokenDefault(jccJson, channelId, settings) {
338
360
  /**
339
361
  * 根据 settings 中的 __jid 字段匹配当前渠道
340
362
  * @param {object} settings Claude settings.json 对象
363
+ * @param {Array<object>} channels 渠道列表,默认使用 API_CHANNELS
341
364
  * @returns {{ channel: object|null, key: string, jid: string }}
342
365
  */
343
- function getCurrentInfo(settings) {
366
+ function getCurrentInfo(settings, channels) {
367
+ var channelList = channels || API_CHANNELS;
344
368
  // 当前渠道 id,存储在 settings 顶层 __jid 字段
345
369
  var currentJid = settings.__jid || '';
346
370
  var currentKey = (settings.env && settings.env.ANTHROPIC_AUTH_TOKEN) || '';
347
371
  // 按 id 匹配渠道
348
- var channel = currentJid ? (API_CHANNELS.find(function (c) { return c.id === currentJid; }) || null) : null;
372
+ var channel = currentJid ? (channelList.find(function (c) { return c.id === currentJid; }) || null) : null;
349
373
  return { channel: channel, key: currentKey, jid: currentJid };
350
374
  }
351
375
 
@@ -362,10 +386,11 @@ function maskKey(key) {
362
386
 
363
387
  /**
364
388
  * 打印当前渠道和Key状态
365
- * @param {object} settings
389
+ * @param {object} settings Claude settings.json 对象
390
+ * @param {Array<object>} channels 渠道列表,默认使用 API_CHANNELS
366
391
  */
367
- function printCurrentInfo(settings) {
368
- var info = getCurrentInfo(settings);
392
+ function printCurrentInfo(settings, channels) {
393
+ var info = getCurrentInfo(settings, channels);
369
394
  // console.log('\n====== 当前 Claude 配置 ======');
370
395
  let curSelectedChannel = '(' + (info.jid || '未设置') + ')';
371
396
  if (info.channel) {
@@ -377,12 +402,14 @@ function printCurrentInfo(settings) {
377
402
 
378
403
  /**
379
404
  * 显示公告信息(黄色字体逐行输出),有公告时等待用户按回车继续
405
+ * @param {string} type 公告类型,weds 使用 noticeWedsList,其它使用默认 noticeList
380
406
  * @returns {Promise<void>}
381
407
  */
382
- function showNotice() {
383
- if (!noticeList.length) return Promise.resolve();
408
+ function showNotice(type) {
409
+ var list = type === 'weds' ? noticeWedsList : noticeList;
410
+ if (!list.length) return Promise.resolve();
384
411
  console.log('\n\x1b[33m=========================== 公告 ===========================');
385
- noticeList.forEach(function (line) {
412
+ list.forEach(function (line) {
386
413
  console.log(line);
387
414
  });
388
415
  console.log('============================================================\x1b[0m');
@@ -399,6 +426,7 @@ function showNotice() {
399
426
  module.exports = {
400
427
  API_CHANNELS,
401
428
  CX_CHANNELS,
429
+ WEDS_CHANNELS,
402
430
  fetchConfig,
403
431
  fetchText,
404
432
  readJsonFile,
@@ -415,4 +443,6 @@ module.exports = {
415
443
  maskKey,
416
444
  printCurrentInfo,
417
445
  showNotice,
446
+ noticeList,
447
+ noticeWedsList,
418
448
  };
@@ -0,0 +1,183 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Claude 类 CLI 公共入口逻辑
5
+ * 供 jcc、weds 等配置 Claude Code 的命令复用
6
+ */
7
+
8
+ var fs = require('fs');
9
+ var os = require('os');
10
+ var path = require('path');
11
+ var { Command } = require('commander');
12
+
13
+ /**
14
+ * 获取 Claude 配置文件路径,并确保基础目录和 settings.json 存在
15
+ * @param {object} cmd commander 解析出的选项
16
+ * @param {object} options CLI 入口配置
17
+ * @returns {object} 构建后的配置对象
18
+ */
19
+ function getBuildCfg(cmd, options) {
20
+ var buildCfg = {};
21
+ var cacheFileName = options.cacheFileName || 'jcc.json';
22
+
23
+ // 配置路径
24
+ if (!cmd.config) {
25
+ cmd.config = process.cwd() + "/jai_cfg.json";
26
+ }
27
+ cmd.config = path.resolve(cmd.config);
28
+
29
+ // 读入 jai_cfg.json,兼容旧入口保留 details/rootPath 等字段
30
+ try {
31
+ buildCfg = JSON.parse(fs.readFileSync(cmd.config, "utf8"));
32
+ } catch (error) {
33
+ buildCfg = {};
34
+ }
35
+
36
+ // 详情输出
37
+ buildCfg.details = cmd.details;
38
+
39
+ // 缺省路径
40
+ if (!buildCfg.rootPath) {
41
+ buildCfg.rootPath = process.cwd();
42
+ }
43
+ buildCfg.rootPath = path.resolve(buildCfg.rootPath);
44
+
45
+ // 从 npm 全局目录下的 @anthropic-ai/claude-code/package.json 提取 Claude 版本号
46
+ try {
47
+ // 通过子进程执行 npm root -g 获取全局包根目录,兼容不同系统安装位置
48
+ var npmRootG = require('child_process').execSync('npm root -g', { encoding: 'utf8' }).trim();
49
+ var claudePkgPath = path.join(npmRootG, '@anthropic-ai', 'claude-code', 'package.json');
50
+ var claudePkg = JSON.parse(fs.readFileSync(claudePkgPath, 'utf8'));
51
+ buildCfg.claudeVersion = claudePkg.version || '';
52
+ } catch (e) {
53
+ buildCfg.claudeVersion = '';
54
+ }
55
+ console.log("[Claude version] " + (buildCfg.claudeVersion || '(未找到)'));
56
+
57
+ // Claude 配置文件路径(跨平台支持)
58
+ // 支持环境变量 JCC_TEST_HOME 覆盖 homedir,方便测试时隔离环境
59
+ var homeDir = process.env.JCC_TEST_HOME || os.homedir();
60
+ // ~/.claude.json 全局配置
61
+ buildCfg.claudeJsonPath = path.join(homeDir, '.claude.json');
62
+ // ~/.claude/settings.json Claude Code 设置文件
63
+ buildCfg.claudeSettingsPath = path.join(homeDir, '.claude', 'settings.json');
64
+ // Claude 渠道 Key 缓存文件,jcc 和 weds 可使用不同文件隔离缓存
65
+ buildCfg.jccJsonPath = path.join(homeDir, '.claude', 'jcc.json');
66
+ buildCfg.channelCachePath = path.join(homeDir, '.claude', cacheFileName);
67
+
68
+ // 确保 ~/.claude 目录存在,防止未安装 Claude 时崩溃
69
+ var claudeDir = path.join(homeDir, '.claude');
70
+ if (!fs.existsSync(claudeDir)) {
71
+ fs.mkdirSync(claudeDir, { recursive: true });
72
+ console.log('[Init] 已创建目录: ' + claudeDir);
73
+ }
74
+ // 确保 settings.json 存在(空对象兜底)
75
+ if (!fs.existsSync(buildCfg.claudeSettingsPath)) {
76
+ fs.writeFileSync(buildCfg.claudeSettingsPath, '{}', 'utf8');
77
+ console.log('[Init] 已创建文件: ' + buildCfg.claudeSettingsPath);
78
+ }
79
+
80
+ return buildCfg;
81
+ }
82
+
83
+ /**
84
+ * 动态加载 lib 下的命令模块(热更新)
85
+ * @param {string} libName lib目录下的文件名(不含.js)
86
+ * @returns {Function} 导出的模块函数
87
+ */
88
+ function loadLib(libName) {
89
+ var libPath = path.resolve(__dirname, libName + '.js');
90
+ // 清除 require 缓存,实现热更新
91
+ delete require.cache[require.resolve(libPath)];
92
+ return require(libPath);
93
+ }
94
+
95
+ /**
96
+ * 检查系统环境变量中是否存在会干扰 Claude 配置的变量
97
+ * 若存在 ANTHROPIC_AUTH_TOKEN 或 ANTHROPIC_BASE_URL,则红色警告并等待用户确认
98
+ * @returns {Promise<void>}
99
+ */
100
+ async function checkEnvConflict() {
101
+ // 检查可能覆盖工具配置的系统环境变量
102
+ var conflictVars = ['ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL'].filter(function (name) {
103
+ return !!process.env[name];
104
+ });
105
+ if (!conflictVars.length) return;
106
+
107
+ // 红色警告输出
108
+ console.log('\x1b[31m');
109
+ console.log('⚠️ 警告:检测到以下系统环境变量,可能导致工具配置无效!');
110
+ conflictVars.forEach(function (name) {
111
+ console.log(' ' + name + ' = ' + process.env[name]);
112
+ });
113
+ console.log('\x1b[0m');
114
+
115
+ // 等待用户按回车确认后继续
116
+ await new Promise(function (resolve) {
117
+ var rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
118
+ rl.question('按回车键继续...', function () {
119
+ rl.close();
120
+ resolve();
121
+ });
122
+ });
123
+ }
124
+
125
+ /**
126
+ * 公共命令执行流程:拉取配置 → 显示公告 → 执行业务模块 → 完成提示
127
+ * @param {string} libName lib 目录下的业务模块名(不含 .js)
128
+ * @param {object} opts commander 解析出的选项
129
+ * @param {object} options CLI 入口配置
130
+ * @returns {Promise<void>}
131
+ */
132
+ async function runCommand(libName, opts, options) {
133
+ // 检查系统环境变量冲突,有冲突则红色警告并等待确认
134
+ await checkEnvConflict();
135
+ var buildCfg = getBuildCfg(opts, options);
136
+ // 从服务端拉取渠道配置(含自动升级检查)
137
+ var utils = loadLib('ai_utils');
138
+ await utils.fetchConfig(buildCfg);
139
+ // 注入当前 CLI 使用的渠道数组,业务模块无需关心来源字段
140
+ buildCfg.channels = options.getChannels(utils);
141
+ // 显示当前 CLI 对应公告,有公告时输出
142
+ await utils.showNotice(options.noticeType);
143
+ // 执行业务模块
144
+ await loadLib(libName)(opts, buildCfg);
145
+ console.log('\n✅ 完成!重启 Claude 后生效。');
146
+ }
147
+
148
+ /**
149
+ * 运行 Claude 类 CLI,可供命令行直接执行或被 base_parts_ai require 调用
150
+ * @param {Array<string>} args 用户参数,不包含 node 和脚本路径
151
+ * @param {object} options CLI 入口配置
152
+ * @returns {Promise<void>}
153
+ */
154
+ async function runClaudeCli(args, options) {
155
+ var cliArgs = (args || []).slice();
156
+ var program = new Command();
157
+
158
+ program
159
+ .name(options.cliName);
160
+
161
+ // 命令:setapi —— 选择 AI 渠道,修改 Claude settings.json 中的 ANTHROPIC_BASE_URL
162
+ program
163
+ .command('setapi')
164
+ .action(async function () {
165
+ await runCommand('setapi_cc', this.opts(), options);
166
+ });
167
+
168
+ // 若未传入任何子命令,默认执行 setapi
169
+ if (cliArgs.length <= 0) {
170
+ cliArgs.push('setapi');
171
+ }
172
+
173
+ // 使用 from:user 避免读取或修改全局 process.argv,便于被主入口 require 调用
174
+ await program.parseAsync(cliArgs, { from: 'user' });
175
+ }
176
+
177
+ module.exports = {
178
+ getBuildCfg,
179
+ loadLib,
180
+ checkEnvConflict,
181
+ runCommand,
182
+ runClaudeCli,
183
+ };
package/lib/setapi_cc.js CHANGED
@@ -41,14 +41,21 @@ function ensureClaudeVersion(requiredVer, currentVer) {
41
41
  }
42
42
 
43
43
  async function setapiCc(cmd, buildCfg) {
44
+ // 渠道列表和缓存路径可由 jcc/weds 入口注入,实现同一套 Claude 配置逻辑复用
45
+ var channels = buildCfg.channels || utils.API_CHANNELS;
46
+ var cachePath = buildCfg.channelCachePath || buildCfg.jccJsonPath;
44
47
  var settings = utils.loadSettings(buildCfg.claudeSettingsPath);
45
- var jccJson = utils.readJsonFile(buildCfg.jccJsonPath, {});
48
+ var jccJson = utils.readJsonFile(cachePath, {});
46
49
 
47
50
  // 显示当前配置状态
48
- utils.printCurrentInfo(settings);
51
+ utils.printCurrentInfo(settings, channels);
52
+
53
+ if (!channels.length) {
54
+ throw new Error('Claude 渠道列表为空,请检查网络或服务端配置');
55
+ }
49
56
 
50
57
  // 构建渠道选择列表
51
- var choices = utils.API_CHANNELS.map(function (c) {
58
+ var choices = channels.map(function (c) {
52
59
  return {
53
60
  name: c.name + ' — ' + c.description,
54
61
  value: c.id,
@@ -66,7 +73,7 @@ async function setapiCc(cmd, buildCfg) {
66
73
  var channelId = answers.channelId;
67
74
 
68
75
  // 找到选中的渠道配置
69
- var selected = utils.API_CHANNELS.find(function (c) { return c.id === channelId; });
76
+ var selected = channels.find(function (c) { return c.id === channelId; });
70
77
 
71
78
  // 将选中渠道 id 写入 settings.__jid,作为当前渠道标识
72
79
  settings.__jid = selected.id;
@@ -152,7 +159,7 @@ async function setapiCc(cmd, buildCfg) {
152
159
  delete jccJson.keys[selected.id];
153
160
  }
154
161
  }
155
- utils.writeJsonFile(buildCfg.jccJsonPath, jccJson);
162
+ utils.writeJsonFile(cachePath, jccJson);
156
163
 
157
164
  console.log('✅ 已切换到渠道: ' + selected.name);
158
165
  console.log(' BASE_URL: ' + (settings.env.ANTHROPIC_BASE_URL || '(已删除)'));
@@ -182,7 +189,7 @@ async function setapiCc(cmd, buildCfg) {
182
189
  if (!jccJson.keys) { jccJson.keys = {}; }
183
190
  jccJson.keys[selected.id] = newKey;
184
191
  utils.saveLastManualAuthToken(jccJson, newKey);
185
- utils.writeJsonFile(buildCfg.jccJsonPath, jccJson);
192
+ utils.writeJsonFile(cachePath, jccJson);
186
193
 
187
194
  console.log('✅ 已切换到渠道: ' + selected.name + ',Key 已保存到本地缓存。');
188
195
  console.log(' Key: ' + utils.maskKey(newKey));