mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-10 01:09:43 +02:00
fix(terminal): strip opencode's mouse DECSETs so a drag selects text again
opencode's TUI enables mouse tracking. tmux runs with `mouse off`, so it passes the PANE's DECSETs straight through to the tmux client, and the browser's xterm obeyed them: `mouseTrackingMode` flipped to 'any' (measured 62 none / 18 any over 16s) and xterm then reported DRAGS to the TUI instead of selecting locally. In that state marking text produced no selection at all, so copy-on-select silently did nothing (5/5 dead drags while `any`), and the obvious fallback — Ctrl+C — is opencode's `app_exit`, which ended the session. Both were hit here. opencode needs the middle strip: alt-screen toggles AND mouse DECSETs, but NOT `3J` (a TUI is not a `clear` consumer). That is `altScreen: 'strip-mux-and-mouse'` + `isMuxMouseStripMode`, applied to the live stream (session.ts) and the replay of a stored buffer, now the exported `stripReplayBuffer()` (session-routes.ts). The browser's mouse-report gate keeps no mode list any more: `_shouldReportMouseToCli()` reads only `cliMouseTracking`. The server sets that flag solely in the mouse-strip branch (`_recordStrippedMouseMode`, one caller), so it can only be true for a mode whose DECSETs are stripped, and whichever modes the registry strips, the browser follows. Clicks still reach opencode through the hand-encoded SGR tap it gates. The `altScreen` JSDoc gets the decision table its three independent choices need (alt-screen / `3J` / mouse DECSETs), written from the predicates, including that `preserve` and `strip-mux-only` take the same runtime row. The table is pinned for every stock CLI, with and without tmux, on both the live strip and the replay strip, plus the published flag (test/claude-scrollback-strip.test.ts), so the two halves cannot drift and a mis-ordered replay branch fails. Docs and comments that still said opencode keeps its mouse reporting or gets the narrow strip are updated (CLAUDE.md, architecture-invariants, scrollback and copy-shortcut plans, session.ts, terminal-ui.js). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5a0018fc86
commit
5ba729fcbb
@@ -366,14 +366,33 @@ describe('terminal touch tap mouse guard', () => {
|
||||
expect(sent).toEqual(['\x1b[<0;1;24M\x1b[<0;1;24m']);
|
||||
});
|
||||
|
||||
it('never hand-reports for a shell session, even with tracking somehow set', () => {
|
||||
// Shell DECSETs are NOT stripped (narrow strip), so xterm's own encoder owns
|
||||
// the mouse there and a second, hand-encoded report would double-report.
|
||||
it('follows the server flag alone, with no mode list of its own', () => {
|
||||
// A shell's DECSETs are not stripped, so xterm's own encoder owns the mouse there
|
||||
// and a hand-encoded report would double-report. That is kept by the SERVER never
|
||||
// setting the flag for a non-stripping mode (pinned in claude-scrollback-strip.test.ts),
|
||||
// not by a mode check here: the browser reads only the flag.
|
||||
const { app } = loadTerminalUiHarness();
|
||||
app.activeSessionId = 'sess-1';
|
||||
app.sessions = new Map([['sess-1', { mode: 'shell', cliMouseTracking: true }]]);
|
||||
|
||||
app.sessions = new Map([['sess-1', { mode: 'shell' }]]);
|
||||
expect(app._shouldReportMouseToCli()).toBe(false);
|
||||
|
||||
app.sessions = new Map([['sess-1', { mode: 'some-future-cli', cliMouseTracking: true }]]);
|
||||
expect(app._shouldReportMouseToCli()).toBe(true);
|
||||
});
|
||||
|
||||
it('hand-reports for opencode, whose DECSETs the server now strips', () => {
|
||||
// opencode's TUI enables mouse tracking, tmux passes the DECSETs through, and
|
||||
// xterm used to report DRAGS to the TUI instead of selecting — so marking text
|
||||
// copied nothing. The server strips them now (isMuxMouseStripMode), which makes
|
||||
// the hand-encoded tap the only way a click still reaches opencode.
|
||||
const { app } = loadTerminalUiHarness();
|
||||
app.activeSessionId = 'sess-1';
|
||||
|
||||
app.sessions = new Map([['sess-1', { mode: 'opencode' }]]);
|
||||
expect(app._shouldReportMouseToCli()).toBe(false);
|
||||
|
||||
app.sessions = new Map([['sess-1', { mode: 'opencode', cliMouseTracking: true }]]);
|
||||
expect(app._shouldReportMouseToCli()).toBe(true);
|
||||
});
|
||||
|
||||
it('hand-reports only while the CLI actually has mouse tracking on', () => {
|
||||
|
||||
Reference in New Issue
Block a user