fix(tool): exempt piped-stdin stages from bash interceptor
The 17.2.2 compound-fragment matching splits commands on every unquoted operator including `|`, so a downstream pipe stage like `grep x` in `printf 'x\n' | grep x` became a standalone interception candidate and was routed to the `grep` tool, which searches paths and cannot consume the previous stage's stdout. `extractFlatShellCommandSegments` now flags each segment that receives piped stdin from a single unquoted `|`, and `interceptionCandidates` skips those: a stdin-consuming stage cannot be replaced by a path-based dedicated tool. Standalone (`grep pattern path`), first-stage (`grep x file | wc`), and `&&`/`||`/`;`-sequenced commands still match. Fixes #7496
This commit is contained in:
+2
-2
@@ -110,7 +110,7 @@ git add file && git commit -m "message"
|
||||
GIT_AUTHOR_NAME=Dev git commit -m "message"
|
||||
```
|
||||
|
||||
An anchored rule such as `^\s*git\s+commit\b` can therefore match the `git commit` command in both examples. Quoted, escaped, and commented text is not treated as a command. Heredocs, parameter expansion, command substitution, backticks, grouping, and malformed quoting retain only the complete-command check; the interceptor deliberately does not attempt to become a full shell parser.
|
||||
An anchored rule such as `^\s*git\s+commit\b` can therefore match the `git commit` command in both examples. A stage that consumes another command's stdout through a single unquoted `|` (for example `grep x` in `printf 'x\n' | grep x`) is **not** treated as an interception candidate: it reads piped stdin, which the path-based dedicated tools cannot supply, so only a standalone or first-stage command is matched. Quoted, escaped, and commented text is not treated as a command. Heredocs, parameter expansion, command substitution, backticks, grouping, and malformed quoting retain only the complete-command check; the interceptor deliberately does not attempt to become a full shell parser.
|
||||
|
||||
### Interaction and selection guide
|
||||
|
||||
@@ -127,7 +127,7 @@ Choose the setting by the desired outcome:
|
||||
1. `BashTool.execute()` in `packages/coding-agent/src/tools/bash.ts` reads `command`, normalizes `env`, and defaults `timeout` to `300`. Commands execute exactly as written — there is no pre-execution rewrite pass.
|
||||
2. If `cwd` is absent, it rewrites a leading `cd <path> && ...` into the structured `cwd` field and strips that prefix from `command`.
|
||||
3. If `async: true` is requested while `async.enabled` is off, it throws `ToolError` before any execution.
|
||||
4. If `bashInterceptor.enabled` is on, `checkBashInterception()` runs against both the original command and the `cd`-stripped command. For each form, configured regexes still check the complete input first, then each flat command separated by unquoted/unescaped `&&`, `||`, `;`, `|`, `&`, or newlines, followed by versions of those fragments without leading `NAME=value` assignments. A matching enabled rule throws before URL expansion or execution.
|
||||
4. If `bashInterceptor.enabled` is on, `checkBashInterception()` runs against both the original command and the `cd`-stripped command. For each form, configured regexes still check the complete input first, then each flat command separated by unquoted/unescaped `&&`, `||`, `;`, `|`, `&`, or newlines (excluding stages that consume piped stdin from a single unquoted `|`), followed by versions of those fragments without leading `NAME=value` assignments. A matching enabled rule throws before URL expansion or execution.
|
||||
5. `expandInternalUrls()` rewrites supported internal URLs inside `command`, each `env` value, and protocol-looking `cwd` values. Command replacements are shell-escaped; `env` and `cwd` replacements use raw filesystem/string values because they are not interpolated into shell text.
|
||||
6. `resolveToCwd()` resolves `cwd` against `session.cwd`; `fs.stat()` verifies that the target exists and is a directory.
|
||||
7. `clampTimeout("bash", requestedTimeoutSec)` enforces `TOOL_TIMEOUTS.bash` (`default: 300`, `min: 1`, `max: 3600`). When clamped, `#buildCompletedResult()` / `#buildBackgroundStartResult()` append a notice line.
|
||||
|
||||
Reference in New Issue
Block a user