Skip to content

fix(terminal): the wheel no longer moves a Codex selection menu's selection - #698

Merged
Ark0N merged 2 commits into
Ark0N:masterfrom
opticon454:fix/codex-plan-menu-wheel
Oct 24, 2026
Merged

Ark0N merged 2 commits into
Ark0N:masterfrom
opticon454:fix/codex-plan-menu-wheel

Conversation

@opticon454

@opticon454 opticon454 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

What

Scrolling the wheel over a Codex selection menu, such as the "Implement this plan?" prompt that follows a plan, no longer moves the menu's selection.

Fixes #696. Related: #699 (the mouse wheel needing 5 or more notches before a Codex pane scrolls at all, #697), which is independent of this one.

Overlap with #681

This conflicts with #681 (fix(terminal): load tmux history instead of paging Claude after a hollow tab switch) in one place, and the resolution is to keep both sides. Both PRs add a guard to _maybePageCliTranscript straight after the existing open-dialog check:

git merge-tree of this branch with #681's head reports a single content conflict, in src/web/public/terminal-ui.js at that spot; terminal-tile.js merges automatically. The two guards are independent, and I would put this one first so a menu is never scrolled locally either. Whichever lands second will need that two-line rebase, and I will do it as soon as the other merges. pr-watch had also held this branch back for the same overlap.

Other open PRs that share a file

pr-watch also lists #510, #608 and #686. They share src/web/public/terminal-ui.js with this branch (#686 also terminal-tile.js). A git merge-tree of this branch with each head: #686 merges cleanly, and #510 and #608 report no conflict in terminal-ui.js either. The conflicts merge-tree does report for those two are in files this branch does not touch (session.ts, mux-interface.ts, keyboard-accessory.js), because #510 and #608 already conflict with current master on their own.

Why

codex-cli 0.162.1 and 0.164.0 never turn on mouse tracking (tmux reports alternate_on=1, mouse_any_flag=0 in the composer, in plan mode and at the prompt; -c tui.alternate_screen="always", tui.fullscreen_transcript=true and tui.mouse_scroll_speed change nothing), so Codeman scrolls a Codex pane by turning the wheel into PageUp and PageDown. In the composer that pages the transcript. In Codex's selection menus the same keys move the selection, so each wheel notch walked the cursor through the options. Measured with a real browser against an isolated Codeman running Codex 0.164.0 at the "Implement this plan?" prompt:

  • one notch down moved the selection from "Yes, implement this plan" to "No, stay in Plan mode";
  • one notch up moved it back to "Yes, implement this plan", one Enter away from starting the implementation.

To the user the wheel (and PageUp/PageDown, which Codex itself binds to the selection there) looked dead, and the transcript behind the menu cannot be scrolled at all: Ctrl+T does nothing in that menu and Codex offers no other key. The 0.163.0 and 0.164.0 release notes do not mention it, so upgrading Codex does not fix it.

How

  • CodemanTerminalInput.isCodexSelectionMenu(terminal) reads the screen: a selected numbered option (› 1. , indented two spaces in a question, or the notes field › Add notes) above a key-hint footer (enter select · esc back, enter continue · esc back, Press enter to confirm ..., tab to add notes ...). The footer must be the last thing on the screen, apart from wrapped hint rows, so an answer that quotes the hints above the composer is not a menu.
  • _maybePageCliTranscript (main pane) and its tile twin consume the wheel without sending a key while such a menu is showing, the same way they already do for a pending approval (tabAlerts action). Once the menu closes the wheel pages the transcript again.
  • It is deliberately not an alert: the "Implement this plan?" prompt stays outside workDetect.blockedLine (test/codex-blocked-detection.test.ts pins that as deliberate), so nothing about blocked state, notifications or wait changes.

Not changed

