strings.Split produces an empty trailing element when the git diff
output ends with \n. The empty element was written into the last file's
buffer, and TrimSuffix only removed one \n — leaving the last Diff
field with an extra trailing newline that earlier files didn't have.
Switch to TrimRight so all Diff values are consistently clean.
Group functionally related files (e.g., impl + test, handler + model) into
a single review context using an LLM clustering step. This improves review
quality by giving the model cross-file awareness within related changes.
Key changes:
- Add file grouping agent with threshold-based decisions and recursive splitting
- Refactor dispatchSubtasks/executeSubtask to operate on DiffGroup instead of
individual diffs, supporting combined multi-file diffs with FILE separators
- Add path validation in code_comment tool for multi-file groups
- Add StripDiffHeaders to reduce token usage in prompts
- Add extractJSONArray fallback for filter response parsing robustness
- Persist file group metadata to JSONL and render groups in viewer UI
- Merge intermediate tool-only agent rounds in viewer for cleaner display
- Update prompt templates: remove {{current_file_path}}, use <pending_review_diff>
When a file was renamed on the target branch, ocr review emitted
'[ocr] WARNING: cannot read file <old path> at ref <to>: exit status 128'.
Two compounding bugs:
1. The parser required 'a/'/'b/' prefixes when matching '--- /dev/null' /
'+++ /dev/null', but git emits these lines without prefixes, so
IsNew/IsDeleted were never set and deleted files fell through to a
doomed 'git show ref:<old path>'.
2. 'rename from' / 'rename to' extended headers were never parsed, and
git diff/show call sites did not force rename detection, so renames
degraded to delete+add whenever the user had diff.renames=false.
Fixes:
- Parse 'rename from'/'rename to', 'new file mode', 'deleted file mode'
and unprefixed /dev/null markers in ParseDiffText.
- Pass --find-renames to all git diff/show invocations so rename
detection no longer depends on user config.
- Add IsRenamed to model.Diff (json: is_renamed) and prefer it in
diffStatus.
- Add parser unit tests and a range-mode rename regression test.
Fixes#99