Skip to content

fix(terminal): page a hollow Codex transcript with PageUp/PageDown from the first wheel event - #527

Draft
aakhter wants to merge 1 commit into
Ark0N:masterfrom
aakhter:pr/codex-hollow-paging
Draft

aakhter wants to merge 1 commit into
Ark0N:masterfrom
aakhter:pr/codex-hollow-paging

Conversation

@aakhter

@aakhter aakhter commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

This changes the last-resort page-key scroll in _maybePageCliTranscript. That path runs when a wheel or touch gesture is not forwarded to the CLI and the local xterm buffer holds no history (normal buffer, baseY === 0). It sends plain PageUp/PageDown keys so the CLI pages its own transcript.

This is not SGR wheel forwarding. Codex still ignores SGR wheel reports (#227), its wheelForward stays never, and _shouldForwardWheelToApp is unchanged.

  1. Codex can use the page-key fallback. Newer Codex draws on tmux's alternate screen, and the full strip hides that from xterm, so a Codex pane has no local scrollback, just like a repaint-mode Claude pane. Scrolling the wheel over it did nothing.

    • Measured with Codex 0.157.1 locally and 0.160 over a remote session: PageUp moves the visible transcript, while SGR wheel reports and local scrolling do nothing.
    • An older inline Codex keeps real local history (baseY > 0), so the guard never fires for it.
    • Which modes may page is a new registry capability, capabilities.transcriptPageKeys (set for claude and codex in stock.ts, an optional boolean in the schema).
    • The server publishes it to the page as window.__codemanTranscriptPageKeys, also in /session/:id windows, so terminal-ui.js holds no CLI id for it. The old mode !== 'claude' check is gone.
  2. The first event of a gesture pages straight away. The fallback used to send a key only after half a screen of accumulated travel (19 rows, about 475 px on a 38-row pane), so an ordinary trackpad flick sent nothing.

    • The first page is paid in advance: the travel it skipped is owed back by the rest of the gesture, so the rate stays at one page per half screen.
    • A pause of more than 150 ms, a change of direction or a tab switch starts a new gesture.
    • Sub-row jitter does not page.

Tests. These fail on master and pass with this change:

  • test/terminal-scroll-routing.test.ts: Codex pages only while hollow; first-event paging and repayment; gesture reset; tab isolation; modes come only from the injected map.
  • test/cli-registry-schema.test.ts: the capability's shape, and exactly claude and codex set in stock.
  • test/render-index-html.test.ts: injection in the main page and the solo window.

docs/architecture-invariants.md is updated.

One trade-off: small gestures now send a key where they used to send nothing, for Claude as well. A Claude menu or dialog open at that moment could react to PageUp, which is the caveat this fallback already carries.

…om the first wheel event

Two changes to the last-resort page-key scroll (_maybePageCliTranscript), the
path a wheel or touch gesture takes when it is not forwarded to the CLI and
the local xterm buffer has no history (normal buffer, baseY 0).

Codex now takes that path too. Newer codex draws on tmux's alternate screen,
which the full strip hides from xterm, so a codex pane is as hollow as a
repaint-mode Claude pane and the wheel did nothing. Codex still ignores SGR
wheel reports and is still never forwarded the wheel; this sends plain
PageUp/PageDown keys, which codex does page its transcript on (measured on
0.157.1 locally and 0.160 over a remote session). Which modes may page is a
new registry capability, capabilities.transcriptPageKeys (claude and codex in
stock.ts), published to the page as window.__codemanTranscriptPageKeys, so
terminal-ui.js holds no CLI id for it.

The first event of a gesture now pages at once. The fallback used to send a
key only after half a screen of accumulated travel (19 rows, about 475px on a
38-row pane), so an ordinary trackpad flick sent nothing. The skipped travel is
owed back by the rest of the gesture, keeping one page per half screen; a pause
of more than 150 ms, a direction change or a tab switch starts a new gesture.
@aakhter

aakhter commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

This is a draft only because GitHub currently won't let my account open regular PRs or mark drafts ready (same as #525 and #526). It's ready for review. It stands alone on master and is independent of the tab-rail stack.

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.

2 participants