@@ -153,6 +153,7 @@ export type ChatProps = {
153153 onDraftChange : ( next : string ) => void ;
154154 onRequestUpdate ?: ( ) => void ;
155155 onHistoryKeydown ?: ( input : ChatInputHistoryKeyInput ) => ChatInputHistoryKeyResult ;
156+ onSlashIntent ?: ( ) => void | Promise < void > ;
156157 onSend : ( ) => void ;
157158 onCompact ?: ( ) => void | Promise < void > ;
158159 onOpenSessionCheckpoints ?: ( ) => void | Promise < void > ;
@@ -454,6 +455,7 @@ interface ChatEphemeralState {
454455 slashMenuCommand : SlashCommandDef | null ;
455456 slashMenuArgItems : string [ ] ;
456457 slashMenuExpanded : boolean ;
458+ slashCommandRefreshPending : boolean ;
457459 searchOpen : boolean ;
458460 searchQuery : string ;
459461 pinnedExpanded : boolean ;
@@ -479,6 +481,7 @@ function createChatEphemeralState(): ChatEphemeralState {
479481 slashMenuCommand : null ,
480482 slashMenuArgItems : [ ] ,
481483 slashMenuExpanded : false ,
484+ slashCommandRefreshPending : false ,
482485 searchOpen : false ,
483486 searchQuery : "" ,
484487 pinnedExpanded : false ,
@@ -1106,10 +1109,44 @@ function closeSlashMenuIfNeeded(requestUpdate: () => void): void {
11061109 requestUpdate ( ) ;
11071110}
11081111
1109- function updateSlashMenu ( value : string , requestUpdate : ( ) => void ) : void {
1112+ function requestSlashCommandRefresh (
1113+ value : string ,
1114+ props : ChatProps ,
1115+ requestUpdate : ( ) => void ,
1116+ getCurrentValue ?: ( ) => string ,
1117+ ) : void {
1118+ if ( ! props . onSlashIntent || vs . slashCommandRefreshPending ) {
1119+ return ;
1120+ }
1121+ const refresh = props . onSlashIntent ( ) ;
1122+ if ( ! refresh || typeof refresh . then !== "function" ) {
1123+ return ;
1124+ }
1125+ vs . slashCommandRefreshPending = true ;
1126+ void Promise . resolve ( refresh ) . finally ( ( ) => {
1127+ vs . slashCommandRefreshPending = false ;
1128+ const nextValue = getCurrentValue ?.( ) ?? props . getDraft ?.( ) ?? value ;
1129+ if ( ! nextValue . startsWith ( "/" ) ) {
1130+ closeSlashMenuIfNeeded ( requestUpdate ) ;
1131+ return ;
1132+ }
1133+ updateSlashMenu ( nextValue , requestUpdate , props , { skipSlashIntent : true } ) ;
1134+ } ) ;
1135+ }
1136+
1137+ function updateSlashMenu (
1138+ value : string ,
1139+ requestUpdate : ( ) => void ,
1140+ props : ChatProps ,
1141+ opts : { skipSlashIntent ?: boolean } = { } ,
1142+ getCurrentValue ?: ( ) => string ,
1143+ ) : void {
11101144 // Arg mode: /command <partial-arg>
11111145 const argMatch = value . match ( / ^ \/ ( \S + ) \s ( .* ) $ / ) ;
11121146 if ( argMatch ) {
1147+ if ( ! opts . skipSlashIntent ) {
1148+ requestSlashCommandRefresh ( value , props , requestUpdate , getCurrentValue ) ;
1149+ }
11131150 const cmdName = argMatch [ 1 ] . toLowerCase ( ) ;
11141151 const argFilter = argMatch [ 2 ] . toLowerCase ( ) ;
11151152 const cmd = SLASH_COMMANDS . find ( ( c ) => c . name === cmdName ) ;
@@ -1135,6 +1172,9 @@ function updateSlashMenu(value: string, requestUpdate: () => void): void {
11351172 // Command mode: /partial-command
11361173 const match = value . match ( / ^ \/ ( \S * ) $ / ) ;
11371174 if ( match ) {
1175+ if ( ! opts . skipSlashIntent ) {
1176+ requestSlashCommandRefresh ( value , props , requestUpdate , getCurrentValue ) ;
1177+ }
11381178 const items = getSlashCommandCompletions ( match [ 1 ] , { showAll : vs . slashMenuExpanded } ) ;
11391179 vs . slashMenuItems = items ;
11401180 vs . slashMenuOpen = items . length > 0 ;
@@ -1512,7 +1552,7 @@ function renderSlashMenu(
15121552 e . preventDefault ( ) ;
15131553 e . stopPropagation ( ) ;
15141554 vs . slashMenuExpanded = true ;
1515- updateSlashMenu ( draft , requestUpdate ) ;
1555+ updateSlashMenu ( draft , requestUpdate , props ) ;
15161556 } }
15171557 >
15181558 Show ${ hiddenCount } more command${ hiddenCount !== 1 ? "s" : "" }
@@ -1941,7 +1981,7 @@ export function renderChat(props: ChatProps) {
19411981 if ( hostDraftNeeded || target . value . startsWith ( "/" ) || hasVisibleSlashMenuState ( ) ) {
19421982 commitComposerDraft ( props , target . value ) ;
19431983 }
1944- updateSlashMenu ( target . value , requestUpdate ) ;
1984+ updateSlashMenu ( target . value , requestUpdate , props , { } , ( ) => target . value ) ;
19451985 } ;
19461986 const handleBlur = ( e : FocusEvent ) => {
19471987 const target = e . target as HTMLTextAreaElement ;
0 commit comments