Skip to content

feat(web): mod+w closes the active right panel tab before the window - #9363

Merged
juliusmarminge merged 1 commit into
mainfrom
mod-w-closes-active-panels
Sep 3, 2026
Merged

feat(web): mod+w closes the active right panel tab before the window#9363
juliusmarminge merged 1 commit into
mainfrom
mod-w-closes-active-panels

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 3, 2026

Copy link
Copy Markdown
Member

Problem

Mod+W only closed a focused terminal. Anywhere else it fell straight through to the desktop close-window accelerator, so closing a stack of right-panel tabs (diff, files, browser, PR) meant reaching for the mouse — or losing the window by accident.

Fix

Add a rightPanel.close keybinding command, bound by default to mod+w when the terminal is not focused (the existing terminal.close rule keeps winning while it is).

  • Closes the active right-panel tab, one per press, through the existing closeRightPanelSurface path so terminal-close and agent-controlled-browser confirmations still apply.
  • With nothing open the keydown is left alone, so the shortcut keeps its native meaning (close window on desktop). Key repeat is ignored so a held key doesn't chew through every tab and then the window.
  • The pull-requests page's shared panel handles the command itself since it renders no ChatView.
  • Works while the in-app preview has focus: the preview WebContentsView already forwards mod+W to the main window.

Browsers reserve mod+w and never deliver it to the page; that was already true of terminal.close. Docs note the rebind.

Testing

  • apps/web/src/keybindings.test.ts: mod+w resolves to terminal.close with terminal focus and rightPanel.close otherwise.
  • apps/server/src/keybindings.test.ts: default binding present.
  • apps/web typecheck clean; targeted lint has no new findings.

Model: Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Low Risk
Keyboard UX and default bindings only; behavior is gated on panel/terminal focus and falls through to native close when nothing is open.

Overview
Adds a rightPanel.close keybinding (default mod+w when the terminal is not focused) so users can dismiss right-panel tabs from the keyboard without immediately triggering close-window.

mod+w now resolves to terminal.close with terminal focus and rightPanel.close otherwise. ChatView handles the command by closing the active right-panel surface through the existing close path, skipping key repeat, and leaving the event untouched when no panel is open so desktop mod+w still closes the window. The pull-requests route registers the same shortcut locally because it does not mount ChatView.

Contracts, shared defaults, server/web tests, and user keybinding docs are updated (including browser mod+w rebind guidance).

Reviewed by Cursor Bugbot for commit 14e8bb0. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add rightPanel.close command bound to mod+w with terminal-focus precedence

  • Adds rightPanel.close to the static keybinding command registry and maps it to mod+w with a context gate so it only applies when terminalFocus is false; the existing terminal.close rule keeps terminal precedence
  • Wires the new command into ChatView.tsx and the pull-requests route pull-requests.tsx; an active right-panel surface closes on the first matching keydown, with repeated keydowns ignored
  • Native browser behavior is preserved when no right-panel surface is active; the docs note users may want an alternate binding to avoid the browser closing the window
  • Risk: the pull-requests route installs its own window keydown listener outside ChatView; if rightPanel.close is not the resolved command it leaves the event untouched, so check the terminal-focus context resolution in pull-requests.tsx for regressions

Macroscope summarized 14e8bb0.

Mod+W only closed a focused terminal; anywhere else it fell straight
through to the desktop close-window accelerator, so closing a stack of
right-panel tabs meant reaching for the mouse.

Add a `rightPanel.close` command bound to `mod+w` when the terminal is
not focused. It closes the active right-panel tab through the existing
close path (so terminal and agent-browser confirmations still apply),
one tab per press, and leaves the event alone once nothing is open so
the shortcut keeps its native meaning. The pull-requests page's shared
panel handles the command itself since it renders no ChatView.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.7 KiB 13.7 KiB +2 B (+0.0%) 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.0 KiB −14 B (−0.2%) 7.3 KiB
Codex Live turn WebSocket wire 6.7 KiB 6.7 KiB +16 B (+0.2%) 7.8 KiB
Codex Live turn WebSocket decoded 58.5 KiB 58.5 KiB 0 B (0.0%) 66.4 KiB
Codex Live turn messages 10 10 0 (0.0%) 21
Claude Total thread wire 13.6 KiB 13.7 KiB +161 B (+1.2%) 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.0 KiB −5 B (−0.1%) 7.3 KiB
Claude Live turn WebSocket wire 6.6 KiB 6.7 KiB +166 B (+2.5%) 7.8 KiB
Claude Live turn WebSocket decoded 57.9 KiB 59.3 KiB +1.4 KiB (+2.5%) 66.4 KiB
Claude Live turn messages 10 10 0 (0.0%) 21

