dbab0ef84d
The grep and rg in-process builtins passed no-op heartbeats to pi_walker when recursing into a directory, so the uutils scope's cancel flag was ignored mid-walk. The shell wrapper sets that flag on abort/timeout and then awaits the blocking task — with no heartbeat hookup, a cancelled recursive grep/rg waited for the whole tree to be scanned before the shell could return exit 130. Add pi_uutils_ctx::is_cancelled() and have grep's search_dir, rg's search_dir, and rg's collect_filtered_files supply heartbeats that return io::ErrorKind::Interrupted when the flag is set. The walker maps that to WalkError::Interrupted, which the utilities now silently treat as a harness cancellation (no spurious 'native directory scan interrupted' on the command's stderr — the shell wrapper owns the user-visible exit code). Regression tests pre-set the cancel flag and assert grep -r / rg / rg --files exit without scanning the matching file in the tree. Fixes #3933