aggregate combines per-hook results into a single [Result].
(results []hookResult, event EventType)
| 425 | |
| 426 | // aggregate combines per-hook results into a single [Result]. |
| 427 | func aggregate(results []hookResult, event EventType) *Result { |
| 428 | final := &Result{Allowed: true} |
| 429 | var messages, contexts, sysMsgs []string |
| 430 | |
| 431 | for _, r := range results { |
| 432 | switch { |
| 433 | case r.err != nil: |
| 434 | policy := ErrorPolicy(r.hook.OnError) |
| 435 | if policy == "" { |
| 436 | policy = ErrorPolicyWarn |
| 437 | } |
| 438 | if failClosed(event) || policy == ErrorPolicyBlock { |
| 439 | slog.Warn("Hook failed; blocking event", "hook", r.hook.DisplayName(), "error", r.err) |
| 440 | final.Allowed = false |
| 441 | final.ExitCode = -1 |
| 442 | final.Stderr = r.Stderr |
| 443 | messages = append(messages, fmt.Sprintf("PreToolUse hook failed to execute: %v", r.err)) |
| 444 | } else if policy != ErrorPolicyIgnore { |
| 445 | slog.Warn("Hook execution error", "hook", r.hook.DisplayName(), "error", r.err) |
| 446 | } |
| 447 | continue |
| 448 | |
| 449 | case r.ExitCode == 2: |
| 450 | final.Allowed = false |
| 451 | final.ExitCode = 2 |
| 452 | if r.Stderr != "" { |
| 453 | final.Stderr = r.Stderr |
| 454 | messages = append(messages, strings.TrimSpace(r.Stderr)) |
| 455 | } |
| 456 | continue |
| 457 | |
| 458 | case r.ExitCode != 0: |
| 459 | slog.Debug("Hook returned non-zero exit code", "exit_code", r.ExitCode, "stderr", r.Stderr) |
| 460 | continue |
| 461 | |
| 462 | case r.Output == nil: |
| 463 | // Plain stdout becomes AdditionalContext only for events |
| 464 | // whose runtime consumes it. |
| 465 | if r.Stdout != "" && stdoutAsContext(event) { |
| 466 | contexts = append(contexts, strings.TrimSpace(r.Stdout)) |
| 467 | } |
| 468 | continue |
| 469 | } |
| 470 | |
| 471 | out := r.Output |
| 472 | if !out.ShouldContinue() { |
| 473 | final.Allowed = false |
| 474 | if out.StopReason != "" { |
| 475 | messages = append(messages, out.StopReason) |
| 476 | } |
| 477 | } |
| 478 | if out.IsBlocked() { |
| 479 | final.Allowed = false |
| 480 | if out.Reason != "" { |
| 481 | messages = append(messages, out.Reason) |
| 482 | } |
| 483 | } |
| 484 | if out.SystemMessage != "" { |