mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 06:59:42 +02:00
fix(terminal): merge-time fixes for #498
- _logScrollRouting() reports cliMouseTracking, the gate's new input, in both the de-dup signature and the console line (xterm's own mouseTracking stays 'none' for Claude, so it gave no reason for a no). - Restore two guard tests the new gate made vacuous: the local-scrollback opt-out footgun test and the codex/gemini "no version rescues it" fixtures now set cliMouseTracking: true, so removing the opt-out or re-adding codex to the gate fails again. - Update the comments and architecture-invariants lines that still described the version-only rule (wheel handler header, gate doc, the false paths of _maybePageCliTranscript, "holds a tracking mode on continuously"). - Name both fullscreen switches (CLAUDE_CODE_NO_FLICKER=1 and "tui": "fullscreen" in ~/.claude/settings.json) in the code comment, the invariants and the two wiki pages. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -650,8 +650,9 @@ Object.assign(CodemanApp.prototype, {
|
||||
}
|
||||
|
||||
// Mouse wheel: forward to the TUI only for sessions verified to handle SGR
|
||||
// wheel reports (claude 2.1.187+ — see _shouldForwardWheelToApp), local
|
||||
// scrollback otherwise. Claude Code 2.1.187+ scrolls its own
|
||||
// wheel reports (claude 2.1.187+ while it tracks the mouse, which only its
|
||||
// fullscreen renderer does; see _shouldForwardWheelToApp), local scrollback
|
||||
// otherwise. Claude Code 2.1.187+ scrolls its own
|
||||
// transcript on SGR wheel reports — scrolled-away tool blocks re-render
|
||||
// live and stay clickable — and its select menus no longer capture wheel
|
||||
// as option navigation (verified against 2.1.202: /model menu highlight
|
||||
@@ -723,7 +724,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
// phone/tablet swipe scrolls the local buffer of stale repaint frames and
|
||||
// drags the CLI's pinned input box off the screen (issue #205's mobile
|
||||
// half). Same gate, so Shift has no touch analog but the local-scrollback
|
||||
// opt-out setting and the CLI-version gate apply to touch exactly as they
|
||||
// opt-out setting and the version/tracking gate apply to touch exactly as they
|
||||
// do to the wheel — including the PageUp/PageDown fallback the wheel uses
|
||||
// when that gate is false and there is no local scrollback to scroll
|
||||
// (_maybePageCliTranscript), which is what keeps a swipe from being a
|
||||
@@ -5086,9 +5087,10 @@ Object.assign(CodemanApp.prototype, {
|
||||
|
||||
// Wheel forwarding gate for the container wheel handler: no Shift override,
|
||||
// xterm's own encoder dormant, viewport at the bottom, and a TUI VERIFIED to
|
||||
// scroll its transcript on SGR wheel reports — which today is claude 2.1.187+
|
||||
// and nothing else (older Claude Code captures wheel as select-menu option
|
||||
// navigation; an unknown version is treated as older). Gemini and codex are
|
||||
// scroll its transcript on SGR wheel reports, which today is claude 2.1.187+
|
||||
// with mouse tracking on (fullscreen) and nothing else (older Claude Code
|
||||
// captures wheel as select-menu option navigation, an unknown version is
|
||||
// treated as older, and inline Claude ignores it). Gemini and codex are
|
||||
// strip modes too but keep the local wheel — taps/clicks are still forwarded
|
||||
// for them (harmless no-ops at worst).
|
||||
//
|
||||
@@ -5159,9 +5161,10 @@ Object.assign(CodemanApp.prototype, {
|
||||
// inline renderer (2.1.280 measured: alternate_on=0, mouse_any_flag=0) the
|
||||
// transcript lives in real scrollback, like codex, and SGR wheel reports are
|
||||
// ignored, so forwarding made every swipe and wheel tick dead. Fullscreen
|
||||
// (CLAUDE_CODE_NO_FLICKER=1) turns on alt-screen + mode 1003/1006, which the
|
||||
// server records as cliMouseTracking. A stale-false flag after a server
|
||||
// restart falls through to _maybePageCliTranscript, so it never goes dead.
|
||||
// (CLAUDE_CODE_NO_FLICKER=1, or "tui": "fullscreen" in ~/.claude/settings.json)
|
||||
// turns on alt-screen + mode 1003/1006, which the server records as
|
||||
// cliMouseTracking. A stale-false flag after a server restart falls through
|
||||
// to _maybePageCliTranscript, so it never goes dead.
|
||||
if (session?.cliMouseTracking !== true) return false;
|
||||
// Deliberately NOT gated on _terminalViewportAtBottom(). It used to be, so
|
||||
// that leaving the bottom handed the wheel back to local scrollback and both
|
||||
@@ -5236,11 +5239,13 @@ Object.assign(CodemanApp.prototype, {
|
||||
*
|
||||
* The rescue path for every way `_shouldForwardWheelToApp` can come back false
|
||||
* on a Claude session that has no local history to fall back on: the CLI
|
||||
* version probe failed or is genuinely older than 2.1.187, or the user turned
|
||||
* on "Wheel scrolls local history" (which pins the wheel to a buffer that,
|
||||
* for a repaint-mode CLI, is empty — the setting's footgun). Before this, all
|
||||
* of those produced a completely dead gesture; the #205 reporter proved the
|
||||
* keyboard route works by paging back through intact text with Fn+Up.
|
||||
* version probe failed or is genuinely older than 2.1.187, the CLI's mouse
|
||||
* tracking flag is unset (the inline renderer, or fullscreen right after a
|
||||
* server restart), or the user turned on "Wheel scrolls local history" (which
|
||||
* pins the wheel to a buffer that, for a repaint-mode CLI, is empty: the
|
||||
* setting's footgun). Before this, all of those produced a completely dead
|
||||
* gesture; the #205 reporter proved the keyboard route works by paging back
|
||||
* through intact text with Fn+Up.
|
||||
*
|
||||
* Triple-guarded (claude mode + gate false + `baseY === 0`), so a session with
|
||||
* real local scrollback is never touched. Shift is excluded on purpose: it is
|
||||
@@ -5284,14 +5289,19 @@ Object.assign(CodemanApp.prototype, {
|
||||
const session = this.sessions?.get(sessionId);
|
||||
const optOut = !!this.loadAppSettingsFromStorage?.()?.terminalWheelLocalScrollback;
|
||||
const tracking = this.terminal?.modes?.mouseTrackingMode || 'none';
|
||||
// xterm's own mode above stays 'none' for a strip mode (the server removes
|
||||
// the DECSETs), so the CLI's real tracking state is reported separately.
|
||||
const cliTracking = session?.cliMouseTracking === true;
|
||||
const baseY = this.terminal?.buffer?.active?.baseY ?? -1;
|
||||
const signature = `${decision}|${session?.mode}|${session?.cliVersion}|${optOut}|${tracking}|${baseY > 0}`;
|
||||
const signature =
|
||||
`${decision}|${session?.mode}|${session?.cliVersion}|${optOut}|${tracking}|${cliTracking}|${baseY > 0}`;
|
||||
if (!this._scrollRoutingLogged) this._scrollRoutingLogged = new Map();
|
||||
if (this._scrollRoutingLogged.get(sessionId) === signature) return;
|
||||
this._scrollRoutingLogged.set(sessionId, signature);
|
||||
console.log(
|
||||
`[scroll] ${sessionId} → ${decision} (mode=${session?.mode || '?'}, cliVersion=${session?.cliVersion || 'unknown'}, ` +
|
||||
`localScrollbackOptOut=${optOut}, mouseTracking=${tracking}, localScrollbackRows=${baseY})`
|
||||
`localScrollbackOptOut=${optOut}, mouseTracking=${tracking}, cliMouseTracking=${cliTracking}, ` +
|
||||
`localScrollbackRows=${baseY})`
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user