@@ -213,8 +213,8 @@ describe("bot/commands/commands", () => {
213213 it ( "shows commands list and starts custom interaction" , async ( ) => {
214214 mocked . commandListMock . mockResolvedValue ( {
215215 data : [
216- { name : "init" , description : "create/update AGENTS.md" } ,
217- { name : "poem" , description : "write a poem" } ,
216+ { name : "init" , description : "create/update AGENTS.md" , source : "command" } ,
217+ { name : "poem" , description : "write a poem" , source : "command" } ,
218218 ] ,
219219 error : null ,
220220 } ) ;
@@ -370,6 +370,7 @@ describe("bot/commands/commands", () => {
370370 const commands = Array . from ( { length : 11 } , ( _ , i ) => ( {
371371 name : `cmd${ i + 1 } ` ,
372372 description : `Command ${ i + 1 } description` ,
373+ source : "command" ,
373374 } ) ) ;
374375
375376 mocked . commandListMock . mockResolvedValueOnce ( {
@@ -397,6 +398,41 @@ describe("bot/commands/commands", () => {
397398 expect ( options . reply_markup . inline_keyboard [ 11 ] ?. [ 0 ] ?. callback_data ) . toBe ( "commands:cancel" ) ;
398399 } ) ;
399400
401+ it ( "filters out non-command sources from command list" , async ( ) => {
402+ mocked . commandListMock . mockResolvedValue ( {
403+ data : [
404+ { name : "init" , description : "create/update AGENTS.md" , source : "command" } ,
405+ { name : "review" , description : "review changes" , source : "command" } ,
406+ { name : "borsch" , description : "Borsch recipe" , source : "skill" } ,
407+ { name : "from-mcp" , description : "MCP prompt" , source : "mcp" } ,
408+ ] ,
409+ error : null ,
410+ } ) ;
411+
412+ const ctx = createCommandContext ( 750 ) ;
413+ await commandsCommand ( ctx as never ) ;
414+
415+ expect ( ctx . reply ) . toHaveBeenCalledTimes ( 1 ) ;
416+
417+ const [ , options ] = ( ctx . reply as ReturnType < typeof vi . fn > ) . mock . calls [ 0 ] as [
418+ string ,
419+ { reply_markup : { inline_keyboard : Array < Array < { callback_data ?: string } > > } } ,
420+ ] ;
421+
422+ expect ( options . reply_markup . inline_keyboard [ 0 ] ?. [ 0 ] ?. callback_data ) . toBe ( "commands:select:0" ) ;
423+ expect ( options . reply_markup . inline_keyboard [ 1 ] ?. [ 0 ] ?. callback_data ) . toBe ( "commands:select:1" ) ;
424+ expect ( options . reply_markup . inline_keyboard [ 2 ] ?. [ 0 ] ?. callback_data ) . toBe ( "commands:cancel" ) ;
425+
426+ const state = interactionManager . getSnapshot ( ) ;
427+ expect ( state ?. kind ) . toBe ( "custom" ) ;
428+ expect ( state ?. metadata . flow ) . toBe ( "commands" ) ;
429+ expect ( state ?. metadata . stage ) . toBe ( "list" ) ;
430+ expect ( state ?. metadata . commands ) . toEqual ( [
431+ { name : "init" , description : "create/update AGENTS.md" } ,
432+ { name : "review" , description : "review changes" } ,
433+ ] ) ;
434+ } ) ;
435+
400436 it ( "handles next-page callback and renders second page with prev button" , async ( ) => {
401437 const commands = Array . from ( { length : 12 } , ( _ , i ) => ( {
402438 name : `cmd${ i + 1 } ` ,
0 commit comments