Skip to content

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Jan 13, 2026

Adds an integration test for the new behavior introduced in #9011. The work to create the test setup was substantial enough that I thought it merited a separate PR.

This integration test spawns codex in TUI mode, which requires spawning a PTY to run successfully, so I had to introduce quite a bit of scaffolding in run_codex_cli(). I was surprised to discover that we have not done this in our codebase before, so perhaps this should get moved to a common location so it can be reused.

The test itself verifies that a malformed rules in $CODEX_HOME prints a human-readable error message and exits nonzero.

Comment on lines +82 to +90
if chunk.windows(4).any(|window| window == b"\x1b[6n") {
let _ = writer_tx.send(b"\x1b[1;1R".to_vec()).await;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

output: String,
}

async fn run_codex_cli(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to have a small amount of inline / doc comments on this one to help give details about how it works.

Right now all I could really say is that there's a bunch of code that seems to work and codex understood it when it wrote it. I'd have to read every line to understand this code and then infer constraints / edge cases that are encoded here.

Base automatically changed from pr9011 to main January 13, 2026 23:21
bolinfest added a commit that referenced this pull request Jan 13, 2026
The underlying issue is that when we encountered an error starting a
conversation (any sort of error, though making `$CODEX_HOME/rules` a
file rather than folder was the example in #8803), then we were writing
the message to stderr, but this could be printed over by our UI
framework so the user would not see it. In general, we disallow the use
of `eprintln!()` in this part of the code for exactly this reason,
though this was suppressed by an `#[allow(clippy::print_stderr)]`.

This attempts to clean things up by changing `handle_event()` and
`handle_tui_event()` to return a `Result<AppRunControl>` instead of a
`Result<bool>`, which is a new type introduced in this PR (and depends
on `ExitReason`, also a new type):

```rust
#[derive(Debug)]
pub(crate) enum AppRunControl {
    Continue,
    Exit(ExitReason),
}

#[derive(Debug, Clone)]
pub enum ExitReason {
    UserRequested,
    Fatal(String),
}
```

This makes it possible to exit the primary control flow of the TUI with
richer information. This PR adds `ExitReason` to the existing
`AppExitInfo` struct and updates `handle_app_exit()` to print the error
and exit code `1` in the event of `ExitReason::Fatal`.

I tried to create an integration test for this, but it was a bit
involved, so I published it as a separate PR:
#9166. For this PR, please have
faith in my manual testing!

Fixes #8803.




---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/9011).
* #9166
* __->__ #9011
@bolinfest bolinfest enabled auto-merge (squash) January 13, 2026 23:24
@bolinfest bolinfest merged commit 4c67308 into main Jan 13, 2026
62 of 64 checks passed
@bolinfest bolinfest deleted the pr9166 branch January 13, 2026 23:39
@github-actions github-actions bot locked and limited conversation to collaborators Jan 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants