Fire dispatches an event to all matching hooks. For PreToolUse events, returns a HookResult — if Blocked is true, the action should be prevented. Other events are fire-and-forget (errors are logged but not returned).
(ctx context.Context, event HookEvent)
| 101 | // For PreToolUse events, returns a HookResult — if Blocked is true, the action should be prevented. |
| 102 | // Other events are fire-and-forget (errors are logged but not returned). |
| 103 | func (m *Manager) Fire(ctx context.Context, event HookEvent) *HookResult { |
| 104 | m.mu.RLock() |
| 105 | hooks := make([]HookConfig, len(m.hooks)) |
| 106 | copy(hooks, m.hooks) |
| 107 | m.mu.RUnlock() |
| 108 | |
| 109 | for _, hook := range hooks { |
| 110 | if !hook.IsEnabled() { |
| 111 | continue |
| 112 | } |
| 113 | if hook.Event != event.Type { |
| 114 | continue |
| 115 | } |
| 116 | |
| 117 | // Apply tool pattern filter for tool events |
| 118 | if hook.ToolPattern != "" && event.ToolName != "" { |
| 119 | if !matchToolPattern(hook.ToolPattern, event.ToolName) { |
| 120 | continue |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | result := m.executeHook(ctx, hook, event) |
| 125 | |
| 126 | // For PreToolUse, a blocking result (exit code 2) stops the action |
| 127 | if event.Type == EventPreToolUse && result.Blocked { |
| 128 | m.logger.Info("Hook blocked tool execution", |
| 129 | zap.String("hook", hook.Name), |
| 130 | zap.String("tool", event.ToolName), |
| 131 | zap.String("reason", result.BlockReason)) |
| 132 | return result |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | return nil // no blocking |
| 137 | } |
| 138 | |
| 139 | // FireAsync dispatches an event asynchronously (non-blocking). |
| 140 | // Use for events where the result doesn't matter (PostToolUse, Notification, etc.). |