bingocode 1.1.71 → 1.1.72
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 +10 -5
- package/src/manager/CliMenuManager.tsx +32 -25
package/package.json
CHANGED
|
@@ -57,7 +57,8 @@ type Stage =
|
|
|
57
57
|
export const ProviderPanel: React.FC<{
|
|
58
58
|
apiUrl: string;
|
|
59
59
|
onBack?: () => void;
|
|
60
|
-
|
|
60
|
+
height?: number;
|
|
61
|
+
}> = ({ apiUrl, onBack, height = 10 }) => {
|
|
61
62
|
const { exit } = useApp();
|
|
62
63
|
const [loading, setLoading] = useState(false);
|
|
63
64
|
const [err, setErr] = useState<string | null>(null);
|
|
@@ -65,6 +66,10 @@ export const ProviderPanel: React.FC<{
|
|
|
65
66
|
// Scrolling
|
|
66
67
|
const [listOffset, setListOffset] = useState(0);
|
|
67
68
|
|
|
69
|
+
// Calculated visible counts based on height
|
|
70
|
+
const MAX_VISIBLE = Math.max(3, height - 7);
|
|
71
|
+
const MAX_VISIBLE_MODELS = Math.max(3, height - 6);
|
|
72
|
+
|
|
68
73
|
const [providers, setProviders] = useState<Provider[]>([]);
|
|
69
74
|
const [currentId, setCurrentId] = useState<string | null>(null);
|
|
70
75
|
|
|
@@ -375,9 +380,9 @@ export const ProviderPanel: React.FC<{
|
|
|
375
380
|
value: pr.id
|
|
376
381
|
}));
|
|
377
382
|
|
|
378
|
-
// Add Custom option
|
|
383
|
+
// Add Custom option only if not already in presets
|
|
379
384
|
const finalItems = [
|
|
380
|
-
{ label: 'Custom (OpenAI Compatible)', value: 'custom' },
|
|
385
|
+
...(presets.some(p => p.id === 'custom') ? [] : [{ label: 'Custom (OpenAI Compatible)', value: 'custom' }]),
|
|
381
386
|
...items
|
|
382
387
|
];
|
|
383
388
|
|
|
@@ -410,7 +415,7 @@ export const ProviderPanel: React.FC<{
|
|
|
410
415
|
);
|
|
411
416
|
}
|
|
412
417
|
|
|
413
|
-
const MAX_VISIBLE = 8;
|
|
418
|
+
// const MAX_VISIBLE = 8;
|
|
414
419
|
const start = Math.min(listOffset, Math.max(0, finalItems.length - MAX_VISIBLE));
|
|
415
420
|
const sliced = finalItems.slice(start, start + MAX_VISIBLE);
|
|
416
421
|
|
|
@@ -756,7 +761,7 @@ export const ProviderPanel: React.FC<{
|
|
|
756
761
|
);
|
|
757
762
|
}
|
|
758
763
|
|
|
759
|
-
const MAX_VISIBLE_MODELS = 8;
|
|
764
|
+
// const MAX_VISIBLE_MODELS = 8;
|
|
760
765
|
const start = Math.min(listOffset, Math.max(0, items.length - MAX_VISIBLE_MODELS));
|
|
761
766
|
const sliced = items.slice(start, start + MAX_VISIBLE_MODELS);
|
|
762
767
|
|
|
@@ -681,18 +681,17 @@ export const CliMenuManager: React.FC = () => {
|
|
|
681
681
|
}
|
|
682
682
|
}, [menuItems, page, historyMenuStage, historyList, historyHasMore, navIndex, sessionMessages, settingData, MID_H, MSGS_PAGE_SIZE, showHelp, theme]);
|
|
683
683
|
|
|
684
|
+
function cleanText(text: string): string {
|
|
685
|
+
return String(text ?? '').replace(/[\n\r]+/g, ' ').replace(/\u001b\[[0-9;]*m/g, '').trim();
|
|
686
|
+
}
|
|
687
|
+
|
|
684
688
|
function clampTextLines(text: string, maxWidth: number, maxLines: number) {
|
|
685
|
-
const
|
|
689
|
+
const cleaned = cleanText(text);
|
|
686
690
|
const out: string[] = [];
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
if (raw.length <= maxWidth) {
|
|
692
|
-
out.push(raw);
|
|
693
|
-
} else {
|
|
694
|
-
out.push(ellipsis(raw, maxWidth));
|
|
695
|
-
}
|
|
691
|
+
if (cleaned.length <= maxWidth) {
|
|
692
|
+
out.push(cleaned);
|
|
693
|
+
} else {
|
|
694
|
+
out.push(cleaned.slice(0, maxWidth - 1) + '…');
|
|
696
695
|
}
|
|
697
696
|
return out.join('\n');
|
|
698
697
|
}
|
|
@@ -999,8 +998,6 @@ export const CliMenuManager: React.FC = () => {
|
|
|
999
998
|
if (historyMenuStage === 'window' && selectedHistory) {
|
|
1000
999
|
// Detailed View with Split
|
|
1001
1000
|
const isMarked = markedSessionIds.has(selectedHistory.id);
|
|
1002
|
-
const PREVIEW_H = Math.max(3, LIST_H - 2);
|
|
1003
|
-
|
|
1004
1001
|
const displayMsgs = sessionMessages.filter(
|
|
1005
1002
|
m => m.type === 'user' || m.type === 'assistant' || m.type === 'system'
|
|
1006
1003
|
);
|
|
@@ -1012,41 +1009,51 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1012
1009
|
return (
|
|
1013
1010
|
<Box width={VIEW_W} height={MID_H} flexDirection="column">
|
|
1014
1011
|
{/* Upper Pane: Preview */}
|
|
1015
|
-
<Box height={LIST_H}
|
|
1016
|
-
<Box justifyContent="space-between">
|
|
1012
|
+
<Box height={LIST_H} flexDirection="column" paddingX={1}>
|
|
1013
|
+
<Box justifyContent="space-between" marginBottom={1}>
|
|
1017
1014
|
<Text color={isMarked ? 'yellow' : 'cyan'} bold>
|
|
1018
1015
|
{isMarked ? '★ ' : ''}{selectedHistory.title || 'Untitled'}
|
|
1019
1016
|
</Text>
|
|
1020
1017
|
<Text dimColor>{selectedHistory.createdAt?.slice(0,16).replace('T',' ')}</Text>
|
|
1021
1018
|
</Box>
|
|
1022
1019
|
|
|
1023
|
-
<Box flexDirection="column" flexGrow={1}
|
|
1024
|
-
{loadingMsgs && <
|
|
1020
|
+
<Box flexDirection="column" flexGrow={1}>
|
|
1021
|
+
{loadingMsgs && <StateDisplay type="loading" message="Loading messages..." />}
|
|
1022
|
+
{msgsErr && <StateDisplay type="error" message={msgsErr} />}
|
|
1023
|
+
{!loadingMsgs && pageMsgs.length === 0 && <StateDisplay type="empty" message="No messages" />}
|
|
1025
1024
|
{pageMsgs.map((msg) => {
|
|
1026
1025
|
const text = extractTextFromContent(msg.content);
|
|
1027
1026
|
const roleLabel = msg.type === 'user' ? 'You' : 'Bot';
|
|
1028
1027
|
const roleColor = msg.type === 'user' ? 'green' : 'cyan';
|
|
1029
1028
|
return (
|
|
1030
|
-
<Box key={msg.id} marginBottom={1}>
|
|
1031
|
-
<Text color={roleColor} bold>{roleLabel}
|
|
1032
|
-
<
|
|
1029
|
+
<Box key={msg.id} marginBottom={1} flexDirection="column">
|
|
1030
|
+
<Text color={roleColor} bold>{roleLabel}:</Text>
|
|
1031
|
+
<Box paddingLeft={2}>
|
|
1032
|
+
<Text>{clampTextLines(text, VIEW_W - 6, 3)}</Text>
|
|
1033
|
+
</Box>
|
|
1033
1034
|
</Box>
|
|
1034
1035
|
);
|
|
1035
1036
|
})}
|
|
1036
1037
|
</Box>
|
|
1037
|
-
{totalPages > 1 &&
|
|
1038
|
+
{totalPages > 1 && (
|
|
1039
|
+
<Box justifyContent="center" marginTop={1}>
|
|
1040
|
+
<Hint>Page {safePage + 1}/{totalPages} (↑↓ to scroll)</Hint>
|
|
1041
|
+
</Box>
|
|
1042
|
+
)}
|
|
1038
1043
|
</Box>
|
|
1039
1044
|
|
|
1045
|
+
<Box height={1}><Text dimColor>{'─'.repeat(VIEW_W - 2)}</Text></Box>
|
|
1046
|
+
|
|
1040
1047
|
{/* Lower Pane: Actions */}
|
|
1041
|
-
<Box height={ACTIONS_H}
|
|
1042
|
-
<Text color="
|
|
1043
|
-
<Box marginTop={
|
|
1048
|
+
<Box height={ACTIONS_H} paddingX={1} flexDirection="column">
|
|
1049
|
+
<Text color="magenta" bold>Actions</Text>
|
|
1050
|
+
<Box marginTop={0}>
|
|
1044
1051
|
<SelectInput
|
|
1045
1052
|
items={secondaryMenu?.items || []}
|
|
1046
1053
|
onSelect={secondaryMenu?.onSelect}
|
|
1047
1054
|
/>
|
|
1048
1055
|
</Box>
|
|
1049
|
-
<Hint>ESC Back · ↑↓ Select Action</Hint>
|
|
1056
|
+
<Hint>ESC Back · ↑↓ Select Action · Q/M/C Shortcut</Hint>
|
|
1050
1057
|
</Box>
|
|
1051
1058
|
</Box>
|
|
1052
1059
|
);
|
|
@@ -1107,7 +1114,7 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1107
1114
|
}
|
|
1108
1115
|
return (
|
|
1109
1116
|
<Box width={VIEW_W} height={MID_H} flexDirection="column">
|
|
1110
|
-
<ProviderPanel apiUrl={apiUrl} onBack={() => setPage(null)} />
|
|
1117
|
+
<ProviderPanel apiUrl={apiUrl} height={MID_H} onBack={() => setPage(null)} />
|
|
1111
1118
|
</Box>
|
|
1112
1119
|
);
|
|
1113
1120
|
}
|