@@ -1449,6 +1449,12 @@ export const ChatInput: React.FC<ChatInputProps> = ({
14491449 command : DEEP_REVIEW_SLASH_COMMAND ,
14501450 label : t ( 'chatInput.deepreviewAction' ) ,
14511451 } ,
1452+ {
1453+ kind : 'action' as const ,
1454+ id : 'reload-skills' ,
1455+ command : '/reload-skills' ,
1456+ label : t ( 'chatInput.reloadSkillsAction' ) ,
1457+ } ,
14521458 ...( ! derivedState ?. isProcessing
14531459 ? [
14541460 {
@@ -1949,6 +1955,47 @@ export const ChatInput: React.FC<ChatInputProps> = ({
19491955 threadGoalController ,
19501956 ] ) ;
19511957
1958+ const submitReloadSkillsFromInput = useCallback ( async ( ) => {
1959+ const message = inputState . value . trim ( ) ;
1960+ if ( ! / ^ \/ r e l o a d - s k i l l s \s * $ / i. test ( message ) ) {
1961+ notificationService . warning ( t ( 'chatInput.reloadSkillsUsage' ) ) ;
1962+ return ;
1963+ }
1964+
1965+ dispatchInput ( { type : 'CLEAR_VALUE' } ) ;
1966+ setQueuedInput ( null ) ;
1967+ setSlashCommandState ( { isActive : false , kind : 'modes' , query : '' , selectedIndex : 0 } ) ;
1968+
1969+ try {
1970+ // Re-fetch skill configs with forceRefresh=true. The Tauri command
1971+ // (skill_api.rs::get_skill_configs) calls SkillRegistry::global().refresh()
1972+ // before serializing the result, so this single call both refreshes
1973+ // the registry cache and returns the new view. Pass workspacePath so
1974+ // workspace-level skills (`.bitfun/skills/`, `.cursor/skills/`, etc.)
1975+ // are included in the count — without it, the registry falls back
1976+ // to user + built-in slots only and the toast would undercount.
1977+ const skills = await configAPI . getSkillConfigs ( {
1978+ forceRefresh : true ,
1979+ workspacePath : workspacePath || undefined ,
1980+ } ) ;
1981+ notificationService . success (
1982+ t ( 'chatInput.reloadSkillsDone' , { count : skills . length } ) ,
1983+ { duration : 3000 }
1984+ ) ;
1985+ } catch ( error ) {
1986+ log . error ( 'Failed to trigger /reload-skills' , { error } ) ;
1987+ dispatchInput ( { type : 'ACTIVATE' } ) ;
1988+ dispatchInput ( { type : 'SET_VALUE' , payload : message } ) ;
1989+ notificationService . error (
1990+ error instanceof Error ? error . message : t ( 'error.unknown' ) ,
1991+ {
1992+ title : t ( 'chatInput.reloadSkillsFailed' ) ,
1993+ duration : 5000 ,
1994+ }
1995+ ) ;
1996+ }
1997+ } , [ inputState . value , setQueuedInput , t , workspacePath ] ) ;
1998+
19521999 const submitDeepreviewFromInput = useCallback ( async ( ) => {
19532000 if ( ! effectiveTargetSessionId || ! effectiveTargetSession ) {
19542001 notificationService . error (
@@ -2211,6 +2258,11 @@ export const ChatInput: React.FC<ChatInputProps> = ({
22112258 return ;
22122259 }
22132260
2261+ if ( localSlashCommandsEnabled && / ^ \/ r e l o a d - s k i l l s \s * $ / i. test ( message ) ) {
2262+ await submitReloadSkillsFromInput ( ) ;
2263+ return ;
2264+ }
2265+
22142266 if ( localSlashCommandsEnabled && resolveTypedMcpPromptCommand ( message ) ) {
22152267 await submitMcpPromptFromInput ( ) ;
22162268 return ;
@@ -2243,6 +2295,11 @@ export const ChatInput: React.FC<ChatInputProps> = ({
22432295 ) ;
22442296 return ;
22452297 }
2298+
2299+ if ( localSlashCommandsEnabled && message . toLowerCase ( ) . startsWith ( '/reload-skills' ) ) {
2300+ notificationService . warning ( t ( 'chatInput.reloadSkillsUsage' ) ) ;
2301+ return ;
2302+ }
22462303
22472304 if ( messageCharCount > CHAT_INPUT_CONFIG . largePaste . maxMessageChars ) {
22482305 notificationService . error (
@@ -2310,6 +2367,7 @@ export const ChatInput: React.FC<ChatInputProps> = ({
23102367 submitInitFromInput ,
23112368 submitDeepreviewFromInput ,
23122369 submitMcpPromptFromInput ,
2370+ submitReloadSkillsFromInput ,
23132371 confirmPromptCacheGuardIfNeeded ,
23142372 t ,
23152373 resolveTypedMcpPromptCommand ,
@@ -2420,6 +2478,11 @@ export const ChatInput: React.FC<ChatInputProps> = ({
24202478 next = '/init' ;
24212479 } else if ( actionId === 'deepreview' ) {
24222480 next = `${ DEEP_REVIEW_SLASH_COMMAND } ` ;
2481+ } else if ( actionId === 'reload-skills' ) {
2482+ // /reload-skills takes no arguments. Setting the value to the bare
2483+ // command lets the user immediately press Enter to dispatch it
2484+ // (which is the same path /usage and /init use).
2485+ next = '/reload-skills' ;
24232486 } else {
24242487 return ;
24252488 }
0 commit comments