@@ -153,6 +153,7 @@ export const PromptInput = React.memo(function PromptInput({
153153 const [ showSkillsDropdown , setShowSkillsDropdown ] = useState ( false ) ;
154154 const [ openRawModelDropdown , setOpenRawModelDropdown ] = useState ( false ) ;
155155 const [ showModelDropdown , setShowModelDropdown ] = useState ( false ) ;
156+ const [ showKeybindMenu , setShowKeybindMenu ] = useState ( false ) ;
156157 const [ fileMentionItems , setFileMentionItems ] = useState < FileMentionItem [ ] > ( ( ) => scanFileMentionItems ( projectRoot ) ) ;
157158 const [ dismissedFileMentionKey , setDismissedFileMentionKey ] = useState < string | null > ( null ) ;
158159 const [ hasTerminalFocus , setHasTerminalFocus ] = useState ( true ) ;
@@ -182,6 +183,7 @@ export const PromptInput = React.memo(function PromptInput({
182183 ! showSkillsDropdown &&
183184 ! showModelDropdown &&
184185 ! openRawModelDropdown &&
186+ ! showKeybindMenu &&
185187 fileMentionToken !== null &&
186188 fileMentionKey !== dismissedFileMentionKey ;
187189 const slashItems = React . useMemo ( ( ) => buildSlashCommands ( skills ) , [ skills ] ) ;
@@ -192,12 +194,20 @@ export const PromptInput = React.memo(function PromptInput({
192194 const slashToken = getCurrentSlashToken ( buffer ) ;
193195 const slashMenu = React . useMemo (
194196 ( ) =>
195- showSkillsDropdown || showModelDropdown || openRawModelDropdown || showFileMentionMenu
197+ showSkillsDropdown || showModelDropdown || openRawModelDropdown || showFileMentionMenu || showKeybindMenu
196198 ? [ ]
197199 : slashToken
198200 ? filterSlashCommands ( slashItems , slashToken )
199201 : [ ] ,
200- [ showSkillsDropdown , showModelDropdown , openRawModelDropdown , showFileMentionMenu , slashToken , slashItems ]
202+ [
203+ showSkillsDropdown ,
204+ showModelDropdown ,
205+ openRawModelDropdown ,
206+ showFileMentionMenu ,
207+ showKeybindMenu ,
208+ slashToken ,
209+ slashItems ,
210+ ]
201211 ) ;
202212 const showMenu = slashMenu . length > 0 ;
203213 const promptHistoryKey = React . useMemo ( ( ) => promptHistory . join ( "\0" ) , [ promptHistory ] ) ;
@@ -219,8 +229,14 @@ export const PromptInput = React.memo(function PromptInput({
219229 ? busyStatusText
220230 : `enter send · shift+enter newline · @ files · ctrl+v image · / commands · ctrl+d exit${ processOrPasteHint } ` ;
221231 const showFooterText = useMemo (
222- ( ) => showMenu || showSkillsDropdown || openRawModelDropdown || showModelDropdown || showFileMentionMenu ,
223- [ showMenu , showSkillsDropdown , showModelDropdown , openRawModelDropdown , showFileMentionMenu ]
232+ ( ) =>
233+ showMenu ||
234+ showSkillsDropdown ||
235+ openRawModelDropdown ||
236+ showModelDropdown ||
237+ showFileMentionMenu ||
238+ showKeybindMenu ,
239+ [ showMenu , showSkillsDropdown , showModelDropdown , openRawModelDropdown , showFileMentionMenu , showKeybindMenu ]
224240 ) ;
225241 const inputContentWidth = Math . max ( 1 , screenWidth - PROMPT_PREFIX_WIDTH ) ;
226242
@@ -333,7 +349,14 @@ export const PromptInput = React.memo(function PromptInput({
333349
334350 // Check custom keybinds before hardcoded shortcuts.
335351 // Only match when no dropdown/menu is open to avoid conflicts.
336- if ( ! openRawModelDropdown && ! showSkillsDropdown && ! showModelDropdown && ! showMenu && ! showFileMentionMenu ) {
352+ if (
353+ ! openRawModelDropdown &&
354+ ! showSkillsDropdown &&
355+ ! showModelDropdown &&
356+ ! showMenu &&
357+ ! showFileMentionMenu &&
358+ ! showKeybindMenu
359+ ) {
337360 for ( const { match, action } of keybindMatchers ) {
338361 if ( match ( input , key ) ) {
339362 const item = slashItems . find ( ( s ) => s . name === action ) ;
@@ -352,6 +375,10 @@ export const PromptInput = React.memo(function PromptInput({
352375 if ( showFileMentionMenu ) {
353376 return ;
354377 }
378+ if ( showKeybindMenu ) {
379+ setShowKeybindMenu ( false ) ;
380+ return ;
381+ }
355382 if ( busy ) {
356383 onInterrupt ( ) ;
357384 setStatusMessage ( "Interrupting…" ) ;
@@ -409,7 +436,7 @@ export const PromptInput = React.memo(function PromptInput({
409436 setPendingExit ( false ) ;
410437 }
411438
412- if ( openRawModelDropdown || showSkillsDropdown || showModelDropdown ) {
439+ if ( openRawModelDropdown || showSkillsDropdown || showModelDropdown || showKeybindMenu ) {
413440 return ;
414441 }
415442
@@ -675,6 +702,7 @@ export const PromptInput = React.memo(function PromptInput({
675702 setImageUrls ( [ ] ) ;
676703 setSelectedSkills ( [ ] ) ;
677704 setShowSkillsDropdown ( false ) ;
705+ setShowKeybindMenu ( false ) ;
678706 exitHistoryBrowsing ( ) ;
679707 resetPastes ( ) ;
680708 }
@@ -738,7 +766,15 @@ export const PromptInput = React.memo(function PromptInput({
738766 return ;
739767 }
740768 if ( item . kind === "keybind" ) {
741- handleKeybindCommand ( ) ;
769+ const parts = buffer . text . trim ( ) . split ( / \s + / ) ;
770+ // If the user typed extra args (add/remove), process as subcommand.
771+ // Otherwise open the interactive menu.
772+ if ( parts . length > 1 ) {
773+ handleKeybindCommand ( ) ;
774+ } else {
775+ clearSlashToken ( ) ;
776+ setShowKeybindMenu ( true ) ;
777+ }
742778 return ;
743779 }
744780 if ( item . kind === "exit" ) {
@@ -946,6 +982,31 @@ export const PromptInput = React.memo(function PromptInput({
946982 onModelConfigChange = { onModelConfigChange }
947983 onStatusMessage = { setStatusMessage }
948984 />
985+ { showKeybindMenu ? (
986+ < Box flexDirection = "column" marginBottom = { 1 } width = { screenWidth } >
987+ < Box marginLeft = { 2 } >
988+ < Text bold > Keybinds</ Text >
989+ </ Box >
990+ { ( keybinds && Object . keys ( keybinds ) . length > 0
991+ ? Object . entries ( keybinds ) . map ( ( [ shortcut , action ] ) => (
992+ < Box key = { shortcut } marginLeft = { 4 } >
993+ < Text > { shortcut } </ Text >
994+ < Text dimColor > → /{ action } </ Text >
995+ </ Box >
996+ ) )
997+ : null ) || (
998+ < Box marginLeft = { 4 } >
999+ < Text dimColor > (no keybinds configured)</ Text >
1000+ </ Box >
1001+ ) }
1002+ < Box marginLeft = { 2 } marginTop = { 1 } >
1003+ < Text dimColor > /keybind add <shortcut> <action> to add</ Text >
1004+ </ Box >
1005+ < Box marginLeft = { 2 } >
1006+ < Text dimColor > /keybind remove <shortcut> to remove</ Text >
1007+ </ Box >
1008+ </ Box >
1009+ ) : null }
9491010 < FileMentionMenu
9501011 open = { showFileMentionMenu }
9511012 width = { screenWidth }
0 commit comments