Await all in-flight fire-and-forget hook tasks.
Call this before the event loop tears down (e.g. at the end of a headless
run driven by asyncio.run) so background dispatches — most importantly the
final tool.result — are not cancelled mid-flight and silently dropped.
Each task's exceptions are already swallowed inside dispatch_hook, and any
stragglers are collected with return_exceptions=True, so this never
raises.
Precondition: this snapshots the in-flight set once and awaits it, so any
hook scheduled after the snapshot (during the await) is not drained. Call
it only once no further dispatches are possible. The headless caller invokes
it after _run_agent_loop has fully returned. The app.py graceful-exit
caller cancels the agent worker first, whose cancel handler
(_handle_interrupt_cleanup) schedules its terminal tool.result hooks
synchronously before this snapshot runs — see the ordering comment there —
so they are captured; a hook scheduled after a slow async write would not
be.