diff --git a/CHANGELOG.md b/CHANGELOG.md index 191c259..ed121bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is based on Keep a Changelog, and this project currently tracks chang - Fixed duplicate response in React TUI caused by double Enter key submission in the input handler. - Fixed concurrent permission modals overwriting each other in TUI default mode when the LLM returns multiple tool calls in one response; `_ask_permission` now serialises callers via an `asyncio.Lock` so each modal is shown and resolved before the next one is emitted. - Fixed React TUI Markdown tables to size columns from rendered cell text so inline formatting like code spans and bold text no longer breaks alignment. +- Fixed grep tool crashing with `ValueError` / `LimitOverrunError` when ripgrep outputs a line longer than 64 KB (e.g. minified assets or lock files). The asyncio subprocess stream limit is now 8 MB and oversized lines are skipped rather than terminating the session. ### Changed diff --git a/src/openharness/tools/grep_tool.py b/src/openharness/tools/grep_tool.py index b4416cf..bef0943 100644 --- a/src/openharness/tools/grep_tool.py +++ b/src/openharness/tools/grep_tool.py @@ -183,6 +183,7 @@ async def _rg_grep( cwd=str(root), stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, + limit=8 * 1024 * 1024, # 8 MB per line — avoids LimitOverrunError on long lines ) matches: list[str] = [] @@ -239,6 +240,7 @@ async def _rg_grep_file( cwd=str(path.parent), stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, + limit=8 * 1024 * 1024, # 8 MB per line — avoids LimitOverrunError on long lines ) matches: list[str] = [] @@ -282,7 +284,11 @@ async def _collect_rg_matches( ) -> None: assert process.stdout is not None while len(matches) < limit: - raw = await process.stdout.readline() + try: + raw = await process.stdout.readline() + except ValueError: + # Line exceeded the stream buffer limit; skip it and continue. + continue if not raw: break line = raw.decode("utf-8", errors="replace").rstrip("\n") @@ -300,7 +306,11 @@ async def _collect_rg_file_matches( ) -> None: assert process.stdout is not None while len(matches) < limit: - raw = await process.stdout.readline() + try: + raw = await process.stdout.readline() + except ValueError: + # Line exceeded the stream buffer limit; skip it and continue. + continue if not raw: break line = raw.decode("utf-8", errors="replace").rstrip("\n")