fix(cli-registry): declare Copilot's wheelForward

The entry inherited wheelForward never from agentDefaults() while _shouldForwardWheelToApp forwards Copilot's wheel whenever the CLI tracks the mouse, at any version. New always mode, set on copilot, pinned by a registry test.
This commit is contained in:
Devvyn committed 2026-10-18 00:47:54 +08:00
1 parent 24031d5b72
commit ebfa4a01b3
4 files changed
+23 -3

No files matched your search

+1 -1
View File
@@ -295,7 +295,7 @@ const capabilitiesSchema = z
altScreen: z.enum(['strip-full', 'strip-mux-only', 'strip-mux-and-mouse', 'preserve']), altScreen: z.enum(['strip-full', 'strip-mux-only', 'strip-mux-and-mouse', 'preserve']),
echo: echoSchema, echo: echoSchema,
wheelForward: z wheelForward: z
.object({ mode: z.enum(['never', 'version-gated']), minVersion: z.string().max(20).optional() }) .object({ mode: z.enum(['never', 'version-gated', 'always']), minVersion: z.string().max(20).optional() })
.strict(), .strict(),
// Whether a hollow pane's wheel/touch scroll may be turned into PageUp/PageDown for // Whether a hollow pane's wheel/touch scroll may be turned into PageUp/PageDown for
// the CLI to page its own transcript. Distinct from wheelForward (SGR reports). // the CLI to page its own transcript. Distinct from wheelForward (SGR reports).
+3
View File
@@ -1758,6 +1758,9 @@ const COPILOT: CliEntry = {
// (`cliMouseTracking`). Same shape and reason as opencode. The wheel keeps working because // (`cliMouseTracking`). Same shape and reason as opencode. The wheel keeps working because
// `_shouldForwardWheelToApp` forwards it as SGR reports while the CLI is tracking. // `_shouldForwardWheelToApp` forwards it as SGR reports while the CLI is tracking.
altScreen: 'strip-mux-and-mouse', altScreen: 'strip-mux-and-mouse',
// Forwards the wheel as SGR reports while the CLI is tracking the mouse, at any version
// (`_shouldForwardWheelToApp` in terminal-ui.js has no version check for copilot).
wheelForward: { mode: 'always' },
// Pages its own transcript on PageUp/PageDown (1.0.95, measured in tmux: three PageUp moved // Pages its own transcript on PageUp/PageDown (1.0.95, measured in tmux: three PageUp moved
// lines 109-140 to 010-042 and PageDown returned). This is the fallback when the // lines 109-140 to 010-042 and PageDown returned). This is the fallback when the
// wheel-forward flag is stale after a server restart, so the wheel and a swipe never go dead. // wheel-forward flag is stale after a server restart, so the wheel and a swipe never go dead.
+6 -2
View File
@@ -539,8 +539,12 @@ export interface CliCapabilities {
/** Names a PREDICT_PROFILES key. Unknown or absent degrades to 'buffer', never to broken. */ /** Names a PREDICT_PROFILES key. Unknown or absent degrades to 'buffer', never to broken. */
predictProfile?: string; predictProfile?: string;
}; };
/** Forwarding the wheel to the CLI's own transcript. 'never' keeps local scrollback. */ /**
wheelForward: { mode: 'never' | 'version-gated'; minVersion?: string }; * Forwarding the wheel to the CLI's own transcript. 'never' keeps local scrollback;
* 'version-gated' forwards from `minVersion` on; 'always' forwards at any version. Either
* forwarding mode applies only while the CLI has mouse tracking on (`cliMouseTracking`).
*/
wheelForward: { mode: 'never' | 'version-gated' | 'always'; minVersion?: string };
/** /**
* The CLI pages its OWN transcript on PageUp/PageDown, so a wheel or touch scroll over * The CLI pages its OWN transcript on PageUp/PageDown, so a wheel or touch scroll over
* a pane with no local history can be turned into those keys instead of doing nothing * a pane with no local history can be turned into those keys instead of doing nothing
+13
View File
@@ -485,6 +485,19 @@ describe('capability shapes', () => {
}, 'transcriptPageKeys is a boolean'); }, 'transcriptPageKeys is a boolean');
}); });
it('declares which CLIs get the wheel forwarded, and whether a version gates it', () => {
// claude forwards from 2.1.187 (fullscreen renderer only); copilot forwards at any version while
// it tracks the mouse. codex ignores SGR wheel reports, so every other entry stays 'never'.
const mode = (id: string) => STOCK_CLIS.find((e) => (e.id as string) === id)?.capabilities.wheelForward;
expect(mode('copilot')).toEqual({ mode: 'always' });
expect(mode('claude')).toEqual({ mode: 'version-gated', minVersion: '2.1.187' });
const forwarding = STOCK_CLIS.filter((e) => e.capabilities.wheelForward.mode !== 'never').map(
(e) => e.id as string
);
expect(forwarding.sort()).toEqual(['claude', 'copilot']);
expect(CliEntrySchema.safeParse(baseEntry('copilot')).success).toBe(true);
});
it('declares transcriptPageKeys for exactly the CLIs measured to page on PageUp/PageDown', () => { it('declares transcriptPageKeys for exactly the CLIs measured to page on PageUp/PageDown', () => {
// claude (repaint mode), codex, opencode and copilot (all on the alternate screen) were // claude (repaint mode), codex, opencode and copilot (all on the alternate screen) were
// measured paging their own transcript on PageUp/PageDown; no other stock entry has been. // measured paging their own transcript on PageUp/PageDown; no other stock entry has been.