| 281 | } |
| 282 | |
| 283 | function matcherMatches(matcher: string | undefined, query: string | undefined): boolean { |
| 284 | if (!matcher || matcher === "*") return true |
| 285 | if (query === undefined) return false |
| 286 | try { |
| 287 | // Auto-anchor so "execute_command" matches exactly that tool name, not |
| 288 | // "execute_command_extra". Alternation ("a|b") still works because the |
| 289 | // anchors wrap a non-capturing group: ^(?:a|b)$. |
| 290 | return new RegExp(`^(?:${matcher})$`).test(query) |
| 291 | } catch { |
| 292 | // An invalid regex degrades to an exact-string comparison. |
| 293 | return matcher === query |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | function parseHookOutput(stdout: string): { json?: HookJsonOutput; plainText?: string } { |
| 298 | const trimmed = stdout.trim() |