codemini-cli 0.1.11 → 0.1.13
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/core/agent-loop.js +17 -0
- package/src/core/chat-runtime.js +477 -46
- package/src/core/config-store.js +39 -3
- package/src/core/reply-language.js +25 -0
- package/src/core/shell-profile.js +1 -1
- package/src/core/soul.js +3 -1
- package/src/core/tools.js +884 -8
- package/src/tui/chat-app.js +255 -16
package/src/tui/chat-app.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Box, Text, useApp, useInput } from 'ink';
|
|
|
3
3
|
import { shouldCaptureEscapeSequence } from './input-escape.js';
|
|
4
4
|
|
|
5
5
|
const h = React.createElement;
|
|
6
|
+
const SUGGESTION_PAGE_SIZE = 8;
|
|
6
7
|
const BANNER = [
|
|
7
8
|
' ██████ ██████ ██████ ███████ ███ ███ ██ ███ ██ ██ ',
|
|
8
9
|
'██ ██ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ',
|
|
@@ -122,13 +123,13 @@ const TUI_COPY = {
|
|
|
122
123
|
},
|
|
123
124
|
suggestion: {
|
|
124
125
|
singleTab: 'Tab 补全当前命令',
|
|
125
|
-
navFill: 'Tab
|
|
126
|
-
navEnter: 'Tab 进入切换模式,再用 ↑↓
|
|
126
|
+
navFill: 'Tab 保持切换模式,↑↓选择,←→翻页,Enter 填入',
|
|
127
|
+
navEnter: 'Tab 进入切换模式,再用 ↑↓ 选择,←→翻页',
|
|
127
128
|
noSuggestions: '/ 查看命令,Tab 自动补全,↑↓ 历史,Ctrl+T 展开工具',
|
|
128
129
|
oneNav: 'Tab 或 Enter 填入当前命令,↑↓ 历史',
|
|
129
130
|
oneIdle: 'Tab 补全当前唯一候选,Enter 直接发送,↑↓ 历史',
|
|
130
|
-
manyNav: (count) => `Tab
|
|
131
|
-
manyIdle: (count) => `Tab 进入候选切换 (${count} 项),↑↓
|
|
131
|
+
manyNav: (count) => `Tab 切换候选,↑↓选择,←→翻页,Enter 填入 (${count} 项)`,
|
|
132
|
+
manyIdle: (count) => `Tab 进入候选切换 (${count} 项),↑↓ 历史,←→翻页`
|
|
132
133
|
},
|
|
133
134
|
runtime: {
|
|
134
135
|
sendingToGateway: '正在发送到网关',
|
|
@@ -224,13 +225,13 @@ const TUI_COPY = {
|
|
|
224
225
|
},
|
|
225
226
|
suggestion: {
|
|
226
227
|
singleTab: 'Tab completes the current command',
|
|
227
|
-
navFill: 'Tab stays in pick mode, ↑↓ select, Enter applies',
|
|
228
|
-
navEnter: 'Tab enters pick mode, then use ↑↓ to choose',
|
|
228
|
+
navFill: 'Tab stays in pick mode, ↑↓ select, ←→ page, Enter applies',
|
|
229
|
+
navEnter: 'Tab enters pick mode, then use ↑↓ to choose, ←→ page',
|
|
229
230
|
noSuggestions: '/ shows commands, Tab autocompletes, ↑↓ history, Ctrl+T tools',
|
|
230
231
|
oneNav: 'Tab or Enter applies the current command, ↑↓ history',
|
|
231
232
|
oneIdle: 'Tab completes the only candidate, Enter sends, ↑↓ history',
|
|
232
|
-
manyNav: (count) => `Tab cycles candidates, ↑↓ select, Enter applies (${count} items)`,
|
|
233
|
-
manyIdle: (count) => `Tab enters candidate mode (${count} items), ↑↓ history`
|
|
233
|
+
manyNav: (count) => `Tab cycles candidates, ↑↓ select, ←→ page, Enter applies (${count} items)`,
|
|
234
|
+
manyIdle: (count) => `Tab enters candidate mode (${count} items), ↑↓ history, ←→ page`
|
|
234
235
|
},
|
|
235
236
|
runtime: {
|
|
236
237
|
sendingToGateway: 'sending to gateway',
|
|
@@ -546,6 +547,161 @@ function renderTextLine(msg, line, idx, color) {
|
|
|
546
547
|
);
|
|
547
548
|
}
|
|
548
549
|
|
|
550
|
+
export function parseAutoPlanSummaryMessage(text) {
|
|
551
|
+
const raw = String(text || '').trim();
|
|
552
|
+
if (!/^Auto plan finished\b/i.test(raw)) return null;
|
|
553
|
+
|
|
554
|
+
const lines = raw
|
|
555
|
+
.split('\n')
|
|
556
|
+
.map((line) => line.trim())
|
|
557
|
+
.filter(Boolean);
|
|
558
|
+
const parsed = {
|
|
559
|
+
statusTitle: lines[0] || '',
|
|
560
|
+
filePath: '',
|
|
561
|
+
planSummary: '',
|
|
562
|
+
finalSummary: '',
|
|
563
|
+
stepsTotal: '',
|
|
564
|
+
completed: '',
|
|
565
|
+
warnings: '',
|
|
566
|
+
failed: '',
|
|
567
|
+
warningSteps: '',
|
|
568
|
+
failedSteps: ''
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
for (const line of lines.slice(1)) {
|
|
572
|
+
if (line.startsWith('File: ')) parsed.filePath = line.slice('File: '.length).trim();
|
|
573
|
+
else if (line.startsWith('Plan Summary: ')) parsed.planSummary = line.slice('Plan Summary: '.length).trim();
|
|
574
|
+
else if (line.startsWith('Final Summary: ')) parsed.finalSummary = line.slice('Final Summary: '.length).trim();
|
|
575
|
+
else if (line.startsWith('Steps: ')) parsed.stepsTotal = line.slice('Steps: '.length).trim();
|
|
576
|
+
else if (line.startsWith('Completed: ')) parsed.completed = line.slice('Completed: '.length).trim();
|
|
577
|
+
else if (line.startsWith('Warnings: ')) parsed.warnings = line.slice('Warnings: '.length).trim();
|
|
578
|
+
else if (line.startsWith('Failed: ')) parsed.failed = line.slice('Failed: '.length).trim();
|
|
579
|
+
else if (line.startsWith('Warning steps: ')) parsed.warningSteps = line.slice('Warning steps: '.length).trim();
|
|
580
|
+
else if (line.startsWith('Failed steps: ')) parsed.failedSteps = line.slice('Failed steps: '.length).trim();
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return parsed;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function PlanSummaryBubble({ msg, copy }) {
|
|
587
|
+
const theme = roleStyle(msg.label);
|
|
588
|
+
const summary = msg.planSummary || parseAutoPlanSummaryMessage(msg.text);
|
|
589
|
+
if (!summary) return null;
|
|
590
|
+
|
|
591
|
+
const statusColor =
|
|
592
|
+
Number(summary.failed || 0) > 0 ? 'redBright' : Number(summary.warnings || 0) > 0 ? 'yellowBright' : 'greenBright';
|
|
593
|
+
const isEnglish = copy?.roleLabels?.system === 'SYSTEM';
|
|
594
|
+
const labels = isEnglish
|
|
595
|
+
? {
|
|
596
|
+
conclusion: 'Conclusion',
|
|
597
|
+
plan: 'Plan',
|
|
598
|
+
warnings: 'Warnings',
|
|
599
|
+
failed: 'Failed',
|
|
600
|
+
file: 'File',
|
|
601
|
+
steps: 'steps',
|
|
602
|
+
done: 'done',
|
|
603
|
+
warn: 'warn',
|
|
604
|
+
fail: 'fail'
|
|
605
|
+
}
|
|
606
|
+
: {
|
|
607
|
+
conclusion: '结论',
|
|
608
|
+
plan: '计划',
|
|
609
|
+
warnings: '警告',
|
|
610
|
+
failed: '失败',
|
|
611
|
+
file: '文件',
|
|
612
|
+
steps: '步骤',
|
|
613
|
+
done: '完成',
|
|
614
|
+
warn: '警告',
|
|
615
|
+
fail: '失败'
|
|
616
|
+
};
|
|
617
|
+
const metaItems = [
|
|
618
|
+
summary.stepsTotal ? `${labels.steps} ${summary.stepsTotal}` : '',
|
|
619
|
+
summary.completed ? `${labels.done} ${summary.completed}` : '',
|
|
620
|
+
summary.warnings ? `${labels.warn} ${summary.warnings}` : '',
|
|
621
|
+
summary.failed ? `${labels.fail} ${summary.failed}` : ''
|
|
622
|
+
].filter(Boolean);
|
|
623
|
+
const shortFile = summary.filePath ? trimText(summary.filePath, 96) : '';
|
|
624
|
+
|
|
625
|
+
return h(
|
|
626
|
+
Box,
|
|
627
|
+
{ marginBottom: 1, flexDirection: 'row' },
|
|
628
|
+
h(Box, { width: 2 }, h(Text, { color: theme.accent }, '│')),
|
|
629
|
+
h(
|
|
630
|
+
Box,
|
|
631
|
+
{
|
|
632
|
+
flexDirection: 'column',
|
|
633
|
+
borderStyle: 'round',
|
|
634
|
+
borderColor: theme.border,
|
|
635
|
+
paddingX: 1,
|
|
636
|
+
paddingY: 0,
|
|
637
|
+
width: '100%'
|
|
638
|
+
},
|
|
639
|
+
h(
|
|
640
|
+
Box,
|
|
641
|
+
{ justifyContent: 'space-between', marginBottom: summary.finalSummary ? 1 : 0 },
|
|
642
|
+
h(
|
|
643
|
+
Box,
|
|
644
|
+
null,
|
|
645
|
+
h(Text, { color: theme.badgeText, backgroundColor: theme.badgeBg }, ` ${messageLabel(msg.label, copy)} `),
|
|
646
|
+
h(Text, { color: 'gray' }, ' '),
|
|
647
|
+
h(Text, { color: statusColor }, summary.statusTitle)
|
|
648
|
+
),
|
|
649
|
+
h(Text, { color: theme.chrome }, ' ')
|
|
650
|
+
),
|
|
651
|
+
summary.finalSummary
|
|
652
|
+
? h(
|
|
653
|
+
Box,
|
|
654
|
+
{ marginBottom: summary.planSummary || metaItems.length > 0 || summary.warningSteps || summary.failedSteps || shortFile ? 1 : 0, flexDirection: 'column' },
|
|
655
|
+
h(Text, { color: statusColor }, labels.conclusion),
|
|
656
|
+
h(Text, { color: 'white' }, summary.finalSummary)
|
|
657
|
+
)
|
|
658
|
+
: null,
|
|
659
|
+
summary.planSummary
|
|
660
|
+
? h(
|
|
661
|
+
Box,
|
|
662
|
+
{ marginBottom: metaItems.length > 0 || summary.warningSteps || summary.failedSteps || shortFile ? 1 : 0, flexDirection: 'column' },
|
|
663
|
+
h(Text, { color: 'cyanBright' }, labels.plan),
|
|
664
|
+
h(Text, { color: 'gray' }, summary.planSummary)
|
|
665
|
+
)
|
|
666
|
+
: null,
|
|
667
|
+
metaItems.length > 0
|
|
668
|
+
? h(
|
|
669
|
+
Box,
|
|
670
|
+
{ marginBottom: summary.warningSteps || summary.failedSteps || shortFile ? 1 : 0 },
|
|
671
|
+
...metaItems.flatMap((item, idx) => [
|
|
672
|
+
idx > 0 ? h(Text, { key: `sep-${idx}`, color: 'gray' }, ' ') : null,
|
|
673
|
+
h(Text, { key: `meta-${idx}`, color: 'gray' }, item)
|
|
674
|
+
])
|
|
675
|
+
)
|
|
676
|
+
: null,
|
|
677
|
+
summary.warningSteps
|
|
678
|
+
? h(
|
|
679
|
+
Box,
|
|
680
|
+
{ marginBottom: summary.failedSteps || shortFile ? 1 : 0, flexDirection: 'column' },
|
|
681
|
+
h(Text, { color: 'yellowBright' }, labels.warnings),
|
|
682
|
+
h(Text, { color: 'gray' }, summary.warningSteps)
|
|
683
|
+
)
|
|
684
|
+
: null,
|
|
685
|
+
summary.failedSteps
|
|
686
|
+
? h(
|
|
687
|
+
Box,
|
|
688
|
+
{ marginBottom: shortFile ? 1 : 0, flexDirection: 'column' },
|
|
689
|
+
h(Text, { color: 'redBright' }, labels.failed),
|
|
690
|
+
h(Text, { color: 'gray' }, summary.failedSteps)
|
|
691
|
+
)
|
|
692
|
+
: null,
|
|
693
|
+
shortFile
|
|
694
|
+
? h(
|
|
695
|
+
Box,
|
|
696
|
+
{ flexDirection: 'column' },
|
|
697
|
+
h(Text, { color: 'gray' }, labels.file),
|
|
698
|
+
h(Text, { color: 'gray' }, shortFile)
|
|
699
|
+
)
|
|
700
|
+
: null
|
|
701
|
+
)
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
|
|
549
705
|
const BUBBLE_CHROME_ROWS = 4;
|
|
550
706
|
|
|
551
707
|
function charDisplayWidth(ch) {
|
|
@@ -728,7 +884,70 @@ function getSuggestionDisplay(item) {
|
|
|
728
884
|
return typeof item === 'string' ? item : String(item?.display || item?.value || '');
|
|
729
885
|
}
|
|
730
886
|
|
|
887
|
+
function getSuggestionDescription(item) {
|
|
888
|
+
return typeof item === 'string' ? '' : String(item?.description || '');
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
export function formatSuggestionDescription(text, maxChars = 40) {
|
|
892
|
+
const value = String(text || '').replace(/\s+/g, ' ').trim();
|
|
893
|
+
if (!value) return '';
|
|
894
|
+
const limit = Math.max(4, Number(maxChars) || 40);
|
|
895
|
+
if (value.length <= limit) return value;
|
|
896
|
+
return `${value.slice(0, limit - 3)}...`;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
export function getSuggestionPageState(commandSuggestions, menuIndex, pageSize = SUGGESTION_PAGE_SIZE) {
|
|
900
|
+
const items = Array.isArray(commandSuggestions) ? commandSuggestions : [];
|
|
901
|
+
const normalizedPageSize = Math.max(1, Number(pageSize) || SUGGESTION_PAGE_SIZE);
|
|
902
|
+
const safeIndex = items.length === 0 ? 0 : Math.max(0, Math.min(Number(menuIndex) || 0, items.length - 1));
|
|
903
|
+
const pageIndex = Math.floor(safeIndex / normalizedPageSize);
|
|
904
|
+
const pageCount = Math.max(1, Math.ceil(items.length / normalizedPageSize));
|
|
905
|
+
const pageStart = pageIndex * normalizedPageSize;
|
|
906
|
+
const pageEnd = Math.min(items.length, pageStart + normalizedPageSize);
|
|
907
|
+
return {
|
|
908
|
+
pageSize: normalizedPageSize,
|
|
909
|
+
safeIndex,
|
|
910
|
+
pageIndex,
|
|
911
|
+
pageCount,
|
|
912
|
+
pageStart,
|
|
913
|
+
pageEnd,
|
|
914
|
+
pageItems: items.slice(pageStart, pageEnd)
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
export function moveSuggestionSelection(currentIndex, itemCount, direction, pageSize = SUGGESTION_PAGE_SIZE) {
|
|
919
|
+
const total = Math.max(0, Number(itemCount) || 0);
|
|
920
|
+
if (total <= 0) return 0;
|
|
921
|
+
const normalizedPageSize = Math.max(1, Number(pageSize) || SUGGESTION_PAGE_SIZE);
|
|
922
|
+
const safeIndex = Math.max(0, Math.min(Number(currentIndex) || 0, total - 1));
|
|
923
|
+
|
|
924
|
+
if (direction === 'left') {
|
|
925
|
+
if (safeIndex < normalizedPageSize) return 0;
|
|
926
|
+
return Math.max(0, safeIndex - normalizedPageSize);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (direction === 'right') {
|
|
930
|
+
const currentPageStart = Math.floor(safeIndex / normalizedPageSize) * normalizedPageSize;
|
|
931
|
+
const currentPageEnd = Math.min(total, currentPageStart + normalizedPageSize);
|
|
932
|
+
if (currentPageEnd >= total) return safeIndex;
|
|
933
|
+
return Math.min(total - 1, safeIndex + normalizedPageSize);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (direction === 'up') {
|
|
937
|
+
return Math.max(0, safeIndex - 1);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
if (direction === 'down') {
|
|
941
|
+
return Math.min(total - 1, safeIndex + 1);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return safeIndex;
|
|
945
|
+
}
|
|
946
|
+
|
|
731
947
|
function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, contentWidth = 72, copy }) {
|
|
948
|
+
if (msg?.planSummary || parseAutoPlanSummaryMessage(msg?.text)) {
|
|
949
|
+
return h(PlanSummaryBubble, { msg, copy });
|
|
950
|
+
}
|
|
732
951
|
const theme = roleStyle(msg.label);
|
|
733
952
|
const allRows = buildMessageRows(msg, showToolDetails, contentWidth);
|
|
734
953
|
const start = rowWindow ? Math.max(0, rowWindow.start || 0) : 0;
|
|
@@ -870,7 +1089,8 @@ function MessageList({ messages, loaderTick, showToolDetails, contentWidth = 72,
|
|
|
870
1089
|
|
|
871
1090
|
function SuggestionPanel({ commandSuggestions, suggestionNav, menuIndex, copy }) {
|
|
872
1091
|
if (commandSuggestions.length === 0) return null;
|
|
873
|
-
const
|
|
1092
|
+
const pageState = getSuggestionPageState(commandSuggestions, menuIndex);
|
|
1093
|
+
const grouped = groupCommandSuggestions(pageState.pageItems);
|
|
874
1094
|
let flatIndex = -1;
|
|
875
1095
|
const panelHint =
|
|
876
1096
|
commandSuggestions.length === 1
|
|
@@ -892,7 +1112,7 @@ function SuggestionPanel({ commandSuggestions, suggestionNav, menuIndex, copy })
|
|
|
892
1112
|
Box,
|
|
893
1113
|
{ marginBottom: 1 },
|
|
894
1114
|
h(Text, { color: 'magentaBright' }, suggestionNav ? copy.generic.commandPaletteGroupedSelect : copy.generic.commandPaletteGroupedSuggestions),
|
|
895
|
-
h(Text, { color: 'gray' }, ` ${panelHint}`)
|
|
1115
|
+
h(Text, { color: 'gray' }, ` ${panelHint} · ${pageState.pageIndex + 1}/${pageState.pageCount}`)
|
|
896
1116
|
),
|
|
897
1117
|
...grouped.flatMap(([group, items]) => {
|
|
898
1118
|
const nodes = [
|
|
@@ -905,13 +1125,17 @@ function SuggestionPanel({ commandSuggestions, suggestionNav, menuIndex, copy })
|
|
|
905
1125
|
];
|
|
906
1126
|
items.forEach((c) => {
|
|
907
1127
|
flatIndex += 1;
|
|
908
|
-
const active = suggestionNav && menuIndex === flatIndex;
|
|
1128
|
+
const active = suggestionNav && menuIndex === pageState.pageStart + flatIndex;
|
|
909
1129
|
const label = getSuggestionDisplay(c);
|
|
1130
|
+
const description = formatSuggestionDescription(getSuggestionDescription(c), 42);
|
|
910
1131
|
nodes.push(
|
|
911
1132
|
h(
|
|
912
1133
|
Box,
|
|
913
1134
|
{ key: `opt-${group}-${getSuggestionValue(c)}` },
|
|
914
|
-
h(Text, { color: active ? 'black' : 'magenta', backgroundColor: active ? 'magentaBright' : undefined }, `${active ? ' > ' : ' '}${label}`)
|
|
1135
|
+
h(Text, { color: active ? 'black' : 'magenta', backgroundColor: active ? 'magentaBright' : undefined }, `${active ? ' > ' : ' '}${label}`),
|
|
1136
|
+
description
|
|
1137
|
+
? h(Text, { color: active ? 'black' : 'gray', backgroundColor: active ? 'magentaBright' : undefined }, ` ${description}`)
|
|
1138
|
+
: null
|
|
915
1139
|
)
|
|
916
1140
|
);
|
|
917
1141
|
});
|
|
@@ -1143,7 +1367,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1143
1367
|
|
|
1144
1368
|
const commandSuggestions =
|
|
1145
1369
|
inputValue.startsWith('/')
|
|
1146
|
-
?
|
|
1370
|
+
? runtime.getCompletionOptions(inputValue) || []
|
|
1147
1371
|
: [];
|
|
1148
1372
|
const hasTransientPanels =
|
|
1149
1373
|
commandSuggestions.length > 0 || pendingQueue.length > 0 || debugKeys || Boolean(planState?.total);
|
|
@@ -1338,9 +1562,16 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1338
1562
|
}
|
|
1339
1563
|
return;
|
|
1340
1564
|
}
|
|
1565
|
+
const parsedPlanSummary = result.type === 'system' ? parseAutoPlanSummaryMessage(result.text || '') : null;
|
|
1341
1566
|
setMessages((prev) => [
|
|
1342
1567
|
...prev,
|
|
1343
|
-
{
|
|
1568
|
+
{
|
|
1569
|
+
id: nextId(),
|
|
1570
|
+
label: 'system',
|
|
1571
|
+
text: result.text || '',
|
|
1572
|
+
color: 'yellowBright',
|
|
1573
|
+
...(parsedPlanSummary ? { planSummary: parsedPlanSummary } : {})
|
|
1574
|
+
}
|
|
1344
1575
|
]);
|
|
1345
1576
|
};
|
|
1346
1577
|
|
|
@@ -1688,7 +1919,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1688
1919
|
|
|
1689
1920
|
if (key.upArrow) {
|
|
1690
1921
|
if (suggestionNav && commandSuggestions.length > 0) {
|
|
1691
|
-
setMenuIndex((prev) =>
|
|
1922
|
+
setMenuIndex((prev) => moveSuggestionSelection(prev, commandSuggestions.length, 'up'));
|
|
1692
1923
|
return;
|
|
1693
1924
|
}
|
|
1694
1925
|
if (history.length === 0) return;
|
|
@@ -1714,7 +1945,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1714
1945
|
|
|
1715
1946
|
if (key.downArrow) {
|
|
1716
1947
|
if (suggestionNav && commandSuggestions.length > 0) {
|
|
1717
|
-
setMenuIndex((prev) =>
|
|
1948
|
+
setMenuIndex((prev) => moveSuggestionSelection(prev, commandSuggestions.length, 'down'));
|
|
1718
1949
|
return;
|
|
1719
1950
|
}
|
|
1720
1951
|
if (history.length === 0 || historyIndex === null) return;
|
|
@@ -1735,6 +1966,10 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1735
1966
|
return;
|
|
1736
1967
|
}
|
|
1737
1968
|
if (key.leftArrow) {
|
|
1969
|
+
if (suggestionNav && commandSuggestions.length > 0) {
|
|
1970
|
+
setMenuIndex((prev) => moveSuggestionSelection(prev, commandSuggestions.length, 'left'));
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1738
1973
|
setSuggestionNav(false);
|
|
1739
1974
|
const next = Math.max(0, cursorIndexRef.current - 1);
|
|
1740
1975
|
cursorIndexRef.current = next;
|
|
@@ -1742,6 +1977,10 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1742
1977
|
return;
|
|
1743
1978
|
}
|
|
1744
1979
|
if (key.rightArrow) {
|
|
1980
|
+
if (suggestionNav && commandSuggestions.length > 0) {
|
|
1981
|
+
setMenuIndex((prev) => moveSuggestionSelection(prev, commandSuggestions.length, 'right'));
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1745
1984
|
setSuggestionNav(false);
|
|
1746
1985
|
const next = Math.min(inputValue.length, cursorIndexRef.current + 1);
|
|
1747
1986
|
cursorIndexRef.current = next;
|