@@ -61,20 +61,20 @@ describe("Command Mentions", () => {
6161 expect ( result ) . toContain ( "Please help me set up the project" )
6262 } )
6363
64- it ( "should only handle command at start of message" , async ( ) => {
65- mockGetCommand . mockResolvedValue ( {
64+ it ( "should handle only first command in message" , async ( ) => {
65+ mockGetCommand . mockResolvedValueOnce ( {
6666 name : "setup" ,
6767 content : "# Setup instructions" ,
6868 source : "project" ,
6969 filePath : "/project/.roo/commands/setup.md" ,
7070 } )
7171
72- // Only the first command should be recognized
72+ // Only first command should be recognized
7373 const input = "/setup the project\nThen /deploy later"
7474 const result = await callParseMentions ( input )
7575
7676 expect ( mockGetCommand ) . toHaveBeenCalledWith ( "/test/cwd" , "setup" )
77- expect ( mockGetCommand ) . toHaveBeenCalledTimes ( 1 ) // Only called once
77+ expect ( mockGetCommand ) . toHaveBeenCalledTimes ( 1 ) // Only first command called
7878 expect ( result ) . toContain ( '<command name="setup">' )
7979 expect ( result ) . toContain ( "# Setup instructions" )
8080 expect ( result ) . not . toContain ( '<command name="deploy">' ) // Second command not processed
@@ -88,7 +88,7 @@ describe("Command Mentions", () => {
8888
8989 expect ( mockGetCommand ) . toHaveBeenCalledWith ( "/test/cwd" , "nonexistent" )
9090 expect ( result ) . toContain ( '<command name="nonexistent">' )
91- expect ( result ) . toContain ( "not found" )
91+ expect ( result ) . toContain ( "Command 'nonexistent' not found" )
9292 expect ( result ) . toContain ( "</command>" )
9393 } )
9494
@@ -172,8 +172,8 @@ npm install
172172 } )
173173
174174 describe ( "command mention regex patterns" , ( ) => {
175- it ( "should match valid command mention patterns at start of message " , ( ) => {
176- const commandRegex = / ^ \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
175+ it ( "should match valid command mention patterns anywhere " , ( ) => {
176+ const commandRegex = / \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
177177
178178 const validPatterns = [ "/setup" , "/build-prod" , "/test_suite" , "/my-command" , "/command123" ]
179179
@@ -184,40 +184,44 @@ npm install
184184 } )
185185 } )
186186
187- it ( "should not match command patterns in middle of text" , ( ) => {
188- const commandRegex = / ^ \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
187+ it ( "should match command patterns in middle of text" , ( ) => {
188+ const commandRegex = / \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
189189
190- const invalidPatterns = [ "Please /setup" , "Run /build now" , "Use /deploy here" ]
190+ const validPatterns = [ "Please /setup" , "Run /build now" , "Use /deploy here" ]
191191
192- invalidPatterns . forEach ( ( pattern ) => {
192+ validPatterns . forEach ( ( pattern ) => {
193193 const match = pattern . match ( commandRegex )
194- expect ( match ) . toBeFalsy ( )
194+ expect ( match ) . toBeTruthy ( )
195+ expect ( match ! [ 0 ] ) . toMatch ( / ^ \/ [ a - z A - Z 0 - 9 _ \. - ] + $ / )
195196 } )
196197 } )
197198
198- it ( "should NOT match commands at start of new lines" , ( ) => {
199- const commandRegex = / ^ \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
199+ it ( "should match commands at start of new lines" , ( ) => {
200+ const commandRegex = / \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
200201
201202 const multilineText = "First line\n/setup the project\nAnother line\n/deploy when ready"
202203 const matches = multilineText . match ( commandRegex )
203204
204- // Should not match any commands since they're not at the very start
205- expect ( matches ) . toBeFalsy ( )
205+ // Should match both commands now
206+ expect ( matches ) . toBeTruthy ( )
207+ expect ( matches ) . toHaveLength ( 2 )
208+ expect ( matches ! [ 0 ] ) . toBe ( "/setup" )
209+ expect ( matches ! [ 1 ] ) . toBe ( "/deploy" )
206210 } )
207211
208- it ( "should only match command at very start of message" , ( ) => {
209- const commandRegex = / ^ \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
212+ it ( "should match only first command in message" , ( ) => {
213+ const commandRegex = / ^ \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / m
210214
211- const validText = "/setup the project\nThen do other things "
212- const matches = validText . match ( commandRegex )
215+ const validText = "/setup the project\nThen /deploy later "
216+ const match = validText . match ( commandRegex )
213217
214- expect ( matches ) . toBeTruthy ( )
215- expect ( matches ) . toHaveLength ( 1 )
216- expect ( matches ! [ 0 ] ) . toBe ( "/ setup" )
218+ expect ( match ) . toBeTruthy ( )
219+ expect ( match ! [ 0 ] ) . toBe ( "/setup" )
220+ expect ( match ! [ 1 ] ) . toBe ( "setup" ) // Captured group
217221 } )
218222
219223 it ( "should not match invalid command patterns" , ( ) => {
220- const commandRegex = / ^ \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
224+ const commandRegex = / \/ ( [ a - z A - Z 0 - 9 _ \. - ] + ) (? = \s | $ ) / g
221225
222226 const invalidPatterns = [ "/ space" , "/with space" , "/with/slash" , "//double" , "/with@symbol" ]
223227
@@ -239,37 +243,48 @@ npm install
239243 expect ( result ) . toContain ( "Command 'setup' (see below for command content)" )
240244 } )
241245
242- it ( "should only process first command in message" , async ( ) => {
246+ it ( "should process only first command in message" , async ( ) => {
247+ mockGetCommand . mockResolvedValueOnce ( {
248+ name : "setup" ,
249+ content : "# Setup instructions" ,
250+ source : "project" ,
251+ filePath : "/project/.roo/commands/setup.md" ,
252+ } )
253+
243254 const input = "/setup the project\nThen /deploy later"
244255 const result = await callParseMentions ( input )
245256
246257 expect ( result ) . toContain ( "Command 'setup' (see below for command content)" )
247- expect ( result ) . not . toContain ( "Command 'deploy'" ) // Second command not processed
258+ expect ( result ) . not . toContain ( "Command 'deploy' (see below for command content)" )
248259 } )
249260
250- it ( "should only match commands at very start of message" , async ( ) => {
261+ it ( "should match commands at start of lines only" , async ( ) => {
262+ mockGetCommand . mockResolvedValue ( {
263+ name : "build" ,
264+ content : "# Build instructions" ,
265+ source : "project" ,
266+ filePath : "/project/.roo/commands/build.md" ,
267+ } )
268+
251269 // At the beginning - should match
252270 let input = "/build the project"
253271 let result = await callParseMentions ( input )
254272 expect ( result ) . toContain ( "Command 'build'" )
255273
256- // In the middle - should NOT match
274+ // In the middle - should NOT match with new regex
257275 input = "Please /build and test"
258276 result = await callParseMentions ( input )
259277 expect ( result ) . not . toContain ( "Command 'build'" )
260- expect ( result ) . toContain ( "Please /build and test" ) // Original text preserved
261278
262- // At the end - should NOT match
279+ // At the end - should NOT match with new regex
263280 input = "Run the /build"
264281 result = await callParseMentions ( input )
265282 expect ( result ) . not . toContain ( "Command 'build'" )
266- expect ( result ) . toContain ( "Run the /build" ) // Original text preserved
267283
268- // At start of new line - should NOT match
284+ // At start of new line - should match
269285 input = "Some text\n/build the project"
270286 result = await callParseMentions ( input )
271- expect ( result ) . not . toContain ( "Command 'build'" )
272- expect ( result ) . toContain ( "Some text\n/build the project" ) // Original text preserved
287+ expect ( result ) . toContain ( "Command 'build'" )
273288 } )
274289 } )
275290} )
0 commit comments