Commit Graph

1111 Commits

  • fix: wrap long exec lines in transcript overlay (#7481)
    What
    -----
    - Fix the Ctrl+T transcript overlay so that very long exec output lines
    are soft‑wrapped to the viewport width instead of being rendered as a
    single truncated row.
    - Add a regression test to `TranscriptOverlay` to ensure long exec
    outputs are rendered on multiple lines in the overlay.
    
    Why
    ----
    - Previously, the transcript overlay rendered extremely long single exec
    lines as one on‑screen row and simply cut them off at the right edge,
    with no horizontal scrolling.
    - This made it impossible to inspect the full content of long tool/exec
    outputs in the transcript view, even though the main TUI view already
    wrapped those lines.
    - Fixes #7454.
    
    How
    ----
    - Update `ExecCell::transcript_lines` to wrap exec output lines using
    the existing `RtOptions`/`word_wrap_line` helpers so that transcript
    rendering is width‑aware.
    - Reuse the existing line utilities to expand the wrapped `Line` values
    into the transcript overlay, preserving styling while respecting the
    current viewport width.
    - Add `transcript_overlay_wraps_long_exec_output_lines` test in
    `pager_overlay.rs` that constructs a long single‑line exec output,
    renders the transcript overlay into a small buffer, and asserts that the
    long marker string spans multiple rendered lines.
  • feat: Support listing and selecting skills via $ or /skills (#7506)
    List/Select skills with $-mention or /skills
  • feat(tui): map Ctrl-P/N to arrow navigation in textarea (#7530)
    - Treat Ctrl-P/N (and their C0 fallbacks) the same as Up/Down so cursor
    movement matches popup/history behavior and control bytes never land in
    the buffer
    
    Fixes #7529
    
    Signed-off-by: Aofei Sheng <aofei@aofeisheng.com>
  • fix(tui): limit user shell output by screen lines (#7448)
    What
    - Limit the TUI "user shell" output panel by the number of visible
    screen lines rather than by the number of logical lines.
    - Apply middle truncation after wrapping, so a few extremely long lines
    cannot expand into hundreds of visible lines.
    - Add a regression test to guard this behavior.
    
    Why
    When the `ExecCommandSource::UserShell` tool returns a small number of
    very long logical lines, the TUI wraps those lines into many visual
    lines. The existing truncation logic applied
    `USER_SHELL_TOOL_CALL_MAX_LINES` to the number of logical lines *before*
    wrapping.
    
    As a result, a command like:
    
    - `Ran bash -lc "grep -R --line-number 'maskAssetId' ."`
    
    or a synthetic command that prints a single ~50,000‑character line, can
    produce hundreds of screen lines and effectively flood the viewport. The
    intended middle truncation for user shell output does not take effect in
    this scenario.
    
    How
    - In `codex-rs/tui/src/exec_cell/render.rs`, change the `ExecCell`
    rendering path for `ExecCommandSource::UserShell` so that:
    - Each logical line from `CommandOutput::aggregated_output` is first
    wrapped via `word_wrap_line` into multiple screen lines using the
    appropriate `RtOptions` and width from the `EXEC_DISPLAY_LAYOUT`
    configuration.
    - `truncate_lines_middle` is then applied to the wrapped screen lines,
    with `USER_SHELL_TOOL_CALL_MAX_LINES` as the limit. This means the limit
    is enforced on visible screen lines, not logical lines.
    - The existing layout struct (`ExecDisplayLayout`) continues to provide
    `output_max_lines`, so user shell output is subject to both
    `USER_SHELL_TOOL_CALL_MAX_LINES` and the layout-specific
    `output_max_lines` constraint.
    - Keep using `USER_SHELL_TOOL_CALL_MAX_LINES` as the cap, but interpret
    it as a per‑tool‑call limit on screen lines.
    - Add a regression test `user_shell_output_is_limited_by_screen_lines`
    in `codex-rs/tui/src/exec_cell/render.rs` that:
    - Constructs two extremely long logical lines containing a short marker
    (`"Z"`), so each wrapped screen line still contains the marker.
      - Wraps them at a narrow width to generate many screen lines.
    - Asserts that the unbounded wrapped output would exceed
    `USER_SHELL_TOOL_CALL_MAX_LINES` screen lines.
    - Renders an `ExecCell` for `ExecCommandSource::UserShell` at the same
    width and counts rendered lines containing the marker.
    - Asserts `output_screen_lines <= USER_SHELL_TOOL_CALL_MAX_LINES`,
    guarding against regressions where truncation happens before wrapping.
    
    This change keeps user shell output readable while ensuring it cannot
    flood the TUI, even when the tool emits a few extremely long lines.
    
    Tests
    - `cargo test -p codex-tui`
    
    Issue
    - Fixes #7447
  • Migrate model preset (#7542)
    - Introduce `openai_models` in `/core`
    - Move `PRESETS` under it
    - Move `ModelPreset`, `ModelUpgrade`, `ReasoningEffortPreset`,
    `ReasoningEffortPreset`, and `ReasoningEffortPreset` to `protocol`
    - Introduce `Op::ListModels` and `EventMsg::AvailableModels`
    
    Next steps:
    - migrate `app-server` and `tui` to use the introduced Operation
  • add slash resume (#7302)
    `codex resume` isn't that discoverable. Adding it to the slash commands
    can help
  • feat: codex tool tips (#7440)
    <img width="551" height="316" alt="Screenshot 2025-12-01 at 12 22 26"
    src="https://github.com/user-attachments/assets/6ca3deff-8ef8-4f74-a8e1-e5ea13fd6740"
    />
  • fix(tui) Support image paste from clipboard on native Windows (#7514)
    Closes #3404 
    
    ## Summary
    On windows, ctrl+v does not work for the same reason that cmd+v does not
    work on macos. This PR adds alt/option+v detection, which allows windows
    users to paste images from the clipboard using.
    
    We could swap between just ctrl on mac and just alt on windows, but this
    felt simpler - I don't feel strongly about it.
    
    Note that this will NOT address image pasting in WSL environments, due
    to issues with WSL <> Windows clipboards. I'm planning to address that
    in a separate PR since it will likely warrant some discussion.
    
    ## Testing
    - [x] Tested locally on a Mac and Windows laptop
  • improve resume performance (#7303)
    Reading the tail can be costly if we have a very big rollout item. we
    can just read the file metadata
  • Ensure duplicate-length paste placeholders stay distinct (#7431)
    Fix issue #7430 
    Generate unique numbered placeholders for multiple large pastes of the
    same length so deleting one no longer removes the others.
    
    Signed-off-by: Joshua <joshua1s@protonmail.com>
  • refactor: tui.rs extract several pieces (#7461)
    Pull FrameRequester out of tui.rs into its own module and make a
    FrameScheduler struct. This is effectively an Actor/Handler approach
    (see https://ryhl.io/blog/actors-with-tokio/). Adds tests and docs.
    
    Small refactor of pending_viewport_area logic.
  • persisting credits if new snapshot does not contain credit info (#7490)
    in response to incoming changes to responses headers where the header
    may sometimes not contain credits info (no longer forcing a credit
    check)
  • Show token used when context window is unknown (#7497)
    - Show context window usage in tokens instead of percentage when the
    window length is unknown.
  • feat: experimental support for skills.md (#7412)
    This change prototypes support for Skills with the CLI. This is an
    **experimental** feature for internal testing.
    
    ---------
    
    Co-authored-by: Gav Verma <gverma@openai.com>
  • fix(tui): handle WSL clipboard image paths (#3990)
    Fixes #3939 
    Fixes #2803
    
    ## Summary
    - convert Windows clipboard file paths into their `/mnt/<drive>`
    equivalents when running inside WSL so pasted images resolve correctly
    - add WSL detection helpers and share them with unit tests to cover both
    native Windows and WSL clipboard normalization cases
    - improve the test suite by exercising Windows path handling plus a
    dedicated WSL conversion scenario and keeping the code path guarded by
    targeted cfgs
    
    ## Testing
    - just fmt
    - cargo test -p codex-tui
    - cargo clippy -p codex-tui --tests
    - just fix -p codex-tui
    
    ## Screenshots
    _Codex TUI screenshot:_
    <img width="1880" height="848" alt="describe this copied image"
    src="https://github.com/user-attachments/assets/c620d43c-f45c-451e-8893-e56ae85a5eea"
    />
    
    _GitHub docs directory screenshot:_
    <img width="1064" height="478" alt="image-copied"
    src="https://github.com/user-attachments/assets/eb5eef6c-eb43-45a0-8bfe-25c35bcae753"
    />
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • correctly recognize WorkspaceWrite policy on /approvals (#7301)
    the `/approvals` popup fails to recognize that the CLI is in
    WorkspaceWrite mode if that policy has extra bits, like `writable_roots`
    etc.
    
    This change matches the policy, ignoring additional config aspects.
  • chore: dedup unified exec "waited" rendering (#7256)
    From
    <img width="477" height="283" alt="Screenshot 2025-11-24 at 18 02 25"
    src="https://github.com/user-attachments/assets/724d1d68-c994-417e-9859-ada8eb173b4c"
    />
    To
    <img width="444" height="174" alt="Screenshot 2025-11-24 at 18 02 40"
    src="https://github.com/user-attachments/assets/40f91247-6d55-4428-84d1-f39c912ac2e7"
    />
  • fix: custom prompt expansion with large pastes (#7154)
    ### **Summary of Changes**
    
    **What?**
    Fix for slash commands (e.g., /prompts:code-review) not being recognized
    when large content (>3000 chars) is pasted.
    [Bug Report](https://github.com/openai/codex/issues/7047)
    **Why?**
    With large pastes, slash commands were ignored, so custom prompts
    weren't expanded and were submitted as literal text.
    
    **How?**
    Refactored the early return block in handle_key_event_without_popup
    (lines 957-968).
    Instead of returning early after replacing placeholders, the code now
    replaces placeholders in the textarea and continues to the normal
    submission flow.
    This reuses the existing slash command detection and custom prompt
    expansion logic (lines 981-1047), avoiding duplication.
    
    **Changes:**
    Modified codex-rs/tui/src/bottom_pane/chat_composer.rs: refactored early
    return block to continue to normal flow instead of returning immediately
    Added test: custom_prompt_with_large_paste_expands_correctly to verify
    the fix
    
    **Code Quality:**
    No lint warnings
    Code follows existing patterns and reuses existing logic
    Atomic change focused on the bug fix
  • Allow enterprises to skip upgrade checks and messages (#7213)
    This is a feature primarily for enterprises who centrally manage Codex
    updates.
  • [feedback] Add source info into feedback metadata. (#7140)
    Verified the source info is correctly attached based on whether it's cli
    or vscode.
  • consolidate world-writable-directories scanning. (#7234)
    clean up the code for scanning for world writable directories
    
    One path (selecting a sandbox mode from /approvals) was using an
    incorrect method that did not use the new method of creating deny aces
    to prevent writing to those directories. Now all paths are the same.
  • support MCP elicitations (#6947)
    No support for request schema yet, but we'll at least show the message
    and allow accept/decline.
    
    <img width="823" height="551" alt="Screenshot 2025-11-21 at 2 44 05 PM"
    src="https://github.com/user-attachments/assets/6fbb892d-ca12-4765-921e-9ac4b217534d"
    />
  • fix(tui): Fail when stdin is not a terminal (#6382)
    Piping to codex fails to do anything useful and locks up the process.
    We currently check for stdout, but not stdin
    
    ```
    ❯ echo foo|just c
    cargo run --bin codex -- "$@"
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21s
         Running `target/debug/codex`
    Error: stdin is not a terminal
    error: Recipe `codex` failed on line 10 with exit code 1
    ```
  • feat(tui): default reasoning selection to medium (#7040)
    ## Summary
    - allow selection popups to request an initial highlighted row
    - begin the /models reasoning selector focused on the default effort
    
    ## Testing
    - just fmt
    - just fix -p codex-tui
    - cargo test -p codex-tui
    
    
    
    https://github.com/user-attachments/assets/b322aeb1-e8f3-4578-92f7-5c2fa5ee4c98
    
    
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_691f75e8fc188322a910fbe2138666ef)
  • [app-server] update doc with codex error info (#6941)
    Document new codex error info. Also fixed the name from
    `codex_error_code` to `codex_error_info`.
  • [app-server & core] introduce new codex error code and v2 app-server error events (#6938)
    This PR does two things:
    1. populate a new `codex_error_code` protocol in error events sent from
    core to client;
    2. old v1 core events `codex/event/stream_error` and `codex/event/error`
    will now both become `error`. We also show codex error code for
    turncompleted -> error status.
    
    new events in app server test:
    ```
    < {
    <   "method": "codex/event/stream_error",
    <   "params": {
    <     "conversationId": "019aa34c-0c14-70e0-9706-98520a760d67",
    <     "id": "0",
    <     "msg": {
    <       "codex_error_code": {
    <         "response_stream_disconnected": {
    <           "http_status_code": 401
    <         }
    <       },
    <       "message": "Reconnecting... 2/5",
    <       "type": "stream_error"
    <     }
    <   }
    < }
    
     {
    <   "method": "error",
    <   "params": {
    <     "error": {
    <       "codexErrorCode": {
    <         "responseStreamDisconnected": {
    <           "httpStatusCode": 401
    <         }
    <       },
    <       "message": "Reconnecting... 2/5"
    <     }
    <   }
    < }
    
    < {
    <   "method": "turn/completed",
    <   "params": {
    <     "turn": {
    <       "error": {
    <         "codexErrorCode": {
    <           "responseTooManyFailedAttempts": {
    <             "httpStatusCode": 401
    <           }
    <         },
    <         "message": "exceeded retry limit, last status: 401 Unauthorized, request id: 9a1b495a1a97ed3e-SJC"
    <       },
    <       "id": "0",
    <       "items": [],
    <       "status": "failed"
    <     }
    <   }
    < }
    ```
  • add deny ACEs for world writable dirs (#7022)
    Our Restricted Token contains 3 SIDs (Logon, Everyone, {WorkspaceWrite
    Capability || ReadOnly Capability})
    
    because it must include Everyone, that left us vulnerable to directories
    that allow writes to Everyone. Even though those directories do not have
    ACEs that enable our capability SIDs to write to them, they could still
    be written to even in ReadOnly mode, or even in WorkspaceWrite mode if
    they are outside of a writable root.
    
    A solution to this is to explicitly add *Deny* ACEs to these
    directories, always for the ReadOnly Capability SID, and for the
    WorkspaceWrite SID if the directory is outside of a workspace root.
    
    Under a restricted token, Windows always checks Deny ACEs before Allow
    ACEs so even though our restricted token would allow a write to these
    directories due to the Everyone SID, it fails first because of the Deny
    ACE on the capability SID
  • fix: route feedback issue links by category (#6840)
    ## Summary
    - TUI feedback note now only links to the bug-report template when the
    category is bug/bad result.
    - Good result/other feedback shows a thank-you+thread ID instead of
    funneling people to file a bug.
    - Added a helper + unit test so future changes keep the behavior
    consistent.
    
    ## Testing
      - just fmt
      - just fix -p codex-tui
      - cargo test -p codex-tui
    
      Fixes #6839
  • Bumped number of fuzzy search results from 8 to 20 (#7013)
    I just noticed that in the VSCode / Codex extension when you type @ the
    number of results is around 70:
    
    - small video of searching for `mod.rs` inside `codex` repository:
    https://github.com/user-attachments/assets/46e53d31-adff-465e-b32b-051c4c1c298c
    
    - while in the CLI the number of results is currently of 8 which is
    quite small:
    <img width="615" height="439" alt="Screenshot 2025-11-20 at 09 42 04"
    src="https://github.com/user-attachments/assets/1c6d12cb-3b1f-4d5b-9ad3-6b12975eaaec"
    />
    
    I bumped it to 20. I had several cases where I wanted a file and did not
    find it because the number of results was too small
    
    Signed-off-by: lionel-oai <lionel@openai.com>
    Co-authored-by: lionel-oai <lionel@openai.com>
  • Added feature switch to disable animations in TUI (#6870)
    This PR adds support for a new feature flag `tui.animations`. By
    default, the TUI uses animations in its welcome screen, "working"
    spinners, and "shimmer" effects. This animations can interfere with
    screen readers, so it's good to provide a way to disable them.
    
    This change is inspired by [a
    PR](https://github.com/openai/codex/pull/4014) contributed by @Orinks.
    That PR has faltered a bit, but I think the core idea is sound. This
    version incorporates feedback from @aibrahim-oai. In particular:
    1. It uses a feature flag (`tui.animations`) rather than the unqualified
    CLI key `no-animations`. Feature flags are the preferred way to expose
    boolean switches. They are also exposed via CLI command switches.
    2. It includes more complete documentation.
    3. It disables a few animations that the other PR omitted.
  • [app-server] feat: v2 apply_patch approval flow (#6760)
    This PR adds the API V2 version of the apply_patch approval flow, which
    centers around `ThreadItem::FileChange`.
    
    This PR wires the new RPC (`item/fileChange/requestApproval`, V2 only)
    and related events (`item/started`, `item/completed` for
    `ThreadItem::FileChange`, which are emitted in both V1 and V2) through
    the app-server
    protocol. The new approval RPC is only sent when the user initiates a
    turn with the new `turn/start` API so we don't break backwards
    compatibility with VSCE.
    
    Similar to https://github.com/openai/codex/pull/6758, the approach I
    took was to make as few changes to the Codex core as possible,
    leveraging existing `EventMsg` core events, and translating those in
    app-server. I did have to add a few additional fields to
    `EventMsg::PatchApplyBegin` and `EventMsg::PatchApplyEnd`, but those
    were fairly lightweight.
    
    However, the `EventMsg`s emitted by core are the following:
    ```
    1) Auto-approved (no request for approval)

    - EventMsg::PatchApplyBegin
    - EventMsg::PatchApplyEnd
    
    2) Approved by user
    - EventMsg::ApplyPatchApprovalRequest
    - EventMsg::PatchApplyBegin
    - EventMsg::PatchApplyEnd
    
    3) Declined by user
    - EventMsg::ApplyPatchApprovalRequest
    - EventMsg::PatchApplyBegin
    - EventMsg::PatchApplyEnd
    ```
    
    For a request triggering an approval, this would result in:
    ```
    item/fileChange/requestApproval
    item/started
    item/completed
    ```
    
    which is different from the `ThreadItem::CommandExecution` flow
    introduced in https://github.com/openai/codex/pull/6758, which does the
    below and is preferable:
    ```
    item/started
    item/commandExecution/requestApproval
    item/completed
    ```
    
    To fix this, we leverage `TurnSummaryStore` on codex_message_processor
    to store a little bit of state, allowing us to fire `item/started` and
    `item/fileChange/requestApproval` whenever we receive the underlying
    `EventMsg::ApplyPatchApprovalRequest`, and no-oping when we receive the
    `EventMsg::PatchApplyBegin` later.
    
    This is much less invasive than modifying the order of EventMsg within
    core (I tried).
    
    The resulting payloads:
    ```
    {
      "method": "item/started",
      "params": {
        "item": {
          "changes": [
            {
              "diff": "Hello from Codex!\n",
              "kind": "add",
              "path": "/Users/owen/repos/codex/codex-rs/APPROVAL_DEMO.txt"
            }
          ],
          "id": "call_Nxnwj7B3YXigfV6Mwh03d686",
          "status": "inProgress",
          "type": "fileChange"
        }
      }
    }
    ```
    
    ```
    {
      "id": 0,
      "method": "item/fileChange/requestApproval",
      "params": {
        "grantRoot": null,
        "itemId": "call_Nxnwj7B3YXigfV6Mwh03d686",
        "reason": null,
        "threadId": "019a9e11-8295-7883-a283-779e06502c6f",
        "turnId": "1"
      }
    }
    ```
    
    ```
    {
      "id": 0,
      "result": {
        "decision": "accept"
      }
    }
    ```
    
    ```
    {
      "method": "item/completed",
      "params": {
        "item": {
          "changes": [
            {
              "diff": "Hello from Codex!\n",
              "kind": "add",
              "path": "/Users/owen/repos/codex/codex-rs/APPROVAL_DEMO.txt"
            }
          ],
          "id": "call_Nxnwj7B3YXigfV6Mwh03d686",
          "status": "completed",
          "type": "fileChange"
        }
      }
    }
    ```
  • Revert "[core] add optional status_code to error events (#6865)" (#6955)
    This reverts commit c2ec477d93.
    
    # 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.
  • execpolicy2 core integration (#6641)
    This PR threads execpolicy2 into codex-core.
    
    activated via feature flag: exec_policy (on by default)
    
    reads and parses all .codexpolicy files in `codex_home/codex`
    
    refactored tool runtime API to integrate execpolicy logic
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • fix(context left after review): review footer context after /review (#5610)
    ## Summary
    - show live review token usage while `/review` runs and restore the main
    session indicator afterward
      - add regression coverage for the footer behavior
    
    ## Testing
      - just fmt
      - cargo test -p codex-tui
    
    Fixes #5604
    
    ---------
    
    Signed-off-by: Fahad <fahad@2doapp.com>
  • [core] add optional status_code to error events (#6865)
    We want to better uncover error status code for clients. Add an optional
    status_code to error events (thread error, error, stream error) so app
    server could uncover the status code from the client side later.
    
    in event log:
    ```
    < {
    <   "method": "codex/event/stream_error",
    <   "params": {
    <     "conversationId": "019a9a32-f576-7292-9711-8e57e8063536",
    <     "id": "0",
    <     "msg": {
    <       "message": "Reconnecting... 5/5",
    <       "status_code": 401,
    <       "type": "stream_error"
    <     }
    <   }
    < }
    < {
    <   "method": "codex/event/error",
    <   "params": {
    <     "conversationId": "019a9a32-f576-7292-9711-8e57e8063536",
    <     "id": "0",
    <     "msg": {
    <       "message": "exceeded retry limit, last status: 401 Unauthorized, request id: 9a0cb03a485067f7-SJC",
    <       "status_code": 401,
    <       "type": "error"
    <     }
    <   }
    < }
    ```
  • storing credits (#6858)
    Expand the rate-limit cache/TUI: store credit snapshots alongside
    primary and secondary windows, render “Credits” when the backend reports
    they exist (unlimited vs rounded integer balances)
  • have world_writable_warning_details accept cwd as a param (#6913)
    this enables app-server to pass in the correct workspace cwd for the
    current conversation
  • feat: arcticfox in the wild (#6906)
    <img width="485" height="600" alt="image"
    src="https://github.com/user-attachments/assets/4341740d-dd58-4a3e-b69a-33a3be0606c5"
    />
    
    ---------
    
    Co-authored-by: jif-oai <jif@openai.com>
  • nit: useless log to debug (#6898)
    When you type too fast in most terminals, it gets interpreted as paste,
    making this log spam
  • fix: typos in model picker (#6859)
    # 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.