9 Commits

  • bazel: enable the full Windows gnullvm CI path (#15952)
    ## Why
    
    This PR is the current, consolidated follow-up to the earlier Windows
    Bazel attempt in #11229. The goal is no longer just to get a tiny
    Windows smoke job limping along: it is to make the ordinary Bazel CI
    path usable on `windows-latest` for `x86_64-pc-windows-gnullvm`, with
    the same broad `//...` test shape that macOS and Linux already use.
    
    The earlier smoke-list version of this work was useful as a foothold,
    but it was not a good long-term landing point. Windows Bazel kept
    surfacing real issues outside that allowlist:
    
    - GitHub's Windows runner exposed runfiles-manifest bugs such as
    `FINDSTR: Cannot open D:MANIFEST`, which broke Bazel test launchers even
    when the manifest file existed.
    - `rules_rs`, `rules_rust`, LLVM extraction, and Abseil still needed
    `windows-gnullvm`-specific fixes for our hermetic toolchain.
    - the V8 path needed more work than just turning the Windows matrix
    entry back on: `rusty_v8` does not ship Windows GNU artifacts in the
    same shape we need, and Bazel's in-tree V8 build needed a set of Windows
    GNU portability fixes.
    
    Windows performance pressure also pushed this toward a full solution
    instead of a permanent smoke suite. During this investigation we hit
    targets such as `//codex-rs/shell-command:shell-command-unit-tests` that
    were much more expensive on Windows because they repeatedly spawn real
    PowerShell parsers (see #16057 for one concrete example of that
    pressure). That made it much more valuable to get the real Windows Bazel
    path working than to keep iterating on a narrowly curated subset.
    
    The net result is that this PR now aims for the same CI contract on
    Windows that we already expect elsewhere: keep standalone
    `//third_party/v8:all` out of the ordinary Bazel lane, but allow V8
    consumers under `//codex-rs/...` to build and test transitively through
    `//...`.
    
    ## What Changed
    
    ### CI and workflow wiring
    
    - re-enable the `windows-latest` / `x86_64-pc-windows-gnullvm` Bazel
    matrix entry in `.github/workflows/bazel.yml`
    - move the Windows Bazel output root to `D:\b` and enable `git config
    --global core.longpaths true` in
    `.github/actions/setup-bazel-ci/action.yml`
    - keep the ordinary Bazel target set on Windows aligned with macOS and
    Linux by running `//...` while excluding only standalone
    `//third_party/v8:all` targets from the normal lane
    
    ### Toolchain and module support for `windows-gnullvm`
    
    - patch `rules_rs` so `windows-gnullvm` is modeled as a distinct Windows
    exec/toolchain platform instead of collapsing into the generic Windows
    shape
    - patch `rules_rust` build-script environment handling so llvm-mingw
    build-script probes do not inherit unsupported `-fstack-protector*`
    flags
    - patch the LLVM module archive so it extracts cleanly on Windows and
    provides the MinGW libraries this toolchain needs
    - patch Abseil so its thread-local identity path matches the hermetic
    `windows-gnullvm` toolchain instead of taking an incompatible MinGW
    pthread path
    - keep both MSVC and GNU Windows targets in the generated Cargo metadata
    because the current V8 release-asset story still uses MSVC-shaped names
    in some places while the Bazel build targets the GNU ABI
    
    ### Windows test-launch and binary-behavior fixes
    
    - update `workspace_root_test_launcher.bat.tpl` to read the runfiles
    manifest directly instead of shelling out to `findstr`, which was the
    source of the `D:MANIFEST` failures on the GitHub Windows runner
    - thread a larger Windows GNU stack reserve through `defs.bzl` so
    Bazel-built binaries that pull in V8 behave correctly both under normal
    builds and under `bazel test`
    - remove the no-longer-needed Windows bootstrap sh-toolchain override
    from `.bazelrc`
    
    ### V8 / `rusty_v8` Windows GNU support
    
    - export and apply the new Windows GNU patch set from
    `patches/BUILD.bazel` / `MODULE.bazel`
    - patch the V8 module/rules/source layers so the in-tree V8 build can
    produce Windows GNU archives under Bazel
    - teach `third_party/v8/BUILD.bazel` to build Windows GNU static
    archives in-tree instead of aliasing them to the MSVC prebuilts
    - reuse the Linux release binding for the experimental Windows GNU path
    where `rusty_v8` does not currently publish a Windows GNU binding
    artifact
    
    ## Testing
    
    - the primary end-to-end validation for this work is the `Bazel`
    workflow plus `v8-canary`, since the hard parts are Windows-specific and
    depend on real GitHub runner behavior
    - before consolidation back onto this PR, the same net change passed the
    full Bazel matrix in [run
    23675590471](https://github.com/openai/codex/actions/runs/23675590471)
    and passed `v8-canary` in [run
    23675590453](https://github.com/openai/codex/actions/runs/23675590453)
    - those successful runs included the `windows-latest` /
    `x86_64-pc-windows-gnullvm` Bazel job with the ordinary `//...` path,
    not the earlier Windows smoke allowlist
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/15952).
    * #16067
    * __->__ #15952
  • feat(network-proxy): structured policy signaling and attempt correlation to core (#11662)
    ## Summary
    When network requests were blocked, downstream code often had to infer
    ask vs deny from free-form response text. That was brittle and led to
    incorrect approval behavior.
    This PR fixes the proxy side so blocked decisions are structured and
    request metadata survives reliably.
    
    ## Description
    - Blocked proxy responses now carry consistent structured policy
    decision data.
    - Request attempt metadata is preserved across proxy env paths
    (including ALL_PROXY flows).
    - Header stripping was tightened so we still remove unsafe forwarding
    headers, but keep metadata needed for policy handling.
    - Block messages were clarified (for example, allowlist miss vs explicit
    deny).
    - Added unified violation log entries so policy failures can be
    inspected in one place.
    - Added/updated tests for these behaviors.
    
    ---------
    
    Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
  • Add feature-gated freeform js_repl core runtime (#10674)
    ## Summary
    
    This PR adds an **experimental, feature-gated `js_repl` core runtime**
    so models can execute JavaScript in a persistent REPL context across
    tool calls.
    
    The implementation integrates with existing feature gating, tool
    registration, prompt composition, config/schema docs, and tests.
    
    ## What changed
    
    - Added new experimental feature flag: `features.js_repl`.
    - Added freeform `js_repl` tool and companion `js_repl_reset` tool.
    - Gated tool availability behind `Feature::JsRepl`.
    - Added conditional prompt-section injection for JS REPL instructions
    via marker-based prompt processing.
    - Implemented JS REPL handlers, including freeform parsing and pragma
    support (timeout/reset controls).
    - Added runtime resolution order for Node:
      1. `CODEX_JS_REPL_NODE_PATH`
      2. `js_repl_node_path` in config
      3. `PATH`
    - Added JS runtime assets/version files and updated docs/schema.
    
    ## Why
    
    This enables richer agent workflows that require incremental JavaScript
    execution with preserved state, while keeping rollout safe behind an
    explicit feature flag.
    
    ## Testing
    
    Coverage includes:
    
    - Feature-flag gating behavior for tool exposure.
    - Freeform parser/pragma handling edge cases.
    - Runtime behavior (state persistence across calls and top-level `await`
    support).
    
    ## Usage
    
    ```toml
    [features]
    js_repl = true
    ```
    
    Optional runtime override:
    
    - `CODEX_JS_REPL_NODE_PATH`, or
    - `js_repl_node_path` in config.
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    - 👉 `1` https://github.com/openai/codex/pull/10674
    -  `2` https://github.com/openai/codex/pull/10672
    -  `3` https://github.com/openai/codex/pull/10671
    -  `4` https://github.com/openai/codex/pull/10673
    -  `5` https://github.com/openai/codex/pull/10670
  • TUI footer: right-align context and degrade shortcut summary + mode cleanly (#9944)
    ## Summary
    Refines the bottom footer layout to keep `% context left` right-aligned
    while making the left side degrade cleanly
    
    ## Behavior with empty textarea
    Full width:
    <img width="607" height="62" alt="Screenshot 2026-01-26 at 2 59 59 PM"
    src="https://github.com/user-attachments/assets/854f33b7-d714-40be-8840-a52eb3bda442"
    />
    Less:
    <img width="412" height="66" alt="Screenshot 2026-01-26 at 2 59 48 PM"
    src="https://github.com/user-attachments/assets/9c501788-c3a2-4b34-8f0b-8ec4395b44fe"
    />
    Min width:
    <img width="218" height="77" alt="Screenshot 2026-01-26 at 2 59 33 PM"
    src="https://github.com/user-attachments/assets/0bed2385-bdbf-4254-8ae4-ab3452243628"
    />
    
    ## Behavior with message in textarea and agent running (steer enabled)
    Full width:
    <img width="753" height="63" alt="Screenshot 2026-01-26 at 4 33 54 PM"
    src="https://github.com/user-attachments/assets/1856b352-914a-44cf-813d-1cb50c7f183b"
    />
    
    Less:
    <img width="353" height="61" alt="Screenshot 2026-01-26 at 4 30 12 PM"
    src="https://github.com/user-attachments/assets/d951c4d5-f3e7-4116-8fe1-6a6c712b3d48"
    />
    
    Less:
    <img width="304" height="64" alt="Screenshot 2026-01-26 at 4 30 51 PM"
    src="https://github.com/user-attachments/assets/1433e994-5cbc-4e20-a98a-79eee13c8699"
    />
    
    Less:
    <img width="235" height="61" alt="Screenshot 2026-01-26 at 4 30 56 PM"
    src="https://github.com/user-attachments/assets/e216c3c6-84cd-40fc-ae4d-83bf28947f0e"
    />
    
    Less:
    <img width="165" height="59" alt="Screenshot 2026-01-26 at 4 31 08 PM"
    src="https://github.com/user-attachments/assets/027de5de-7185-47ce-b1cc-5363ea33d9b1"
    />
    
    ## Notes / Edge Cases
    - In steer mode while typing, the queue hint no longer replaces the mode
    label; it renders as `tab to queue message · {Mode}`.
    - Collapse priorities differ by state:
    - With the queue hint active, `% context left` is hidden before
    shortening or dropping the queue hint.
    - In the empty + non-running state, `? for shortcuts` is dropped first,
    and `% context left` is only shown if `(shift+tab to
    cycle)` can also fit.
    - Transient instructional states (`?` overlay, Esc hint, Ctrl+C/D
    reminders, and flash/override hints) intentionally suppress the
    mode label (and context) to focus the next action.
    
    ## Implementation Notes
    - Renamed the base footer modes to make the state explicit:
    `ComposerEmpty` and `ComposerHasDraft`, and compute the base mode
    directly from emptiness.
    - Unified collapse behavior in `single_line_footer_layout` for both base
    modes, with:
    - Queue-hint behavior that prefers keeping the queue hint over context.
    - A cycle-hint guard that prevents context from reappearing after
    `(shift+tab to cycle)` is dropped.
    - Kept rendering responsibilities explicit:
      - `single_line_footer_layout` decides what fits.
      - `render_footer_line` renders a chosen line.
    - `render_footer_from_props` renders the canonical mode-to-text mapping.
    - Expanded snapshot coverage:
    - Added `footer_collapse_snapshots` in `chat_composer.rs` to lock the
    distinct collapse states across widths.
    - Consolidated the width-aware snapshot helper usage (e.g.,
    `snapshot_composer_state_with_width`,
    `snapshot_footer_with_mode_indicator`).
  • Terminal Detection Metadata for Per-Terminal Scroll Scaling (#8252)
    # Terminal Detection Metadata for Per-Terminal Scroll Scaling
    
    ## Summary
    Expand terminal detection into structured metadata (`TerminalInfo`) with
    multiplexer awareness, plus a testable environment shim and
    characterization tests.
    
    ## Context / Motivation
    - TUI2 owns its viewport and scrolling model (see
    `codex-rs/tui2/docs/tui_viewport_and_history.md`), so scroll behavior
    must be consistent across terminals and independent of terminal
    scrollback quirks.
    - Prior investigations show mouse wheel scroll deltas vary noticeably by
    terminal. To tune scroll scaling (line increments per wheel tick) we
    need reliable terminal identification, including when running inside
    tmux/zellij.
    - tmux is especially tricky because it can mask the underlying terminal;
    we now consult `tmux display-message` client termtype/name to attribute
    sessions to the actual terminal rather than tmux itself.
    - This remains backwards compatible with the existing OpenTelemetry
    user-agent token because `user_agent()` is still derived from the same
    environment signals (now via `TerminalInfo`).
    
    ## Changes
    - Introduce `TerminalInfo`, `TerminalName`, and `Multiplexer` with
    `TERM_PROGRAM`/`TERM`/multiplexer detection and user-agent formatting in
    `codex-rs/core/src/terminal.rs`.
    - Add an injectable `Environment` trait + `FakeEnvironment` for testing,
    and comprehensive characterization tests covering known terminals, tmux
    client termtype/name, and zellij.
    - Document module usage and detection order; update `terminal_info()` to
    be the primary interface for callers.
    
    ## Testing
    - `cargo test -p codex-core terminal::tests`
    - manually checked ghostty, iTerm2, Terminal.app, vscode, tmux, zellij,
    Warp, alacritty, kitty.
    ```
    2025-12-18T07:07:49.191421Z  INFO Detected terminal info terminal=TerminalInfo { name: Iterm2, term_program: Some("iTerm.app"), version: Some("3.6.6"), term: None, multiplexer: None }
    2025-12-18T07:07:57.991776Z  INFO Detected terminal info terminal=TerminalInfo { name: AppleTerminal, term_program: Some("Apple_Terminal"), version: Some("455.1"), term: None, multiplexer: None }
    2025-12-18T07:08:07.732095Z  INFO Detected terminal info terminal=TerminalInfo { name: WarpTerminal, term_program: Some("WarpTerminal"), version: Some("v0.2025.12.10.08.12.stable_03"), term: None, multiplexer: None }
    2025-12-18T07:08:24.860316Z  INFO Detected terminal info terminal=TerminalInfo { name: Kitty, term_program: None, version: None, term: None, multiplexer: None }
    2025-12-18T07:08:38.302761Z  INFO Detected terminal info terminal=TerminalInfo { name: Alacritty, term_program: None, version: None, term: None, multiplexer: None }
    2025-12-18T07:08:50.887748Z  INFO Detected terminal info terminal=TerminalInfo { name: VsCode, term_program: Some("vscode"), version: Some("1.107.1"), term: None, multiplexer: None }
    2025-12-18T07:10:01.309802Z  INFO Detected terminal info terminal=TerminalInfo { name: WezTerm, term_program: Some("WezTerm"), version: Some("20240203-110809-5046fc22"), term: None, multiplexer: None }
    2025-12-18T08:05:17.009271Z  INFO Detected terminal info terminal=TerminalInfo { name: Ghostty, term_program: Some("ghostty"), version: Some("1.2.3"), term: None, multiplexer: None }
    2025-12-18T08:05:23.819973Z  INFO Detected terminal info terminal=TerminalInfo { name: Ghostty, term_program: Some("ghostty"), version: Some("1.2.3"), term: Some("xterm-ghostty"), multiplexer: Some(Tmux { version: Some("3.6a") }) }
    2025-12-18T08:05:35.572853Z  INFO Detected terminal info terminal=TerminalInfo { name: Ghostty, term_program: Some("ghostty"), version: Some("1.2.3"), term: None, multiplexer: Some(Zellij) }
    ```
    
    ## Notes / Follow-ups
    - Next step is to wire `TerminalInfo` into TUI2’s scroll scaling
    configuration and add a per-terminal tuning table.
    - The log output in TUI2 helps validate real-world detection before
    applying behavior changes.
  • Re-add markdown streaming (#2029)
    Wait for newlines, then render markdown on a line by line basis. Word wrap it for the current terminal size and then spit it out line by line into the UI. Also adds tests and fixes some UI regressions.
  • Add codespell support (config, workflow to detect/not fix) and make it fix some typos (#903)
    More about codespell: https://github.com/codespell-project/codespell .
    
    I personally introduced it to dozens if not hundreds of projects already
    and so far only positive feedback.
    
    CI workflow has 'permissions' set only to 'read' so also should be safe.
    
    Let me know if just want to take typo fixes in and get rid of the CI
    
    ---------
    
    Signed-off-by: Yaroslav O. Halchenko <debian@onerussian.com>