@@ -117,6 +117,243 @@ describe("extractCommandPatterns", () => {
117117 expect ( patterns ) . toEqual ( [ "git" , "git add" , "git status" ] )
118118 } )
119119 } )
120+
121+ describe ( "complex real-world examples" , ( ) => {
122+ it ( "should correctly parse unzip with pipe chain" , ( ) => {
123+ const command = "unzip -l builds/roo-cline-3.21.5-error-boundary-component.vsix|grep map"
124+ const patterns = extractCommandPatterns ( command )
125+
126+ // Should extract individual commands from the chain
127+ expect ( patterns ) . toContain ( "unzip" )
128+ expect ( patterns ) . toContain ( "grep" )
129+
130+ // Should not include the full chain
131+ expect ( patterns ) . not . toContain ( command )
132+
133+ // Should not include flags or arguments
134+ expect ( patterns ) . not . toContain ( "unzip -l" )
135+ expect ( patterns ) . not . toContain ( "grep map" )
136+ } )
137+
138+ it ( "should correctly parse git push with multiple arguments" , ( ) => {
139+ const command = "git push github refactor-use-files-for-history -f"
140+ const patterns = extractCommandPatterns ( command )
141+
142+ // Should extract base command and subcommand
143+ expect ( patterns ) . toContain ( "git" )
144+ expect ( patterns ) . toContain ( "git push" )
145+
146+ // Should not include remote, branch, or flags
147+ expect ( patterns ) . not . toContain ( "git push github" )
148+ expect ( patterns ) . not . toContain ( "github" )
149+ expect ( patterns ) . not . toContain ( "refactor-use-files-for-history" )
150+ expect ( patterns ) . not . toContain ( "-f" )
151+ } )
152+
153+ it ( "should correctly parse complex build and install chain" , ( ) => {
154+ const command =
155+ "../roo-main/build.sh && code --install-extension builds/roo-cline-3.21.5-error-boundary-component.vsix && code"
156+ const patterns = extractCommandPatterns ( command )
157+
158+ // Should extract script file
159+ expect ( patterns ) . toContain ( "../roo-main/build.sh" )
160+
161+ // Should extract code command (appears twice, but set will dedupe)
162+ expect ( patterns ) . toContain ( "code" )
163+
164+ // Should not include the full chain
165+ expect ( patterns ) . not . toContain ( command )
166+
167+ // Should not include flags or arguments
168+ expect ( patterns ) . not . toContain ( "code --install-extension" )
169+ expect ( patterns ) . not . toContain ( "--install-extension" )
170+ expect ( patterns ) . not . toContain ( "builds/roo-cline-3.21.5-error-boundary-component.vsix" )
171+ } )
172+
173+ it ( "should handle npm scripts with arguments" , ( ) => {
174+ const command = "npm run build -- --watch"
175+ const patterns = extractCommandPatterns ( command )
176+
177+ expect ( patterns ) . toContain ( "npm" )
178+ expect ( patterns ) . toContain ( "npm run" )
179+ // Should stop at 'run' to allow any script
180+ expect ( patterns ) . not . toContain ( "npm run build" )
181+ } )
182+
183+ it ( "should handle docker commands with subcommands" , ( ) => {
184+ const command = "docker compose up -d"
185+ const patterns = extractCommandPatterns ( command )
186+
187+ expect ( patterns ) . toContain ( "docker" )
188+ expect ( patterns ) . toContain ( "docker compose" )
189+ expect ( patterns ) . not . toContain ( "docker compose up" )
190+ expect ( patterns ) . not . toContain ( "-d" )
191+ } )
192+
193+ it ( "should handle kubectl commands" , ( ) => {
194+ const command = "kubectl get pods -n production"
195+ const patterns = extractCommandPatterns ( command )
196+
197+ expect ( patterns ) . toContain ( "kubectl" )
198+ expect ( patterns ) . toContain ( "kubectl get" )
199+ expect ( patterns ) . not . toContain ( "kubectl get pods" )
200+ expect ( patterns ) . not . toContain ( "-n" )
201+ expect ( patterns ) . not . toContain ( "production" )
202+ } )
203+
204+ it ( "should handle make targets" , ( ) => {
205+ const command = "make clean && make build"
206+ const patterns = extractCommandPatterns ( command )
207+
208+ expect ( patterns ) . toContain ( "make" )
209+ expect ( patterns ) . toContain ( "make clean" )
210+ expect ( patterns ) . toContain ( "make build" )
211+ } )
212+
213+ it ( "should handle python scripts with arguments" , ( ) => {
214+ const command = "python3 scripts/deploy.py --env production"
215+ const patterns = extractCommandPatterns ( command )
216+
217+ expect ( patterns ) . toContain ( "python3" )
218+ // Should stop after interpreter
219+ expect ( patterns ) . not . toContain ( "scripts/deploy.py" )
220+ expect ( patterns ) . not . toContain ( "--env" )
221+ } )
222+
223+ it ( "should handle environment variables with commands" , ( ) => {
224+ const command = "NODE_ENV=test npm test && NODE_ENV=production npm start"
225+ const patterns = extractCommandPatterns ( command )
226+
227+ expect ( patterns ) . toContain ( "npm" )
228+ expect ( patterns ) . toContain ( "npm test" )
229+ expect ( patterns ) . toContain ( "npm start" )
230+ expect ( patterns ) . not . toContain ( "NODE_ENV=test" )
231+ expect ( patterns ) . not . toContain ( "NODE_ENV=production" )
232+ } )
233+
234+ it ( "should handle complex pipe with multiple tools" , ( ) => {
235+ const command = "ps aux | grep node | awk '{print $2}' | xargs kill -9"
236+ const patterns = extractCommandPatterns ( command )
237+
238+ expect ( patterns ) . toContain ( "ps" )
239+ expect ( patterns ) . toContain ( "grep" )
240+ expect ( patterns ) . toContain ( "awk" )
241+ expect ( patterns ) . toContain ( "xargs" )
242+ // Note: "xargs kill -9" is parsed as a single command where xargs is the command
243+ // and "kill -9" are arguments, so kill is not extracted as a separate pattern
244+ expect ( patterns ) . not . toContain ( "kill" )
245+ expect ( patterns ) . not . toContain ( "ps aux" )
246+ expect ( patterns ) . not . toContain ( "grep node" )
247+ expect ( patterns ) . not . toContain ( "kill -9" )
248+ } )
249+
250+ it ( "should handle yarn workspaces commands" , ( ) => {
251+ const command = "yarn workspace @myapp/frontend build"
252+ const patterns = extractCommandPatterns ( command )
253+
254+ expect ( patterns ) . toContain ( "yarn" )
255+ expect ( patterns ) . toContain ( "yarn workspace" )
256+ // Should not include the workspace name
257+ expect ( patterns ) . not . toContain ( "@myapp/frontend" )
258+ expect ( patterns ) . not . toContain ( "build" )
259+ } )
260+
261+ it ( "should handle pnpm commands" , ( ) => {
262+ const command = "pnpm --filter ./packages/* test"
263+ const patterns = extractCommandPatterns ( command )
264+
265+ expect ( patterns ) . toContain ( "pnpm" )
266+ // Should stop at flags
267+ expect ( patterns ) . not . toContain ( "pnpm --filter" )
268+ expect ( patterns ) . not . toContain ( "test" )
269+ } )
270+
271+ it ( "should handle curl with complex arguments" , ( ) => {
272+ const command =
273+ "curl -X POST https://api.example.com/data -H 'Content-Type: application/json' -d '{\"key\": \"value\"}'"
274+ const patterns = extractCommandPatterns ( command )
275+
276+ expect ( patterns ) . toContain ( "curl" )
277+ // Should stop at flags
278+ expect ( patterns ) . not . toContain ( "curl -X" )
279+ expect ( patterns ) . not . toContain ( "POST" )
280+ expect ( patterns ) . not . toContain ( "https://api.example.com/data" )
281+ } )
282+
283+ it ( "should handle ssh commands" , ( ) => {
284+ const command = "ssh [email protected] 'cd /app && npm restart'" 285+ const patterns = extractCommandPatterns ( command )
286+
287+ expect ( patterns ) . toContain ( "ssh" )
288+ // Should not include user@server or remote command
289+ expect ( patterns ) . not . toContain ( "[email protected] " ) 290+ expect ( patterns ) . not . toContain ( "cd" )
291+ expect ( patterns ) . not . toContain ( "npm" )
292+ } )
293+
294+ it ( "should handle rsync commands" , ( ) => {
295+ const command = "rsync -avz --delete ./dist/ user@server:/var/www/html/"
296+ const patterns = extractCommandPatterns ( command )
297+
298+ expect ( patterns ) . toContain ( "rsync" )
299+ // Should stop at flags
300+ expect ( patterns ) . not . toContain ( "rsync -avz" )
301+ expect ( patterns ) . not . toContain ( "--delete" )
302+ } )
303+
304+ it ( "should handle find with exec" , ( ) => {
305+ const command = "find . -name '*.log' -exec rm {} \\;"
306+ const patterns = extractCommandPatterns ( command )
307+
308+ expect ( patterns ) . toContain ( "find" )
309+ // Should not include dangerous operations
310+ expect ( patterns ) . not . toContain ( "rm" )
311+ expect ( patterns ) . not . toContain ( "-exec" )
312+ } )
313+
314+ it ( "should handle systemctl commands" , ( ) => {
315+ const command = "sudo systemctl restart nginx"
316+ const patterns = extractCommandPatterns ( command )
317+
318+ expect ( patterns ) . toContain ( "sudo" )
319+ // Note: sudo is the command, systemctl is treated as an argument
320+ // The parser doesn't have special handling for sudo to extract the actual command
321+ expect ( patterns ) . not . toContain ( "systemctl" )
322+ expect ( patterns ) . not . toContain ( "nginx" )
323+ } )
324+
325+ it ( "should handle aws cli commands" , ( ) => {
326+ const command = "aws s3 sync ./build s3://my-bucket --delete"
327+ const patterns = extractCommandPatterns ( command )
328+
329+ expect ( patterns ) . toContain ( "aws" )
330+ // aws is not in special handling, so behavior may vary
331+ expect ( patterns ) . not . toContain ( "--delete" )
332+ } )
333+
334+ it ( "should handle multiple redirects" , ( ) => {
335+ const command = "echo 'test' > file.txt && cat file.txt >> output.log"
336+ const patterns = extractCommandPatterns ( command )
337+
338+ expect ( patterns ) . toContain ( "echo" )
339+ expect ( patterns ) . toContain ( "cat" )
340+ expect ( patterns ) . not . toContain ( "echo 'test'" )
341+ expect ( patterns ) . not . toContain ( "file.txt" )
342+ expect ( patterns ) . not . toContain ( "output.log" )
343+ } )
344+
345+ it ( "should handle background processes" , ( ) => {
346+ const command = "npm start & npm run worker &"
347+ const patterns = extractCommandPatterns ( command )
348+
349+ expect ( patterns ) . toContain ( "npm" )
350+ expect ( patterns ) . toContain ( "npm start" )
351+ // Note: The & operator is not in the chainOperators list (only &&, ||, ;, |)
352+ // So this is parsed as a single command "npm start & npm run worker &"
353+ // The parser stops at the first & character when parsing "npm start &..."
354+ expect ( patterns ) . not . toContain ( "npm run" )
355+ } )
356+ } )
120357} )
121358
122359describe ( "getPatternDescription" , ( ) => {
0 commit comments