As described in
https://github.com/openai/codex/issues/392#issuecomment-2817090022
introduced by #400
The testing I'd done worked correctly because I was using the (s)
shortcut, but selecting the same option using arrow‑key → Enter on
“Switch approval mode” was preventing the user from subsequently exiting
the Switch approval mode dialog, requiring a ^C to quit codex entirely.
With this fix, both entry methods work correctly in my testing.
Per codex:
Issue
- When you navigated down (↓) to “Switch approval mode (s)” in the Shell
Command review dialog and pressed Enter, the ApprovalModeOverlay would
open—but because the underlying `TerminalChatCommandReview` component
stayed mounted (albeit disabled), its own Ink input handlers immediately
re‑captured the same key events and re‑opened the overlay as soon as you
hit Esc or Enter again. In practice this made it impossible to exit the
submenu.
Root cause
- We only disabled the SelectInput via `isDisabled`, but never fully
unmounted the review UI when an overlay was shown, so its `useInput` and
`<Select>` hooks were still active and “stealing” keys.
Fix
- In `terminal-chat.tsx` we now only render `<TerminalChatInput>` (and
by extension `TerminalChatCommandReview`) when `overlayMode === "none"`.
That unmounts all of its key handlers whenever any overlay (history,
model, approval, help, diff) is open, so no input leaks through.
Files changed
- **src/components/chat/terminal-chat.tsx**: Wrapped the entire
`<TerminalChatInput>` block in `overlayMode === "none" && agent`
With that in place, arrow‑key → Enter on “Switch approval mode”
correctly opens the overlay, and then you can use Enter/Esc inside the
overlay without getting stuck or immediately re‑opening it.
## Description
This PR fixes Issue #421 where commands with pipes (e.g., `grep -R ...
-n | head -n 20`) were failing to execute properly after PR #391 was
merged.
## Changes
- Modified the `requiresShell` function to only enable shell mode when
the command is a single string containing shell operators
- Added logic to handle the case where shell operators are passed as
separate arguments
- Added comprehensive tests to verify the fix
## Root Cause
The issue was that the `requiresShell` function was detecting shell
operators like `|` even when they were passed as separate arguments,
which caused the command to be executed with `shell: true`
unnecessarily. This was causing syntax errors when running commands with
pipes.
## Testing
- Added unit tests to verify the fix
- Manually tested with real commands using pipes
- Ensured all existing tests pass
Fixes#421
This PR improves the reliability of `raw-exec-process-group.test`,
addressing [#415](https://github.com/openai/codex/issues/415)
Before: The test would fail sporadically in CI because it checked for
process termination immediately after abort, without accounting for the
time it takes for processes to fully terminate.
Now: We've added a robust `ensureProcessGone` helper that:
- Polls the process status with a 500ms timeout
- Retries every 50ms if the process is still alive
- Provides clear error messages if termination takes too long
We now wait for the child process to fully exit after sending abort
signals, instead of assuming instant death, fixing flakiness caused by
asynchronous process termination.
Changes:
- Added `ensureProcessGone` helper function with retry logic
- Improved error handling and timeout management
See [this bash
demo](https://gist.github.com/jdocherty/a84dbca2fbf7b47e5f95c87a07034ae8)
for a minimal reproduction of why process death is asynchronous and why
the test needs to retry after aborting.
It appears that use of `isLoggingEnabled()` was erroneously copypasta'd
in many places. This PR updates its docstring to clarify that should
only be used to avoid constructing a potentially expensive docstring.
With this change, the only function that merits/uses this check is
`execCommand()`.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/420).
* #423
* __->__ #420
* #419
To play it safe, let's keep `CONFIG_DIR` out of the default list of
writable roots.
This also fixes an issue where `execWithSeatbelt()` was modifying
`writableRoots` instead of creating a new array.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/419).
* #423
* #420
* __->__ #419
## Description
This PR implements multi-line input support for Codex when it asks for
user feedback (Issue #344). Users can now use Shift+Enter to add new
lines in their responses, making it easier to provide formatted code
snippets, lists, or other structured content.
## Changes
- Replace the single-line TextInput component with the
MultilineTextEditor component in terminal-chat-input.tsx
- Add support for Shift+Enter to create new lines
- Update key handling logic to properly handle history navigation in a
multi-line context
- Add reference to the editor to access cursor position information
- Update help text to inform users about the Shift+Enter functionality
- Add tests for the new functionality
## Testing
- Added new test file (terminal-chat-input-multiline.test.tsx) to test
the multi-line input functionality
- All existing tests continue to pass
- Manually tested the feature to ensure it works as expected
## Fixes
Closes#344
## Screenshots
N/A
## Additional Notes
This implementation maintains backward compatibility while adding the
requested multi-line input functionality. The UI remains clean and
intuitive, with a simple hint about using Shift+Enter for new lines.
---------
Co-authored-by: Thibault Sottiaux <tibo@openai.com>
https://github.com/openai/codex/pull/160 introduced a call to `exec()`
that takes a format string as an argument, but it is not clear that the
expansions within the format string are escaped safely. As written, it
is possible a carefully crafted command (e.g., if `cwd` were `"; && rm
-rf` or something...) could run arbitrary code.
Moving to `spawn()` makes this a bit better, as now at least `spawn()`
itself won't run an arbitrary process, though I suppose `osascript`
itself still could if the value passed to `-e` were abused. I'm not
clear on the escaping rules for AppleScript to ensure that `safePreview`
and `cwd` are injected safely.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/416).
* #423
* #420
* #419
* __->__ #416
This check was lost in https://github.com/openai/codex/pull/287. Both
the root folder and `codex-cli/` have their own `pnpm format` commands
that check the formatting of different things.
Also ran `pnpm format:fix` to fix the formatting violations that got in
while this was disabled in CI.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/417).
* #420
* #419
* #416
* __->__ #417