fix(read): make head/tail rewrites faithful to the native commands
The hook rewrites `head -N FILE` to `rtk read FILE --max-lines N`, but `--max-lines` routes through smart_truncate, which keeps a non-important line only while kept_lines < max_lines / 2. Every rewritten `head -N` therefore showed about half the requested lines, and `head -1` showed none at all. Bare `head FILE` rewrote to an unbounded read of the whole file, which a test asserted as intended. Add `--head-lines N` for an exact first-N-lines window and point the head rewrites at it, leaving `--max-lines` preview semantics unchanged for existing callers. Both windows now slice on byte offsets at the Nth newline instead of round-tripping through lines(), so CRLF endings and an unterminated final line survive. The shipped `--tail-lines` path had the same normalization loss. `--max-lines 0` returned a marker with no content and underflowed max_lines - 1 on usize; it now returns empty, matching `--tail-lines 0`. Gate the rewrites on is_single_file_operand, an allowlist of characters that cannot change an operand's word count or turn it into an option. A whitespace-delimited token is not a shell operand: `head -n 1 *.rs` expanded to sixteen files and lost the `==> name <==` banners, `head -n 1 --help` printed rtk's own help, and a leading `#` opened a comment that swallowed the appended flags. Uncertain operands stay with the native binary, which costs coverage on quoted literals such as 'literal*.txt' and keeps behavior correct. Separate a stripped trailing redirect from the appended flag value. `head -n 1 a>b` produced `--head-lines 1>b`, which the shell reads as an fd-1 redirect, leaving the flag without a value and the redirect target empty.
I
Ilia Alshanetsky committed
ed8480f3e279719e5a2ab5209e2bf41e12004c5c
Parent: f749546