#20640: fix: prevent zsh glob expansion errors in exec commands
agents
size: XS
## Summary
- zsh's `nomatch` option (enabled by default) causes `no matches found` errors when exec commands contain unquoted glob characters like `?` or `[]`, which are common in URLs (e.g. `https://example.com/page?si=abc`)
- Adds `wrapCommandForShell()` helper in `shell-utils.ts` that prefixes commands with `setopt nonomatch;` when the resolved shell is zsh, letting unmatched globs pass through as literal strings
- Applied to both PTY and child-process execution paths
## Motivation
When OpenClaw runs on macOS with zsh as the default shell, commands like:
```
yt-summary add https://www.youtube.com/watch?v=xxxxx
```
fail with `zsh: no matches found: https://www.youtube.com/watch?v=xxxxx` because zsh interprets `?v=xxxxx` as a glob pattern.
The `setopt nonomatch` builtin tells zsh to pass unmatched glob patterns through as literal strings (matching bash's default behavior), without affecting any other shell behavior.
## Changes
| File | Change |
|------|--------|
| `src/agents/shell-utils.ts` | Add `wrapCommandForShell()` — prefixes with `setopt nonomatch;` for zsh, no-op for other shells |
| `src/agents/bash-tools.exec-runtime.ts` | Wrap `execCommand` before passing to child argv and PTY |
| `src/process/supervisor/supervisor.ts` | Wrap `ptyCommand` in the PTY adapter path |
| `src/process/supervisor/supervisor.pty-command.test.ts` | Add `wrapCommandForShell` to the shell-utils mock |
## Test plan
- [x] `tsgo --noEmit` passes (no type errors in modified files)
- [x] Existing `supervisor.pty-command.test.ts` passes (mock updated)
- [ ] Manual test: run `exec` with a URL containing `?` on zsh — should no longer error
Fixes #19496
Related #12727
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes zsh glob expansion errors by prefixing commands with `setopt nonomatch;` when the resolved shell is zsh. This prevents `no matches found` errors for unquoted glob characters (like `?` in URLs). The fix is applied consistently across both PTY and child-process execution paths in `bash-tools.exec-runtime.ts` and `supervisor.ts`.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge after addressing the test assertion issue
- The fix correctly addresses the zsh glob expansion issue with a minimal, targeted change. The implementation is sound and applied consistently across all execution paths. However, there's a test assertion that assumes commands are passed verbatim, which will fail when the actual shell is zsh since `wrapCommandForShell` will modify the command.
- src/process/supervisor/supervisor.pty-command.test.ts - test assertion needs adjustment
<sub>Last reviewed commit: d1076ad</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#11961: fix: exec tool wraps shebang scripts in heredoc to use correct inte...
by scott-memco · 2026-02-08
76.8%
#12308: fix(cli): redirect log output to stderr during completion script ge...
by mcaxtr · 2026-02-09
76.4%
#11300: feat(exec): make shell configurable via tools.exec.shell
by imjszhang · 2026-02-07
75.3%
#17437: fix(completion): avoid rc=1 for optionless zsh leaf commands
by ephelia-ai · 2026-02-15
74.4%
#11362: fix: name parent shim processes for clarity in ps output
by anooprdawar · 2026-02-07
74.1%
#6382: fix(cli): silence Powerlevel10k Zsh warning from completion script
by dungngo4520 · 2026-02-01
74.0%
#9148: Fix: Speed up shell completion generation from ~4.6s to <200ms
by vishaltandale00 · 2026-02-04
73.7%
#17325: fix(completion): avoid zsh compdef error when compinit is not initi...
by ephelia-ai · 2026-02-15
73.1%
#20553: fix(completion): guard zsh compdef call for environments without co...
by mr-sk · 2026-02-19
73.1%
#20177: fix(security): block command substitution in unquoted heredoc bodies
by orlyjamie · 2026-02-18
72.8%