cmux NEXT Inspector: Esc closes it only from inside it, and a close gives the keyboard to its toggle

Merged
TE
13d ago
+128-15

Follow-up to #24126.

Leo-ask: ask-fb8ef121dc

#24126 gave the agent chat's Inspector an x and Esc-to-close. Its Esc handler closed the panel on Esc from anywhere except a text field or an open popup. Two problems:

  • With a turn running, focus on the page body and the Inspector open, the first Esc closed the panel instead of arming the composer's double-press stop (escapeStop.ts). The Inspector's listener runs on the document and calls preventDefault, so the stop's window listener never counted that press.
  • After a close by Esc or the x, focus was dropped on the page instead of going back to the header toggle (.acpmux-chat-inspector-toggle).

Change

  • inspector/ChatInspector.tsx: Esc closes the Inspector only while focus is inside the panel or on its toggle (text fields and open popups inside still keep their Esc). Anywhere else, Esc keeps its old meaning: escapeStop, a diff in place's Esc, and so on.
  • Closing by Esc or the x moves focus to the toggle (preventScroll). When the header is hidden (over a diff in place) the toggle can't take focus, so the behaviour there is the same as before.
  • test/support/papercutChat.ts: the stand-in daemon now records the methods the page sends it (methods), so a test can see the stop's session/cancel.

Tests (webviews/test/chat-inspector-overlay-toggle.test.ts, Chromium and WebKit)

  1. Turn running, nothing focused, Inspector open: the first Esc arms Stop ("Press Esc again to stop") and the Inspector stays open. The second Esc sends session/cancel and the Inspector is still open.
  2. Focus on a button inside the panel: Esc closes it and focus lands on the toggle. Focus on the toggle: Esc closes it too.
  3. The x closes it and focus lands on the toggle.

The #24126 test still passes. Its popover now sits inside the panel (where Esc would otherwise close it), and its last Esc is pressed with focus on the panel's close button.

Command (huge-blue, scratch clone):
cd webviews && CMUX_BROWSER_TESTS=1 bun test test/chat-inspector-overlay-toggle.test.ts

  • Base (test commit only, b95be286d2e plus the test commit): 10 pass, 6 fail. All three new tests fail in both engines (armed/openAfterFirst/stopped/openAfterStop: false; focusFromPanel: false; x focus false).
  • Head (with the fix): 16 pass, 0 fail.

Also run: scripts/web-lint.sh (passed) and python3 scripts/cmux-next/prepush-gate.py (no new violations).

Observed / Not run

  • Observed: the browser test above, failing at base and passing at head, in real Chromium and WebKit against the pane's dev entry.
  • Not run: the full webviews suite (CI runs it), and a check in the real app. This is a webview-only change; the fleet compile-check covers the app build.

No capture: webview-only behaviour

🤖 Generated with Claude Code

Agent session: cosmic-gray


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes the cmux NEXT Inspector's Esc handling. Esc previously closed the panel from anywhere except a text field or popup, so with a turn running and nothing focused, the first Esc closed the panel instead of arming the composer's double-press Stop. Esc now closes the panel only while focus is inside it or on its header toggle; elsewhere Esc keeps its usual meaning. Closing by Esc or the x moves focus to the toggle, so it isn't dropped on the page.

  • The papercut test harness records the methods pages send the daemon, so tests can verify session/cancel.
  • New browser tests (Chromium and WebKit) cover Esc arming and stopping a turn, Esc from inside the panel or its toggle, and the x's focus handoff.