@@ -792,26 +792,30 @@ export function useTypeahead({
792792 }
793793
794794 // Determine whether to display the argument hint and command suggestions.
795+ // Only consider text up to the cursor — when the cursor is mid-input (e.g.,
796+ // user typed "/com" before existing text), text after the cursor shouldn't
797+ // affect command matching or argument detection.
798+ const commandInput = value . substring ( 0 , effectiveCursorOffset ) ;
795799 if (
796800 mode === 'prompt' &&
797- isCommandInput ( value ) &&
801+ isCommandInput ( commandInput ) &&
798802 effectiveCursorOffset > 0 &&
799- ! hasCommandWithArguments ( isAtEndWithWhitespace , value )
803+ ! hasCommandWithArguments ( isAtEndWithWhitespace , commandInput )
800804 ) {
801805 let commandArgumentHint : string | undefined ;
802- if ( value . length > 1 ) {
806+ if ( commandInput . length > 1 ) {
803807 // We have a partial or complete command without arguments
804808 // Check if it matches a command exactly and has an argument hint
805809
806810 // Extract command name: everything after / until the first space (or end)
807- const spaceIndex = value . indexOf ( ' ' ) ;
808- const commandName = spaceIndex === - 1 ? value . slice ( 1 ) : value . slice ( 1 , spaceIndex ) ;
811+ const spaceIndex = commandInput . indexOf ( ' ' ) ;
812+ const commandName = spaceIndex === - 1 ? commandInput . slice ( 1 ) : commandInput . slice ( 1 , spaceIndex ) ;
809813
810814 // Check if there are real arguments (non-whitespace after the command)
811- const hasRealArguments = spaceIndex !== - 1 && value . slice ( spaceIndex + 1 ) . trim ( ) . length > 0 ;
815+ const hasRealArguments = spaceIndex !== - 1 && commandInput . slice ( spaceIndex + 1 ) . trim ( ) . length > 0 ;
812816
813817 // Check if input is exactly "command + single space" (ready for arguments)
814- const hasExactlyOneTrailingSpace = spaceIndex !== - 1 && value . length === spaceIndex + 1 ;
818+ const hasExactlyOneTrailingSpace = spaceIndex !== - 1 && commandInput . length === spaceIndex + 1 ;
815819
816820 // If input has a space after the command, don't show suggestions
817821 // This prevents Enter from selecting a different command after Tab completion
@@ -826,8 +830,8 @@ export function useTypeahead({
826830 commandArgumentHint = exactMatch . argumentHint ;
827831 }
828832 // Priority 2: Progressive hint from argNames (show when trailing space)
829- else if ( exactMatch ?. type === 'prompt' && exactMatch . argNames ?. length && value . endsWith ( ' ' ) ) {
830- const argsText = value . slice ( spaceIndex + 1 ) ;
833+ else if ( exactMatch ?. type === 'prompt' && exactMatch . argNames ?. length && commandInput . endsWith ( ' ' ) ) {
834+ const argsText = commandInput . slice ( spaceIndex + 1 ) ;
831835 const typedArgs = parseArguments ( argsText ) ;
832836 commandArgumentHint = generateProgressiveArgumentHint ( exactMatch . argNames , typedArgs ) ;
833837 }
@@ -846,7 +850,7 @@ export function useTypeahead({
846850 // (set above when hasExactlyOneTrailingSpace is true)
847851 }
848852
849- const commandItems = generateCommandSuggestions ( value , commands ) ;
853+ const commandItems = generateCommandSuggestions ( commandInput , commands ) ;
850854 setSuggestionsState ( ( ) => ( {
851855 commandArgumentHint,
852856 suggestions : commandItems ,
@@ -867,7 +871,7 @@ export function useTypeahead({
867871 // because there may be relevant @ symbol and file suggestions.
868872 debouncedFetchFileSuggestions . cancel ( ) ;
869873 clearSuggestions ( ) ;
870- } else if ( isCommandInput ( value ) && hasCommandWithArguments ( isAtEndWithWhitespace , value ) ) {
874+ } else if ( isCommandInput ( commandInput ) && hasCommandWithArguments ( isAtEndWithWhitespace , commandInput ) ) {
871875 // If we have a command with arguments (no trailing space), clear any stale hint
872876 // This prevents the hint from flashing when transitioning between states
873877 setSuggestionsState ( prev => ( prev . commandArgumentHint ? { ...prev , commandArgumentHint : undefined } : prev ) ) ;
@@ -1030,14 +1034,20 @@ export function useTypeahead({
10301034
10311035 if ( suggestionType === 'command' && index < suggestions . length ) {
10321036 if ( suggestion ) {
1033- applyCommandSuggestion (
1034- suggestion ,
1035- false , // don't execute on tab
1036- commands ,
1037- onInputChange ,
1038- setCursorOffset ,
1039- onSubmit ,
1040- ) ;
1037+ // Splice the completed command at the cursor position, preserving
1038+ // any text after the cursor (e.g., user typed "/com" before existing text).
1039+ const metadata = suggestion . metadata ;
1040+ if (
1041+ metadata &&
1042+ typeof metadata === 'object' &&
1043+ 'name' in metadata &&
1044+ 'type' in metadata
1045+ ) {
1046+ const commandName = getCommandName ( metadata as Command ) ;
1047+ const replacement = `/${ commandName } ` ;
1048+ onInputChange ( replacement + input . slice ( cursorOffset ) ) ;
1049+ setCursorOffset ( replacement . length ) ;
1050+ }
10411051 clearSuggestions ( ) ;
10421052 }
10431053 } else if ( suggestionType === 'custom-title' && suggestions . length > 0 ) {
0 commit comments