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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bingocode",
3
- "version": "1.1.71",
3
+ "version": "1.1.72",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude": "bin/claude-win.cjs",
@@ -57,7 +57,8 @@ type Stage =
57
57
  export const ProviderPanel: React.FC<{
58
58
  apiUrl: string;
59
59
  onBack?: () => void;
60
- }> = ({ apiUrl, onBack }) => {
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 at the beginning
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 lines = String(text ?? '').split(/\r?\n/);
689
+ const cleaned = cleanText(text);
686
690
  const out: string[] = [];
687
- let used = 0;
688
- for (let i = 0; i < lines.length; i++) {
689
- if (out.length >= maxLines) break;
690
- const raw = lines[i];
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} borderStyle="single" borderColor="gray" flexDirection="column" paddingX={1}>
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} marginTop={1}>
1024
- {loadingMsgs && <Text dimColor>Loading messages...</Text>}
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}: </Text>
1032
- <Text>{clampTextLines(text, VIEW_W - 10, 2)}</Text>
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 && <Hint alignSelf="center">Page {safePage + 1}/{totalPages} (j/k to scroll)</Hint>}
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} marginTop={1} paddingX={1} flexDirection="column">
1042
- <Text color="cyan" bold>Session Actions</Text>
1043
- <Box marginTop={1}>
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
  }