cmux NEXT spaces: Move Space to This Window and Merge All Windows

Closed
TE
7d ago
+755-26

Leo (2026-10-29): "could u guys also now work on the per space pins and groups? rn anything u make in teh default space goes across to new ones... there's also other ergo wrt new windows being like new spaces, incognito spaces, etc... this could legit make our thing more useful than chrome by having windows be switchable in this way. think of the potential perf savings~"

This PR covers the windows part of that ask. Per-space pins and groups are not in it.

What changed

  • space.bringHere "Move Space to This Window": the reverse of Open Space in New Window. Every workspace of the space that another normal window holds (open or closed) moves into the acting window. That window then shows the space and selects the workspace the space last showed (the one a window showing the space had selected, else the one remembered for the space). If no other window holds any of the space's workspaces, it is a plain space switch. Workspaces only change owner, so terminals keep running and nothing restarts. A source window left with no workspace closes through the existing WindowRegistry.move / closeEmptied path. A source window that still holds other spaces' workspaces stays open. Moving an incognito space, or moving into an incognito window, is refused with the existing RefusalStrings.incognitoMismatch HUD. Surfaces: the palette, the space's right-click menu ("Move to This Window", next to Open in New Window), cmux space bring-here, and MCP (spaces-overhaul-DESIGN.md rule 7).
  • window.mergeAll "Merge All Windows": every other open normal window's workspaces move into the acting window, and each workspace keeps its space. The other windows close. The acting window stays on its space with the same selection. For spaces it never showed, it takes each merged window's last shown workspace, so switching there shows what that window showed. Incognito windows are left alone, and running it from an incognito window is refused. Surfaces: the Window menu (after New Incognito Window), the palette, cmux app merge-all-windows, and MCP. It has a context-menu exemption, as Close Other Windows does.
  • Titles are in ProfileActions.xcstrings and ActionCatalog.xcstrings (en and ja translated; the other locales are needs_review, as in neighbouring entries).
  • plans/cmux-next/action-surfaces.json and actions.md are left to the base autofix (regenerate-action-exports.sh).

Risk

  • Additive. No existing default, component or menu row is changed or removed.
  • The Window menu gains one row, so MainMenuPlacementTests now expects 10 Window rows instead of 9.
  • Both actions run one registry transition (transition { $0.move(...) }), the same path switchProfile adoption and Move to Window use. Incognito windows are filtered out of the sources before the move, so crossesIncognito never drops the batch.

Tests

  • New GatherWindowsTests (.closesItsWindows):
    • Bring-here closes the window it emptied and keeps the space's last shown workspace selected.
    • Only that space's workspaces move, and a source window that keeps other spaces stays open.
    • Incognito space or window is refused and nothing changes.
    • Merge-all keeps each workspace's space, closes the merged windows and leaves the incognito window alone.
  • SpaceSurfacesTests names space.bringHere and checks it is in the space menu.
  • Focused fleet Mac run (package-test-lane.sh suite GatherWindowsTests, SpaceSurfacesTests, MainMenuPlacementTests, ActionSurfaceParityTests, ShowWorkspaceOtherRoomTests, IncognitoSpaceTests): all 6 suites passed (ActionSurfaceParityTests: 2 export-freshness tests skipped as usual). cmux-ci step 0ca0e2da7b669522ed80b23f, at 62fed54c5b9f: this head (69b56f9016ae) with #27301 merged in, on a CI-only branch. At this head alone, CmuxNextAppTests does not compile because of the base red from #27166 (BrowserEntryRetirementTests.swift:43:57, "returning main actor-isolated ... as a 'sending' result"; step c559ae7de547b95c91d859b5). This PR does not touch that file, and #27301 fixes it.

No capture: the only visible change is new rows in the Window menu, the space's right-click menu and the command palette, and the main window is unchanged. A fleet capture (steps-6d58e8bbea at 59c45ae21f5a: open the palette, type "merge all", then "to this window") keeps one still of the main window, and the palette panel and menus draw in their own windows outside it, so the still shows nothing new. SpaceSurfacesTests and MainMenuPlacementTests pin the new rows instead.

Performance

No perf numbers: the word "perf" here is Leo's quote ("think of the potential perf savings"). This PR adds two window actions and changes no hot path, timer or observer; it measures nothing.

Agent session: agent session

šŸ¤– Generated with Claude Code