base_parts_ai 1.0.34 → 1.0.35

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/CLAUDE.md CHANGED
@@ -26,7 +26,7 @@ test_jcc.js # 功能测试脚本(npm test)
26
26
  - 同时写入固定字段到 `settings.json`:`hooks`(SessionStart curl 上报)、`language`(简体中文)、`autoUpdatesChannel`(stable)
27
27
  - 同时写入固定字段到 `~/.claude.json`:`autoUpdaterStatus: 'disabled'`、`hasCompletedOnboarding: true`
28
28
  - 若该渠道有缓存 Key(来自 `~/.claude/jcc.json`),自动切换;若无,提示用户输入并保存
29
- - 切换后检测 Claude 版本:若当前版本与渠道 `ccVersion` 不符,自动从 OSS 下载对应 tgz 并通过 `npm install -g` 安装
29
+ - 切换后检测 Claude 版本:根据 `ccVersionList` 确定目标版本(只有一个选项时直接使用,多个选项时询问用户选择上下文大小),版本不符时自动从 OSS 下载对应 tgz 并通过 `npm install -g` 安装
30
30
 
31
31
  ### `jcc setkey`
32
32
  设置当前渠道的 API Key,写入 `settings.json` 并缓存到 `jcc.json`。
@@ -53,7 +53,7 @@ test_jcc.js # 功能测试脚本(npm test)
53
53
  | `id` | string | 唯一标识,写入 `settings.__jid` |
54
54
  | `name` | string | 显示名称 |
55
55
  | `description` | string | 简短描述 |
56
- | `ccVersion` | string | 该渠道要求的 Claude Code 版本号 |
56
+ | `ccVersionList` | object | 上下文描述 Claude Code 版本号的映射,如 `{"200K上下文":"2.1.22","1M上下文":"2.1.76"}` |
57
57
  | `envObj` | object | 完整 env 配置对象,合并到 `settings.env` |
58
58
 
59
59
  `envObj` 由服务端直接返回已合并好的完整对象,客户端不再维护 `jpub_EnvObj`、`jai_EnvObj` 等模板。
@@ -79,7 +79,7 @@ npm test
79
79
  4. `getCurrentInfo` 渠道识别
80
80
  5. `setkey` 更新 Key 并同步 jcc.json
81
81
  6. 切换渠道时 envObj 覆盖逻辑(`ANTHROPIC_DEFAULT_OPUS_MODEL` 空值被清除)
82
- 7. `API_CHANNELS` 列表结构验证(含 ccVersion / envObj)
82
+ 7. `API_CHANNELS` 列表结构验证(含 ccVersionList / envObj)
83
83
  8. `maskKey` 脱敏显示
84
84
  9. `jai_low_cost` 渠道 GLM 模型字段验证
85
85
  10. `printCurrentInfo` smoke test(不抛异常)
package/README.md ADDED
@@ -0,0 +1,6 @@
1
+
2
+ ## 下载发布的包
3
+ https://registry.npmjs.org/base_parts_ai/-/base_parts_ai-1.0.34.tgz
4
+
5
+ ## 然后放在jdwfiles目录下
6
+ https://jdwfiles.oss-cn-hangzhou.aliyuncs.com/npm_pkg/base_parts_ai-1.0.34.tgz
package/bin/jcc.js CHANGED
@@ -96,12 +96,44 @@ function loadLib(libName) {
96
96
  return require(libPath);
97
97
  }
98
98
 
99
+ /**
100
+ * 检查系统环境变量中是否存在会干扰 Claude 配置的变量
101
+ * 若存在 ANTHROPIC_AUTH_TOKEN 或 ANTHROPIC_BASE_URL,则红色警告并等待用户确认
102
+ * @returns {Promise<void>}
103
+ */
104
+ async function checkEnvConflict() {
105
+ // 检查可能覆盖工具配置的系统环境变量
106
+ var conflictVars = ['ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL'].filter(function (name) {
107
+ return !!process.env[name];
108
+ });
109
+ if (!conflictVars.length) return;
110
+
111
+ // 红色警告输出
112
+ console.log('\x1b[31m');
113
+ console.log('⚠️ 警告:检测到以下系统环境变量,可能导致工具配置无效!');
114
+ conflictVars.forEach(function (name) {
115
+ console.log(' ' + name + ' = ' + process.env[name]);
116
+ });
117
+ console.log('\x1b[0m');
118
+
119
+ // 等待用户按回车确认后继续
120
+ await new Promise(function (resolve) {
121
+ var rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
122
+ rl.question('按回车键继续...', function () {
123
+ rl.close();
124
+ resolve();
125
+ });
126
+ });
127
+ }
128
+
99
129
  /**
100
130
  * 公共命令执行流程:拉取配置 → 显示公告 → 执行业务模块 → 完成提示
101
131
  * @param {string} libName lib 目录下的业务模块名(不含 .js)
102
132
  * @param {object} opts commander 解析出的选项
103
133
  */
