IntentDebounce reads-and-discards any input arriving on ch during the configured window. Returns the count of discarded lines. The context is honored: cancellation aborts the wait without blocking.
(ctx context.Context, ch <-chan string)
| 107 | // configured window. Returns the count of discarded lines. The context is |
| 108 | // honored: cancellation aborts the wait without blocking. |
| 109 | func (g *InputGuard) IntentDebounce(ctx context.Context, ch <-chan string) int { |
| 110 | if g.debounceWindow <= 0 || ch == nil { |
| 111 | return 0 |
| 112 | } |
| 113 | timer := time.NewTimer(g.debounceWindow) |
| 114 | defer timer.Stop() |
| 115 | |
| 116 | discarded := 0 |
| 117 | for { |
| 118 | select { |
| 119 | case <-ctx.Done(): |
| 120 | return discarded |
| 121 | case <-timer.C: |
| 122 | if discarded > 0 { |
| 123 | g.logger.Debug("input guard: debounced spurious input during intent window", |
| 124 | zap.Int("count", discarded), |
| 125 | zap.Duration("window", g.debounceWindow)) |
| 126 | } |
| 127 | return discarded |
| 128 | case line, ok := <-ch: |
| 129 | if !ok { |
| 130 | return discarded |
| 131 | } |
| 132 | _ = line |
| 133 | discarded++ |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // Guard runs the full pre-prompt sequence: flush TTY → drain channel. |
| 139 | // Callers should invoke this BEFORE rendering the UI, then call |