bingocode 1.1.68 → 1.1.69
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/package.json +1 -1
- package/src/cli/ProviderPanel.tsx +58 -20
- package/src/manager/CliMenuManager.tsx +10 -5
package/package.json
CHANGED
|
@@ -374,21 +374,45 @@ export const ProviderPanel: React.FC<{
|
|
|
374
374
|
: `${pr.label || pr.name || pr.id}`,
|
|
375
375
|
value: pr.id
|
|
376
376
|
}));
|
|
377
|
+
|
|
378
|
+
// Add Custom option at the beginning
|
|
379
|
+
const finalItems = [
|
|
380
|
+
{ label: 'Custom (OpenAI Compatible)', value: 'custom' },
|
|
381
|
+
...items
|
|
382
|
+
];
|
|
383
|
+
|
|
377
384
|
if (!items.length) {
|
|
378
385
|
return (
|
|
379
386
|
<Box flexDirection="column" flexGrow={1}>
|
|
380
|
-
<
|
|
387
|
+
<Title color="cyan">Select Preset</Title>
|
|
381
388
|
<SelectInput
|
|
382
|
-
items={
|
|
383
|
-
onSelect={
|
|
389
|
+
items={finalItems}
|
|
390
|
+
onSelect={it => {
|
|
391
|
+
if (it.value === 'custom') {
|
|
392
|
+
const fields: ProviderField[] = [
|
|
393
|
+
{ key: 'name', label: 'Provider Nickname', required: true, placeholder: 'My Custom API' },
|
|
394
|
+
{ key: 'baseUrl', label: 'Base URL', required: true, placeholder: 'https://api.example.com/v1' },
|
|
395
|
+
{ key: 'apiKey', label: 'API Key', required: true, secret: true },
|
|
396
|
+
];
|
|
397
|
+
setSelectedPresetId('custom');
|
|
398
|
+
setAddFields(fields);
|
|
399
|
+
setAddFieldValues({});
|
|
400
|
+
setAddFieldIndex(0);
|
|
401
|
+
setListOffset(0);
|
|
402
|
+
setStage('add_input_fields');
|
|
403
|
+
} else {
|
|
404
|
+
setStage('list');
|
|
405
|
+
}
|
|
406
|
+
}}
|
|
384
407
|
/>
|
|
408
|
+
{!items.length && <Hint dimColor>No presets found from server, only Custom available.</Hint>}
|
|
385
409
|
</Box>
|
|
386
410
|
);
|
|
387
411
|
}
|
|
388
412
|
|
|
389
413
|
const MAX_VISIBLE = 8;
|
|
390
|
-
const start = Math.min(listOffset, Math.max(0,
|
|
391
|
-
const sliced =
|
|
414
|
+
const start = Math.min(listOffset, Math.max(0, finalItems.length - MAX_VISIBLE));
|
|
415
|
+
const sliced = finalItems.slice(start, start + MAX_VISIBLE);
|
|
392
416
|
|
|
393
417
|
return (
|
|
394
418
|
<Box flexDirection="column" flexGrow={1}>
|
|
@@ -398,24 +422,38 @@ export const ProviderPanel: React.FC<{
|
|
|
398
422
|
<SelectInput
|
|
399
423
|
items={sliced}
|
|
400
424
|
onSelect={it => {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
:
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
425
|
+
if (it.value === 'custom') {
|
|
426
|
+
const fields: ProviderField[] = [
|
|
427
|
+
{ key: 'name', label: 'Provider Nickname', required: true, placeholder: 'My Custom API' },
|
|
428
|
+
{ key: 'baseUrl', label: 'Base URL', required: true, placeholder: 'https://api.example.com/v1' },
|
|
429
|
+
{ key: 'apiKey', label: 'API Key', required: true, secret: true },
|
|
430
|
+
];
|
|
431
|
+
setSelectedPresetId('custom');
|
|
432
|
+
setAddFields(fields);
|
|
433
|
+
setAddFieldValues({});
|
|
434
|
+
setAddFieldIndex(0);
|
|
435
|
+
setListOffset(0);
|
|
436
|
+
setStage('add_input_fields');
|
|
437
|
+
} else {
|
|
438
|
+
const preset = presets.find(p => p.id === (it.value as string));
|
|
439
|
+
const fields: ProviderField[] =
|
|
440
|
+
preset?.fields && preset.fields.length > 0
|
|
441
|
+
? preset.fields
|
|
442
|
+
: [
|
|
443
|
+
{ key: 'name', label: 'Provider Nickname', required: true },
|
|
444
|
+
{ key: 'apiKey', label: 'API Key', required: true, secret: true },
|
|
445
|
+
];
|
|
446
|
+
setSelectedPresetId(it.value as string);
|
|
447
|
+
setAddFields(fields);
|
|
448
|
+
setAddFieldValues({});
|
|
449
|
+
setAddFieldIndex(0);
|
|
450
|
+
setListOffset(0);
|
|
451
|
+
setStage('add_input_fields');
|
|
452
|
+
}
|
|
415
453
|
}}
|
|
416
454
|
/>
|
|
417
455
|
</Box>
|
|
418
|
-
<ScrollBar total={
|
|
456
|
+
<ScrollBar total={finalItems.length} offset={start} height={MAX_VISIBLE} />
|
|
419
457
|
</Box>
|
|
420
458
|
<Hint>↑↓: Select · j Next Page · k Prev Page · ESC: Back</Hint>
|
|
421
459
|
</Box>
|
|
@@ -294,7 +294,7 @@ export const CliMenuManager: React.FC = () => {
|
|
|
294
294
|
|
|
295
295
|
// Compute viewport
|
|
296
296
|
const TOP_H = page === null ? TOP_H_HOME : TOP_H_COMPACT;
|
|
297
|
-
const MID_H = Math.max(5, VIEW_H - TOP_H - BOTTOM_H);
|
|
297
|
+
const MID_H = Math.max(5, VIEW_H - TOP_H - BOTTOM_H - (page === null ? 0 : 2));
|
|
298
298
|
const MSGS_PAGE_SIZE = Math.max(1, MID_H - 2);
|
|
299
299
|
const [expandMsgs, setExpandMsgs] = useState(false);
|
|
300
300
|
|
|
@@ -593,9 +593,10 @@ export const CliMenuManager: React.FC = () => {
|
|
|
593
593
|
// History shortcuts
|
|
594
594
|
if (!showHelp && page === 'history') {
|
|
595
595
|
if (historyMenuStage === 'list') {
|
|
596
|
+
const HIST_VISIBLE = Math.max(1, MID_H - 1);
|
|
596
597
|
if (key.downArrow || input === 'j') {
|
|
597
598
|
// Internal SelectInput handles cursor, we just need to track offset for ScrollBar
|
|
598
|
-
setListOffset(o => o + 1);
|
|
599
|
+
setListOffset(o => Math.min(o + 1, Math.max(0, groupedHistoryItems.length - HIST_VISIBLE)));
|
|
599
600
|
}
|
|
600
601
|
if (key.upArrow || input === 'k') {
|
|
601
602
|
setListOffset(o => Math.max(0, o - 1));
|
|
@@ -1043,12 +1044,16 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1043
1044
|
|
|
1044
1045
|
|
|
1045
1046
|
// History List
|
|
1047
|
+
const HIST_VISIBLE = Math.max(1, MID_H - 1);
|
|
1048
|
+
const start = Math.min(listOffset, Math.max(0, groupedHistoryItems.length - HIST_VISIBLE));
|
|
1049
|
+
const slicedItems = groupedHistoryItems.slice(start, start + HIST_VISIBLE);
|
|
1050
|
+
|
|
1046
1051
|
return (
|
|
1047
1052
|
<Box width={VIEW_W} height={MID_H} flexDirection="row">
|
|
1048
1053
|
<Box flexDirection="column" flexGrow={1}>
|
|
1049
1054
|
<SelectInput
|
|
1050
|
-
key={`${historyCursor ?? 'first'}:${
|
|
1051
|
-
items={
|
|
1055
|
+
key={`${historyCursor ?? 'first'}:${slicedItems.length}:${start}`}
|
|
1056
|
+
items={slicedItems}
|
|
1052
1057
|
onSelect={item => {
|
|
1053
1058
|
if (String(item.value).startsWith('__group_')) return; // Ignore group headers
|
|
1054
1059
|
const session = historyList.find(h => h.id === item.value);
|
|
@@ -1070,7 +1075,7 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1070
1075
|
/>
|
|
1071
1076
|
<Hint>{i18nMap[lang].historyHint}</Hint>
|
|
1072
1077
|
</Box>
|
|
1073
|
-
<ScrollBar total={groupedHistoryItems.length} offset={
|
|
1078
|
+
<ScrollBar total={groupedHistoryItems.length} offset={start} height={MID_H} />
|
|
1074
1079
|
</Box>
|
|
1075
1080
|
);
|
|
1076
1081
|
}
|