base_parts_ai 1.0.34 → 1.0.36
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 +3 -3
- package/README.md +6 -0
- package/bin/jcc.js +32 -0
- package/lib/claude_utils.js +25 -16
- package/lib/setapi.js +52 -9
- package/package.json +1 -1
- package/test_jcc.js +5 -3
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
|
|
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
|
-
| `
|
|
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` 列表结构验证(含
|
|
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
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');
|
package/lib/claude_utils.js
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
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');
|
|
12
|
+
var { select } = require('@inquirer/prompts');
|
|
13
13
|
|
|
14
14
|
// ============================================================
|
|
15
15
|
// AI 渠道列表(运行时由 fetchConfig 从服务端拉取填充)
|
|
@@ -30,7 +30,7 @@ function fetchConfig(buildCfg) {
|
|
|
30
30
|
http.get(url, { timeout: 8000 }, function (res) {
|
|
31
31
|
var chunks = '';
|
|
32
32
|
res.on('data', function (chunk) { chunks += chunk; });
|
|
33
|
-
res.on('end', function () {
|
|
33
|
+
res.on('end', async function () {
|
|
34
34
|
try {
|
|
35
35
|
var result = JSON.parse(chunks);
|
|
36
36
|
if (result.code === 0 && result.data) {
|
|
@@ -49,24 +49,33 @@ function fetchConfig(buildCfg) {
|
|
|
49
49
|
noticeList.push(item);
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
|
-
// 检查 jcc
|
|
52
|
+
// 检查 jcc 自身版本,若需要升级则询问用户确认后安装
|
|
53
53
|
var currentVer = '';
|
|
54
54
|
try { currentVer = require('../package.json').version; } catch (e) { }
|
|
55
55
|
var newVer = result.data.newVer || '';
|
|
56
56
|
if (newVer && newVer !== currentVer) {
|
|
57
|
-
console.log('[fetchConfig] 检测到新版本 jcc: ' + newVer + '(当前 ' + currentVer + '
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
console.log('[fetchConfig] 检测到新版本 jcc: ' + newVer + '(当前 ' + currentVer + ')');
|
|
58
|
+
// 用 select 上下选,默认高亮"立即升级"
|
|
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,19 +73,42 @@ module.exports = async function (cmd, buildCfg) {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
//
|
|
80
|
-
settings.env.
|
|
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({
|
|
93
|
+
message: '请输入 ANTHROPIC_AUTH_TOKEN:',
|
|
94
|
+
default: defaultToken,
|
|
95
|
+
validate: function (v) {
|
|
96
|
+
return v.trim().length > 0 ? true : 'ANTHROPIC_AUTH_TOKEN 不能为空';
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
settings.env.ANTHROPIC_AUTH_TOKEN = newToken.trim();
|
|
100
|
+
|
|
101
|
+
// 写入 settings.json(useSettingsFile 模式不缓存 Key 到 jcc.json)
|
|
81
102
|
utils.writeJsonFile(buildCfg.claudeSettingsPath, settings);
|
|
82
103
|
console.log('✅ 已切换到渠道: ' + selected.name);
|
|
83
|
-
console.log('
|
|
104
|
+
console.log(' BASE_URL: ' + settings.env.ANTHROPIC_BASE_URL);
|
|
105
|
+
console.log(' Token: ' + utils.maskKey(settings.env.ANTHROPIC_AUTH_TOKEN));
|
|
84
106
|
} else {
|
|
85
|
-
//
|
|
86
|
-
|
|
107
|
+
// 查询该渠道是否有缓存的 Key,作为输入框默认值(方便用户确认或修改)
|
|
108
|
+
var savedKey = (jccJson.keys && jccJson.keys[selected.id]) || '';
|
|
87
109
|
var newKey = await input({
|
|
88
110
|
message: '请输入 ANTHROPIC_AUTH_TOKEN:',
|
|
111
|
+
default: savedKey,
|
|
89
112
|
validate: function (v) {
|
|
90
113
|
return v.trim().length > 0 ? true : 'Key 不能为空';
|
|
91
114
|
},
|
|
@@ -102,10 +125,30 @@ module.exports = async function (cmd, buildCfg) {
|
|
|
102
125
|
utils.writeJsonFile(buildCfg.jccJsonPath, jccJson);
|
|
103
126
|
|
|
104
127
|
console.log('✅ 已切换到渠道: ' + selected.name + ',Key 已保存到本地缓存。');
|
|
128
|
+
console.log(' Key: ' + utils.maskKey(newKey));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 从 ccVersionList 对象中确定目标版本号
|
|
132
|
+
// ccVersionList 格式:{ "200K上下文": "2.1.22", "1M上下文": "2.1.76" }
|
|
133
|
+
var requiredVer = '';
|
|
134
|
+
var ccVersionList = selected.ccVersionList || {};
|
|
135
|
+
var ctxKeys = Object.keys(ccVersionList);
|
|
136
|
+
if (ctxKeys.length === 1) {
|
|
137
|
+
// 只有一个上下文选项,直接使用对应版本,无需询问
|
|
138
|
+
requiredVer = ccVersionList[ctxKeys[0]];
|
|
139
|
+
} else if (ctxKeys.length > 1) {
|
|
140
|
+
// 多个上下文选项,询问用户选择,每次都要询问(不做缓存)
|
|
141
|
+
var ctxChoices = ctxKeys.map(function (k) {
|
|
142
|
+
return { name: k + ' (Claude ' + ccVersionList[k] + ')', value: k };
|
|
143
|
+
});
|
|
144
|
+
var selectedCtx = await select({
|
|
145
|
+
message: '请选择上下文大小:',
|
|
146
|
+
choices: ctxChoices,
|
|
147
|
+
});
|
|
148
|
+
requiredVer = ccVersionList[selectedCtx];
|
|
105
149
|
}
|
|
106
150
|
|
|
107
151
|
// 检测当前 Claude 版本是否与渠道要求一致,不一致则从 OSS 下载 tgz 安装
|
|
108
|
-
var requiredVer = selected.ccVersion || '';
|
|
109
152
|
var currentVer = buildCfg.claudeVersion || '';
|
|
110
153
|
if (requiredVer && requiredVer !== currentVer) {
|
|
111
154
|
console.log('\n⚠️ Claude 版本不匹配:当前 ' + (currentVer || '未知') + ',渠道要求 ' + requiredVer);
|
package/package.json
CHANGED
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
|
-
|
|
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 &&
|
|
279
|
-
console.log(' 渠道 [' + c.id + ']: id✅ name✅
|
|
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
|
});
|