@@ -244,6 +244,118 @@ describe("isToolAllowedForMode", () => {
244244 expect ( isToolAllowedForMode ( "use_mcp_tool" , "architect" , [ ] ) ) . toBe ( true )
245245 } )
246246 } )
247+ describe ( "slugRegex restrictions" , ( ) => {
248+ const modesWithSlugRegex : ModeConfig [ ] = [
249+ {
250+ slug : "subtask-runner" ,
251+ name : "Subtask Runner" ,
252+ roleDefinition : "Runs subtasks" ,
253+ groups : [ [ "subtask" , { slugRegex : "^subtask-target-.*" } ] ] ,
254+ } ,
255+ {
256+ slug : "mode-switcher" ,
257+ name : "Mode Switcher" ,
258+ roleDefinition : "Switches modes" ,
259+ groups : [ [ "switch" , { slugRegex : "^switch-target-.*" } ] ] ,
260+ } ,
261+ {
262+ slug : "subtask-no-regex" ,
263+ name : "Subtask No Regex" ,
264+ roleDefinition : "Runs any subtask" ,
265+ groups : [ "subtask" ] , // No slugRegex defined
266+ } ,
267+ {
268+ slug : "switch-no-regex" ,
269+ name : "Switch No Regex" ,
270+ roleDefinition : "Switches to any mode" ,
271+ groups : [ "switch" ] , // No slugRegex defined
272+ } ,
273+ ]
274+
275+ // --- subtask tool tests ---
276+ it ( "subtask: allows when slugRegex matches toolParams.mode" , ( ) => {
277+ expect (
278+ isToolAllowedForMode ( "new_task" , "subtask-runner" , modesWithSlugRegex , undefined , {
279+ mode : "subtask-target-allowed" ,
280+ message : "test" ,
281+ } ) ,
282+ ) . toBe ( true ) // Should FAIL until implemented
283+ } )
284+
285+ it ( "subtask: rejects when slugRegex does not match toolParams.mode" , ( ) => {
286+ expect (
287+ isToolAllowedForMode ( "new_task" , "subtask-runner" , modesWithSlugRegex , undefined , {
288+ mode : "other-mode" ,
289+ message : "test" ,
290+ } ) ,
291+ ) . toBe ( false ) // Should PASS (as false is default), but confirms logic path
292+ } )
293+
294+ it ( "subtask: allows when slugRegex matches toolParams.mode_slug (legacy)" , ( ) => {
295+ // Test legacy parameter name if needed
296+ expect (
297+ isToolAllowedForMode ( "new_task" , "subtask-runner" , modesWithSlugRegex , undefined , {
298+ mode_slug : "subtask-target-allowed" ,
299+ message : "test" ,
300+ } ) ,
301+ ) . toBe ( true ) // Should FAIL until implemented
302+ } )
303+
304+ it ( "subtask: rejects when slugRegex does not match toolParams.mode_slug (legacy)" , ( ) => {
305+ expect (
306+ isToolAllowedForMode ( "new_task" , "subtask-runner" , modesWithSlugRegex , undefined , {
307+ mode_slug : "other-mode" ,
308+ message : "test" ,
309+ } ) ,
310+ ) . toBe ( false ) // Should PASS (as false is default), but confirms logic path
311+ } )
312+
313+ it ( "subtask: allows when group exists but no slugRegex is defined" , ( ) => {
314+ expect (
315+ isToolAllowedForMode ( "new_task" , "subtask-no-regex" , modesWithSlugRegex , undefined , {
316+ mode : "any-mode" ,
317+ message : "test" ,
318+ } ) ,
319+ ) . toBe ( true ) // Should PASS (current behavior)
320+ } )
321+
322+ it ( "subtask: allows when slugRegex exists but toolParams are missing" , ( ) => {
323+ // If toolParams are missing, the regex check shouldn't run/fail
324+ expect ( isToolAllowedForMode ( "new_task" , "subtask-runner" , modesWithSlugRegex ) ) . toBe ( true ) // Should PASS (current behavior)
325+ } )
326+
327+ // --- switch_mode tool tests ---
328+ it ( "switch: allows when slugRegex matches toolParams.mode_slug" , ( ) => {
329+ expect (
330+ isToolAllowedForMode ( "switch_mode" , "mode-switcher" , modesWithSlugRegex , undefined , {
331+ mode_slug : "switch-target-allowed" ,
332+ } ) ,
333+ ) . toBe ( true ) // Should FAIL until implemented
334+ } )
335+
336+ it ( "switch: rejects when slugRegex does not match toolParams.mode_slug" , ( ) => {
337+ expect (
338+ isToolAllowedForMode ( "switch_mode" , "mode-switcher" , modesWithSlugRegex , undefined , {
339+ mode_slug : "other-mode" ,
340+ } ) ,
341+ ) . toBe ( false ) // Should PASS (as false is default), but confirms logic path
342+ } )
343+
344+ // Note: switch_mode only uses mode_slug, no need to test 'mode' param
345+
346+ it ( "switch: allows when group exists but no slugRegex is defined" , ( ) => {
347+ expect (
348+ isToolAllowedForMode ( "switch_mode" , "switch-no-regex" , modesWithSlugRegex , undefined , {
349+ mode_slug : "any-mode" ,
350+ } ) ,
351+ ) . toBe ( true ) // Should PASS (current behavior)
352+ } )
353+
354+ it ( "switch: allows when slugRegex exists but toolParams are missing" , ( ) => {
355+ // If toolParams are missing, the regex check shouldn't run/fail
356+ expect ( isToolAllowedForMode ( "switch_mode" , "mode-switcher" , modesWithSlugRegex ) ) . toBe ( true ) // Should PASS (current behavior)
357+ } )
358+ } )
247359
248360 it ( "handles non-existent modes" , ( ) => {
249361 expect ( isToolAllowedForMode ( "write_to_file" , "non-existent" , customModes ) ) . toBe ( false )
0 commit comments