795de325d7
grep_files runs its directory walk and per-file regex synchronously inside the async execute(). On a large tree this pins the runtime worker for minutes, so the turn loop can't observe the cancel token and the stop button stays unresponsive — the same failure file_search fixed in #2035. Mirror that fix: move the blocking walk onto spawn_blocking, bounded by a 30s hard timeout with a biased select on the cancel token, via a run_blocking_grep helper that parallels run_blocking_file_search. Output and the existing per-file/per-line cancel checks are unchanged. Co-authored-by: hexin <he.xin@h3c.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>