104
134
  async function runCommand(libName, opts) {
135
+ // 检查系统环境变量冲突,有冲突则红色警告并等待确认
136
+ await checkEnvConflict();
105
137
  var buildCfg = getBuildCfg(opts);
106
138
  // 从服务端拉取渠道配置(含 jcc 自动升级检查)
107
139
  var utils = loadLib('claude_utils');
@@ -8,7 +8,6 @@
8
8
  var fs = require('fs');
9
9
  var path = require('path');
10
10
  var http = require('http');
11
- var readline = require('readline');
12
11
  var { execSync } = require('child_process');
13
12
 
14
13
  // ============================================================
@@ -30,7 +29,7 @@ function fetchConfig(buildCfg) {
30
29
  http.get(url, { timeout: 8000 }, function (res) {
31
30
  var chunks = '';
32
31
  res.on('data', function (chunk) { chunks += chunk; });
33
- res.on('end', function () {
32
+ res.on('end', async function () {
34
33
  try {
35
34
  var result = JSON.parse(chunks);
36
35
  if (result.code === 0 && result.data) {
@@ -49,24 +48,34 @@ function fetchConfig(buildCfg) {
49
48
  noticeList.push(item);
50
49
  });
51
50
  }
52
- // 检查 jcc 自身版本,若需要升级则自动安装新版后退出
51
+ // 检查 jcc 自身版本,若需要升级则询问用户确认后安装
53
52
  var currentVer = '';
54
53
  try { currentVer = require('../package.json').version; } catch (e) { }
55
54
  var newVer = result.data.newVer || '';
56
55
  if (newVer && newVer !== currentVer) {
57
- console.log('[fetchConfig] 检测到新版本 jcc: ' + newVer + '(当前 ' + currentVer + '),正在升级...');
58
- try {
59
- var tgzUrl = 'https://jdwfiles.oss-cn-hangzhou.aliyuncs.com/npm_pkg/base_parts_ai-' + newVer + '.tgz';
60
- execSync('npm install -g ' + tgzUrl + ' --force', { stdio: 'inherit' });
61
-
62
- // require('child_process').execSync(
63
- // 'npm i -g base_parts_ai@' + newVer + ' --force',
64
- // { stdio: 'inherit' }
65
- // );
66
- console.log('[fetchConfig] 升级完成,请重新运行 jcc');
67
- process.exit(0);
68
- } catch (e) {
69
- console.warn('[fetchConfig] 自动升级失败:', e.message);
56
+ console.log('[fetchConfig] 检测到新版本 jcc: ' + newVer + '(当前 ' + currentVer + '');
57
+ // 用 select 上下选,默认高亮"立即升级"
58
+ var { select } = require('@inquirer/prompts');
59
+ var confirmed = await select({
60
+ message: '是否立即升级?',
61
+ default: 'yes',
62
+ choices: [
63
+ { name: '立即升级', value: 'yes' },
64
+ { name: '跳过', value: 'no' },
65
+ ],
66
+ });
67
+ if (confirmed === 'yes') {
68
+ console.log('[fetchConfig] 正在升级...');
69
+ try {
70
+ var tgzUrl = 'https://jdwfiles.oss-cn-hangzhou.aliyuncs.com/npm_pkg/base_parts_ai-' + newVer + '.tgz';
71
+ execSync('npm install -g ' + tgzUrl + ' --force', { stdio: 'inherit' });
72
+ console.log('[fetchConfig] 升级完成,请重新运行 jcc');
73
+ process.exit(0);
74
+ } catch (e) {
75
+ console.warn('[fetchConfig] 自动升级失败:', e.message);
76
+ }
77
+ } else {
78
+ console.log('[fetchConfig] 已跳过升级,继续使用当前版本');
70
79
  }
71
80
  }
72
81
  } else {
package/lib/setapi.js CHANGED
@@ -73,39 +73,90 @@ module.exports = async function (cmd, buildCfg) {
73
73
  }
74
74
  });
75
75
 
76
- // 查询该渠道是否有缓存的 Key
77
- var savedKey = (jccJson.keys && jccJson.keys[selected.id]) || '';
78
- if (savedKey) {
79
- // 已有缓存 Key,直接切换
80
- settings.env.ANTHROPIC_AUTH_TOKEN = savedKey;
81
- utils.writeJsonFile(buildCfg.claudeSettingsPath, settings);
82
- console.log(' 已切换到渠道: ' + selected.name);
83
- console.log(' Key: ' + utils.maskKey(savedKey) + ' (来自本地缓存)');
84
- } else {
85
- // 无缓存 Key,提示用户输入
86
- console.log('⚠️ 渠道 [' + selected.name + '] 尚未设置 Key,请输入:');
87
- var newKey = await input({
76
+ // useSettingsFile=true 时,ANTHROPIC_BASE_URL 和 ANTHROPIC_AUTH_TOKEN 需手动输入
77
+ // settings.json 里的 env 值作为默认值,方便用户确认或修改
78
+ if (selected.useSettingsFile) {
79
+ // 手动输入 ANTHROPIC_BASE_URL,默认值取自当前 settings.env
80
+ var defaultBaseUrl = settings.env.ANTHROPIC_BASE_URL || '';
81
+ var newBaseUrl = await input({
82
+ message: '请输入 ANTHROPIC_BASE_URL:',
83
+ default: defaultBaseUrl,
84
+ validate: function (v) {
85
+ return v.trim().length > 0 ? true : 'ANTHROPIC_BASE_URL 不能为空';
86
+ },
87
+ });
88
+ settings.env.ANTHROPIC_BASE_URL = newBaseUrl.trim();
89
+
90
+ // 手动输入 ANTHROPIC_AUTH_TOKEN,默认值取自当前 settings.env
91
+ var defaultToken = settings.env.ANTHROPIC_AUTH_TOKEN || '';
92
+ var newToken = await input({
88
93
  message: '请输入 ANTHROPIC_AUTH_TOKEN:',
94
+ default: defaultToken,
89
95
  validate: function (v) {
90
- return v.trim().length > 0 ? true : 'Key 不能为空';
96
+ return v.trim().length > 0 ? true : 'ANTHROPIC_AUTH_TOKEN 不能为空';
91
97
  },
92
98
  });
93
- newKey = newKey.trim();
99
+ settings.env.ANTHROPIC_AUTH_TOKEN = newToken.trim();
94
100
 
95
- // 写入 settings.json
96
- settings.env.ANTHROPIC_AUTH_TOKEN = newKey;
101
+ // 写入 settings.json(useSettingsFile 模式不缓存 Key 到 jcc.json)
97
102
  utils.writeJsonFile(buildCfg.claudeSettingsPath, settings);
103
+ console.log('✅ 已切换到渠道: ' + selected.name);
104
+ console.log(' BASE_URL: ' + settings.env.ANTHROPIC_BASE_URL);
105
+ console.log(' Token: ' + utils.maskKey(settings.env.ANTHROPIC_AUTH_TOKEN));
106
+ } else {
107
+ // 查询该渠道是否有缓存的 Key
108
+ var savedKey = (jccJson.keys && jccJson.keys[selected.id]) || '';
109
+ if (savedKey) {
110
+ // 已有缓存 Key,直接切换
111
+ settings.env.ANTHROPIC_AUTH_TOKEN = savedKey;
112
+ utils.writeJsonFile(buildCfg.claudeSettingsPath, settings);
113
+ console.log('✅ 已切换到渠道: ' + selected.name);
114
+ console.log(' Key: ' + utils.maskKey(savedKey));
115
+ } else {
116
+ // 无缓存 Key,提示用户输入
117
+ // console.log('⚠️ 渠道 [' + selected.name + '] 尚未设置 Key,请输入:');
118
+ var newKey = await input({
119
+ message: '请输入 ANTHROPIC_AUTH_TOKEN:',
120
+ validate: function (v) {
121
+ return v.trim().length > 0 ? true : 'Key 不能为空';
122
+ },
123
+ });
124
+ newKey = newKey.trim();
125
+
126
+ // 写入 settings.json
127
+ settings.env.ANTHROPIC_AUTH_TOKEN = newKey;
128
+ utils.writeJsonFile(buildCfg.claudeSettingsPath, settings);
129
+
130
+ // 缓存到 jcc.json
131
+ if (!jccJson.keys) { jccJson.keys = {}; }
132
+ jccJson.keys[selected.id] = newKey;
133
+ utils.writeJsonFile(buildCfg.jccJsonPath, jccJson);
134
+
135
+ console.log('✅ 已切换到渠道: ' + selected.name + ',Key 已保存到本地缓存。');
136
+ }
137
+ }
98
138
 
99
- // 缓存到 jcc.json
100
- if (!jccJson.keys) { jccJson.keys = {}; }
101
- jccJson.keys[selected.id] = newKey;
102
- utils.writeJsonFile(buildCfg.jccJsonPath, jccJson);
103
-
104
- console.log('✅ 已切换到渠道: ' + selected.name + ',Key 已保存到本地缓存。');
139
+ // ccVersionList 对象中确定目标版本号
140
+ // ccVersionList 格式:{ "200K上下文": "2.1.22", "1M上下文": "2.1.76" }
141
+ var requiredVer = '';
142
+ var ccVersionList = selected.ccVersionList || {};
143
+ var ctxKeys = Object.keys(ccVersionList);
144
+ if (ctxKeys.length === 1) {
145
+ // 只有一个上下文选项,直接使用对应版本,无需询问
146
+ requiredVer = ccVersionList[ctxKeys[0]];
147
+ } else if (ctxKeys.length > 1) {
148
+ // 多个上下文选项,询问用户选择,每次都要询问(不做缓存)
149
+ var ctxChoices = ctxKeys.map(function (k) {
150
+ return { name: k + ' (Claude ' + ccVersionList[k] + ')', value: k };
151
+ });
152
+ var selectedCtx = await select({
153
+ message: '请选择上下文大小:',
154
+ choices: ctxChoices,
155
+ });
156
+ requiredVer = ccVersionList[selectedCtx];
105
157
  }
106
158
 
107
159
  // 检测当前 Claude 版本是否与渠道要求一致,不一致则从 OSS 下载 tgz 安装
108
- var requiredVer = selected.ccVersion || '';
109
160
  var currentVer = buildCfg.claudeVersion || '';
110
161
  if (requiredVer && requiredVer !== currentVer) {
111
162
  console.log('\n⚠️ Claude 版本不匹配:当前 ' + (currentVer || '未知') + ',渠道要求 ' + requiredVer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "base_parts_ai",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
4
4
  "description": "jaskle base_parts_ai",
5
5
  "main": "./main.js",
6
6
  "registry": true,
package/test_jcc.js CHANGED
@@ -272,11 +272,13 @@ console.log('\n======= Test 7: API_CHANNELS 结构验证 =======');
272
272
  var hasId = typeof c.id === 'string' && c.id.length > 0;
273
273
  var hasName = typeof c.name === 'string' && c.name.length > 0;
274
274
  var hasDesc = typeof c.description === 'string';
275
- var hasCcVer = typeof c.ccVersion === 'string' && c.ccVersion.length > 0;
275
+ // ccVersionList 为对象且至少有一个 key
276
+ var hasCcVerList = c.ccVersionList && typeof c.ccVersionList === 'object'
277
+ && Object.keys(c.ccVersionList).length > 0;
276
278
  var hasEnvObj = c.envObj && typeof c.envObj === 'object';
277
279
 
278
- var ok = hasId && hasName && hasDesc && hasCcVer && hasEnvObj;
279
- console.log(' 渠道 [' + c.id + ']: id✅ name✅ ccVersion=' + c.ccVersion
280
+ var ok = hasId && hasName && hasDesc && hasCcVerList && hasEnvObj;
281
+ console.log(' 渠道 [' + c.id + ']: id✅ name✅ ccVersionList=' + JSON.stringify(c.ccVersionList)
280
282
  + ' envObj✅ ' + (ok ? '✅' : '❌'));
281
283
  if (!ok) { allOk = false; }
282
284
  });