Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion aai_coding/harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

NO_TRUNCATE = 'Output pipe truncates below 20 lines. Drop the pipe or keep >=20: truncation is decided before the output exists, so keep enough to diagnose surprises.'
NO_STDERR_MERGE = 'Do not merge stderr into stdout with 2>&1. Run the command bare: the harness pushes large output to a file by itself, and stderr kept separate makes a crash unmissable.'
_TRUNC = re.compile(r'\|\s*(tail|head)\s+(-n\s*)?-?([1-9]|1[0-9])\b')
# Two ways a head/tail pipe truncates below 20: an explicit count under 20, or no count at all -
# bare `head`/`tail` default to 10, so a countless pipe cuts exactly as hard as the `-10` we reject.
_TRUNC = re.compile(r'\|\s*(?:tail|head)'
r'(?:\s+(?:-n\s*)?-?(?:[1-9]|1[0-9])\b' # explicit: -5, -n 5, -19
r'|(?=\s*(?:$|[|;&\n])))') # bare: defaults to 10
_MERGE = re.compile(r'2>\s*&\s*1')


Expand Down
13 changes: 12 additions & 1 deletion tests/test_harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@
import pytest
from shutil import which

from aai_coding.harness import claude_air, claude_drop_sentinel, claude_slop, synthetic_resume
from aai_coding.harness import bash_guard_msg, claude_air, claude_drop_sentinel, claude_slop, synthetic_resume


def test_bash_guard_bare_head_tail():
"A countless head/tail keeps 10 lines, the same cut as the -10 form the guard already rejects"
assert bash_guard_msg('tar tzf x.tgz | head')
assert bash_guard_msg('ls ~ | tail')
assert bash_guard_msg('cat big.log | head | wc -l')
assert bash_guard_msg('ls | head; echo done')
assert bash_guard_msg('ls | header') is None # merely starts with those four letters
assert bash_guard_msg('cat f | head -c 200') is None # bytes, not lines
assert bash_guard_msg('git status | head -30') is None


def test_synthetic_resume(tmp_path):
Expand Down