Tests

  • test/codex-menu-scroll.test.ts: the detector against the live capture fixtures in test/fixtures/codex-dialogs/ (22 menus and dialogs read as menus; 10 idle, composer, working, slash-popup and quoted-dialog screens do not), the main pane sending no key at the "Implement this plan?" menu while paging from the composer, another CLI showing the same text still paging, and the tile asking the same question for its own terminal and session.
  • Related terminal scroll, tile and touch tests pass; lint, tsc, the frontend syntax check and prettier pass.
  • Checked end to end in Chromium against Codeman built from this branch with Codex 0.164.0: at the prompt, 24 wheel notches (6 down, 6 up, 12 down) left the selection on option 1; after Escape the wheel scrolled the transcript again.

@Ark0N

Ark0N commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Thank you, opticon454, for tracking this down and measuring it against a real Codex 0.164.0. This PR stops the wheel and touch scroll from walking the selection in Codex's own menus (the "Implement this plan?" prompt, the /model, /permissions and /review pickers, questions and approvals) by recognising the menu on screen and consuming the gesture instead of sending PageUp/PageDown.

The fix is right and the test is good: I ran test/codex-menu-scroll.test.ts against master's terminal-ui.js and terminal-tile.js and it fails there, and passes here, along with typecheck, lint, the frontend syntax check, prettier, the related scroll and tile suites and the touch-paging browser test.

Three small things, which I will apply at merge time unless you would rather push them yourself:

  1. docs/architecture-invariants.md:246 still says "Three gestures are consumed WITHOUT paging" and "The dialog check is the one rule outside the helper". With this PR there is a fourth case (an open Codex selection menu, logged as page-keys-menu-open) and a second per-pane rule, so that paragraph needs the menu case added.
  2. src/web/public/terminal-ui.js:332: the scan stops after CODEX_MENU_SCAN_ROWS = 24 non-blank rows. In question-w36.txt the selected › 1. Blue row is already 16 rows up from the bottom, and a question with sentence-length option descriptions on a phone-width pane pushes it past 24, where the menu is missed and the wheel moves the selection again (I reproduced that by adding 12 wrapped description rows to that fixture). The loop is already bounded by the screen, so I will drop the cap.
  3. Optional: the tile case in test/codex-menu-scroll.test.ts:163 checks the source text of the call. A mirrored case in test/terminal-tile-scroll.test.ts, next to the dialog-check block at lines 821 to 840, would drive the real tile with a menu on its screen.

One note for later, no change needed here: _codexMenuOpen gates on session?.mode !== 'codex' (terminal-ui.js:6153). terminal-ui.js is allowed its own per-CLI rules for now, so this matches the file, but the paging gate next to it reads a capability (transcriptPageKeys), and this check belongs on one too when those rules move to the registry. I will open a follow-up for it.

On #681: thanks for working out the conflict ahead of time. I agree with your ordering (this menu guard first), and whichever lands second gets that two-line resolution.

I will merge this with the fixes above.

@opticon454

Copy link
Copy Markdown
Contributor Author

