base_parts_ai 1.0.47 → 1.0.49
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/lib/ai_utils.js +7 -6
- package/lib/setapi_cx.js +47 -1
- package/package.json +1 -1
- package/test_home/.codex/auth.json +5 -1
- package/test_jcc.js +4 -0
- package/test_jcx.js +51 -1
package/lib/ai_utils.js
CHANGED
|
@@ -76,7 +76,7 @@ function rerunCurrentCli() {
|
|
|
76
76
|
*/
|
|
77
77
|
function fetchConfig(buildCfg) {
|
|
78
78
|
return new Promise(function (resolve) {
|
|
79
|
-
var url = '
|
|
79
|
+
var url = 'https://jai.jaskle.cn/hm/hm_pub/ai_cc_cfg?r=' + Math.random();
|
|
80
80
|
http.get(url, { timeout: 8000 }, function (res) {
|
|
81
81
|
var chunks = '';
|
|
82
82
|
res.on('data', function (chunk) { chunks += chunk; });
|
|
@@ -122,7 +122,7 @@ function fetchConfig(buildCfg) {
|
|
|
122
122
|
return false;
|
|
123
123
|
}
|
|
124
124
|
if (newVer && process.env.BASE_PARTS_AI_SKIP_SELF_UPDATE !== '1' && semverGt(newVer, currentVer)) {
|
|
125
|
-
console.log('[fetchConfig]
|
|
125
|
+
console.log('[fetchConfig] 检测到新版本: ' + newVer + '(当前 ' + currentVer + ')');
|
|
126
126
|
var confirmed = "yes"
|
|
127
127
|
// confirmed = await select({
|
|
128
128
|
// message: '是否立即升级?',
|
|
@@ -234,7 +234,7 @@ function getAiTipOsParam() {
|
|
|
234
234
|
* @returns {string}
|
|
235
235
|
*/
|
|
236
236
|
function buildAiTipCommand() {
|
|
237
|
-
return 'curl -s -m
|
|
237
|
+
return 'curl -s -m 5 ' + buildAiTipUrl('cc');
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
/**
|
|
@@ -243,7 +243,7 @@ function buildAiTipCommand() {
|
|
|
243
243
|
* @returns {string}
|
|
244
244
|
*/
|
|
245
245
|
function buildAiTipUrl(cli) {
|
|
246
|
-
return '
|
|
246
|
+
return 'https://jai.jaskle.cn/hm/pub/ai_tip?cli=' + cli + '-' + getAiTipOsParam();
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
/**
|
|
@@ -306,7 +306,7 @@ function getLastManualAuthToken(jccJson) {
|
|
|
306
306
|
|
|
307
307
|
/**
|
|
308
308
|
* 计算需要提示用户输入 Token 时的默认值
|
|
309
|
-
*
|
|
309
|
+
* 优先使用当前渠道缓存;只有该渠道无缓存时,才使用当前渠道配置或最后一次手动 Token 兜底
|
|
310
310
|
* @param {object} jccJson jcc.json 对象
|
|
311
311
|
* @param {string} channelId 当前渠道 id
|
|
312
312
|
* @param {object} settings Claude settings.json 对象
|
|
@@ -315,7 +315,8 @@ function getLastManualAuthToken(jccJson) {
|
|
|
315
315
|
function getManualAuthTokenDefault(jccJson, channelId, settings) {
|
|
316
316
|
var cachedToken = (jccJson.keys && jccJson.keys[channelId]) || '';
|
|
317
317
|
var currentToken = (settings.env && settings.env.ANTHROPIC_AUTH_TOKEN) || '';
|
|
318
|
-
|
|
318
|
+
var currentChannelToken = (!settings.__jid || settings.__jid === channelId) ? currentToken : '';
|
|
319
|
+
return cachedToken || currentChannelToken || getLastManualAuthToken(jccJson) || currentToken;
|
|
319
320
|
}
|
|
320
321
|
|
|
321
322
|
/**
|
package/lib/setapi_cx.js
CHANGED
|
@@ -369,6 +369,48 @@ function getCurrentCodexChannelId(auth, toml) {
|
|
|
369
369
|
return channel ? channel.id : '';
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
/**
|
|
373
|
+
* 记录最后一次由用户手动输入的 Codex Key
|
|
374
|
+
* 该值仅作为新渠道无专属 Key 时的默认输入提示
|
|
375
|
+
* @param {object} auth auth.json 对象
|
|
376
|
+
* @param {string} key 用户手动输入的 OPENAI_API_KEY
|
|
377
|
+
*/
|
|
378
|
+
function saveLastManualOpenAiKey(auth, key) {
|
|
379
|
+
if (key) {
|
|
380
|
+
auth.__lastManualOpenAiKey = key;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* 获取 Codex 手动 Key 输入框默认值
|
|
386
|
+
* 优先使用当前渠道专属缓存;没有缓存时才用当前渠道 Key 或最后手动 Key 兜底
|
|
387
|
+
* @param {object} auth auth.json 对象
|
|
388
|
+
* @param {string} channelId 当前选择的渠道 id
|
|
389
|
+
* @returns {string}
|
|
390
|
+
*/
|
|
391
|
+
function getManualOpenAiKeyDefault(auth, channelId) {
|
|
392
|
+
var cachedKey = (auth.__keys && auth.__keys[channelId]) || '';
|
|
393
|
+
var currentKey = auth.OPENAI_API_KEY || '';
|
|
394
|
+
var currentChannelKey = (!auth.__jid || auth.__jid === channelId) ? currentKey : '';
|
|
395
|
+
return cachedKey || currentChannelKey || auth.__lastManualOpenAiKey || currentKey;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* 保存或删除 Codex 渠道专属 Key 缓存
|
|
400
|
+
* @param {object} auth auth.json 对象
|
|
401
|
+
* @param {string} channelId 当前选择的渠道 id
|
|
402
|
+
* @param {string} key 用户手动输入的 OPENAI_API_KEY,空值表示删除该渠道缓存
|
|
403
|
+
*/
|
|
404
|
+
function saveManualOpenAiKey(auth, channelId, key) {
|
|
405
|
+
if (!auth.__keys) { auth.__keys = {}; }
|
|
406
|
+
if (key) {
|
|
407
|
+
auth.__keys[channelId] = key;
|
|
408
|
+
saveLastManualOpenAiKey(auth, key);
|
|
409
|
+
} else {
|
|
410
|
+
delete auth.__keys[channelId];
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
372
414
|
/**
|
|
373
415
|
* 执行 Codex setapi 交互配置
|
|
374
416
|
* @param {object} cmd 命令参数
|
|
@@ -420,9 +462,10 @@ async function setapiCx(cmd, buildCfg) {
|
|
|
420
462
|
type: 'input',
|
|
421
463
|
name: 'value',
|
|
422
464
|
message: '请输入 OPENAI_API_KEY(输入空格后回车删除该配置):',
|
|
423
|
-
default: auth.
|
|
465
|
+
default: getManualOpenAiKeyDefault(auth, selected.id),
|
|
424
466
|
}]);
|
|
425
467
|
forcedKey = keyAnswer.value.trim();
|
|
468
|
+
saveManualOpenAiKey(auth, selected.id, forcedKey);
|
|
426
469
|
} else {
|
|
427
470
|
console.log('已使用渠道配置中的 OPENAI_API_KEY,跳过 Key 输入。');
|
|
428
471
|
}
|
|
@@ -472,6 +515,9 @@ setapiCx._private = {
|
|
|
472
515
|
setJcodexWireApi: setJcodexWireApi,
|
|
473
516
|
setJcodexProvider: setJcodexProvider,
|
|
474
517
|
getCurrentCodexChannelId: getCurrentCodexChannelId,
|
|
518
|
+
saveLastManualOpenAiKey: saveLastManualOpenAiKey,
|
|
519
|
+
getManualOpenAiKeyDefault: getManualOpenAiKeyDefault,
|
|
520
|
+
saveManualOpenAiKey: saveManualOpenAiKey,
|
|
475
521
|
resolveRequiredCodexVersion: resolveRequiredCodexVersion,
|
|
476
522
|
ensureCodexVersion: ensureCodexVersion,
|
|
477
523
|
};
|
package/package.json
CHANGED
package/test_jcc.js
CHANGED
|
@@ -378,12 +378,15 @@ console.log('\n======= Test 10: Token 默认值与强制配置 =======');
|
|
|
378
378
|
|
|
379
379
|
settings.env.ANTHROPIC_AUTH_TOKEN = 'sk-current-settings';
|
|
380
380
|
var currentDefault = utils.getManualAuthTokenDefault({ keys: {} }, 'channel_c', settings);
|
|
381
|
+
settings.__jid = 'other_channel';
|
|
382
|
+
var otherChannelDefault = utils.getManualAuthTokenDefault(jccJson, 'channel_b', settings);
|
|
381
383
|
|
|
382
384
|
console.log('强制 Token:', forcedToken);
|
|
383
385
|
console.log('空强制 Token:', emptyForcedToken || '(空)');
|
|
384
386
|
console.log('渠道缓存默认值:', cachedDefault);
|
|
385
387
|
console.log('最后手动默认值:', lastManualDefault);
|
|
386
388
|
console.log('当前 settings 默认值:', currentDefault);
|
|
389
|
+
console.log('其它渠道 settings 兜底默认值:', otherChannelDefault);
|
|
387
390
|
|
|
388
391
|
var ok = true;
|
|
389
392
|
ok = ok && (forcedToken === 'sk-forced-token');
|
|
@@ -391,6 +394,7 @@ console.log('\n======= Test 10: Token 默认值与强制配置 =======');
|
|
|
391
394
|
ok = ok && (cachedDefault === 'sk-channel-cache');
|
|
392
395
|
ok = ok && (lastManualDefault === 'sk-last-manual');
|
|
393
396
|
ok = ok && (currentDefault === 'sk-current-settings');
|
|
397
|
+
ok = ok && (otherChannelDefault === 'sk-last-manual');
|
|
394
398
|
|
|
395
399
|
console.log('✅ Test 10 通过:', ok);
|
|
396
400
|
if (!ok) { process.exit(1); }
|
package/test_jcx.js
CHANGED
|
@@ -286,7 +286,12 @@ async function runTests() {
|
|
|
286
286
|
console.log('\n======= jcx Test 6: 可删除输入框保留默认值 =======');
|
|
287
287
|
await withMockFetchText(async function () {
|
|
288
288
|
writeText(buildCfg.codexConfigPath, 'model_provider = "jcodex"\n\n[model_providers.jcodex]\nname = "jcodex"\nbase_url = "https://old.example.com/v1"\n');
|
|
289
|
-
utils.writeJsonFile(buildCfg.codexAuthPath, {
|
|
289
|
+
utils.writeJsonFile(buildCfg.codexAuthPath, {
|
|
290
|
+
OPENAI_API_KEY: 'sk-old-key',
|
|
291
|
+
__keys: {
|
|
292
|
+
manual_channel: 'sk-old-key',
|
|
293
|
+
},
|
|
294
|
+
});
|
|
290
295
|
utils.CX_CHANNELS.length = 0;
|
|
291
296
|
utils.CX_CHANNELS.push({
|
|
292
297
|
id: 'manual_channel',
|
|
@@ -322,6 +327,51 @@ async function runTests() {
|
|
|
322
327
|
if (!ok) { process.exit(1); }
|
|
323
328
|
});
|
|
324
329
|
|
|
330
|
+
// ============================================================
|
|
331
|
+
// 测试 6.1:Codex Key 按渠道缓存,当前其它渠道 Key 不覆盖专属默认值
|
|
332
|
+
// ============================================================
|
|
333
|
+
console.log('\n======= jcx Test 6.1: Codex Key 按渠道缓存 =======');
|
|
334
|
+
await withMockFetchText(async function () {
|
|
335
|
+
writeText(buildCfg.codexConfigPath, 'sandbox_mode = "danger-full-access"\n');
|
|
336
|
+
utils.writeJsonFile(buildCfg.codexAuthPath, {
|
|
337
|
+
__jid: 'channel_a',
|
|
338
|
+
OPENAI_API_KEY: 'sk-current-channel-a',
|
|
339
|
+
__lastManualOpenAiKey: 'sk-last-manual',
|
|
340
|
+
__keys: {
|
|
341
|
+
channel_b: 'sk-channel-b-cache',
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
utils.CX_CHANNELS.length = 0;
|
|
345
|
+
utils.CX_CHANNELS.push({
|
|
346
|
+
id: 'channel_b',
|
|
347
|
+
name: 'Channel B',
|
|
348
|
+
description: 'manual key cache channel',
|
|
349
|
+
useSettingsFile: false,
|
|
350
|
+
envObj: {
|
|
351
|
+
base_url: 'https://channel-b.example.com/v1',
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
var captured = [];
|
|
355
|
+
await withCapturedPrompts([
|
|
356
|
+
{ channelId: 'channel_b' },
|
|
357
|
+
{ value: 'sk-channel-b-new' },
|
|
358
|
+
], captured, async function () {
|
|
359
|
+
await setapiCx({}, buildCfg);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
var auth = JSON.parse(readText(buildCfg.codexAuthPath));
|
|
363
|
+
var ok = true;
|
|
364
|
+
ok = ok && captured.length === 2;
|
|
365
|
+
ok = ok && captured[1].message.indexOf('OPENAI_API_KEY') !== -1;
|
|
366
|
+
ok = ok && captured[1].default === 'sk-channel-b-cache';
|
|
367
|
+
ok = ok && auth.__jid === 'channel_b';
|
|
368
|
+
ok = ok && auth.OPENAI_API_KEY === 'sk-channel-b-new';
|
|
369
|
+
ok = ok && auth.__keys.channel_b === 'sk-channel-b-new';
|
|
370
|
+
ok = ok && auth.__lastManualOpenAiKey === 'sk-channel-b-new';
|
|
371
|
+
console.log('✅ Test 6.1 通过:', ok);
|
|
372
|
+
if (!ok) { process.exit(1); }
|
|
373
|
+
});
|
|
374
|
+
|
|
325
375
|
// ============================================================
|
|
326
376
|
// 测试 7:base_url 为空时仍强制写入非空 wire_api
|
|
327
377
|
// ============================================================
|