Skip to content

Commit a280f87

Browse files
committed
fix: prevent full command chains from being extracted as patterns
Fixed the pattern extraction logic to only extract individual commands and their subcommands, never full command chains. This prevents issues where complex piped or chained commands would be incorrectly treated as single patterns. - Updated extractCommandPatterns to stop at command boundaries (&&, ||, |, ;) - Added comprehensive tests for command chain scenarios - Ensures only atomic commands are whitelisted, not entire command sequences
1 parent 0a067f0 commit a280f87

File tree

3 files changed

+139
-267
lines changed

3 files changed

+139
-267
lines changed

webview-ui/src/components/chat/CommandExecution.tsx

Lines changed: 8 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { safeJsonParse } from "@roo/safeJsonParse"
99

1010
import { vscode } from "@src/utils/vscode"
1111
import { parseCommandAndOutput } from "@src/utils/commandParsing"
12-
import { extractCommandPattern, getPatternDescription } from "@src/utils/commandPatterns"
12+
import { extractCommandPatterns, getPatternDescription } from "@src/utils/commandPatterns"
1313
import { useExtensionState } from "@src/context/ExtensionStateContext"
1414
import { useAppTranslation } from "@src/i18n/TranslationContext"
1515
import { cn } from "@src/lib/utils"
@@ -61,97 +61,14 @@ export const CommandExecution = ({ executionId, text, icon, title }: CommandExec
6161
// If no LLM suggestions but we have a command, extract patterns programmatically
6262
if (!command?.trim()) return []
6363

64-
// Check if this is a chained command
65-
const operators = ["&&", "||", ";", "|"]
66-
const patterns: Array<{ pattern: string; description: string }> = []
67-
68-
// Split by operators while respecting quotes
69-
let inSingleQuote = false
70-
let inDoubleQuote = false
71-
let escapeNext = false
72-
let currentCommand = ""
73-
let i = 0
74-
75-
while (i < command.length) {
76-
const char = command[i]
77-
78-
if (escapeNext) {
79-
currentCommand += char
80-
escapeNext = false
81-
i++
82-
continue
83-
}
84-
85-
if (char === "\\") {
86-
escapeNext = true
87-
currentCommand += char
88-
i++
89-
continue
90-
}
91-
92-
if (char === "'" && !inDoubleQuote) {
93-
inSingleQuote = !inSingleQuote
94-
currentCommand += char
95-
i++
96-
continue
97-
}
98-
99-
if (char === '"' && !inSingleQuote) {
100-
inDoubleQuote = !inDoubleQuote
101-
currentCommand += char
102-
i++
103-
continue
104-
}
105-
106-
// Check for operators outside quotes
107-
if (!inSingleQuote && !inDoubleQuote) {
108-
let foundOperator = false
109-
for (const op of operators) {
110-
if (command.substring(i, i + op.length) === op) {
111-
// Found an operator, process the current command
112-
const trimmedCommand = currentCommand.trim()
113-
if (trimmedCommand) {
114-
// Extract pattern for the command
115-
const pattern = extractCommandPattern(trimmedCommand)
116-
if (pattern) {
117-
patterns.push({
118-
pattern,
119-
description: getPatternDescription(pattern),
120-
})
121-
}
122-
}
123-
currentCommand = ""
124-
i += op.length
125-
foundOperator = true
126-
break
127-
}
128-
}
129-
if (foundOperator) continue
130-
}
131-
132-
currentCommand += char
133-
i++
134-
}
135-
136-
// Process the last command
137-
const trimmedCommand = currentCommand.trim()
138-
if (trimmedCommand) {
139-
// Extract pattern for the command
140-
const pattern = extractCommandPattern(trimmedCommand)
141-
if (pattern) {
142-
patterns.push({
143-
pattern,
144-
description: getPatternDescription(pattern),
145-
})
146-
}
147-
}
148-
149-
// Remove duplicates
150-
const uniquePatterns = patterns.filter(
151-
(item, index, self) => index === self.findIndex((p) => p.pattern === item.pattern),
152-
)
64+
// Use the new extractCommandPatterns function which handles all parsing
65+
const extractedPatterns = extractCommandPatterns(command)
15366

154-
return uniquePatterns
67+
// Convert to the expected format with descriptions
68+
return extractedPatterns.map((pattern) => ({
69+
pattern,
70+
description: getPatternDescription(pattern),
71+
}))
15572
}, [command, suggestions])
15673

15774
// The command's output can either come from the text associated with the

0 commit comments

Comments
 (0)