Commit Graph

3718 Commits

  • Added allow-expect-in-tests / allow-unwrap-in-tests (#2328)
    This PR:
    * Added the clippy.toml to configure allowable expect / unwrap usage in
    tests
    * Removed as many expect/allow lines as possible from tests
    * moved a bunch of allows to expects where possible
    
    Note: in integration tests, non `#[test]` helper functions are not
    covered by this so we had to leave a few lingering `expect(expect_used`
    checks around
  • fix: trying to simplify rust-ci.yml (#2327)
    It turns out that https://github.com/openai/codex/pull/2324 did not
    quite work as intended. Chat's new idea is to have this catch-all "CI
    results" job and update our branch protection rules to require this
    instead.
  • Fix AF_UNIX, sockpair, recvfrom in linux sandbox (#2309)
    When using codex-tui on a linux system I was unable to run `cargo
    clippy` inside of codex due to:
    ```
    [pid 3548377] socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0,  <unfinished ...>
    [pid 3548370] close(8 <unfinished ...>
    [pid 3548377] <... socketpair resumed>0x7ffb97f4ed60) = -1 EPERM (Operation not permitted)
    ```
    And
    ```
    3611300 <... recvfrom resumed>0x708b8b5cffe0, 8, 0, NULL, NULL) = -1 EPERM (Operation not permitted)
    ```
    
    This PR:
    * Fixes a bug that disallowed AF_UNIX to allow it on `socket()`
    * Adds recvfrom() to the syscall allow list, this should be fine since
    we disable opening new sockets. But we should validate there is not a
    open socket inheritance issue.
    * Allow socketpair to be called for AF_UNIX
    * Adds tests for AF_UNIX components
    * All of which allows running `cargo clippy` within the sandbox on
    linux, and possibly other tooling using a fork server model + AF_UNIX
    comms.
  • Port login server to rust (#2294)
    Port the login server to rust.
    
    ---------
    
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • clear running commands in various places (#2325)
    we have a very unclear lifecycle for the chatwidget—this should only
    have to be added in one place! but this fixes the "hanging commands"
    issue where the active_exec_cell wasn't correctly cleared when commands
    finished.
    
    To repro w/o this PR:
    1. prompt "run sleep 10"
    2. once the command starts running, press <kbd>Esc</kbd>
    3. prompt "run echo hi"
    
    Expected: 
    
    ```
    ✓ Completed
      └ ⌨️ echo hi
    
    codex
    hi
    ```
    
    Actual:
    
    ```
    ⚙︎ Working
      └ ⌨️ echo hi
    
    ▌ Ask Codex to do anything
    ```
    
    i.e. the "Working" never changes to "Completed".
    
    The bug is fixed with this PR.
  • fix: ensure rust-ci always "runs" when a PR is submitted (#2324)
    Our existing path filters for `rust-ci.yml`:
    
    
    https://github.com/openai/codex/blob/235987843c3d6647c0819c1071f9b9f064673e9c/.github/workflows/rust-ci.yml#L1-L11
    
    made it so that PRs that touch only `README.md` would not trigger those
    builds, which is a problem because our branch protection rules are set
    as follows:
    
    <img width="1569" height="1883" alt="Screenshot 2025-08-14 at 4 45
    59 PM"
    src="https://github.com/user-attachments/assets/5a61f8cc-cdaf-4341-abda-7faa7b46dbd4"
    />
    
    With the existing setup, a change to `README.md` would get stuck in
    limbo because not all the CI jobs required to merge would get run. It
    turns out that we need to "run" all the jobs, but make them no-ops when
    the `codex-rs` and `.github` folders are untouched to get the best of
    both worlds.
    
    I asked chat how to fix this, as we want CI to be fast for
    documentation-only changes. It had two suggestions:
    
    - Use https://github.com/dorny/paths-filter or some other third-party
    action.
    - Write an inline Bash script to avoid a third-party dependency.
    
    This PR takes the latter approach so that we are clear about what we're
    running in CI.
  • add a timer to running exec commands (#2321)
    sometimes i switch back to codex and i don't know how long a command has
    been running.
    
    <img width="744" height="462" alt="Screenshot 2025-08-14 at 3 30 07 PM"
    src="https://github.com/user-attachments/assets/bd80947f-5a47-43e6-ad19-69c2995a2a29"
    />
  • fix: run python_multiprocessing_lock_works integration test on Mac and Linux (#2318)
    The high-order bit on this PR is that it makes it so `sandbox.rs` tests
    both Mac and Linux, as we introduce a general
    `spawn_command_under_sandbox()` function with platform-specific
    implementations for testing.
    
    An important, and interesting, discovery in porting the test to Linux is
    that (for reasons cited in the code comments), `/dev/shm` has to be
    added to `writable_roots` on Linux in order for `multiprocessing.Lock`
    to work there. Granting write access to `/dev/shm` comes with some
    degree of risk, so we do not make this the default for Codex CLI.
    
    Piggybacking on top of #2317, this moves the
    `python_multiprocessing_lock_works` test yet again, moving
    `codex-rs/core/tests/sandbox.rs` to `codex-rs/exec/tests/sandbox.rs`
    because in `codex-rs/exec/tests` we can use `cargo_bin()` like so:
    
    ```
    let codex_linux_sandbox_exe = assert_cmd::cargo::cargo_bin("codex-exec");
    ```
    
    which is necessary so we can use `codex_linux_sandbox_exe` and therefore
    `spawn_command_under_linux_sandbox` in an integration test.
    
    This also moves `spawn_command_under_linux_sandbox()` out of `exec.rs`
    and into `landlock.rs`, which makes things more consistent with
    `seatbelt.rs` in `codex-core`.
    
    For reference, https://github.com/openai/codex/pull/1808 is the PR that
    made the change to Seatbelt to get this test to pass on Mac.
  • fix: move general sandbox tests to codex-rs/core/tests/sandbox.rs (#2317)
    Previous to this PR, `codex-rs/core/tests/sandbox.rs` contained
    integration tests that were specific to Seatbelt. This PR moves those
    tests to `codex-rs/core/src/seatbelt.rs` and designates
    `codex-rs/core/tests/sandbox.rs` to be used as the home for
    cross-platform (well, Mac and Linux...) sandbox tests.
    
    To start, this migrates
    `python_multiprocessing_lock_works_under_seatbelt()` from #1823 to the
    new `sandbox.rs` because this is the type of thing that should work on
    both Mac _and_ Linux, though I still need to do some work to clean up
    the test so it works on both platforms.
  • test(core): add seatbelt sem lock tests (#1823)
    ## Summary
    - add a unit test to ensure the macOS seatbelt policy allows POSIX
    semaphores
    - add a macOS-only test that runs a Python multiprocessing Lock under
    Seatbelt
    
    ## Testing
    - `cargo test -p codex_core seatbelt_base_policy_allows_ipc_posix_sem
    --no-fail-fast` (failed: failed to download from
    `https://static.crates.io/crates/tokio-stream/0.1.17/download`)
    - `cargo test -p codex_core seatbelt_base_policy_allows_ipc_posix_sem
    --no-fail-fast --offline` (failed: attempting to make an HTTP request,
    but --offline was specified)
    - `cargo test --all-features --no-fail-fast --offline` (failed:
    attempting to make an HTTP request, but --offline was specified)
    - `just fmt` (failed: command not found: just)
    - `just fix` (failed: command not found: just)
    
    Ran tests locally to confirm it passes on master and failed before my
    previous change
    
    ------
    https://chatgpt.com/codex/tasks/task_i_6890f221e0a4833381cfb53e11499bcc
  • fix bash commands being incorrectly quoted in display (#2313)
    The "display format" of commands was sometimes producing incorrect
    quoting like `echo foo '>' bar`, which is importantly different from the
    actual command that was being run. This refactors ParsedCommand to have
    a string in `cmd` instead of a vec, as a `vec` can't accurately capture
    a full command.
  • use a central animation loop (#2268)
    instead of each shimmer needing to have its own animation thread, have
    render_ref schedule a new frame if it wants one and coalesce to the
    earliest next frame. this also makes the animations
    frame-timing-independent, based on start time instead of frame count.
  • text elements in textarea for pasted content (#2302)
    This improves handling of pasted content in the textarea. It's no longer
    possible to partially delete a placeholder (e.g. by ^W or ^D), nor is it
    possible to place the cursor inside a placeholder. Also, we now render
    placeholders in a different color to make them more clearly
    differentiated.
    
    
    https://github.com/user-attachments/assets/2051b3c3-963d-4781-a610-3afee522ae29
  • fix: do not allow dotenv to create/modify environment variables starting with CODEX_ (#2308)
    This ensures Codex cannot drop a `.env` file with a value of
    `CODEX_HOME` that points to a folder that Codex can control.
  • fix: parallelize logic in Session::new() (#2305)
    #2291 made it so that `Session::new()` is on the critical path to
    `Codex::spawn()`, which means it is on the hot path to CLI startup. This
    refactors `Session::new()` to run a number of async tasks in parallel
    that were previously run serially to try to reduce latency.
  • remove logs from composer by default (#2307)
    Currently the composer shows `handle_codex_event:<event name>` by
    default which feels confusing. Let's make it appear in trace.
  • remove the · animation (#2271)
    the pulsing dot felt too noisy to me next to the shimmering "Working"
    text. we'll bring it back for streaming response text perhaps?
  • [context] Store context messages in rollouts (#2243)
    ## Summary
    Currently, we use request-time logic to determine the user_instructions
    and environment_context messages. This means that neither of these
    values can change over time as conversations go on. We want to add in
    additional details here, so we're migrating these to save these messages
    to the rollout file instead. This is simpler for the client, and allows
    us to append additional environment_context messages to each turn if we
    want
    
    ## Testing
    - [x] Integration test coverage
    - [x] Tested locally with a few turns, confirmed model could reference
    environment context and cached token metrics were reasonably high
  • remove "status text" in bottom line (#2279)
    this used to hold the most recent log line, but it was kinda broken and
    not that useful.
  • HistoryCell is a trait (#2283)
    refactors HistoryCell to be a trait instead of an enum. Also collapse
    the many "degenerate" HistoryCell enums which were just a store of lines
    into a single PlainHistoryCell type.
    
    The goal here is to allow more ways of rendering history cells (e.g.
    expanded/collapsed/"live"), and I expect we will return to more varied
    types of HistoryCell as we develop this area.
  • Tag InputItem (#2304)
    Instead of:
    ```
    { Text: { text: string } }
    ```
    
    It is now:
    ```
    { type: "text", data: { text: string } }
    ```
    which makes for cleaner discriminated unions
  • exploration: create Session as part of Codex::spawn() (#2291)
    Historically, `Codex::spawn()` would create the instance of `Codex` and
    enforce, by construction, that `Op::ConfigureSession` was the first `Op`
    submitted via `submit()`. Then over in `submission_loop()`, it would
    handle the case for taking the parameters of `Op::ConfigureSession` and
    turning it into a `Session`.
    
    This approach has two challenges from a state management perspective:
    
    
    https://github.com/openai/codex/blob/f968a1327ad39a7786759ea8f1d1c088fe41e91b/codex-rs/core/src/codex.rs#L718
    
    - The local `sess` variable in `submission_loop()` has to be `mut` and
    `Option<Arc<Session>>` because it is not invariant that a `Session` is
    present for the lifetime of the loop, so there is a lot of logic to deal
    with the case where `sess` is `None` (e.g., the `send_no_session_event`
    function and all of its callsites).
    - `submission_loop()` is written in such a way that
    `Op::ConfigureSession` could be observed multiple times, but in
    practice, it is only observed exactly once at the start of the loop.
    
    In this PR, we try to simplify the state management by _removing_ the
    `Op::ConfigureSession` enum variant and constructing the `Session` as
    part of `Codex::spawn()` so that it can be passed to `submission_loop()`
    as `Arc<Session>`. The original logic from the `Op::ConfigureSession`
    has largely been moved to the new `Session::new()` constructor.
    
    ---
    
    Incidentally, I also noticed that the handling of `Op::ConfigureSession`
    can result in events being dispatched in addition to
    `EventMsg::SessionConfigured`, as an `EventMsg::Error` is created for
    every MCP initialization error, so it is important to preserve that
    behavior:
    
    
    https://github.com/openai/codex/blob/f968a1327ad39a7786759ea8f1d1c088fe41e91b/codex-rs/core/src/codex.rs#L901-L916
    
    Though admittedly, I believe this does not play nice with #2264, as
    these error messages will likely be dispatched before the client has a
    chance to call `addConversationListener`, so we likely need to make it
    so `newConversation` automatically creates the subscription, but we must
    also guarantee that the "ack" from `newConversation` is returned before
    any other conversation-related notifications are sent so the client
    knows what `conversation_id` to match on.
  • feat: add support for an InterruptConversation request (#2287)
    This adds `ClientRequest::InterruptConversation`, which effectively maps
    directly to `Op::Interrupt`.
    
    ---
    
    * __->__  #2287
    * #2286
    * #2285
  • fix: add support for exec and apply_patch approvals in the new wire format (#2286)
    Now when `CodexMessageProcessor` receives either a
    `EventMsg::ApplyPatchApprovalRequest` or a
    `EventMsg::ExecApprovalRequest`, it sends the appropriate request from
    the server to the client. When it gets a response, it forwards it on to
    the `CodexConversation`.
    
    Note this takes a lot of code from:
    
    
    https://github.com/openai/codex/blob/main/codex-rs/mcp-server/src/conversation_loop.rs
    
    https://github.com/openai/codex/blob/main/codex-rs/mcp-server/src/exec_approval.rs
    
    https://github.com/openai/codex/blob/main/codex-rs/mcp-server/src/patch_approval.rs
    
    I am copy/pasting for now because I am trying to consolidate around the
    new `wire_format.rs`, so I plan to delete these other files soon.
    
    Now that we have requests going both from client-to-server and
    server-to-client, I renamed `CodexRequest` to `ClientRequest`.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2286).
    * #2287
    * __->__ #2286
    * #2285
  • fix: make all fields of Session private (#2285)
    As `Session` needs a bit of work, it will make things easier to move
    around if we can start by reducing the extent of its public API. This
    makes all the fields private, though adds three `pub(crate)` getters.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2285).
    * #2287
    * #2286
    * __->__ #2285
  • Parse reasoning text content (#2277)
    Sometimes COT is returns as text content instead of `ReasoningText`. We
    should parse it but not serialize back on requests.
    
    ---------
    
    Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
  • fix: verify notifications are sent with the conversationId set (#2278)
    This updates `CodexMessageProcessor` so that each notification it sends
    for a `EventMsg` from a `CodexConversation` such that:
    
    - The `params` always has an appropriate `conversationId` field.
    - The `method` is now includes the name of the `EventMsg` type rather
    than using `codex/event` as the `method` type for all notifications. (We
    currently prefix the method name with `codex/event/`, but I think that
    should go away once we formalize the notification schema in
    `wire_format.rs`.)
    
    As part of this, we update `test_codex_jsonrpc_conversation_flow()` to
    verify that the `task_finished` notification has made it through the
    system instead of sleeping for 5s and "hoping" the server finished
    processing the task. Note we have seen some flakiness in some of our
    other, similar integration tests, and I expect adding a similar check
    would help in those cases, as well.
  • feat: support traditional JSON-RPC request/response in MCP server (#2264)
    This introduces a new set of request types that our `codex mcp`
    supports. Note that these do not conform to MCP tool calls so that
    instead of having to send something like this:
    
    ```json
    {
      "jsonrpc": "2.0",
      "method": "tools/call",
      "id": 42,
      "params": {
        "name": "newConversation",
        "arguments": {
          "model": "gpt-5",
          "approvalPolicy": "on-request"
        }
      }
    }
    ```
    
    we can send something like this:
    
    
    ```json
    {
      "jsonrpc": "2.0",
      "method": "newConversation",
      "id": 42,
      "params": {
        "model": "gpt-5",
        "approvalPolicy": "on-request"
      }
    }
    ```
    
    Admittedly, this new format is not a valid MCP tool call, but we are OK
    with that right now. (That is, not everything we might want to request
    of `codex mcp` is something that is appropriate for an autonomous agent
    to do.)
    
    To start, this introduces four request types:
    
    - `newConversation`
    - `sendUserMessage`
    - `addConversationListener`
    - `removeConversationListener`
    
    The new `mcp-server/tests/codex_message_processor_flow.rs` shows how
    these can be used.
    
    The types are defined on the `CodexRequest` enum, so we introduce a new
    `CodexMessageProcessor` that is responsible for dealing with requests
    from this enum. The top-level `MessageProcessor` has been updated so
    that when `process_request()` is called, it first checks whether the
    request conforms to `CodexRequest` and dispatches it to
    `CodexMessageProcessor` if so.
    
    Note that I also decided to use `camelCase` for the on-the-wire format,
    as that seems to be the convention for MCP.
    
    For the moment, the new protocol is defined in `wire_format.rs` within
    the `mcp-server` crate, but in a subsequent PR, I will probably move it
    to its own crate to ensure the protocol has minimal dependencies and
    that we can codegen a schema from it.
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2264).
    * #2278
    * __->__ #2264
  • Enable reasoning for codex-prefixed models (#2275)
    ## Summary
    - enable reasoning for any model slug starting with `codex-`
    - provide default model info for `codex-*` slugs
    - test that codex models are detected and support reasoning
    
    ## Testing
    - `just fmt`
    - `just fix` *(fails: E0658 `let` expressions in this position are
    unstable)*
    - `cargo test --all-features` *(fails: E0658 `let` expressions in this
    position are unstable)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_689d13f8705483208a6ed21c076868e1
  • fix: skip cargo test for release builds on ordinary CI because it is slow, particularly with --all-features set (#2276)
    I put this PR together because I noticed I have to wait quite a bit
    longer on my PRs since we added
    https://github.com/openai/codex/pull/2242 to catch more build issues.
    
    I think we should think about reigning in our use of create features,
    but this should be good enough to speed things up for now.
  • tui: standardize tree prefix glyphs to └ (#2274)
    Replace mixed `⎿` and `L` prefixes with `└` in TUI rendering.
    
    <img width="454" height="659" alt="Screenshot 2025-08-13 at 4 02 03 PM"
    src="https://github.com/user-attachments/assets/61c9c7da-830b-4040-bb79-a91be90870ca"
    />
  • use modifier dim instead of gray and .dim (#2273)
    gray color doesn't work very well with white terminals. `.dim` doesn't
    have an effect for some reason.
    
    after:
    <img width="1080" height="149" alt="image"
    src="https://github.com/user-attachments/assets/26c0f8bb-550d-4d71-bd06-11b3189bc1d7"
    />
    
    Before
    <img width="1077" height="186" alt="image"
    src="https://github.com/user-attachments/assets/b1fba0c7-bc4d-4da1-9754-6c0a105e8cd1"
    />
  • Wait for requested delay in rate limit errors (#2266)
    Fixes: https://github.com/openai/codex/issues/2131
    
    Response doesn't have the delay in a separate field (yet) so parse the
    message.
  • fix: update OutgoingMessageSender::send_response() to take Serialize (#2263)
    This makes `send_response()` easier to work with.
  • [codex-cli] Add ripgrep as a dependency for node environment (#2237)
    ## Summary
    Ripgrep is our preferred tool for file search. When users install via
    `brew install codex`, it's automatically installed as a dependency. We
    want to ensure that users running via an npm install also have this
    tool! Microsoft has already solved this problem for VS Code - let's not
    reinvent the wheel.
    
    This approach of appending to the PATH directly might be a bit
    heavy-handed, but feels reasonably robust to a variety of environment
    concerns. Open to thoughts on better approaches here!
    
    ## Testing
    - [x] confirmed this import approach works with `node -e "const { rgPath
    } = require('@vscode/ripgrep'); require('child_process').spawn(rgPath,
    ['--version'], { stdio: 'inherit' })"`
    - [x] Ran codex.js locally with `rg` uninstalled, asked it to run `which
    rg`. Output below:
    
    ```
     Ran command which rg; echo $?
      ⎿ /Users/dylan.hurd/code/dh--npm-rg/node_modules/@vscode/ripgrep/bin/rg
        0
    
    codex
    Re-running to confirm the path and exit code.
    
    - Path: `/Users/dylan.hurd/code/dh--npm-rg/node_modules/@vscode/ripgrep/bin/rg`
    - Exit code: `0`
    ```
  • chore: introduce ConversationManager as a clearinghouse for all conversations (#2240)
    This PR does two things because after I got deep into the first one I
    started pulling on the thread to the second:
    
    - Makes `ConversationManager` the place where all in-memory
    conversations are created and stored. Previously, `MessageProcessor` in
    the `codex-mcp-server` crate was doing this via its `session_map`, but
    this is something that should be done in `codex-core`.
    - It unwinds the `ctrl_c: tokio::sync::Notify` that was threaded
    throughout our code. I think this made sense at one time, but now that
    we handle Ctrl-C within the TUI and have a proper `Op::Interrupt` event,
    I don't think this was quite right, so I removed it. For `codex exec`
    and `codex proto`, we now use `tokio::signal::ctrl_c()` directly, but we
    no longer make `Notify` a field of `Codex` or `CodexConversation`.
    
    Changes of note:
    
    - Adds the files `conversation_manager.rs` and `codex_conversation.rs`
    to `codex-core`.
    - `Codex` and `CodexSpawnOk` are no longer exported from `codex-core`:
    other crates must use `CodexConversation` instead (which is created via
    `ConversationManager`).
    - `core/src/codex_wrapper.rs` has been deleted in favor of
    `ConversationManager`.
    - `ConversationManager::new_conversation()` returns `NewConversation`,
    which is in line with the `new_conversation` tool we want to add to the
    MCP server. Note `NewConversation` includes `SessionConfiguredEvent`, so
    we eliminate checks in cases like `codex-rs/core/tests/client.rs` to
    verify `SessionConfiguredEvent` is the first event because that is now
    internal to `ConversationManager`.
    - Quite a bit of code was deleted from
    `codex-rs/mcp-server/src/message_processor.rs` since it no longer has to
    manage multiple conversations itself: it goes through
    `ConversationManager` instead.
    - `core/tests/live_agent.rs` has been deleted because I had to update a
    bunch of tests and all the tests in here were ignored, and I don't think
    anyone ever ran them, so this was just technical debt, at this point.
    - Removed `notify_on_sigint()` from `util.rs` (and in a follow-up, I
    hope to refactor the blandly-named `util.rs` into more descriptive
    files).
    - In general, I started replacing local variables named `codex` as
    `conversation`, where appropriate, though admittedly I didn't do it
    through all the integration tests because that would have added a lot of
    noise to this PR.
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/2240).
    * #2264
    * #2263
    * __->__ #2240
  • fix: remove behavioral prompting from update_plan tool def (#2261)
    - Moved some of the content to the main prompt.
  • Update header from Working once batched commands are done (#2249)
    Update commands from Working to Complete or Failed after they're done
    
    before:
    <img width="725" height="332" alt="image"
    src="https://github.com/user-attachments/assets/fb93d21f-5c4a-42bc-a154-14f4fe99d5f9"
    />
    
    after:
    <img width="464" height="65" alt="image"
    src="https://github.com/user-attachments/assets/15ec7c3b-355f-473e-9a8e-eab359ec5f0d"
    />
  • feat(tui): add ctrl-b and ctrl-f shortcuts (#2260)
    ## Summary
    - support Ctrl-b and Ctrl-f to move the cursor left and right in the
    chat composer text area
    - test Ctrl-b/Ctrl-f cursor movements
    
    ## Testing
    - `just fmt`
    - `just fix` *(fails: `let` expressions in this position are unstable)*
    - `cargo test --all-features` *(fails: `let` expressions in this
    position are unstable)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_689cbd1d7968832e876fff169891e486
  • fix: display canonical command name in help (#2246)
    ## Summary
    - ensure CLI help uses `codex` as program name regardless of binary
    filename
    
    ## Testing
    - `just fmt`
    - `just fix` *(fails: `let` expressions in this position are unstable)*
    - `cargo test --all-features` *(fails: `let` expressions in this
    position are unstable)*
    
    ------
    https://chatgpt.com/codex/tasks/task_i_689bd5a731188320814dcbbc546ce22a
  • Fix frontend test (#2247)
    UI fixtures are brittle! Who knew.
  • Re-add markdown streaming (#2029)
    Wait for newlines, then render markdown on a line by line basis. Word wrap it for the current terminal size and then spit it out line by line into the UI. Also adds tests and fixes some UI regressions.
  • Fix build break and build release (#2242)
    Build release profile for one configuration.