Commit Graph

223 Commits

  • fix: windows can now paste non-ascii multiline text (#8774)
    ## Summary
    This PR builds _heavily_ on the work from @occurrent in #8021 - I've
    only added a small fix, added additional tests, and propagated the
    changes to tui2.
    
    From the original PR:
    
    > On Windows, Codex relies on PasteBurst for paste detection because
    bracketed paste is not reliably available via crossterm.
    > 
    > When pasted content starts with non-ASCII characters, input is routed
    through handle_non_ascii_char, which bypasses the normal paste burst
    logic. This change extends the paste burst window for that path, which
    should ensure that Enter is correctly grouped as part of the paste.
    
    
    ## Testing
    - [x] tested locally cross-platform
    - [x] added regression tests
    
    ---------
    
    Co-authored-by: occur <occurring@outlook.com>
  • add ability to disable input temporarily in the TUI. (#8876)
    We will disable input while the elevated sandbox setup is running.
  • add footer note to TUI (#8867)
    This will be used by the elevated sandbox NUX to give a hint on how to
    run the elevated sandbox when in the non-elevated mode.
  • fix: implement 'Allow this session' for apply_patch approvals (#8451)
    **Summary**
    This PR makes “ApprovalDecision::AcceptForSession / don’t ask again this
    session” actually work for `apply_patch` approvals by caching approvals
    based on absolute file paths in codex-core, properly wiring it through
    app-server v2, and exposing the choice in both TUI and TUI2.
    - This brings `apply_patch` calls to be at feature-parity with general
    shell commands, which also have a "Yes, and don't ask again" option.
    - This also fixes VSCE's "Allow this session" button to actually work.
    
    While we're at it, also split the app-server v2 protocol's
    `ApprovalDecision` enum so execpolicy amendments are only available for
    command execution approvals.
    
    **Key changes**
    - Core: per-session patch approval allowlist keyed by absolute file
    paths
    - Handles multi-file patches and renames/moves by recording both source
    and destination paths for `Update { move_path: Some(...) }`.
    - Extend the `Approvable` trait and `ApplyPatchRuntime` to work with
    multiple keys, because an `apply_patch` tool call can modify multiple
    files. For a request to be auto-approved, we will need to check that all
    file paths have been approved previously.
    - App-server v2: honor AcceptForSession for file changes
    - File-change approval responses now map AcceptForSession to
    ReviewDecision::ApprovedForSession (no longer downgraded to plain
    Approved).
    - Replace `ApprovalDecision` with two enums:
    `CommandExecutionApprovalDecision` and `FileChangeApprovalDecision`
    - TUI / TUI2: expose “don’t ask again for these files this session”
    - Patch approval overlays now include a third option (“Yes, and don’t
    ask again for these files this session (s)”).
        - Snapshot updates for the approval modal.
    
    **Tests added/updated**
    - Core:
    - Integration test that proves ApprovedForSession on a patch skips the
    next patch prompt for the same file
    - App-server:
    - v2 integration test verifying
    FileChangeApprovalDecision::AcceptForSession works properly
    
    **User-visible behavior**
    - When the user approves a patch “for session”, future patches touching
    only those previously approved file(s) will no longer prompt gain during
    that session (both via app-server v2 and TUI/TUI2).
    
    **Manual testing**
    Tested both TUI and TUI2 - see screenshots below.
    
    TUI:
    <img width="1082" height="355" alt="image"
    src="https://github.com/user-attachments/assets/adcf45ad-d428-498d-92fc-1a0a420878d9"
    />
    
    
    TUI2:
    <img width="1089" height="438" alt="image"
    src="https://github.com/user-attachments/assets/dd768b1a-2f5f-4bd6-98fd-e52c1d3abd9e"
    />
  • fix: handle /review arguments in TUI (#8823)
    Handle /review <instructions> in the TUI and TUI2 by routing it as a
    custom review command instead of plain text, wiring command dispatch and
    adding composer coverage so typing /review text starts a review directly
    rather than posting a message. User impact: /review with arguments now
    kicks off the review flow, previously it would just forward as a plain
    command and not actually start a review.
  • fix: truncate long approval prefixes when rendering (#8734)
    Fixes inscrutable multiline approval requests:
    <img width="686" height="844" alt="image"
    src="https://github.com/user-attachments/assets/cf9493dc-79e6-4168-8020-0ef0fe676d5e"
    />
  • [tui] add optional details to TUI status header (#8293)
    ### What
    
    Add optional `details` field to TUI's status indicator header. `details`
    is shown under the header with text wrapping and a max height of 3
    lines.
    
    Duplicated changes to `tui2`.
    
    ### Why
    
    Groundwork for displaying error details under `Reconnecting...` for
    clarity with retryable errors.
    
    Basic examples
    <img width="1012" height="326" alt="image"
    src="https://github.com/user-attachments/assets/dd751ceb-b179-4fb2-8fd1-e4784d6366fb"
    />
    
    <img width="1526" height="358" alt="image"
    src="https://github.com/user-attachments/assets/bbe466fc-faff-4a78-af7f-3073ccdd8e34"
    />
    
    Truncation example
    <img width="936" height="189" alt="image"
    src="https://github.com/user-attachments/assets/f3f1b5dd-9050-438b-bb07-bd833c03e889"
    />
    
    ### Tests
    Tested locally, added tests for truncation.
  • feat: open prompt in configured external editor (#7606)
    Add `ctrl+g` shortcut to enable opening current prompt in configured
    editor (`$VISUAL` or `$EDITOR`).
    
    
    - Prompt is updated with editor's content upon editor close.
    - Paste placeholders are automatically expanded when opening the
    external editor, and are not "recompressed" on close
    - They could be preserved in the editor, but it would be hard to prevent
    the user from modifying the placeholder text directly, which would drop
    the mapping to the `pending_paste` value
    - Image placeholders stay as-is
    - `ctrl+g` explanation added to shortcuts menu, snapshot tests updated
    
    
    
    https://github.com/user-attachments/assets/4ee05c81-fa49-4e99-8b07-fc9eef0bbfce
  • UI tweaks on skills popup. (#8250)
    Only display the skill name (not the folder), and truncate the skill
    description to a maximum of two lines.
  • Support skills shortDescription. (#8278)
    Allow SKILL.md to specify a more human-readable short description as
    skill metadata.
  • feat: add /ps (#8279)
    See snapshots for view of edge cases
    This is still named `UnifiedExecSessions` for consistency across the
    code but should be renamed to `BackgroundTerminals` in a follow-up
    
    Example:
    <img width="945" height="687" alt="Screenshot 2025-12-18 at 20 12 53"
    src="https://github.com/user-attachments/assets/92f39ff2-243c-4006-b402-e3fa9e93c952"
    />
  • feat: unified exec footer (#8117)
    # With `unified_exec`
    Known tools are correctly casted
    <img width="1150" height="312" alt="Screenshot 2025-12-16 at 19 27 28"
    src="https://github.com/user-attachments/assets/24150ee5-e88d-461b-a459-483c24784196"
    />
    If a session exit the turn, we render it with the "Ran ..."
    <img width="1168" height="355" alt="Screenshot 2025-12-16 at 19 27 58"
    src="https://github.com/user-attachments/assets/3f00b60c-2d57-4f9d-a201-9cc8388957cb"
    />
    If a session does not exit during the turn, it is closed at the end of
    the turn but this is not rendered
    <img width="642" height="342" alt="Screenshot 2025-12-16 at 19 34 37"
    src="https://github.com/user-attachments/assets/c2bd9283-7017-4915-ba73-c52199b0b28e"
    />
    
    # Without `unified_exec`
    No changes
    <img width="740" height="603" alt="Screenshot 2025-12-16 at 19 31 21"
    src="https://github.com/user-attachments/assets/ca5d90fe-a9b2-42ba-bcd7-3e98c4ed22e8"
    />
  • feat: experimental menu (#8071)
    This will automatically render any `Stage::Beta` features.
    
    The change only gets applied to the *next session*. This started as a
    bug but actually this is a good thing to prevent out of distribution
    push
    
    <img width="986" height="288" alt="Screenshot 2025-12-15 at 15 38 35"
    src="https://github.com/user-attachments/assets/78b7a71d-0e43-4828-a118-91c5237909c7"
    />
    
    
    <img width="509" height="109" alt="Screenshot 2025-12-15 at 17 35 44"
    src="https://github.com/user-attachments/assets/6933de52-9b66-4abf-b58b-a5f26d5747e2"
    />
  • feat: Constrain values for approval_policy (#7778)
    Constrain `approval_policy` through new `admin_policy` config.
    
    This PR will:
    1. Add a `admin_policy` section to config, with a single field (for now)
    `allowed_approval_policies`. This list constrains the set of
    user-settable `approval_policy`s.
    2. Introduce a new `Constrained<T>` type, which combines a current value
    and a validator function. The validator function ensures disallowed
    values are not set.
    3. Change the type of `approval_policy` on `Config` and
    `SessionConfiguration` from `AskForApproval` to
    `Constrained<AskForApproval>`. The validator function is set by the
    values passed into `allowed_approval_policies`.
    4. `GenericDisplayRow`: add a `disabled_reason: Option<String>`. When
    set, it disables selection of the value and indicates as such in the
    menu. This also makes it unselectable with arrow keys or numbers. This
    is used in the `/approvals` menu.
    
    Follow ups are:
    1. Do the same thing to `sandbox_policy`.
    2. Propagate the allowed set of values through app-server for the
    extension (though already this should prevent app-server from setting
    this values, it's just that we want to disable UI elements that are
    unsettable).
    
    Happy to split this PR up if you prefer, into the logical numbered areas
    above. Especially if there are parts we want to gavel on separately
    (e.g. admin_policy).
    
    Disabled full access:
    <img width="1680" height="380" alt="image"
    src="https://github.com/user-attachments/assets/1fb61c8c-1fcb-4dc4-8355-2293edb52ba0"
    />
    
    Disabled `--yolo` on startup:
    <img width="749" height="76" alt="image"
    src="https://github.com/user-attachments/assets/0a1211a0-6eb1-40d6-a1d7-439c41e94ddb"
    />
    
    CODEX-4087
  • feat: unified exec footer (#8067)
    <img width="452" height="205" alt="Screenshot 2025-12-15 at 17 54 44"
    src="https://github.com/user-attachments/assets/9ece0b1c-8387-4dfc-b883-c6a68ea1b663"
    />
  • fix: Don't trigger keybindings view on input burst (#7980)
    Human TL;DR - in some situations, pasting/rapidly inputting text will
    currently cause `?` characters to be stripped from the input message
    content, and display the key bindings helper. For instance, writing
    "Where is X defined? Can we do Y?" results in "Where is X defined Can we
    do Y" being added to the message draft area. This is mildly annoying.
    
    The fix was a simple one line addition. Added a test, ran linters, and
    all looks good to me. I didn't create an issue to link to in this PR - I
    had submitted this bug as a report a while ago but can't seem to find it
    now. Let me know if it's an absolute must for the PR to be accepted.
    
    I have read the CLA Document and I hereby sign the CLA
    
    Below is Codex's summary.
    
    ---
    
    # `?` characters toggling shortcuts / being dropped
    
    ## Symptom
    
    On Termux (and potentially other terminal environments), composing text
    in the native input field and sending it to the TTY can cause:
    
    - The shortcuts overlay to appear (as if `?` was pressed on an empty
    prompt), and
    - All of the literal `?` characters in the text to be **missing** from
    the composer input,
      even when `?` is not the first character.
    
    This typically happens when the composer was previously empty and the
    terminal delivers the text as a rapid sequence of key events rather than
    a single bracketed paste event.
    
    ## Root cause
    
    The TUI has two relevant behaviors:
    
    1. **Shortcut toggle on `?` when empty**
    - `ChatComposer::handle_shortcut_overlay_key` treats a plain `?` press
    as a toggle between the shortcut summary and the full shortcut overlay,
    but only when the composer is empty.
    - When it toggles, it consumes the key event (so `?` is *not* inserted
    into the text input).
    
    2. **“Paste burst” buffering for fast key streams**
    - The TUI uses a heuristic to detect “paste-like” input bursts even when
    the terminal doesn’t send an explicit paste event.
    - During that burst detection, characters can be buffered (and the text
    area can remain empty temporarily) while the system decides whether to
    treat the stream as paste-like input.
    
    In Termux’s “send composed text all at once” mode, the input often
    arrives as a very fast stream of `KeyCode::Char(...)` events. While that
    stream is being buffered as a burst, the visible textarea can still be
    empty. If a `?` arrives during this window, it matches “empty composer”
    and is interpreted as “toggle shortcuts” instead of “insert literal
    `?`”, so the `?` is dropped.
    
    ## Fix
    
    Make the `?` toggle conditional on not being in any paste-burst
    transient state.
    
    Implementation:
    
    - `ChatComposer::handle_shortcut_overlay_key` now checks
    `!self.is_in_paste_burst()` in addition to `self.is_empty()` before
    toggling.
    - This ensures that when input is arriving as a fast burst (including
    the “pending first char” case), `?` is treated as normal text input
    rather than a UI toggle.
    
    ## Test coverage
    
    Added a test that simulates a Termux-like fast stream:
    
    - Sends `h i ? t h e r e` as immediate successive `KeyEvent::Char`
    events (no delays).
    - Asserts that a paste burst is active and the textarea is still empty
    while buffering.
    - Flushes the burst and verifies:
      - The final text contains the literal `?` (`"hi?there"`), and
      - The footer mode is not `ShortcutOverlay`.
    
    ## Notes
    
    This fix intentionally keeps the existing UX:
    
    - `?` still toggles shortcuts when the composer is genuinely empty and
    the user is not in the middle of entering text.
    - `?` typed while composing content (including IME/native-input fast
    streams) remains literal.
  • Fixed regression that broke fuzzy matching for slash commands (#7859)
    This addresses bug #7857 which was introduced recently as part of PR
    #7704.
  • Inject SKILL.md when it's explicitly mentioned. (#7763)
    1. Skills load once in core at session start; the cached outcome is
    reused across core and surfaced to TUI via SessionConfigured.
    2. TUI detects explicit skill selections, and core injects the matching
    SKILL.md content into the turn when a selected skill is present.
  • fix: Prevent slash command popup from activating on invalid inputs (#7704)
    ## Slash Command popup issue
    
    #7659
    
    When recalling history, the
    composer(`codex_tui::bottom_pane::chat_composer`) restores the previous
    prompt text (which may start with `/`) and then calls
    `sync_command_popup`. The logic in `sync_command_popup` treats any first
    line that starts with `/` and has the caret inside the initial `/name`
    token as an active slash command name:
    
    ```rust
    let is_editing_slash_command_name = if first_line.starts_with('/') && caret_on_first_line {
        let token_end = first_line
            .char_indices()
            .find(|(_, c)| c.is_whitespace())
            .map(|(i, _)| i)
            .unwrap_or(first_line.len());
        cursor <= token_end
    } else {
        false
    };
    ```
    
    This detection does not distinguish between an actual interactive slash
    command being typed and a normal historical prompt that happens to begin
    with `/`. As a result, after history recall, the restored prompt like `/
    test` is interpreted as an "editing command name" context and the
    slash-command popup is (re)activated. Once `active_popup` is
    `ActivePopup::Command`, subsequent `Up` key presses are handled by
    `handle_key_event_with_slash_popup` instead of
    `handle_key_event_without_popup`, so they no longer trigger
    `history.navigate_up(...)` and the session prompt history cannot be
    scrolled.
  • Removed experimental "command risk assessment" feature (#7799)
    This experimental feature received lukewarm reception during internal
    testing. Removing from the code base.
  • Add vim-style navigation for CLI option selection (#7784)
    ## Summary
    
    Support "j" and "k" keys as aliases for "down" and "up" so vim users
    feel loved. Only support these keys when the selection is not
    searchable.
    
    ## Testing
    - env -u NO_COLOR TERM=xterm-256color cargo test -p codex-tui
    
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_693771b53bc8833088669060dfac2083)
  • fix(tui): add missing Ctrl+n/Ctrl+p support to ListSelectionView (#7629)
    ## Summary
    
    Extend Ctrl+n/Ctrl+p navigation support to selection popups (model
    picker, approval mode, etc.)
    
    This is a follow-up to #7530, which added Ctrl+n/Ctrl+p navigation to
    the textarea.
    The same keybindings were missing from `ListSelectionView`, causing
    inconsistent behavior
      when navigating selection popups.
    
      ## Related
    
      - #7530 - feat(tui): map Ctrl-P/N to arrow navigation in textarea
    
      ## Changes
    
      - Added Ctrl+n as alternative to Down arrow in selection popups
      - Added Ctrl+p as alternative to Up arrow in selection popups
      - Added unit tests for the new keybindings
    
      ## Test Plan
    
      - [x] `cargo test -p codex-tui list_selection_view` - all tests pass
    - [x] Manual testing: verified Ctrl+n/p navigation works in model
    selection popup
    
    ---------
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • fix wrap behavior for long commands (#7655)
    before:
    <img width="720" height="225" alt="image"
    src="https://github.com/user-attachments/assets/19b7ad7c-db14-4792-97cc-80677a3a52ec"
    />
    after:
    <img width="500" height="219" alt="Screenshot 2025-12-05 at 4 37 14 PM"
    src="https://github.com/user-attachments/assets/f877f846-5943-4ca7-8949-89e8524ffdb9"
    />
    
    
    also removes `is_current`, which is deadcode
  • Fix handle_shortcut_overlay_key for cross-platform consistency (#7583)
    **Summary**
    - Shortcut toggle using `?` in `handle_shortcut_overlay_key` fails to
    trigger on some platforms (notably Windows). Current match requires
    `KeyCode::Char('?')` with `KeyModifiers::NONE`. Some terminals set
    `SHIFT` when producing `?` (since it is typically `Shift + /`), so the
    strict `NONE` check prevents toggling.
    
    **Impact**
    - On Windows consoles/terminals, pressing `?` with an empty composer
    often does nothing, leading to inconsistent UX compared to macOS/Linux.
    
    **Root Cause**
    - Crossterm/terminal backends report modifiers inconsistently across
    platforms. Generating `?` may include `SHIFT`. The code enforces
    `modifiers == NONE`, so valid `?` presses with `SHIFT` are ignored.
    AltGr keyboards may also surface as `ALT`.
    
    **Repro Steps**
    - Open the TUI, ensure the composer is empty.
    - Press `?`.
    - Expected: Shortcut overlay toggles.
    - Actual (Windows frequently): No toggle occurs.
    
    **Fix Options**
    - Option 1 (preferred): Accept `?` regardless of `SHIFT`, but reject
    `CONTROL` and `ALT`.
    - Rationale: Keeps behavior consistent across platforms with minimal
    code change.
    	- Example change:
    		- Before: matching `KeyModifiers::NONE` only.
    		- After: allow `SHIFT`, disallow `CONTROL | ALT`.
    		- Suggested condition:
    			```rust
    			let toggles = matches!(key_event.code, KeyCode::Char('?'))
    && !key_event.modifiers.intersects(KeyModifiers::CONTROL |
    KeyModifiers::ALT)
    					&& self.is_empty();
    			```
    
    - Option 2: Platform-specific handling (Windows vs non-Windows).
    - Implement two variants or conditional branches using `#[cfg(target_os
    = "windows")]`.
    - On Windows, accept `?` with `SHIFT`; on other platforms, retain
    current behavior.
    - Trade-off: Higher maintenance burden and code divergence for limited
    benefit.
    
    ---
    
    close #5495
  • FIX: WSL Paste image does not work (#6793)
    ## Related issues:  
    - https://github.com/openai/codex/issues/3939  
    - https://github.com/openai/codex/issues/2292  
    - https://github.com/openai/codex/issues/7528 (After correction
    https://github.com/openai/codex/pull/3990)
    
    **Area:** `codex-cli` (image handling / clipboard & file uploads)  
    **Platforms affected:** WSL (Ubuntu on Windows 10/11). No behavior
    change on native Linux/macOS/Windows.
    
    ## Summary
    
    This PR fixes image pasting and file uploads when running `codex-cli`
    inside WSL. Previously, image operations failed silently or with
    permission errors because paths weren't properly mapped between Windows
    and WSL filesystems.
    
    ## Visual Result
    
    <img width="1118" height="798" alt="image"
    src="https://github.com/user-attachments/assets/14e10bc4-6b71-4d1f-b2a6-52c0a67dd069"
    />
    
    ## Last Rust-Cli
    
    <img width="1175" height="859" alt="image"
    src="https://github.com/user-attachments/assets/7ef41e29-9118-42c9-903c-7116d21e1751"
    />
    
    ## Root cause
    
    The CLI assumed native Linux/Windows environments and didn't handle the
    WSL↔Windows boundary:
    
    - Used Linux paths for files that lived on the Windows host
    - Missing path normalization between Windows (`C:\...`) and WSL
    (`/mnt/c/...`)
    - Clipboard access failed under WSL
    
    ### Why `Ctrl+V` doesn't work in WSL terminals
    
    Most WSL terminal emulators (Windows Terminal, ConEmu, etc.) intercept
    `Ctrl+V` at the terminal level to paste text from the Windows clipboard.
    This keypress never reaches the CLI application itself, so our clipboard
    image handler never gets triggered. Users need `Ctrl+Alt+V`.
    
    ## Changes
    
    ### WSL detection & path mapping
    
    - Detects WSL by checking `/proc/sys/kernel/osrelease` and the
    `WSL_INTEROP` env var
    - Maps Windows drive paths to WSL mount paths (`C:\...` → `/mnt/c/...`)
    
    ### Clipboard fallback for WSL
    
    - When clipboard access fails under WSL, falls back to PowerShell to
    extract images from the Windows clipboard
    - Saves to a temp file and maps the path back to WSL
    
    ### UI improvements
    
    - Shows `Ctrl+Alt+V` hint on WSL (many terminals intercept plain
    `Ctrl+V`)
    - Better error messages for unreadable images
    
    ## Performance
    
    - Negligible overhead. The fallback adds a single FS copy to a temp file
    only when needed.
    - Direct streaming remains the default.
    
    ## Files changed
    
    - `protocol/src/lib.rs` – Added platform detection module  
    - `protocol/src/models.rs` – Added WSL path mapping for local images  
    - `protocol/src/platform.rs` – New module with WSL detection utilities  
    - `tui/src/bottom_pane/chat_composer.rs` – Added base64 data URL support
    and WSL path mapping
    - `tui/src/bottom_pane/footer.rs` – WSL-aware keyboard shortcuts  
    - `tui/src/clipboard_paste.rs` – PowerShell clipboard fallback
    
    ## How to reproduce the original bug (pre-fix)
    
    1. Run `codex-cli` inside WSL2 on Windows.  
    2. Paste an image from the Windows clipboard or drag an image from
    `C:\...` into the terminal.
    3. Observe that the image is not attached (silent failure) or an error
    is logged; no artifact reaches the tool.
    
    ## How to verify the fix
    
    1. Build this branch and run `codex-cli` inside WSL2.  
    2. Paste from clipboard and drag from both Windows and WSL paths.  
    3. Confirm that the image appears in the tool and the CLI shows a single
    concise info line (no warning unless fallback was used).
    
    I’m happy to adjust paths, naming, or split helpers into a separate
    module if you prefer.
    
    ## How to try this branch
    
    If you want to try this before it’s merged, you can use my Git branch:
    
    Repository: https://github.com/Waxime64/codex.git  
    Branch: `wsl-image-2`
    
    1. Start WSL on your Windows machine.
    2. Clone the repository and switch to the branch:
       ```bash
       git clone https://github.com/Waxime64/codex.git
       cd codex
       git checkout wsl-image-2
       # then go into the Rust workspace root, e.g.:
       cd codex-rs
    3. Build the TUI binary:
      cargo build -p codex-tui --bin codex-tui --release
    4. Install the binary:
       sudo install -m 0755 target/release/codex-tui /usr/local/bin/codex
    5. From the project directory where you want to use Codex, start it
    with:
       cd /path/to/your/project
       /usr/local/bin/codex
    
    On WSL, use CTRL+ALT+V to paste an image from the Windows clipboard into
    the chat.
  • execpolicy tui flow (#7543)
    ## Updating the `execpolicy` TUI flow
    
    In the TUI, when going through the command approval flow, codex will now
    ask the user if they would like to whitelist the FIRST unmatched command
    among a chain of commands.
    
    For example, let's say the agent wants to run `apple | pear` with an
    empty `execpolicy`
    
    Neither apple nor pear will match to an `execpolicy` rule. Thus, when
    prompting the user, codex tui will ask the user if they would like to
    whitelist `apple`.
    
    If the agent wants to run `apple | pear` again, they would be prompted
    again because pear is still unknown. when prompted, the user will now be
    asked if they'd like to whitelist `pear`.
    
    Here's a demo video of this flow:
    
    
    https://github.com/user-attachments/assets/fd160717-f6cb-46b0-9f4a-f0a974d4e710
    
    This PR also removed the `allow for this session` option from the TUI.
  • Refactor execpolicy fallback evaluation (#7544)
    ## Refactor of the `execpolicy` crate
    
    To illustrate why we need this refactor, consider an agent attempting to
    run `apple | rm -rf ./`. Suppose `apple` is allowed by `execpolicy`.
    Before this PR, `execpolicy` would consider `apple` and `pear` and only
    render one rule match: `Allow`. We would skip any heuristics checks on
    `rm -rf ./` and immediately approve `apple | rm -rf ./` to run.
    
    To fix this, we now thread a `fallback` evaluation function into
    `execpolicy` that runs when no `execpolicy` rules match a given command.
    In our example, we would run `fallback` on `rm -rf ./` and prevent
    `apple | rm -rf ./` from being run without approval.
  • whitelist command prefix integration in core and tui (#7033)
    this PR enables TUI to approve commands and add their prefixes to an
    allowlist:
    <img width="708" height="605" alt="Screenshot 2025-11-21 at 4 18 07 PM"
    src="https://github.com/user-attachments/assets/56a19893-4553-4770-a881-becf79eeda32"
    />
    
    note: we only show the option to whitelist the command when 
    1) command is not multi-part (e.g `git add -A && git commit -m 'hello
    world'`)
    2) command is not already matched by an existing rule
  • 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>
  • add slash resume (#7302)
    `codex resume` isn't that discoverable. Adding it to the slash commands
    can help
  • 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>
  • Show token used when context window is unknown (#7497)
    - Show context window usage in tokens instead of percentage when the
    window length is unknown.
  • 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
  • [feedback] Add source info into feedback metadata. (#7140)
    Verified the source info is correctly attached based on whether it's cli
    or vscode.
  • 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"
    />
  • 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)
  • 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
  • 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.
  • 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>
  • nit: useless log to debug (#6898)
    When you type too fast in most terminals, it gets interpreted as paste,
    making this log spam
  • Fix TUI issues with Alt-Gr on Windows (#6799)
    This PR fixes keyboard handling for the Right Alt (aka "Alt-Gr") key on
    Windows. This key appears on keyboards in Central and Eastern Europe.
    Codex has effectively never worked for Windows users in these regions
    because the code didn't properly handle this key, which is used for
    typing common symbols like `\` and `@`.
    
    A few days ago, I merged a [community-authored
    PR](https://github.com/openai/codex/pull/6720) that supplied a partial
    fix for this issue. Upon closer inspect, that PR was 1) too broad (not
    scoped to Windows only) and 2) incomplete (didn't fix all relevant code
    paths, so paste was still broken).
    
    This improvement is based on another [community-provided
    PR](https://github.com/openai/codex/pull/3241) by @marektomas-cz. He
    submitted it back in September and later closed it because it didn't
    receive any attention.
    
    This fix addresses the following bugs: #5922, #3046, #3092, #3519,
    #5684, #5843.