Conversation
…lows
`_rewrite_compound_background` turns `A && B &` into `A && { B & }` to
avoid the subshell-wait process leak. But when a command follows the
backgrounded job on the same line (`A && B & C`), the rewrite produced
`A && { B & } C` — a bash syntax error, since a brace group needs a
separator before the next command. Valid commands like
`build && python app.py & echo started` were rejected with
"syntax error near unexpected token". Splice in a `;` when the tail is a
same-line command; tails that already start with a separator (newline,
`&&`/`||`/`|`) are untouched.
## What does this PR do?
Fixes `_rewrite_compound_background` emitting invalid bash when a command
trails the backgrounded job on the same line.
## Related Issue
N/A
## Type of Change
- [x] 🐛 Bug fix (non-breaking change that fixes an issue)
## Changes Made
- `tools/terminal_tool.py`: in `_rewrite_compound_background`, insert `;`
after the brace group when a same-line command follows; leave tails
beginning with a separator unchanged.
- `tests/tools/test_terminal_compound_background.py`: add regression tests
for trailing same-line commands, `bash -n` validity, and idempotence.
## How to Test
1. `from tools.terminal_tool import _rewrite_compound_background as r`
2. `r("A && B & C")` → `"A && { B & }; C"` (was `"A && { B & } C"`).
3. `bash -n -c "$(echo a && sleep 100 & echo done)"` style output now
passes; pre-fix it failed.
4. `pytest tests/tools/test_terminal_compound_background.py -q` → 39 passed.
## Checklist
### Code
- [x] I've read the Contributing Guide
- [x] My commit messages follow Conventional Commits
- [x] I searched for existing PRs to make sure this isn't a duplicate
- [x] My PR contains only changes related to this fix
- [x] I've run the affected tests and they pass
- [x] I've added tests for my changes
- [x] I've tested on my platform: macOS 15 (Darwin 25.5)
### Documentation & Housekeeping
- [x] I've updated relevant documentation — N/A
- [x] I've updated `cli-config.yaml.example` if I added/changed config keys — N/A
- [x] I've updated `CONTRIBUTING.md` or `AGENTS.md` — N/A
- [x] I've considered cross-platform impact — pure string logic, platform-agnostic
- [x] I've updated tool descriptions/schemas — N/A
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating a real terminal rewrite bug. Current main still concatenates the suffix directly after the closing brace at tools/terminal_tool.py:866, and BaseEnvironment.execute() applies that rewriter by default at tools/environments/base.py:915-917.
Problems
tests/tools/test_terminal_compound_background.py:96invokesbashunconditionally. Bash is not guaranteed on native Windows or minimal test environments; existing bash-dependent tests skip whenshutil.which("bash")is unavailable (for exampletests/tools/test_base_environment.py:222-224).
Suggested changes
- Add that availability guard around the
bash -ntest. Keep the string-level regression assertions platform-independent.
The targeted production hunk remains unchanged on current main despite the PR's age, so the fix should otherwise salvage cleanly. This is an automated hermes-sweeper review.
| "build && run & tail -f log", | ||
| ): | ||
| out = rewrite(cmd) | ||
| proc = subprocess.run( |
There was a problem hiding this comment.
Please skip this bash-dependent assertion when shutil.which("bash") is unavailable. Existing tests use that guard, and without it this regression test fails on native Windows or minimal environments before it can assert rewrite behavior.
|
Supporting datapoint: this fix is still needed, still applies, and still works at current HEAD. Verified against
Impact evidence (same failure as #98222): on an ssh terminal backend we observed 893 consecutive kernel spawn failures with zero successes — every spawn died with The one change requested in review — skipping the bash-dependent assertion when 🤖 Generated with Claude Code |
|
Fixed via #101662 (salvage of #42278 — the earliest PR on this rewrite and the one with the full separator set; the |
_rewrite_compound_backgroundturnsA && B &intoA && { B & }toavoid the subshell-wait process leak. But when a command follows the
backgrounded job on the same line (
A && B & C), the rewrite producedA && { B & } C— a bash syntax error, since a brace group needs aseparator before the next command. Valid commands like
build && python app.py & echo startedwere rejected with"syntax error near unexpected token". Splice in a
;when the tail is asame-line command; tails that already start with a separator (newline,
&&/||/|) are untouched.What does this PR do?
Fixes
_rewrite_compound_backgroundemitting invalid bash when a commandtrails the backgrounded job on the same line.
Related Issue
N/A
Type of Change
Changes Made
tools/terminal_tool.py: in_rewrite_compound_background, insert;after the brace group when a same-line command follows; leave tails
beginning with a separator unchanged.
tests/tools/test_terminal_compound_background.py: add regression testsfor trailing same-line commands,
bash -nvalidity, and idempotence.How to Test
from tools.terminal_tool import _rewrite_compound_background as rr("A && B & C")→"A && { B & }; C"(was"A && { B & } C").bash -n -c "$(echo a && sleep 100 & echo done)"style output nowpasses; pre-fix it failed.
pytest tests/tools/test_terminal_compound_background.py -q→ 39 passed.Checklist
Code
Documentation & Housekeeping
cli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.md— N/A