Thanks @Ark0N. All three are pushed in 372df864, so there is nothing for you to apply.

  1. docs/architecture-invariants.md. The paragraph now says "Four gestures are consumed WITHOUT paging" and adds the Codex selection menu (what it covers, why Codex's PageUp/PageDown move the selection, that it is read off the screen and deliberately not an alert, the page-keys-menu-open log line). The closing sentence now names the two per-pane rules outside the helper, the alert check and the menu check.
  2. The row cap. CODEX_MENU_SCAN_ROWS is gone; the scan is bounded by the screen. The new case in test/codex-menu-scroll.test.ts takes question-w36.txt and adds 12 wrapped description rows under the selected option, as you described, and reads it as a menu.
  3. A tile case that drives the real tile. test/terminal-tile-scroll.test.ts has a new block after the dialog-check one: with the "Implement this plan?" menu on the tile's own screen, three wheel events are consumed and no key is flushed, and with the composer back on screen the same wheel pages. A second case gives the active pane a blank screen and checks the tile reads its own terminal, not the active tab's.

Typecheck, lint, prettier, the frontend syntax check and the related scroll, tile, touch and blocked-detection tests pass (286 in the files I ran).

One thing to expect when both land: #699 edits the same long paragraph at docs/architecture-invariants.md:246 (the gesture rules), so whichever merges second needs a trivial manual merge there.

@Ark0N

Ark0N commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Thank you, opticon454, for the quick turnaround. This PR stops the wheel and touch scroll from walking the selection in Codex's own menus by reading the menu off the screen and consuming the gesture instead of sending PageUp/PageDown.

All three items from the first review are in 372df864: the invariants paragraph now covers the fourth case and the second per-pane rule, the row cap is gone (and the wrapped-description case is pinned), and the new block in test/terminal-tile-scroll.test.ts drives a real tile. Typecheck, lint, the frontend syntax check, prettier, the touched-area suites and the touch-paging browser test all pass, and the new tests fail against master's terminal-ui.js and terminal-tile.js.

Two one-line text edits I will make at merge time:

  1. .changeset/codex-menu-wheel.md:5 says Codex does not track the mouse "on 0.162 to 0.164", but docs/architecture-invariants.md:236 records Codex 0.163.0 fullscreen with mouse_any_flag=1. I will reword it to "When Codex does not track the mouse (measured on 0.162.1 and 0.164.0)".
  2. docs/architecture-invariants.md:248 lists the [scroll] decisions as forward-sgr|page-keys|local-scrollback|repull-refused-downgrade. I will add page-keys-dialog-open and your new page-keys-menu-open.

One follow-up for later, no change needed here: page keys wait on the 40 ms coalescing timer, so a PageUp queued from the composer just before the menu paints still reaches it (the existing tabAlerts check has the same window). Re-checking the menu and the alert in _flushWheelSgrQueue and the tile's flush would close it. I will open an issue for it next to the mode !== 'codex' one.

I will merge this with those two edits, and #681 then gets the two-line resolution with your menu guard first, as you proposed.

@Ark0N
Ark0N merged commit 372df86 into Ark0N:master Oct 24, 2026
2 checks passed
Ark0N pushed a commit that referenced this pull request Oct 24, 2026
changeset: say Codex does not track the mouse "measured on 0.162.1 and 0.164.0", since 0.163.0 fullscreen was measured tracking it
docs/architecture-invariants.md: list page-keys-dialog-open and page-keys-menu-open among the [scroll] decisions

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Ark0N pushed a commit that referenced this pull request Oct 24, 2026
…odex selection menu's selection

Conflicts resolved by keeping both sides:
- src/web/public/terminal-ui.js (_maybePageCliTranscript): #698's
  Codex-menu consume check sits right after the open-dialog consume
  check (its sibling, as the docblock lists them), and #681's
  unloaded-scrollback fall-through (paneHistoryLines > 0) follows it.
- docs/architecture-invariants.md: the hollow-pane paragraph carries
  #681's unloaded-scrollback sentence and #698's menu rewording.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Ark0N pushed a commit that referenced this pull request Oct 24, 2026
… CLI's transcript at once

Conflict in docs/architecture-invariants.md resolved by keeping both
sides: the hollow-pane paragraph carries #681's unloaded-scrollback
sentence, #698's Codex-menu rewording and #699's notch rewording (a
word-level three-way merge; the three edits touch disjoint sentences).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Ark0N

Ark0N commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Merged, thank you! This ships in 1.45.0 and closes #696.

It met #681 and #699 in _maybePageCliTranscript. Your menu check sits right after the open-dialog one, its sibling, followed by #681's unloaded-scrollback fall-through. At merge the changeset says Codex doesn't track the mouse "measured on 0.162.1 and 0.164.0" (0.163.0 fullscreen was measured tracking it), and architecture-invariants lists page-keys-dialog-open and page-keys-menu-open among the [scroll] decisions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex: the mouse wheel moves the selection in menus such as "Implement this plan?"

2 participants