bingocode 1.1.70 → 1.1.71
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
|
@@ -141,13 +141,13 @@ export const ProviderPanel: React.FC<{
|
|
|
141
141
|
loadPresets();
|
|
142
142
|
}, [loadProviders, loadPresets]);
|
|
143
143
|
|
|
144
|
-
// Key processing for Page Up/Down in scrolling lists
|
|
144
|
+
// Key processing for Page Up/Down and Arrow keys in scrolling lists
|
|
145
145
|
useEffect(() => {
|
|
146
146
|
const handler = (buf: Buffer) => {
|
|
147
147
|
const s = buf.toString();
|
|
148
148
|
if (stage === 'add_select_preset' || stage === 'slot_select_model') {
|
|
149
|
-
if (s === 'j') setListOffset(prev => prev + 1);
|
|
150
|
-
if (s === 'k') setListOffset(prev => Math.max(0, prev - 1));
|
|
149
|
+
if (s === 'j' || s === '\u001b[B') setListOffset(prev => prev + 1); // j or Down
|
|
150
|
+
if (s === 'k' || s === '\u001b[A') setListOffset(prev => Math.max(0, prev - 1)); // k or Up
|
|
151
151
|
}
|
|
152
152
|
};
|
|
153
153
|
process.stdin.on('data', handler);
|
|
@@ -607,12 +607,12 @@ export const CliMenuManager: React.FC = () => {
|
|
|
607
607
|
// History shortcuts
|
|
608
608
|
if (!showHelp && page === 'history') {
|
|
609
609
|
if (historyMenuStage === 'list') {
|
|
610
|
-
const HIST_VISIBLE =
|
|
611
|
-
if (key.downArrow || input === 'j') {
|
|
610
|
+
const HIST_VISIBLE = MID_H - 2;
|
|
611
|
+
if (key.downArrow || input === 'j' || input === '\u001b[B') {
|
|
612
612
|
// Internal SelectInput handles cursor, we just need to track offset for ScrollBar
|
|
613
613
|
setListOffset(o => Math.min(o + 1, Math.max(0, groupedHistoryItems.length - HIST_VISIBLE)));
|
|
614
614
|
}
|
|
615
|
-
if (key.upArrow || input === 'k') {
|
|
615
|
+
if (key.upArrow || input === 'k' || input === '\u001b[A') {
|
|
616
616
|
setListOffset(o => Math.max(0, o - 1));
|
|
617
617
|
}
|
|
618
618
|
if (input === 'q') {
|
|
@@ -965,48 +965,45 @@ export const CliMenuManager: React.FC = () => {
|
|
|
965
965
|
if (historyMenuStage === 'deleteConfirm' && selectedHistory) {
|
|
966
966
|
const halfH = Math.floor(MID_H / 2);
|
|
967
967
|
const items = [
|
|
968
|
-
{ label: 'Yes,
|
|
969
|
-
{ label: 'No,
|
|
968
|
+
{ label: 'Yes, Delete', value: '__confirm_delete' },
|
|
969
|
+
{ label: 'No, Back', value: '__cancel_delete' },
|
|
970
970
|
];
|
|
971
971
|
return (
|
|
972
972
|
<Box width={VIEW_W} height={MID_H} flexDirection="column">
|
|
973
|
-
<Box height={halfH} flexDirection="column">
|
|
974
|
-
<Text color="red">
|
|
975
|
-
<Text>
|
|
976
|
-
<Text>
|
|
977
|
-
<Text>
|
|
973
|
+
<Box height={halfH} flexDirection="column" paddingX={1} paddingTop={1}>
|
|
974
|
+
<Text color="red" bold>Confirm Delete?</Text>
|
|
975
|
+
<Text>Title: {selectedHistory.title || 'Untitled'}</Text>
|
|
976
|
+
<Text dimColor>Time: {selectedHistory.createdAt?.replace('T',' ')}</Text>
|
|
977
|
+
<Text dimColor>ID: {selectedHistory.id}</Text>
|
|
978
978
|
</Box>
|
|
979
979
|
<Panel height={MID_H - halfH} borderStyle="round" borderColor="red" paddingX={1}>
|
|
980
|
-
<Text>Confirm Delete</Text>
|
|
981
980
|
<SelectInput
|
|
982
981
|
items={items}
|
|
983
982
|
onSelect={(item) => handleHistoryMenuAction(String(item.value))}
|
|
984
983
|
/>
|
|
985
|
-
<Hint
|
|
984
|
+
<Hint>Enter Confirm · q Cancel</Hint>
|
|
986
985
|
</Panel>
|
|
987
986
|
</Box>
|
|
988
987
|
);
|
|
989
988
|
}
|
|
990
989
|
if (!historyList.length && loadingHist) {
|
|
991
|
-
return <StateDisplay type="loading" message="
|
|
990
|
+
return <StateDisplay type="loading" message="Loading..." />;
|
|
992
991
|
}
|
|
993
992
|
if (!historyList.length) {
|
|
994
993
|
return <StateDisplay type="empty" message={i18nMap[lang].emptyHistory} />;
|
|
995
994
|
}
|
|
996
995
|
|
|
996
|
+
const LIST_H = Math.floor(MID_H * 0.7);
|
|
997
|
+
const ACTIONS_H = MID_H - LIST_H - 1; // -1 for separator/buffer
|
|
998
|
+
|
|
997
999
|
if (historyMenuStage === 'window' && selectedHistory) {
|
|
1000
|
+
// Detailed View with Split
|
|
998
1001
|
const isMarked = markedSessionIds.has(selectedHistory.id);
|
|
1002
|
+
const PREVIEW_H = Math.max(3, LIST_H - 2);
|
|
999
1003
|
|
|
1000
|
-
// INFO_H: Title + Metadata + Hint (3 lines)
|
|
1001
|
-
const INFO_H = 3;
|
|
1002
|
-
const MSGS_H = Math.max(3, MID_H - INFO_H);
|
|
1003
|
-
|
|
1004
|
-
// Filter messages
|
|
1005
1004
|
const displayMsgs = sessionMessages.filter(
|
|
1006
1005
|
m => m.type === 'user' || m.type === 'assistant' || m.type === 'system'
|
|
1007
1006
|
);
|
|
1008
|
-
|
|
1009
|
-
// Pagination
|
|
1010
1007
|
const totalPages = Math.max(1, Math.ceil(displayMsgs.length / MSGS_PAGE_SIZE));
|
|
1011
1008
|
const safePage = Math.min(msgsPage, totalPages - 1);
|
|
1012
1009
|
const pageStart = safePage * MSGS_PAGE_SIZE;
|
|
@@ -1014,62 +1011,60 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1014
1011
|
|
|
1015
1012
|
return (
|
|
1016
1013
|
<Box width={VIEW_W} height={MID_H} flexDirection="column">
|
|
1017
|
-
{/*
|
|
1018
|
-
<Box height={
|
|
1019
|
-
<
|
|
1020
|
-
{isMarked ? '
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1014
|
+
{/* Upper Pane: Preview */}
|
|
1015
|
+
<Box height={LIST_H} borderStyle="single" borderColor="gray" flexDirection="column" paddingX={1}>
|
|
1016
|
+
<Box justifyContent="space-between">
|
|
1017
|
+
<Text color={isMarked ? 'yellow' : 'cyan'} bold>
|
|
1018
|
+
{isMarked ? '★ ' : ''}{selectedHistory.title || 'Untitled'}
|
|
1019
|
+
</Text>
|
|
1020
|
+
<Text dimColor>{selectedHistory.createdAt?.slice(0,16).replace('T',' ')}</Text>
|
|
1021
|
+
</Box>
|
|
1022
|
+
|
|
1023
|
+
<Box flexDirection="column" flexGrow={1} marginTop={1}>
|
|
1024
|
+
{loadingMsgs && <Text dimColor>Loading messages...</Text>}
|
|
1025
|
+
{pageMsgs.map((msg) => {
|
|
1026
|
+
const text = extractTextFromContent(msg.content);
|
|
1027
|
+
const roleLabel = msg.type === 'user' ? 'You' : 'Bot';
|
|
1028
|
+
const roleColor = msg.type === 'user' ? 'green' : 'cyan';
|
|
1029
|
+
return (
|
|
1030
|
+
<Box key={msg.id} marginBottom={1}>
|
|
1031
|
+
<Text color={roleColor} bold>{roleLabel}: </Text>
|
|
1032
|
+
<Text>{clampTextLines(text, VIEW_W - 10, 2)}</Text>
|
|
1033
|
+
</Box>
|
|
1034
|
+
);
|
|
1035
|
+
})}
|
|
1036
|
+
</Box>
|
|
1037
|
+
{totalPages > 1 && <Hint alignSelf="center">Page {safePage + 1}/{totalPages} (j/k to scroll)</Hint>}
|
|
1027
1038
|
</Box>
|
|
1028
1039
|
|
|
1029
|
-
{/*
|
|
1030
|
-
<Box height={
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
const isUser = msg.type === 'user';
|
|
1040
|
-
const isSystem = msg.type === 'system';
|
|
1041
|
-
const roleLabel = isUser ? '👤 You' : isSystem ? '⚙ System' : '🤖 Assistant';
|
|
1042
|
-
const roleColor = isUser ? 'green' : isSystem ? 'gray' : 'cyan';
|
|
1043
|
-
return (
|
|
1044
|
-
<Box key={msg.id} flexDirection="column" marginBottom={1}>
|
|
1045
|
-
<Text color={roleColor} bold>{roleLabel}</Text>
|
|
1046
|
-
{isUser ? (
|
|
1047
|
-
<Text>{text}</Text>
|
|
1048
|
-
) : (
|
|
1049
|
-
<Ansi>{applyMarkdown(text, theme)}</Ansi>
|
|
1050
|
-
)}
|
|
1051
|
-
</Box>
|
|
1052
|
-
);
|
|
1053
|
-
})}
|
|
1040
|
+
{/* 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}>
|
|
1044
|
+
<SelectInput
|
|
1045
|
+
items={secondaryMenu?.items || []}
|
|
1046
|
+
onSelect={secondaryMenu?.onSelect}
|
|
1047
|
+
/>
|
|
1048
|
+
</Box>
|
|
1049
|
+
<Hint>ESC Back · ↑↓ Select Action</Hint>
|
|
1054
1050
|
</Box>
|
|
1055
1051
|
</Box>
|
|
1056
1052
|
);
|
|
1057
1053
|
}
|
|
1058
1054
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
const HIST_VISIBLE = Math.max(1, MID_H - 1);
|
|
1055
|
+
// History List View (Default)
|
|
1056
|
+
const HIST_VISIBLE = MID_H - 2;
|
|
1062
1057
|
const start = Math.min(listOffset, Math.max(0, groupedHistoryItems.length - HIST_VISIBLE));
|
|
1063
1058
|
const slicedItems = groupedHistoryItems.slice(start, start + HIST_VISIBLE);
|
|
1064
1059
|
|
|
1065
1060
|
return (
|
|
1066
1061
|
<Box width={VIEW_W} height={MID_H} flexDirection="row">
|
|
1067
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
1062
|
+
<Box flexDirection="column" flexGrow={1} paddingX={1}>
|
|
1068
1063
|
<SelectInput
|
|
1069
1064
|
key={`${historyCursor ?? 'first'}:${slicedItems.length}:${start}`}
|
|
1070
1065
|
items={slicedItems}
|
|
1071
1066
|
onSelect={item => {
|
|
1072
|
-
if (String(item.value).startsWith('__group_')) return;
|
|
1067
|
+
if (String(item.value).startsWith('__group_')) return;
|
|
1073
1068
|
const session = historyList.find(h => h.id === item.value);
|
|
1074
1069
|
if (session) {
|
|
1075
1070
|
setSelectedHistory(session);
|
|
@@ -1082,12 +1077,14 @@ export const CliMenuManager: React.FC = () => {
|
|
|
1082
1077
|
const color = it?.color;
|
|
1083
1078
|
return (
|
|
1084
1079
|
<Text color={isGroup ? 'gray' : (color ? color : (isSelected ? 'cyan' : undefined))}>
|
|
1085
|
-
{label}
|
|
1080
|
+
{isSelected ? '> ' : ' '}{label}
|
|
1086
1081
|
</Text>
|
|
1087
1082
|
)
|
|
1088
1083
|
}}
|
|
1089
1084
|
/>
|
|
1090
|
-
<
|
|
1085
|
+
<Box marginTop="auto">
|
|
1086
|
+
<Hint>{i18nMap[lang].historyHint}</Hint>
|
|
1087
|
+
</Box>
|
|
1091
1088
|
</Box>
|
|
1092
1089
|
<ScrollBar total={groupedHistoryItems.length} offset={start} height={MID_H} />
|
|
1093
1090
|
</Box>
|