@@ -700,7 +700,7 @@ export const Chat = ({
700700 } )
701701 } )
702702
703- // handleSlashItemClick is defined later after openPublishMode is available
703+ // handleSlashItemClick is defined later after feedback/publish stores are available
704704
705705 const handleMentionItemClick = useCallback (
706706 ( index : number ) => {
@@ -779,24 +779,52 @@ export const Chat = ({
779779
780780 const publishMutation = usePublishMutation ( )
781781
782- // Click handler for slash menu items (defined here after openPublishMode is available)
782+ // Click handler for slash menu items - executes command immediately
783783 const handleSlashItemClick = useCallback (
784784 async ( index : number ) => {
785785 const selected = slashMatches [ index ]
786786 if ( ! selected ) return
787+
787788 // Execute the selected slash command immediately
788789 const commandString = `/${ selected . id } `
789790 setSlashSelectedIndex ( 0 )
791+
792+ ensureQueueActiveBeforeSubmit ( )
790793 const result = await onSubmitPrompt ( commandString , agentMode )
794+
791795 if ( result ?. openFeedbackMode ) {
796+ // Save the feedback text that was set by the command handler before opening feedback mode
797+ const prefilledText = useFeedbackStore . getState ( ) . feedbackText
798+ const prefilledCursor = useFeedbackStore . getState ( ) . feedbackCursor
792799 saveCurrentInput ( '' , 0 )
793800 openFeedbackForMessage ( null )
801+ // Restore the prefilled text after openFeedbackForMessage resets it
802+ if ( prefilledText ) {
803+ useFeedbackStore . getState ( ) . setFeedbackText ( prefilledText )
804+ useFeedbackStore . getState ( ) . setFeedbackCursor ( prefilledCursor )
805+ }
794806 }
795807 if ( result ?. openPublishMode ) {
796- openPublishMode ( )
808+ if ( result . preSelectAgents && result . preSelectAgents . length > 0 ) {
809+ // preSelectAgents already sets publishMode: true, so don't call openPublishMode
810+ // which would reset the selectedAgentIds
811+ preSelectAgents ( result . preSelectAgents )
812+ } else {
813+ openPublishMode ( )
814+ }
797815 }
798816 } ,
799- [ slashMatches , setSlashSelectedIndex , onSubmitPrompt , agentMode , saveCurrentInput , openFeedbackForMessage , openPublishMode ] ,
817+ [
818+ slashMatches ,
819+ setSlashSelectedIndex ,
820+ ensureQueueActiveBeforeSubmit ,
821+ onSubmitPrompt ,
822+ agentMode ,
823+ saveCurrentInput ,
824+ openFeedbackForMessage ,
825+ openPublishMode ,
826+ preSelectAgents ,
827+ ] ,
800828 )
801829
802830 const inputValueRef = useRef ( inputValue )
@@ -902,16 +930,24 @@ export const Chat = ({
902930 } )
903931
904932 if ( result ?. openFeedbackMode ) {
933+ // Save the feedback text that was set by the command handler before opening feedback mode
934+ const prefilledText = useFeedbackStore . getState ( ) . feedbackText
935+ const prefilledCursor = useFeedbackStore . getState ( ) . feedbackCursor
905936 saveCurrentInput ( '' , 0 )
906937 openFeedbackForMessage ( null )
938+ // Restore the prefilled text after openFeedbackForMessage resets it
939+ if ( prefilledText ) {
940+ useFeedbackStore . getState ( ) . setFeedbackText ( prefilledText )
941+ useFeedbackStore . getState ( ) . setFeedbackCursor ( prefilledCursor )
942+ }
907943 }
908944
909945 if ( result ?. openPublishMode ) {
910946 if ( result . preSelectAgents && result . preSelectAgents . length > 0 ) {
911- // Pre-select agents and skip to confirmation
947+ // preSelectAgents already sets publishMode: true, so don't call openPublishMode
948+ // which would reset the selectedAgentIds
912949 preSelectAgents ( result . preSelectAgents )
913950 } else {
914- // Open selection UI
915951 openPublishMode ( )
916952 }
917953 }
@@ -1028,28 +1064,9 @@ export const Chat = ({
10281064 } ,
10291065 onSlashMenuDown : ( ) => setSlashSelectedIndex ( ( prev ) => prev + 1 ) ,
10301066 onSlashMenuUp : ( ) => setSlashSelectedIndex ( ( prev ) => prev - 1 ) ,
1031- onSlashMenuTab : async ( ) => {
1032- // If only one match, execute it immediately (unless the command opts out)
1033- if ( slashMatches . length === 1 ) {
1034- const selected = slashMatches [ 0 ]
1035- if ( ! selected ) return
1036- // Don't auto-execute commands that opt out (e.g. /exit)
1037- if ( selected . noTabAutoExecute ) {
1038- return
1039- }
1040- const commandString = `/${ selected . id } `
1041- setSlashSelectedIndex ( 0 )
1042- const result = await onSubmitPrompt ( commandString , agentMode )
1043- if ( result ?. openFeedbackMode ) {
1044- saveCurrentInput ( '' , 0 )
1045- openFeedbackForMessage ( null )
1046- }
1047- if ( result ?. openPublishMode ) {
1048- openPublishMode ( )
1049- }
1050- return
1051- }
1052- // Otherwise cycle through options
1067+ onSlashMenuTab : ( ) => {
1068+ // Do nothing if there's only one match - user needs to press Enter to select
1069+ if ( slashMatches . length <= 1 ) return
10531070 setSlashSelectedIndex ( ( prev ) => ( prev + 1 ) % slashMatches . length )
10541071 } ,
10551072 onSlashMenuShiftTab : ( ) =>
@@ -1059,18 +1076,52 @@ export const Chat = ({
10591076 onSlashMenuSelect : async ( ) => {
10601077 const selected = slashMatches [ slashSelectedIndex ] || slashMatches [ 0 ]
10611078 if ( ! selected ) return
1079+
10621080 // Execute the selected slash command immediately
10631081 const commandString = `/${ selected . id } `
10641082 setSlashSelectedIndex ( 0 )
1083+
1084+ ensureQueueActiveBeforeSubmit ( )
10651085 const result = await onSubmitPrompt ( commandString , agentMode )
1086+
10661087 if ( result ?. openFeedbackMode ) {
1088+ // Save the feedback text that was set by the command handler before opening feedback mode
1089+ const prefilledText = useFeedbackStore . getState ( ) . feedbackText
1090+ const prefilledCursor = useFeedbackStore . getState ( ) . feedbackCursor
10671091 saveCurrentInput ( '' , 0 )
10681092 openFeedbackForMessage ( null )
1093+ // Restore the prefilled text after openFeedbackForMessage resets it
1094+ if ( prefilledText ) {
1095+ useFeedbackStore . getState ( ) . setFeedbackText ( prefilledText )
1096+ useFeedbackStore . getState ( ) . setFeedbackCursor ( prefilledCursor )
1097+ }
10691098 }
10701099 if ( result ?. openPublishMode ) {
1071- openPublishMode ( )
1100+ if ( result . preSelectAgents && result . preSelectAgents . length > 0 ) {
1101+ // preSelectAgents already sets publishMode: true, so don't call openPublishMode
1102+ // which would reset the selectedAgentIds
1103+ preSelectAgents ( result . preSelectAgents )
1104+ } else {
1105+ openPublishMode ( )
1106+ }
10721107 }
10731108 } ,
1109+ onSlashMenuComplete : ( ) => {
1110+ // Complete the word without executing - same as clicking on the item
1111+ const selected = slashMatches [ slashSelectedIndex ] || slashMatches [ 0 ]
1112+ if ( ! selected || slashContext . startIndex < 0 ) return
1113+ const before = inputValue . slice ( 0 , slashContext . startIndex )
1114+ const after = inputValue . slice (
1115+ slashContext . startIndex + 1 + slashContext . query . length ,
1116+ )
1117+ const replacement = `/${ selected . id } `
1118+ setInputValue ( {
1119+ text : before + replacement + after ,
1120+ cursorPosition : before . length + replacement . length ,
1121+ lastEditDueToNav : false ,
1122+ } )
1123+ setSlashSelectedIndex ( 0 )
1124+ } ,
10741125 onMentionMenuDown : ( ) => setAgentSelectedIndex ( ( prev ) => prev + 1 ) ,
10751126 onMentionMenuUp : ( ) => setAgentSelectedIndex ( ( prev ) => prev - 1 ) ,
10761127 onMentionMenuTab : ( ) => {
@@ -1114,6 +1165,33 @@ export const Chat = ({
11141165 // Try current selection, fall back to first item
11151166 trySelectAtIndex ( agentSelectedIndex ) || trySelectAtIndex ( 0 )
11161167 } ,
1168+ onMentionMenuComplete : ( ) => {
1169+ // Complete the word without executing - same as select for mentions
1170+ if ( mentionContext . startIndex < 0 ) return
1171+
1172+ let replacement : string
1173+ const index = agentSelectedIndex
1174+ if ( index < agentMatches . length ) {
1175+ const selected = agentMatches [ index ] || agentMatches [ 0 ]
1176+ if ( ! selected ) return
1177+ replacement = `@${ selected . displayName } `
1178+ } else {
1179+ const fileIndex = index - agentMatches . length
1180+ const selectedFile = fileMatches [ fileIndex ] || fileMatches [ 0 ]
1181+ if ( ! selectedFile ) return
1182+ replacement = `@${ selectedFile . filePath } `
1183+ }
1184+ const before = inputValue . slice ( 0 , mentionContext . startIndex )
1185+ const after = inputValue . slice (
1186+ mentionContext . startIndex + 1 + mentionContext . query . length ,
1187+ )
1188+ setInputValue ( {
1189+ text : before + replacement + after ,
1190+ cursorPosition : before . length + replacement . length ,
1191+ lastEditDueToNav : false ,
1192+ } )
1193+ setAgentSelectedIndex ( 0 )
1194+ } ,
11171195 onOpenFileMenuWithTab : ( ) => {
11181196 const safeCursor = Math . max (
11191197 0 ,
@@ -1187,8 +1265,13 @@ export const Chat = ({
11871265 setSlashSelectedIndex ,
11881266 slashMatches ,
11891267 slashSelectedIndex ,
1268+ ensureQueueActiveBeforeSubmit ,
11901269 onSubmitPrompt ,
11911270 agentMode ,
1271+ saveCurrentInput ,
1272+ openFeedbackForMessage ,
1273+ openPublishMode ,
1274+ preSelectAgents ,
11921275 setAgentSelectedIndex ,
11931276 agentMatches ,
11941277 fileMatches ,
0 commit comments