Baseline: 9f9359b · PR result: 14e8bb0 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a new default mod+w action that changes shipped keyboard behavior and can be backfilled into users' persisted keybinding configurations. Although the implementation is contained, product-default changes require human review.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarminge merged commit d4bd892 into main Sep 3, 2026
23 checks passed
@juliusmarminge
juliusmarminge deleted the mod-w-closes-active-panels branch September 3, 2026 06:15
aorwall added a commit to aorwall/t3code that referenced this pull request Sep 5, 2026
Merges 137 upstream commits (`d937e3075..36c4e9c`) into the fork,
following the `fork-upstream-merge` skill. Landed as a merge commit;
conflicts resolved by the inventory's cached verdicts.

## Merge shape

816 files landed (`git diff --stat HEAD^1 HEAD`) against 811 in the
upstream range; fork delta 650 files. The gap of five is all in landed
and not the range: two fork-owned files touched during resolution
(`sandboxControl.placement.test.tsx` test-prop fixup,
`useSandboxCommandsBanner.tsx` reformat) plus the three fork docs this
merge writes (`inventory.json`, `gaps.md`, `upstream-merge-log.md`). No
upstream work was dropped.

## Conflicts

Resolved by inventory verdict — `AGENTS.md` (kept the fork's slimmed
shape, added Antigravity to the provider list), `contracts/rpc.ts` and
`environment.ts`, the ChatView/MessagesTimeline thread-fork +
message-origin convergence, the preview cluster (`addBrowserSurface`
`profileId` beside the fork's `url`, `rightPanelStore` `openAttachment`
beside `retargetFile`), the settings gates, and the two upstream pingdotgg#9364
test deletions.

Two latent fork bugs surfaced and were fixed: `PreviewView`'s hosted
annotation handler called an unexported helper, now routed through the
exported `capturePreviewAnnotationScreenshot` wrapper (matching the
sibling native handler); and `ChatView` passed a `configuredUrls` prop
the fork's hosted `PreviewPanel` does not accept.

## Unsupported methods

`unsupported-methods.mjs` reported ADD 10; recomputed to 0 by adding
`UnsupportedMethodError` to the shared `ProviderSetupRpcError` union
(nine `provider.auth.*` / `provider.install.*` methods) and to
`server.refreshUsageRates`. `gaps.md` grown with a _Provider setup_
bullet and a `refreshUsageRates` clause on _Usage summary_. The three
DROP entries (`scripts.run`, `subtasks.list`, `threads.getShell`) are
the documented keep-anyway exceptions — `apps/server` still refuses
them.

## Feature classification

**Usable as-is** (UI only, no backend dependency): mod+w tab close
(pingdotgg#9363), PageUp/PageDown chat nav (pingdotgg#9315), diff/PR file tree (pingdotgg#9330),
diff-header copy path (pingdotgg#2403), error-report copy (pingdotgg#9166), opt-in
context-window indicator (pingdotgg#9190), opt-in panel animations (pingdotgg#8830),
proactive panels (pingdotgg#9276), button press feedback (pingdotgg#9349), provider-editor
redesign chrome (pingdotgg#8508).

**Unsupported in Moatless** (resolve to a refusal): Antigravity provider
auth/install and all `provider.*` setup (pingdotgg#9348, pingdotgg#8508),
`server.refreshUsageRates`. Desktop-only and already capability- or
desktop-gated, so no new fork work: preview browser profiles (pingdotgg#7254),
open-links-in-app (pingdotgg#9339), ssh-host suggestions (pingdotgg#9171),
environment-as-machine (pingdotgg#9299), continue-threads-across-restart (pingdotgg#9167,
rides the new `serverUpdateThreadContinuation` capability).

**Backend behavior to reproduce** if Moatless wants it: project icons
(pingdotgg#9137, migration 047), auto-pull clean default branches (pingdotgg#9277,
migration 045), inline citations (pingdotgg#9146, needs the backend to emit
them), the usage page. Migration 046
(RepairAutomaticSettlementTimestamps) is upstream-server-only.

Net-zero: context compaction (pingdotgg#8808) landed and was reverted (pingdotgg#9284).

## Verification

`fmt:check`, `lint`, `typecheck`, `tripwires` and `inventory-check`
green. Full test suite green — one web test failed initially
(`addBrowserSurface.test.ts` did not expect the converged default
`profileId`), fixed and re-run.

Two `verify.mjs` checks exit non-zero and are the caveated machine
failures: `unsupported-methods` on the three documented DROP exceptions
above, and `duplicate-adds` on three confirmed false positives
(`openPreview` in a `ChatView` object literal vs its deps array; three
distinct `it()` blocks in `addBrowserSurface.test.ts`).

Written by Claude Opus 5 in Claude Code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
Moatless task:
https://moatless.soaplabstest.com/tasks/4e881239-73d1-4a93-9563-6a926e920b42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant