(command: string)
| 265 | } |
| 266 | |
| 267 | function suggestionForExactCommand(command: string): PermissionUpdate[] { |
| 268 | // Heredoc commands contain multi-line content that changes each invocation, |
| 269 | // making exact-match rules useless (they'll never match again). Extract a |
| 270 | // stable prefix before the heredoc operator and suggest a prefix rule instead. |
| 271 | const heredocPrefix = extractPrefixBeforeHeredoc(command) |
| 272 | if (heredocPrefix) { |
| 273 | return sharedSuggestionForPrefix(BashTool.name, heredocPrefix) |
| 274 | } |
| 275 | |
| 276 | // Multiline commands without heredoc also make poor exact-match rules. |
| 277 | // Saving the full multiline text can produce patterns containing `:*` in |
| 278 | // the middle, which fails permission validation and corrupts the settings |
| 279 | // file. Use the first line as a prefix rule instead. |
| 280 | if (command.includes('\n')) { |
| 281 | const firstLine = command.split('\n')[0]!.trim() |
| 282 | if (firstLine) { |
| 283 | return sharedSuggestionForPrefix(BashTool.name, firstLine) |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | // Single-line commands: extract a 2-word prefix for reusable rules. |
| 288 | // Without this, exact-match rules are saved that never match future |
| 289 | // invocations with different arguments. |
| 290 | const prefix = getSimpleCommandPrefix(command) |
| 291 | if (prefix) { |
| 292 | return sharedSuggestionForPrefix(BashTool.name, prefix) |
| 293 | } |
| 294 | |
| 295 | return sharedSuggestionForExactCommand(BashTool.name, command) |
| 296 | } |
| 297 | |
| 298 | /** |
| 299 | * If the command contains a heredoc (<<), extract the command prefix before it. |
no test coverage detected