Async version of grep.
Wraps the sync call with an async timeout as a safety net. The timeout
bounds how long the caller waits; it does not stop the worker thread
created by asyncio.to_thread.
max_count is forwarded when the concrete grep accepts it (so the
search can bound itself); backends that don't accept it run uncapped and
are trimmed afterward. Either way the return value is always passed
through _apply_grep_max_count (a no-op when already within the cap), so
callers get the same guarantee regardless of which path runs.