bingocode 1.1.74 → 1.1.76

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.74",
3
+ "version": "1.1.76",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude": "bin/claude-win.cjs",
@@ -91,6 +91,8 @@ const i18nMap = {
91
91
  about: 'Bingo CLI - Version Info & About',
92
92
  aboutContent: [
93
93
  'Bingo is an AI assistant terminal client.',
94
+ 'Author: leanchy (Email: leanchy07@outlook.com)',
95
+ 'Github: github.com/leanchy/bingo-claude-code-offline-installer',
94
96
  '1. API Config: Press "P" or select "API Config" to set up your keys.',
95
97
  '2. Model Slots: Configure specific models in the Provider panel.',
96
98
  '3. Background Service: Bingo runs a local server to manage sessions.',
@@ -117,6 +119,8 @@ const i18nMap = {
117
119
  about: 'Bingo CLI Terminal - Version Info & About',
118
120
  aboutContent: [
119
121
  'Bingo is an AI assistant terminal client.',
122
+ 'Author: leanchy (Email: leanchy07@outlook.com)',
123
+ 'Github: github.com/leanchy/bingo-claude-code-offline-installer',
120
124
  '1. API Config: Press "P" or select "API Config" to set up your keys.',
121
125
  '2. Model Slots: Configure specific models in the Provider panel.',
122
126
  '3. Background Service: Bingo runs a local server to manage sessions.',
@@ -739,47 +743,54 @@ export const CliMenuManager: React.FC = () => {
739
743
  }
740
744
 
741
745
 
742
- // 历史分组展示
743
- const groupedHistoryItems = useMemo(() => {
744
- if (!historyList || !Array.isArray(historyList)) return [];
745
- const now = new Date();
746
- const today: any[] = [];
747
- const week: any[] = [];
748
- const earlier: any[] = [];
749
- for (const item of historyList) {
750
- const dt = new Date(item.createdAt);
751
- const isToday =
752
- dt.getFullYear() === now.getFullYear() &&
753
- dt.getMonth() === now.getMonth() &&
754
- dt.getDate() === now.getDate();
755
- const weekStart = new Date(now);
756
- weekStart.setDate(now.getDate() - ((now.getDay() + 6) % 7));
757
- weekStart.setHours(0, 0, 0, 0);
758
- if (isToday) today.push(item);
759
- else if (dt >= weekStart) week.push(item);
760
- else earlier.push(item);
761
- }
762
- function groupToItems(group: any[], groupTitle: string) {
763
- if (group.length === 0) return [];
764
- return [
765
- { label: groupTitle, value: `__group_${groupTitle}`, isGroup: true },
766
- ...group.map(item => {
767
- const isMarked = markedSessionIds.has(item.id);
768
- return {
769
- label: makeHistoryLabel(item, Math.max(20, VIEW_W - 8), isMarked),
770
- value: item.id,
771
- color: isMarked ? 'yellow' : undefined,
772
- };
773
- })
774
- ];
775
- }
776
- const items = [
777
- ...groupToItems(today, '—— Today ——'),
778
- ...groupToItems(week, '—— This Week ——'),
779
- ...groupToItems(earlier, '—— Earlier ——'),
780
- ];
781
- return items;
782
- }, [historyList, markedSessionIds]);
746
+ // 历史分组展示
747
+ const groupedHistoryItems = useMemo(() => {
748
+ if (!historyList || !Array.isArray(historyList)) return [];
749
+ const now = new Date();
750
+ const today: any[] = [];
751
+ const week: any[] = [];
752
+ const earlier: any[] = [];
753
+ const marked: any[] = [];
754
+
755
+ for (const item of historyList) {
756
+ if (markedSessionIds.has(item.id)) {
757
+ marked.push(item);
758
+ continue;
759
+ }
760
+ const dt = new Date(item.createdAt);
761
+ const isToday =
762
+ dt.getFullYear() === now.getFullYear() &&
763
+ dt.getMonth() === now.getMonth() &&
764
+ dt.getDate() === now.getDate();
765
+ const weekStart = new Date(now);
766
+ weekStart.setDate(now.getDate() - ((now.getDay() + 6) % 7));
767
+ weekStart.setHours(0, 0, 0, 0);
768
+ if (isToday) today.push(item);
769
+ else if (dt >= weekStart) week.push(item);
770
+ else earlier.push(item);
771
+ }
772
+ function groupToItems(group: any[], groupTitle: string) {
773
+ if (group.length === 0) return [];
774
+ return [
775
+ { label: groupTitle, value: `__group_${groupTitle}`, isGroup: true },
776
+ ...group.map(item => {
777
+ const isMarked = markedSessionIds.has(item.id);
778
+ return {
779
+ label: makeHistoryLabel(item, Math.max(20, VIEW_W - 8), isMarked),
780
+ value: item.id,
781
+ color: isMarked ? 'yellow' : undefined,
782
+ };
783
+ })
784
+ ];
785
+ }
786
+ const items = [
787
+ ...groupToItems(marked, '—— Marked ——'),
788
+ ...groupToItems(today, '—— Today ——'),
789
+ ...groupToItems(week, '—— This Week ——'),
790
+ ...groupToItems(earlier, '—— Earlier ——'),
791
+ ];
792
+ return items;
793
+ }, [historyList, markedSessionIds]);
783
794
 
784
795
  // Toggle Mark
785
796
  const toggleMarkSession = (sessionId: string) => {
@@ -986,8 +997,8 @@ export const CliMenuManager: React.FC = () => {
986
997
  return <StateDisplay type="empty" message={i18nMap[lang].emptyHistory} />;
987
998
  }
988
999
 
989
- const LIST_H = Math.floor(MID_H * 0.7);
990
- const ACTIONS_H = MID_H - LIST_H - 1; // -1 for separator/buffer
1000
+ const ACTIONS_H = 6;
1001
+ const LIST_H = Math.max(2, MID_H - ACTIONS_H - 1);
991
1002
 
992
1003
  if (historyMenuStage === 'window' && selectedHistory) {
993
1004
  // Detailed View with Split
@@ -1003,15 +1014,15 @@ export const CliMenuManager: React.FC = () => {
1003
1014
  return (
1004
1015
  <Box width={VIEW_W} height={MID_H} flexDirection="column">
1005
1016
  {/* Upper Pane: Preview */}
1006
- <Box height={LIST_H} flexDirection="column" paddingX={1}>
1007
- <Box justifyContent="space-between" marginBottom={1}>
1017
+ <Box height={LIST_H} flexDirection="column" paddingX={1} overflow="hidden">
1018
+ <Box justifyContent="space-between" marginBottom={0}>
1008
1019
  <Text color={isMarked ? 'yellow' : 'cyan'} bold>
1009
- {isMarked ? '★ ' : ''}{selectedHistory.title || 'Untitled'}
1020
+ {isMarked ? '★ ' : ''}{truncate(selectedHistory.title || 'Untitled', VIEW_W - 24)}
1010
1021
  </Text>
1011
1022
  <Text dimColor>{selectedHistory.createdAt?.slice(0,16).replace('T',' ')}</Text>
1012
1023
  </Box>
1013
1024
 
1014
- <Box flexDirection="column" flexGrow={1}>
1025
+ <Box flexDirection="column" flexGrow={1} overflow="hidden">
1015
1026
  {loadingMsgs && <StateDisplay type="loading" message="Loading messages..." />}
1016
1027
  {msgsErr && <StateDisplay type="error" message={msgsErr} />}
1017
1028
  {!loadingMsgs && pageMsgs.length === 0 && <StateDisplay type="empty" message="No messages" />}
@@ -1020,28 +1031,25 @@ export const CliMenuManager: React.FC = () => {
1020
1031
  const roleLabel = msg.type === 'user' ? 'You' : 'Bot';
1021
1032
  const roleColor = msg.type === 'user' ? 'green' : 'cyan';
1022
1033
  return (
1023
- <Box key={msg.id} marginBottom={1} flexDirection="column">
1024
- <Text color={roleColor} bold>{roleLabel}:</Text>
1025
- <Box paddingLeft={2}>
1026
- <Text>{clampTextLines(text, VIEW_W - 6, 3)}</Text>
1027
- </Box>
1034
+ <Box key={msg.id} marginBottom={0} flexDirection="column" height={1} overflow="hidden">
1035
+ <Text color={roleColor} bold>{roleLabel}: <Text color="white" bold={false}>{clampTextLines(text, VIEW_W - 10, 1)}</Text></Text>
1028
1036
  </Box>
1029
1037
  );
1030
1038
  })}
1031
1039
  </Box>
1032
1040
  {totalPages > 1 && (
1033
- <Box justifyContent="center" marginTop={1}>
1041
+ <Box justifyContent="center" height={1}>
1034
1042
  <Hint>Page {safePage + 1}/{totalPages} (↑↓ to scroll)</Hint>
1035
1043
  </Box>
1036
1044
  )}
1037
1045
  </Box>
1038
1046
 
1039
- <Box height={1}><Text dimColor>{'─'.repeat(VIEW_W - 2)}</Text></Box>
1047
+ <Box height={1} marginBottom={0}><Text dimColor>{'─'.repeat(VIEW_W - 2)}</Text></Box>
1040
1048
 
1041
1049
  {/* Lower Pane: Actions */}
1042
- <Box height={ACTIONS_H} paddingX={1} flexDirection="column">
1050
+ <Box height={ACTIONS_H} paddingX={1} flexDirection="column" overflow="hidden">
1043
1051
  <Text color="magenta" bold>Actions</Text>
1044
- <Box marginTop={0}>
1052
+ <Box marginTop={0} height={ACTIONS_H - 2} overflow="hidden">
1045
1053
  <SelectInput
1046
1054
  items={secondaryMenu?.items || []}
1047
1055
  onSelect={secondaryMenu?.onSelect}
@@ -1053,44 +1061,46 @@ export const CliMenuManager: React.FC = () => {
1053
1061
  );
1054
1062
  }
1055
1063
 
1056
- // History List View (Default)
1057
- const HIST_VISIBLE = MID_H - 2;
1058
- const start = Math.min(listOffset, Math.max(0, groupedHistoryItems.length - HIST_VISIBLE));
1059
- const slicedItems = groupedHistoryItems.slice(start, start + HIST_VISIBLE);
1060
-
1061
- return (
1062
- <Box width={VIEW_W} height={MID_H} flexDirection="row" position="relative">
1063
- <Box flexDirection="column" flexGrow={1} paddingX={1}>
1064
- <SelectInput
1065
- key={`${historyCursor ?? 'first'}:${slicedItems.length}:${start}`}
1066
- items={slicedItems}
1067
- onSelect={item => {
1068
- if (String(item.value).startsWith('__group_')) return;
1069
- const session = historyList.find(h => h.id === item.value);
1070
- if (session) {
1071
- setSelectedHistory(session);
1072
- setHistoryMenuStage('window');
1073
- }
1074
- }}
1075
- itemComponent={({ isSelected, label }) => {
1076
- const it = groupedHistoryItems.find(i => i.label === label);
1077
- const isGroup = it?.isGroup;
1078
- const color = it?.color;
1079
- return (
1080
- <Text color={isGroup ? 'gray' : (color ? color : (isSelected ? 'cyan' : undefined))}>
1081
- {isSelected ? '> ' : ' '}{label}
1082
- </Text>
1083
- )
1084
- }}
1085
- />
1086
- <Box marginTop="auto">
1087
- <Hint>{i18nMap[lang].historyHint}</Hint>
1088
- </Box>
1089
- </Box>
1090
- <ScrollBar total={groupedHistoryItems.length} offset={start} height={MID_H - 2} />
1091
- </Box>
1092
- );
1093
- }
1064
+ // History List View (Default)
1065
+ const HIST_VISIBLE = MID_H - 2;
1066
+ const start = Math.min(listOffset, Math.max(0, groupedHistoryItems.length - HIST_VISIBLE));
1067
+ const slicedItems = groupedHistoryItems.slice(start, start + HIST_VISIBLE);
1068
+
1069
+ return (
1070
+ <Box width={VIEW_W} height={MID_H} flexDirection="row" position="relative">
1071
+ <Box flexDirection="column" flexGrow={1} paddingX={1}>
1072
+ <SelectInput
1073
+ key={`${historyCursor ?? 'first'}:${slicedItems.length}:${start}`}
1074
+ items={slicedItems}
1075
+ onSelect={item => {
1076
+ if (String(item.value).startsWith('__group_')) return;
1077
+ const session = historyList.find(h => h.id === item.value);
1078
+ if (session) {
1079
+ setSelectedHistory(session);
1080
+ setHistoryMenuStage('window');
1081
+ }
1082
+ }}
1083
+ itemComponent={({ isSelected, label }) => {
1084
+ const it = groupedHistoryItems.find(i => i.label === label);
1085
+ const isGroup = it?.isGroup;
1086
+ const color = it?.color;
1087
+ return (
1088
+ <Box height={1} overflow="hidden">
1089
+ <Text wrap="truncate" color={isGroup ? 'gray' : (color ? color : (isSelected ? 'cyan' : undefined))}>
1090
+ {isSelected ? '> ' : ' '}{label}
1091
+ </Text>
1092
+ </Box>
1093
+ )
1094
+ }}
1095
+ />
1096
+ </Box>
1097
+ <ScrollBar total={groupedHistoryItems.length} offset={start} height={MID_H - 2} />
1098
+ <Box position="absolute" bottom={0} left={1} width={VIEW_W - 4}>
1099
+ <Hint>{i18nMap[lang].historyHint}</Hint>
1100
+ </Box>
1101
+ </Box>
1102
+ );
1103
+ }
1094
1104
 
1095
1105
  // Provider
1096
1106
  if (page === 'provider') {
@@ -1124,7 +1134,7 @@ export const CliMenuManager: React.FC = () => {
1124
1134
  const sliced = entries.slice(start, start + visible);
1125
1135
  return (
1126
1136
  <Box width={VIEW_W} height={MID_H} flexDirection="column">
1127
- <ScrollBar total={entries.length} offset={start} height={visible} />
1137
+ <ScrollBar total={entries.length} offset={start} height={visible - 1} />
1128
1138
  {sliced.map(([k, v]) => <Text key={k}>{k}: {typeof v === 'object' ? JSON.stringify(v) : String(v)}</Text>)}
1129
1139
  <Hint>
1130
1140
  ↑/k and ↓/j scroll · {start+1}-{Math.min(start+visible, entries.length)}/{entries.length}