fix(chat): prevent shell prefix from corrupting input

This commit is contained in:
RyderAsking
2026-08-10 09:22:56 +00:00
parent 4e7eb81036
commit 0b2b697aa5
+22 -2
View File
@@ -1402,6 +1402,19 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
// Uses keyCode === 229 fallback for WebKit where compositionend fires before keydown.
if (isIMECompositionEvent(e)) return;
// Enter shell mode before CodeMirror inserts the trigger. Keeping the
// document unchanged also keeps the caret at the start for the first
// command character.
if (inputMode === 'normal' && e.key === '!') {
const selection = composerRef.current?.getSelection();
if (selection?.start === 0 && selection.end === 0) {
e.preventDefault();
setInputMode('shell');
closeAutocomplete();
return;
}
}
if (inputMode === 'shell' && e.key === 'Escape') {
e.preventDefault();
setInputMode('normal');
@@ -1723,13 +1736,20 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
const inputSource: FileMentionAutocompleteInputSource = isPasteInput ? 'paste' : 'manual';
// A leading `!` switches the composer into shell mode and is consumed.
// Mobile keyboards and paste may update the document without a usable
// keydown, so consume the trigger in the same editor transaction rather
// than moving the caret in a later frame against stale text.
if (inputMode === 'normal' && value.startsWith('!')) {
const shellCommand = value.slice(1);
const nextCursor = Math.max(0, selection.start - 1);
setInputMode('shell');
setMessage(shellCommand);
closeAutocomplete();
requestAnimationFrame(() => composerRef.current?.setSelection(nextCursor));
const editor = composerRef.current;
if (editor) {
editor.replaceRange(0, 1, '', nextCursor);
} else {
setMessage(shellCommand);
}
return;
}