Commit Graph

3999 Commits

  • chore: change catalog mode to enum (#12656)
    make presence of custom catalog more clear by changing to enum instead
    of bool.
  • Fix js_repl view_image attachments in nested tool calls (#12725)
    ## Summary
    
    - Fix `js_repl` so `await codex.tool("view_image", { path })` actually
    attaches the image to the active turn when called from inside the JS
    REPL.
    - Restore the behavior expected by the existing `js_repl`
    image-attachment test.
    - This is a follow-up to
    [#12553](https://github.com/openai/codex/pull/12553), which changed
    `view_image` to return structured image content.
    
    ## Root Cause
    
    - [#12553](https://github.com/openai/codex/pull/12553) changed
    `view_image` from directly injecting a pending user image message to
    returning structured `function_call_output` content items.
    - The nested tool-call bridge inside `js_repl` serialized that tool
    response back to the JS runtime, but it did not mirror returned image
    content into the active turn.
    - As a result, `view_image` appeared to succeed inside `js_repl`, but no
    `input_image` was actually attached for the outer turn.
    
    ## What Changed
    
    - Updated the nested tool-call path in `js_repl` to inspect function
    tool responses for structured content items.
    - When a nested tool response includes `input_image` content, `js_repl`
    now injects a corresponding user `Message` into the active turn before
    returning the raw tool result back to the JS runtime.
    - Kept the normal JSON result flow intact, so `codex.tool(...)` still
    returns the original tool output object to JavaScript.
    
    ## Why
    
    - `js_repl` documentation and tests already assume that `view_image` can
    be used from inside the REPL to attach generated images to the model.
    - Without this fix, the nested call path silently dropped that
    attachment behavior.
  • add AWS_LC_SYS_NO_JITTER_ENTROPY=1 to release musl build step to unblock releases (#12720)
    linux musl build steps in `rust-release.yml` are [currently
    broken](https://github.com/openai/codex/actions/runs/22367312571)
    because of linking issues due to ubsan-calling types (`jitterentropy`)
    leaking into the build.
    
    add `AWS_LC_SYS_NO_JITTER_ENTROPY=1` to the musl build step to avoid
    linking those ubsan-calling types. this is a more temporary fix, we need
    to clean up ubsan usage upstream so they dont leak into release-build
    steps anyways.
    
    codex's more thorough explanation below:
    
    [pr 9859](https://github.com/openai/codex/pull/9859) added [MITM
    init](https://github.com/openai/codex/pull/9859/changes#diff-db782967007060c5520651633e1ea21681d64be21f2b791d3d84519860245b97R62-R68)
    in network-proxy, which wires in cert generation code (rcgen/rustls).
    this didnt bump/change dep versions, but it changed symbol reachability
    at link time.
    
    for musl builds, that made aws-lc-sys’s jitterentropy objects get pulled
    into the final link. those objects contain UBSan calls
    (__ubsan_handle_*). musl release linking is static (*-linux-musl-gcc,
    -nodefaultlibs) and does not link a musl UBSan runtime, so link fails
    with undefined __ubsan_*.
    
    before, our custom musl CI UBSan steps (install libubsan1, RUSTC_WRAPPER
    + LD_PRELOAD, partial flag scrubbing) masked some sanitizer issues.
    after this pr, more aws-lc code became link-reachable, and that band-aid
    wasn't enough.
  • feat: pass helper executable paths via Arg0DispatchPaths (#12719)
    ## Why
    
    `codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs` previously
    located `codex-execve-wrapper` by scanning `PATH` and sibling
    directories. That lookup is brittle and can select the wrong binary when
    the runtime environment differs from startup assumptions.
    
    We already pass `codex-linux-sandbox` from `codex-arg0`;
    `codex-execve-wrapper` should use the same startup-driven path plumbing.
    
    ## What changed
    
    - Introduced `Arg0DispatchPaths` in `codex-arg0` to carry both helper
    executable paths:
      - `codex_linux_sandbox_exe`
      - `main_execve_wrapper_exe`
    - Updated `arg0_dispatch_or_else()` to pass `Arg0DispatchPaths` to
    top-level binaries and preserve helper paths created in
    `prepend_path_entry_for_codex_aliases()`.
    - Threaded `Arg0DispatchPaths` through entrypoints in `cli`, `exec`,
    `tui`, `app-server`, and `mcp-server`.
    - Added `main_execve_wrapper_exe` to core configuration plumbing
    (`Config`, `ConfigOverrides`, and `SessionServices`).
    - Updated zsh-fork shell escalation to consume the configured
    `main_execve_wrapper_exe` and removed path-sniffing fallback logic.
    - Updated app-server config reload paths so reloaded configs keep the
    same startup-provided helper executable paths.
    
    ## References
    
    - [`Arg0DispatchPaths`
    definition](https://github.com/openai/codex/blob/e355b43d5c2a771f045296a6deae10d7c9c36ec6/codex-rs/arg0/src/lib.rs#L20-L24)
    - [`arg0_dispatch_or_else()` forwarding both
    paths](https://github.com/openai/codex/blob/e355b43d5c2a771f045296a6deae10d7c9c36ec6/codex-rs/arg0/src/lib.rs#L145-L176)
    - [zsh-fork escalation using configured wrapper
    path](https://github.com/openai/codex/blob/e355b43d5c2a771f045296a6deae10d7c9c36ec6/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs#L109-L150)
    
    ## Testing
    
    - `cargo check -p codex-arg0 -p codex-core -p codex-exec -p codex-tui -p
    codex-mcp-server -p codex-app-server`
    - `cargo test -p codex-arg0`
    - `cargo test -p codex-core tools::runtimes::shell::unix_escalation:: --
    --nocapture`
  • fix: clarify the value of SkillMetadata.path (#12729)
    Rename `SkillMetadata.path` to `SkillMetadata.path_to_skills_md` for
    clarity.
    
    Would ideally change the type to `AbsolutePathBuf`, but that can be done
    later.
  • fix(js_repl): surface uncaught kernel errors and reset cleanly (#12636)
    ## Summary
    
    Improve `js_repl` behavior when the Node kernel hits a process-level
    failure (for example, an uncaught exception or unhandled Promise
    rejection).
    
    Instead of only surfacing a generic `js_repl kernel exited unexpectedly`
    after stdout EOF, `js_repl` now returns a clearer exec error for the
    active request, then resets the kernel cleanly.
    
    ## Why
    
    Some sandbox-denied operations can trigger Node errors that become
    process-level failures (for example, an unhandled EventEmitter `'error'`
    event). In that case:
    
    - the kernel process exits,
    - the host sees stdout EOF,
    - the user gets a generic kernel-exit error,
    - and the next request can briefly race with stale kernel state.
    
    This change improves that failure mode without monkeypatching Node APIs.
    
    ## Changes
    
    ### Kernel-side (`js_repl` Node process)
    - Add process-level handlers for:
      - `uncaughtException`
      - `unhandledRejection`
    - When one of these fires:
      - best-effort emit a normal `exec_result` error for the active exec
    - include actionable guidance to catch/handle async errors (including
    Promise rejections and EventEmitter `'error'` events)
      - exit intentionally so the host can reset/restart the kernel
    
    ### Host-side (`JsReplManager`)
    - Clear dead kernel state as soon as the stdout reader observes
    unexpected kernel exit/EOF.
    - This lets the next `js_repl` exec start a fresh kernel instead of
    hitting a stale broken-pipe path.
    
    ### Tests
    - Add regression coverage for:
    - uncaught async exception -> exec error + kernel recovery on next exec
    - Update forced-kernel-exit test to validate recovery behavior (next
    exec restarts cleanly)
    
    ## Impact
    
    - Better user-facing error for kernel crashes caused by
    uncaught/unhandled async failures.
    - Cleaner recovery behavior after kernel exit.
    
    ## Validation
    
    - `cargo test -p codex-core --lib
    tools::js_repl::tests::js_repl_uncaught_exception_returns_exec_error_and_recovers
    -- --exact`
    - `cargo test -p codex-core --lib
    tools::js_repl::tests::js_repl_forced_kernel_exit_recovers_on_next_exec
    -- --exact`
    - `just fmt`
  • codex-rs/app-server: graceful websocket restart on Ctrl-C (#12517)
    ## Summary
    - add graceful websocket app-server restart on Ctrl-C by draining until
    no assistant turns are running
    - stop the websocket acceptor and disconnect existing connections once
    the drain condition is met
    - add a websocket integration test that verifies Ctrl-C waits for an
    in-flight turn before exit
    
    ## Verification
    - `cargo check -p codex-app-server --quiet`
    - `cargo test -p codex-app-server --test all
    suite::v2::connection_handling_websocket`
    - I (maxj) tested remote and local Codex.app
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: make EscalateServer public and remove shell escalation wrappers (#12724)
    ## Why
    
    `codex-shell-escalation` exposed a `codex-core`-specific adapter layer
    (`ShellActionProvider`, `ShellPolicyFactory`, and `run_escalate_server`)
    that existed only to bridge `codex-core` to `EscalateServer`. That
    indirection increased API surface and obscured crate ownership without
    adding behavior.
    
    This change moves orchestration into `codex-core` so boundaries are
    clearer: `codex-shell-escalation` provides reusable escalation
    primitives, and `codex-core` provides shell-tool policy decisions.
    
    Admittedly, @pakrym rightfully requested this sort of cleanup as part of
    https://github.com/openai/codex/pull/12649, though this avoids moving
    all of `codex-shell-escalation` into `codex-core`.
    
    ## What changed
    
    - Made `EscalateServer` public and exported it from `shell-escalation`.
    - Removed the adapter layer from `shell-escalation`:
      - deleted `shell-escalation/src/unix/core_shell_escalation.rs`
    - removed exports for `ShellActionProvider`, `ShellPolicyFactory`,
    `EscalationPolicyFactory`, and `run_escalate_server`
    - Updated `core/src/tools/runtimes/shell/unix_escalation.rs` to:
      - create `Stopwatch`/cancellation in `codex-core`
      - instantiate `EscalateServer` directly
      - implement `EscalationPolicy` directly on `CoreShellActionProvider`
    
    Net effect: same escalation flow with fewer wrappers and a smaller
    public API.
    
    ## Verification
    
    - Manually reviewed the old vs. new escalation call flow to confirm
    timeout/cancellation behavior and approval policy decisions are
    preserved while removing wrapper types.
  • Raise image byte estimate for compaction token accounting (#12717)
    Increase `IMAGE_BYTES_ESTIMATE` from 340 bytes to 7,373 bytes so the
    existing 4-bytes/token heuristic yields an image estimate of ~1,844
    tokens instead of ~85. This makes auto-compaction more conservative for
    image-heavy transcripts and avoids underestimating context usage, which
    can otherwise cause compaction to fail when there is not enough free
    context remaining. The new value was chosen because that's the image
    resolution cap used for our latest models.
    
    Follow-up to [#12419](https://github.com/openai/codex/pull/12419).
    Refs [#11845](https://github.com/openai/codex/issues/11845).
  • Add app-server event tracing (#12695)
    To help with debugging
  • feat(tui) - /copy (#12613)
    # /copy!
    
    /copy allows you to copy the latest **complete** message from Codex on
    the TUI.
  • fix: temp remove citation (#12711)
    - **temp remove citation**
  • Agent jobs (spawn_agents_on_csv) + progress UI (#10935)
    ## Summary
    - Add agent job support: spawn a batch of sub-agents from CSV, auto-run,
    auto-export, and store results in SQLite.
    - Simplify workflow: remove run/resume/get-status/export tools; spawn is
    deterministic and completes in one call.
    - Improve exec UX: stable, single-line progress bar with ETA; suppress
    sub-agent chatter in exec.
    
    ## Why
    Enables map-reduce style workflows over arbitrarily large repos using
    the existing Codex orchestrator. This addresses review feedback about
    overly complex job controls and non-deterministic monitoring.
    
    ## Demo (progress bar)
    ```
    ./codex-rs/target/debug/codex exec \
      --enable collab \
      --enable sqlite \
      --full-auto \
      --progress-cursor \
      -c agents.max_threads=16 \
      -C /Users/daveaitel/code/codex \
      - <<'PROMPT'
    Create /tmp/agent_job_progress_demo.csv with columns: path,area and 30 rows:
    path = item-01..item-30, area = test.
    
    Then call spawn_agents_on_csv with:
    - csv_path: /tmp/agent_job_progress_demo.csv
    - instruction: "Run `python - <<'PY'` to sleep a random 0.3–1.2s, then output JSON with keys: path, score (int). Set score = 1."
    - output_csv_path: /tmp/agent_job_progress_demo_out.csv
    PROMPT
    ```
    
    ## Review feedback addressed
    - Auto-start jobs on spawn; removed run/resume/status/export tools.
    - Auto-export on success.
    - More descriptive tool spec + clearer prompts.
    - Avoid deadlocks on spawn failure; pending/running handled safely.
    - Progress bar no longer scrolls; stable single-line redraw.
    
    ## Tests
    - `cd codex-rs && cargo test -p codex-exec`
    - `cd codex-rs && cargo build -p codex-cli`
  • Honor project_root_markers when discovering AGENTS.md (#12639)
    Fixes #12128
    
    The docs indicates that `project_root_markers` are used to discover the
    project root for local config as well as `AGENTS.md`. It looks like it
    was never wired up to support the latter.
    
    Summary
    - resolve project docs by walking to the configured
    `project_root_markers` (or defaults) instead of assuming the Git root,
    while honoring CLI overrides and handling malformed configs
    - fall back to the project’s canonical path chain and add a test that
    makes sure custom markers upstream of `.git` are respected
  • Add TUI realtime conversation mode (#12687)
    - Add a hidden `realtime_conversation` feature flag and `/realtime`
    slash command for start/stop live voice sessions.
    - Reuse transcription composer/footer UI for live metering, stream mic
    audio, play assistant audio, render realtime user text events, and
    force-close on feature disable.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • refactor: remove unused seatbelt unix socket arg (#12707)
    https://github.com/openai/codex/pull/12052 introduced an
    `allowed_unix_socket_paths` parameter to
    `create_seatbelt_command_args()`, but
    https://github.com/openai/codex/pull/12649 removed the abstraction that
    #12052 introduced, so this parameter is no longer necessary as it is
    always an empty slice.
  • Ensure shell command skills trigger approval (#12697)
    Summary
    - detect skill-invoking shell commands based on the original command
    string, request approvals when needed, and cache positive decisions per
    session
    - keep implicit skill invocation emitted after approval and keep skill
    approval decline messaging centralized to the shell handler
    - expand and adjust skill approval tests to cover shell-based skill
    scripts while matching the new detection expectations
    
    Testing
    - Not run (not requested)
  • feat(tui): add theme-aware diff backgrounds with capability-graded palettes (#12581)
    ## Problem
    
    Diff lines used only foreground colors (green/red) with no background
    tinting, making them hard to scan. The gutter (line numbers) also had no
    theme awareness — dimmed text was fine on dark terminals but unreadable
    on light ones.
    
    ## Mental model
    
    Each diff line now has four styled layers: **gutter** (line number),
    **sign** (`+`/`-`), **content** (text), and **line background** (full
    terminal width). A `DiffTheme` enum (`Dark` / `Light`) is selected once
    per render by probing the terminal's queried background via
    `default_bg()`. A companion `DiffColorLevel` enum (`TrueColor` /
    `Ansi256` / `Ansi16`) is derived from `stdout_color_level()` and gates
    which palette is used. All style helpers dispatch on `(theme,
    DiffLineType, color_level)` to pick the right colors.
    
    | Theme Picker Wide | Theme Picker Narrow |
    |---|---|
    | <img width="1552" height="1012" alt="image"
    src="https://github.com/user-attachments/assets/231b21b7-32d4-4727-80ed-7d01924954be"
    /> | <img width="795" height="1012" alt="image"
    src="https://github.com/user-attachments/assets/549cacdf-daec-43c9-ad64-2a28d16d140e"
    /> |
    
    | Dark BG - 16 colors | Dark BG - 256 colors | Dark BG - True Colors |
    |---|---|---|
    | <img width="1552" height="1012" alt="dark-16colors"
    src="https://github.com/user-attachments/assets/fba36de3-c101-47d4-9e63-88cdd00410d0"
    /> | <img width="1552" height="1012" alt="dark-256colors"
    src="https://github.com/user-attachments/assets/f39e4307-c6b0-49c4-b4fe-bd26d3d8e41c"
    /> | <img width="1552" height="1012" alt="dark-truecolor"
    src="https://github.com/user-attachments/assets/1af4ec57-04bf-4dfb-8a44-0ab5e5aaaf18"
    /> |
    
    | Light BG - 16 colors | Light BG - 256 colors | Light BG - True Colors
    |
    |---|---|---|
    | <img width="1552" height="1012" alt="light-16colors"
    src="https://github.com/user-attachments/assets/2b5423d1-74b4-4b1e-8123-7c2488ff436b"
    /> | <img width="1552" height="1012" alt="light-256colors"
    src="https://github.com/user-attachments/assets/c94cff9a-8d3e-42c9-bbe7-079da39953a8"
    /> | <img width="1552" height="1012" alt="light-truecolor"
    src="https://github.com/user-attachments/assets/f73da626-725f-4452-99ee-69ef706df2c6"
    /> |
    
    ## Non-goals
    
    - No runtime theme switching beyond what `default_bg()` already
    provides.
    - No change to syntax highlighting theme selection or the highlight
    module.
    
    ## Tradeoffs
    
    - Three fixed palettes (truecolor RGB, 256-color indexed, 16-color
    named) are maintained rather than using `best_color` nearest-match. This
    is deliberate: `supports_color::on_cached(Stream::Stdout)` can misreport
    capabilities once crossterm enters the alternate screen, so hand-picked
    palette entries give better visual results than automatic quantization.
    - Delete lines in the syntax-highlighted path get `Modifier::DIM` to
    visually recede compared to insert lines. This trades some readability
    of deleted code for scan-ability of additions.
    - The theme picker's diff preview sets `preserve_side_content_bg: true`
    on `ListSelectionView` so diff background tints survive into the side
    panel. Other popups keep the default (`false`) to preserve their
    reset-background look.
    
    ## Architecture
    
    - **Color constants** are module-level `const` items grouped by palette
    tier: `DARK_TC_*` / `LIGHT_TC_*` (truecolor RGB tuples), `DARK_256_*` /
    `LIGHT_256_*` (xterm indexed), with named `Color` variants used for the
    16-color tier.
    - **`DiffTheme`** is a private enum; `diff_theme()` probes the terminal
    and `diff_theme_for_bg()` is the testable pure-function version.
    - **`DiffColorLevel`** is a private enum derived from `StdoutColorLevel`
    via `diff_color_level()`.
    - **Palette helpers** (`add_line_bg`, `del_line_bg`, `light_gutter_fg`,
    `light_add_num_bg`, `light_del_num_bg`) each take `(DiffTheme,
    DiffColorLevel)` or just `DiffColorLevel` and return a `Color`.
    - **Style helpers** (`style_line_bg_for`, `style_gutter_for`,
    `style_sign_add`, `style_sign_del`, `style_add`, `style_del`) each take
    `(DiffLineType, DiffTheme, DiffColorLevel)` or `(DiffTheme,
    DiffColorLevel)` and return a `Style`.
    - **`push_wrapped_diff_line_inner_with_theme_and_color_level`** is the
    innermost renderer, accepting both theme and color level so tests can
    exercise any combination without depending on the terminal.
    - **Line-level background** is applied via
    `RtLine::from(...).style(line_bg)` so the tint extends across the full
    terminal width, not just the text content.
    - **Theme picker integration**: `ListSelectionView` gained a
    `preserve_side_content_bg` flag. When `true`, the side panel skips
    `force_bg_to_terminal_bg`, letting diff preview backgrounds render
    faithfully.
    
    ## Observability
    
    No new logging. Theme selection is deterministic from `default_bg()`,
    which is already queried and cached at TUI startup.
    
    ## Tests
    
    1. **`DiffTheme` is determined per `render_change` call** — if
    `default_bg()` changes mid-render (e.g. `requery_default_colors()`
    fires), different file chunks could render with different themes. Low
    risk in practice since re-query only happens on explicit user action.
    2. **16-color tier uses named `Color` variants** (`Color::Green`,
    `Color::Red`, etc.) which the terminal maps to its own palette. On
    unusual terminal themes these could clash with the background.
    Acceptable since 16-color terminals already have unpredictable color
    rendering.
    3. **Light-theme `style_add` / `style_del` set bg but no fg** — on light
    terminals, non-syntax-highlighted content uses the terminal's default
    foreground against a pastel background. If the terminal's default fg
    happens to be very light, contrast could suffer. This is an edge case
    since light-terminal users typically have dark default fg.
    4. **`preserve_side_content_bg` is a general-purpose flag but only used
    by the theme picker** — if other popups start using side content with
    intentional backgrounds they'll need to opt in explicitly. Not a real
    risk today, just a note for future callers.
  • feat(sleep-inhibitor): add Linux and Windows idle-sleep prevention (#11766)
    ## Background
    - follow-up to previous macOS-only PR:
    https://github.com/openai/codex/pull/11711
    - follow-up macOS refactor PR (current structural approach used here):
    https://github.com/openai/codex/pull/12340
    
    ## Summary
    - extend `codex-utils-sleep-inhibitor` with Linux and Windows backends
    while preserving existing macOS behavior
    - Linux backend:
      - use `systemd-inhibit` (`--what=idle --mode=block`) when available
    - fall back to `gnome-session-inhibit` (`--inhibit idle`) when available
      - keep no-op behavior if neither backend exists on host
    - Windows backend:
    - use Win32 power request handles (`PowerCreateRequest` +
    `PowerSetRequest` / `PowerClearRequest`) with
    `PowerRequestSystemRequired`
    - make `prevent_idle_sleep` Experimental on macOS/Linux/Windows; keep
    under development on other targets
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-utils-sleep-inhibitor`
    - `cargo test -p codex-core features::tests::`
    - `cargo test -p codex-tui chatwidget::tests::`
    - `just fix -p codex-utils-sleep-inhibitor`
    - `just fix -p codex-core`
    
    ## Semantics and API references
    - Goal remains: prevent idle system sleep while a turn is running.
    - Linux:
      - `systemd-inhibit` / login1 inhibitor model:
    -
    https://www.freedesktop.org/software/systemd/man/latest/systemd-inhibit.html
    -
    https://www.freedesktop.org/software/systemd/man/org.freedesktop.login1.html
        - https://systemd.io/INHIBITOR_LOCKS/
      - xdg-desktop-portal Inhibit (relevant for sandboxed apps):
    -
    https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Inhibit.html
    - Windows:
      - `PowerCreateRequest`:
    -
    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-powercreaterequest
      - `PowerSetRequest`:
    -
    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-powersetrequest
      - `PowerClearRequest`:
    -
    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-powerclearrequest
      - `SetThreadExecutionState` (alternative baseline API):
    -
    https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate
    
    ## Chromium vs this PR
    - Chromium Linux backend:
    -
    https://github.com/chromium/chromium/blob/main/services/device/wake_lock/power_save_blocker/power_save_blocker_linux.cc
    - Chromium Windows backend:
    -
    https://github.com/chromium/chromium/blob/main/services/device/wake_lock/power_save_blocker/power_save_blocker_win.cc
    - Electron powerSaveBlocker entry point:
    -
    https://github.com/electron/electron/blob/main/shell/browser/api/electron_api_power_save_blocker.cc
    
    ## Why we differ from Chromium
    - Linux implementation mechanism:
    - Chromium uses in-process D-Bus APIs plus UI-integrated screen-saver
    suspension.
    - This PR uses command-based inhibitor backends (`systemd-inhibit`,
    `gnome-session-inhibit`) instead of linking a Linux D-Bus client in this
    crate.
    - Reason: keep `codex-utils-sleep-inhibitor` dependency-light and avoid
    Linux CI/toolchain fragility from new native D-Bus linkage, while
    preserving the same runtime intent (hold an inhibitor while a turn
    runs).
    - Linux UI integration scope:
    - Chromium also uses `display::Screen::SuspendScreenSaver()` in its UI
    stack.
    - Codex `codex-rs` does not have that display abstraction in this crate,
    so this PR scopes Linux behavior to process-level sleep inhibition only.
    - Windows wake-lock type breadth:
    - Chromium supports both display/system wake-lock types and extra
    display-specific handling for some pre-Win11 scenarios.
    - Codex’s feature is scoped to turn execution continuity (not forcing
    display on), so this PR uses `PowerRequestSystemRequired` only.
  • fix: also try matching namespaced prefix for modelinfo candidate (#12658)
    #### What
    Try matching `\w+`-namespaced model after `longest prefix` as heuristic
    to match `ModelInfo` from list of candidates.
    
    This shouldn't regress existing behavior:
    - `gpt-5.2-codex` -> `gpt-5.2` if `gpt-5.2-codex` not present
    - `gpt-5.3` -> `gpt-5` if `gpt-5.3` not present
    - `gpt-9` still doesn't match anything
    
    while being more forgiving for custom prefixes:
    - `oai/gpt-5.3-codex` -> `gpt-5.3-codex`
    
    #### Tests
    Added unit test.
  • Fix @mention token parsing in chat composer (#12643)
    Fixes #12175
    
    If a user types an npm package name with multiple `@` symbols like `npx
    -y @foo/bar@latest`, the TUI currently treats this as though it's
    attempting to invoke the file picker.
    
    ### What changed
    
    - **Generalized `@` token parsing**
    - `current_prefixed_token(...)` now treats `@` as a token start **only
    at a whitespace boundary** (or start-of-line).
    - If the cursor is on a nested `@` inside an existing
    whitespace-delimited token (for example `@scope/pkg@latest`), it keeps
    the surrounding token active instead of starting a new token at the
    second `@`.
    - It also avoids misclassifying mid-word usages like `foo@bar` as an `@`
    file token.
    
    - **Enter behavior with file popup**
    - If the file-search popup is open but has **no selected match**,
    pressing `Enter` now closes the popup and falls through to normal submit
    behavior.
    - This prevents pasted strings containing `@...` from blocking
    submission just because file-search was active with no actionable
    selection.
    
    ### Testing
    I manually built and tested the scenarios involved with the bug report
    and related use of `@` mentions to verify no regressions
  • feat: run zsh fork shell tool via shell-escalation (#12649)
    ## Why
    
    This PR switches the `shell_command` zsh-fork path over to
    `codex-shell-escalation` so the new shell tool can use the shared
    exec-wrapper/escalation protocol instead of the `zsh_exec_bridge`
    implementation that was introduced in
    https://github.com/openai/codex/pull/12052. `zsh_exec_bridge` relied on
    UNIX domain sockets, which is not as tamper-proof as the FD-based
    approach in `codex-shell-escalation`.
    
    ## What Changed
    
    - Added a Unix zsh-fork runtime adapter in `core`
    (`core/src/tools/runtimes/shell/unix_escalation.rs`) that:
    - runs zsh-fork commands through
    `codex_shell_escalation::run_escalate_server`
      - bridges exec-policy / approval decisions into `ShellActionProvider`
    - executes escalated commands via a `ShellCommandExecutor` that calls
    `process_exec_tool_call`
    - Updated `ShellRuntime` / `ShellCommandHandler` / tool spec wiring to
    select a `shell_command` backend (`classic` vs `zsh-fork`) while leaving
    the generic `shell` tool path unchanged.
    - Removed the `zsh_exec_bridge`-based session service and deleted
    `core/src/zsh_exec_bridge/mod.rs`.
    - Moved exec-wrapper entrypoint dispatch to `arg0` by handling the
    `codex-execve-wrapper` arg0 alias there, and removed the old
    `codex_core::maybe_run_zsh_exec_wrapper_mode()` hooks from `cli` and
    `app-server` mains.
    - Added the needed `codex-shell-escalation` dependencies for `core` and
    `arg0`.
    
    ## Tests
    
    - `cargo test -p codex-core
    shell_zsh_fork_prefers_shell_command_over_unified_exec`
    - `cargo test -p codex-app-server turn_start_shell_zsh_fork --
    --nocapture`
    - verifies zsh-fork command execution and approval flows through the new
    backend
    - includes subcommand approve/decline coverage using the shared zsh
    DotSlash fixture in `app-server/tests/suite/zsh`
    - To test manually, I added the following to `~/.codex/config.toml`:
    
    ```toml
    zsh_path = "/Users/mbolin/code/codex3/codex-rs/app-server/tests/suite/zsh"
    
    [features]
    shell_zsh_fork = true
    ```
    
    Then I ran `just c` to run the dev build of Codex with these changes and
    sent it the message:
    
    ```
    run `echo $0`
    ```
    
    And it replied with:
    
    ```
      echo $0 printed:
    
      /Users/mbolin/code/codex3/codex-rs/app-server/tests/suite/zsh
    
      In this tool context, $0 reflects the script path used to invoke the shell, not just zsh.
    ```
    
    so the tool appears to be wired up correctly.
    
    ## Notes
    
    - The zsh subcommand-decline integration test now uses `rm` under a
    `WorkspaceWrite` sandbox. The previous `/usr/bin/true` scenario is
    auto-allowed by the new `shell-escalation` policy path, which no longer
    produces subcommand approval prompts.
  • feat(network-proxy): add MITM support and gate limited-mode CONNECT (#9859)
    ## Description
    - Adds MITM support (CA load/issue, TLS termination, optional body
    inspection).
    - Adds `codex-network-proxy init` to create
    `CODEX_HOME/network_proxy/mitm`.
    - Enforces limited-mode HTTPS correctly: `CONNECT` requires MITM,
    otherwise blocked with `mitm_required`.
    - Keeps `origin/main` layering/reload semantics (managed layers included
    in reload checks).
    - Centralizes block reasons (`REASON_MITM_REQUIRED`) and removes
    `println!`.
    - Scope is MITM-only (no SOCKS changes).
    
    gated by `mitm=false` (default)
  • ctrl-L (clears terminal but does not start a new chat) (#12628)
    # ctrl-L
    
    - Clears your terminal window
    - Does not start a new chat
  • feat(core) Introduce Feature::RequestPermissions (#11871)
    ## Summary
    Introduces the initial implementation of Feature::RequestPermissions.
    RequestPermissions allows the model to request that a command be run
    inside the sandbox, with additional permissions, like writing to a
    specific folder. Eventually this will include other rules as well, and
    the ability to persist these permissions, but this PR is already quite
    large - let's get the core flow working and go from there!
    
    <img width="1279" height="541" alt="Screenshot 2026-02-15 at 2 26 22 PM"
    src="https://github.com/user-attachments/assets/0ee3ec0f-02ec-4509-91a2-809ac80be368"
    />
    
    ## Testing
    - [x] Added tests
    - [x] Tested locally
    - [x] Feature
  • feat: use process group to kill the PTY (#12688)
    Use the process group kill logic to kill the PTY
  • Send warmup request (#11258)
    Send a request with `generate: falls` but a full set of tools and
    instructions to pre-warm inference.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: replay after /agent (#12663)
    Filter the events after a`/agent` replay to prevent replaying decision
    events
  • memories: tighten memory lookup guidance and citation requirements (#12635)
    ## Summary
    - tighten the memory-use decision boundary so agents skip memory only
    for clearly self-contained asks
    - make the quick memory pass more explicit and bounded (including a
    lightweight search budget)
    - add structured `<memory_citation>` requirements and examples for final
    replies
    - clarify memory update guidance and end-state wording for memory lookup
    
    ## Why
    The previous template was directionally correct, but still left room for
    inconsistent memory lookup behavior and citation formatting. This change
    makes the default behavior, quick-pass scope, and citation output
    contract much more explicit.
    
    ## Testing
    - not run (prompt/template text change only)
    
    Co-authored-by: jif-oai <jif@openai.com>
  • feat: mutli agents persist config overrides (#12667)
    Fix propagation of runtime config changes and `--yolo`
  • memories: tighten consolidation prompt schema and indexing guidance (#12653)
    ## Summary
    - tighten the Phase 2 consolidation prompt for task-oriented `MEMORY.md`
    generation
    - address Phase 2 under-coverage / "laziness" with stronger workflow +
    final-pass checks
    - improve recency/ordering behavior for `MEMORY.md` and
    `memory_summary.md`
    - rewrite `## What's in Memory` as a clearer routing index with explicit
    recent-3-day structure
    
    ## Key Changes
    - `MEMORY.md` schema cleanup:
    - align on `## Task <n>` task sections (remove stale `task:`
    rule/example references)
      - include `thread_id` in rollout provenance examples
      - compact comma-separated `### keywords` format
    - Phase 2 completeness guardrails:
      - chunked INIT coverage pass over `raw_memories.md`
      - incremental net-new indexing / routing steps
    - stronger final checks (day ordering, topic coverage, keyword
    searchability, accidental duplication)
    - Recency / ordering rules:
    - clearer scan-order guidance for raw memories (newest-first bias in
    incremental mode)
    - utility+recency ordering guidance for `MEMORY.md` task groups and
    summary topics
      - rebuild recent active window from current `updated_at` coverage
    - `## What's in Memory` rewrite:
      - index/routing-layer framing (not a mini-handbook)
      - explicit recent 3 distinct memory-day layout
      - richer recent-topic entries + compact lower-priority routing entries
    - clearer `desc` / `learnings` expectations and separation from `##
    General Tips`
    - Explicitly allow rollout-summary reuse across multiple tasks/blocks
    when it supports distinct task angles (with distinct task-local value)
    
    ## Notes
    - Prompt-template only:
    `codex-rs/core/templates/memories/consolidation.md`
    - No runtime/code changes
    
    ## Validation
    - Manual diff review only
  • Simplify skill tracking (#12652)
    Remove a few layers of structs and store SkillMetadata.
    
    ---------
    
    Co-authored-by: alexsong-oai <alexsong@openai.com>
  • chore: rm hardcoded PRESETS list (#12650)
    rm `PRESETS` list harcoded in `model_presets` as we now have bundled
    `models.json` with equivalent info.
    
    update logic to rely on bundled models instead, update tests.
  • Add skill approval event/response (#12633)
    Set the stage for skill-level permission approval in addition to
    command-level.
    
    Behind a feature flag.
  • Avoid AbsolutePathBuf::parent() panic under EMFILE by skipping re-absolutization (#12647)
    Fixes #12216
    
    Fixes a panic in `AbsolutePathBuf::parent()` when the process hits file
    descriptor exhaustion (`EMFILE` / "Too many open files").
    
    ### Root cause
    
    `AbsolutePathBuf::parent()` was re-validating the parent path via
    `from_absolute_path(...).expect(...)`.
    
    `from_absolute_path()` calls `path_absolutize::absolutize()`, which can
    depend on `std::env::current_dir()`. Under `EMFILE`, that can fail,
    causing `parent()` to panic even though the parent of an absolute path
    is already known.
    
    ### Change
    
    - Stop re-absolutizing the result of `self.0.parent()`
    - Construct `AbsolutePathBuf` directly from the known parent path
    - Keep an invariant check with `debug_assert!(p.is_absolute())`
    
    ### Why this is safe
    
    `self` is already an `AbsolutePathBuf`, so `self.0` is
    absolute/normalized. The parent of an absolute path is expected to be
    absolute, so re-running fallible normalization here is unnecessary and
    can introduce unrelated panics.
  • Support implicit skill invocation analytics events (#12049)
    - use `skills_for_cwd` lookup to scope allowed skills and build
    invocation context for downstream processing
    - add detection in `stream_events_utils` to classify tool calls as
    implicit skill invocations per the proposal (script runners, extensions,
    `scripts` dirs, and SKILL.md reads)
    - deduplicate invocations per turn and emit analytics/OTEL events on the
    same background queue as explicit invokes
  • fix(exec) Patch resume test race condition (#12648)
    ## Summary
    The test exec_resume_last_respects_cwd_filter_and_all_flag makes one
    session “newest” by resuming it, but rollout updated_at is stored/sorted
    at second precision. On fast CI (especially Windows), the touch could
    land in the same second as initial session creation, making ordering
    nondeterministic.
    
    This change adds a short sleep before the recency-touch step so the
    resumed session is guaranteed to have a later updated_at, preserving the
    intended assertion without changing product behavior.
  • feat(core): persist network approvals in execpolicy (#12357)
    ## Summary
    Persist network approval allow/deny decisions as `network_rule(...)`
    entries in execpolicy (not proxy config)
    
    It adds `network_rule` parsing + append support in `codex-execpolicy`,
    including `decision="prompt"` (parse-only; not compiled into proxy
    allow/deny lists)
    - compile execpolicy network rules into proxy allow/deny lists and
    update the live proxy state on approval
    - preserve requirements execpolicy `network_rule(...)` entries when
    merging with file-based execpolicy
    - reject broad wildcard hosts (for example `*`) for persisted
    `network_rule(...)`
  • refactor: decouple shell-escalation from codex-core (#12638)
    ## Why
    
    After removing `exec-server`, the next step is to wire a new shell tool
    to `codex-rs/shell-escalation` directly.
    
    That is blocked while `codex-shell-escalation` depends on `codex-core`,
    because the new integration would require `codex-core` to depend on
    `codex-shell-escalation` and create a dependency cycle.
    
    This change ports the reusable pieces from the earlier prep work, but
    drops the old compatibility shim because `exec-server`/MCP support is
    already gone.
    
    ## What Changed
    
    ### Decouple `shell-escalation` from `codex-core`
    
    - Introduce a crate-local `SandboxState` in `shell-escalation`
    - Introduce a `ShellCommandExecutor` trait so callers provide process
    execution/sandbox integration
    - Update `EscalateServer::exec(...)` and `run_escalate_server(...)` to
    use the injected executor
    - Remove the direct `codex_core::exec::process_exec_tool_call(...)` call
    from `shell-escalation`
    - Remove the `codex-core` dependency from `codex-shell-escalation`
    
    ### Restore reusable policy adapter exports
    
    - Re-enable `unix::core_shell_escalation`
    - Export `ShellActionProvider` and `ShellPolicyFactory` from
    `shell-escalation`
    - Keep the crate root API simple (no `legacy_api` compatibility layer)
    
    ### Port socket fixes from the earlier prep commit
    
    - Use `socket2::Socket::pair_raw(...)` for AF_UNIX socketpairs and
    restore `CLOEXEC` explicitly on both endpoints
    - Keep `CLOEXEC` cleared only on the single datagram client FD that is
    intentionally passed across `exec`
    - Clean up `tokio::AsyncFd::try_io(...)` error handling in the socket
    helpers
    
    ## Verification
    
    - `cargo shear`
    - `cargo clippy -p codex-shell-escalation --tests`
    - `cargo test -p codex-shell-escalation`
  • refactor: delete exec-server and move execve wrapper into shell-escalation (#12632)
    ## Why
    
    We already plan to remove the shell-tool MCP path, and doing that
    cleanup first makes the follow-on `shell-escalation` work much simpler.
    
    This change removes the last remaining reason to keep
    `codex-rs/exec-server` around by moving the `codex-execve-wrapper`
    binary and shared shell test fixtures to the crates/tests that now own
    that functionality.
    
    ## What Changed
    
    ### Delete `codex-rs/exec-server`
    
    - Remove the `exec-server` crate, including the MCP server binary,
    MCP-specific modules, and its test support/test suite
    - Remove `exec-server` from the `codex-rs` workspace and update
    `Cargo.lock`
    
    ### Move `codex-execve-wrapper` into `codex-rs/shell-escalation`
    
    - Move the wrapper implementation into `shell-escalation`
    (`src/unix/execve_wrapper.rs`)
    - Add the `codex-execve-wrapper` binary entrypoint under
    `shell-escalation/src/bin/`
    - Update `shell-escalation` exports/module layout so the wrapper
    entrypoint is hosted there
    - Move the wrapper README content from `exec-server` to
    `shell-escalation/README.md`
    
    ### Move shared shell test fixtures to `app-server`
    
    - Move the DotSlash `bash`/`zsh` test fixtures from
    `exec-server/tests/suite/` to `app-server/tests/suite/`
    - Update `app-server` zsh-fork tests to reference the new fixture paths
    
    ### Keep `shell-tool-mcp` as a shell-assets package
    
    - Update `.github/workflows/shell-tool-mcp.yml` packaging so the npm
    artifact contains only patched Bash/Zsh payloads (no Rust binaries)
    - Update `shell-tool-mcp/package.json`, `shell-tool-mcp/src/index.ts`,
    and docs to reflect the shell-assets-only package shape
    - `shell-tool-mcp-ci.yml` does not need changes because it is already
    JS-only
    
    ## Verification
    
    - `cargo shear`
    - `cargo clippy -p codex-shell-escalation --tests`
    - `just clippy`
  • app-server: fix connecting via websockets with Sec-WebSocket-Extensions: permessage-deflate (#12629)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • Update models.json (#11408)
    Automated update of models.json.
    
    ---------
    
    Co-authored-by: sayan-oai <244841968+sayan-oai@users.noreply.github.com>
    Co-authored-by: sayan-oai <sayan@openai.com>
  • voice transcription (#3381)
    Adds voice transcription on press-and-hold of spacebar.
    
    
    https://github.com/user-attachments/assets/85039314-26f3-46d1-a83b-8c4a4a1ecc21
    
    ---------
    
    Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
    Co-authored-by: David Zbarsky <zbarsky@openai.com>
  • fix: show command running in background terminal in details under status indicator (#12549)
    #### What
    Display in-progress background terminal command in `status.details`
    (right under header) rather than inline, as it gets cut off currently.
    
    ###### Before
    <img width="993" height="395" alt="image"
    src="https://github.com/user-attachments/assets/6792b666-8184-40f7-bf29-409bb06c21d5"
    />
    
    ###### After
    <img width="469" height="137" alt="image"
    src="https://github.com/user-attachments/assets/4d6a2481-bd19-4333-8c1a-92f521b09b3d"
    />
    
    #### Tests
    Added/updated tests
  • chore(deps): bump owo-colors from 4.2.3 to 4.3.0 in /codex-rs (#12530)
    Bumps [owo-colors](https://github.com/owo-colors/owo-colors) from 4.2.3
    to 4.3.0.
    <details>
    <summary>Release notes</summary>
    <p><em>Sourced from <a
    href="https://github.com/owo-colors/owo-colors/releases">owo-colors's
    releases</a>.</em></p>
    <blockquote>
    <h2>owo-colors 4.3.0</h2>
    <h3>Fixed</h3>
    <ul>
    <li>Scripts in the <code>scripts/</code> directory are no longer
    published in the crate package. Thanks <a
    href="https://redirect.github.com/owo-colors/owo-colors/pull/152">weiznich</a>
    for your first contribution!</li>
    </ul>
    <h3>Changed</h3>
    <ul>
    <li>
    <p>Mark methods with
    <code>#[rust_analyzer::completions(ignore_flyimport)]</code> and the
    <code>OwoColorize</code> trait with
    <code>#[rust_analyzer::completions(ignore_flyimport_methods)]</code>.
    This prevents owo-colors methods from being completed with rust-analyzer
    unless the <code>OwoColorize</code> trait is included.</p>
    <p>Unfortunately, this also breaks explicit autocomplete commands such
    as Ctrl-Space in many editors. (The language server protocol doesn't
    appear to have a way to differentiate between implicit and explicit
    autocomplete commands.) On balance we believe this is the right
    approach, but please do provide feedback on [PR <a
    href="https://redirect.github.com/owo-colors/owo-colors/issues/141">#141</a>](<a
    href="https://redirect.github.com/owo-colors/owo-colors/pull/141">owo-colors/owo-colors#141</a>)
    if it negatively affects you.</p>
    </li>
    <li>
    <p>Updated MSRV to Rust 1.81.</p>
    </li>
    </ul>
    </blockquote>
    </details>
    <details>
    <summary>Changelog</summary>
    <p><em>Sourced from <a
    href="https://github.com/owo-colors/owo-colors/blob/main/CHANGELOG.md">owo-colors's
    changelog</a>.</em></p>
    <blockquote>
    <h2>[4.3.0] - 2026-02-22</h2>
    <h3>Fixed</h3>
    <ul>
    <li>Scripts in the <code>scripts/</code> directory are no longer
    published in the crate package. Thanks <a
    href="https://redirect.github.com/owo-colors/owo-colors/pull/152">weiznich</a>
    for your first contribution!</li>
    </ul>
    <h3>Changed</h3>
    <ul>
    <li>
    <p>Mark methods with
    <code>#[rust_analyzer::completions(ignore_flyimport)]</code> and the
    <code>OwoColorize</code> trait with
    <code>#[rust_analyzer::completions(ignore_flyimport_methods)]</code>.
    This prevents owo-colors methods from being completed with rust-analyzer
    unless the <code>OwoColorize</code> trait is included.</p>
    <p>Unfortunately, this also breaks explicit autocomplete commands such
    as Ctrl-Space in many editors. (The language server protocol doesn't
    appear to have a way to differentiate between implicit and explicit
    autocomplete commands.) On balance we believe this is the right
    approach, but please do provide feedback on [PR <a
    href="https://redirect.github.com/owo-colors/owo-colors/issues/141">#141</a>](<a
    href="https://redirect.github.com/owo-colors/owo-colors/pull/141">owo-colors/owo-colors#141</a>)
    if it negatively affects you.</p>
    </li>
    <li>
    <p>Updated MSRV to Rust 1.81.</p>
    </li>
    </ul>
    </blockquote>
    </details>
    <details>
    <summary>Commits</summary>
    <ul>
    <li><a
    href="https://github.com/owo-colors/owo-colors/commit/baf10f9a74007501379afdc002394a15a787dc59"><code>baf10f9</code></a>
    [owo-colors] version 4.3.0</li>
    <li><a
    href="https://github.com/owo-colors/owo-colors/commit/6abe2026c56ef6eefda30d417462f28f9ea8854d"><code>6abe202</code></a>
    [meta] prepare changelog</li>
    <li><a
    href="https://github.com/owo-colors/owo-colors/commit/ca814470410c819568b381b9b2b3f7a184e7de28"><code>ca81447</code></a>
    [RFC] add ignore_flyimport and ignore_flyimport_methods (<a
    href="https://redirect.github.com/owo-colors/owo-colors/issues/141">#141</a>)</li>
    <li><a
    href="https://github.com/owo-colors/owo-colors/commit/61de72e7f9487a945e8ea59afb9aa1b2046a2bd7"><code>61de72e</code></a>
    Exclude development script from published package (<a
    href="https://redirect.github.com/owo-colors/owo-colors/issues/152">#152</a>)</li>
    <li><a
    href="https://github.com/owo-colors/owo-colors/commit/b2ad6bcd4156207bcbc4c756c0c926e02667a872"><code>b2ad6bc</code></a>
    update MSRV to Rust 1.81 (<a
    href="https://redirect.github.com/owo-colors/owo-colors/issues/156">#156</a>)</li>
    <li>See full diff in <a
    href="https://github.com/owo-colors/owo-colors/compare/v4.2.3...v4.3.0">compare
    view</a></li>
    </ul>
    </details>
    <br />
    
    
    [![Dependabot compatibility
    score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=owo-colors&package-manager=cargo&previous-version=4.2.3&new-version=4.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
    
    Dependabot will resolve any conflicts with this PR as long as you don't
    alter it yourself. You can also trigger a rebase manually by commenting
    `@dependabot rebase`.
    
    [//]: # (dependabot-automerge-start)
    [//]: # (dependabot-automerge-end)
    
    ---
    
    <details>
    <summary>Dependabot commands and options</summary>
    <br />
    
    You can trigger Dependabot actions by commenting on this PR:
    - `@dependabot rebase` will rebase this PR
    - `@dependabot recreate` will recreate this PR, overwriting any edits
    that have been made to it
    - `@dependabot show <dependency name> ignore conditions` will show all
    of the ignore conditions of the specified dependency
    - `@dependabot ignore this major version` will close this PR and stop
    Dependabot creating any more for this major version (unless you reopen
    the PR or upgrade to it yourself)
    - `@dependabot ignore this minor version` will close this PR and stop
    Dependabot creating any more for this minor version (unless you reopen
    the PR or upgrade to it yourself)
    - `@dependabot ignore this dependency` will close this PR and stop
    Dependabot creating any more for this dependency (unless you reopen the
    PR or upgrade to it yourself)
    
    
    </details>
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • fix(tui): queue steer Enter while final answer is still streaming to prevent dead state (#12569)
    ## Summary
    This fixes a TUI race (https://github.com/openai/codex/issues/11008)
    where pressing Enter with Steer enabled while the assistant is still
    streaming the final answer could put Codex into a non-recoverable
    “running” state (no further prompts handled until exiting and resuming).
    
    ## Root Cause
    In steer mode, `InputResult::Submitted` could submit immediately even
    while a final-answer stream was active. That immediate submission races
    with turn completion and can strand turn state.
    
    ## Fix
    When handling `InputResult::Submitted`, we now queue instead of
    immediate-submit if a final-answer stream is active
    (`stream_controller.is_some()`).
    
    This keeps behavior deterministic:
    - Prompt is preserved in the queue.
    - `on_task_complete()` drains queued input through
    `maybe_send_next_queued_input()`.
    - Follow-up prompts continue in FIFO order after completion.
    
    ## Why this resolves the “dead mode”
    The problematic timing window is now converted into queueing, so prompts
    entered during final streaming are not lost and are processed after the
    current output ends. The model continues handling prompts normally
    without requiring `/quit` + `resume`.
    
    ## Tests
    Added regression coverage in `tui/src/chatwidget/tests.rs`:
    
    - `steer_enter_queues_while_final_answer_stream_is_active`
    - `steer_enter_during_final_stream_preserves_follow_up_prompts_in_order`
    
    Both fail on old behavior and pass with this fix.
  • fix(tui): recover on owned wrap mapping mismatch (#12609)
    ## Summary
    
    - Replace the `panic!` in `map_owned_wrapped_line_to_range` with a
    recoverable flow that skips synthetic leading characters, logs a warning
    on mid-line mismatch, and returns the mapped prefix range instead of
    crashing
    - Fixes a crash when `textwrap` produces owned lines with synthetic
    indent prefixes (e.g. non-space indents via
    `initial_indent`/`subsequent_indent`)
    
    ## Test plan
    
    - [x] Added unit test for direct mismatch recovery
    (`map_owned_wrapped_line_to_range_recovers_on_non_prefix_mismatch`)
    - [x] Added end-to-end `wrap_ranges` test with non-space indents that
    forces owned wrapped lines and validates full source reconstruction
    - [x] Verify no regressions in existing `wrapping.rs` tests (`cargo test
    -p codex-tui`)
  • fix: add ellipsis for truncated status indicator (#12540)
    #### What
    
    - Add ellipsis truncation of the status indicator, similar to equivalent
    truncation done in the footer.
    - Extract truncation helpers into separate file
    
    
    
    https://github.com/user-attachments/assets/a2d5f22f-8adc-456e-8059-97359194c25c
    
    
    #### Tests
    Updated relevant snapshot tests