cmux NEXT Files: the row menu comes from the action registry (check-menu-actions red)
python3 scripts/cmux-next/check-menu-actions.py has been red on feat-cmux-next since 56d448575ce5 (the right sidebar's Files section):
Packages/macOS/CmuxNext/Sources/CmuxNextApp/FileExplorer/FileExplorerSectionView.swift: 1 inline menu row(s), 0 allowed
The Files row's right-click menu built its rows with inline selectors and its own titles. The menu ran the explorer actions through a second path next to the registry. The inline path existed so the run got fileExplorerFocused: ActionMenuTarget.performAction runs with the live key context, and right-clicking a row doesn't focus the list.
The base merge (682021091d9c) rewrote this fix for the rows base added after the PR opened. Base added New File, New Folder, Rename and Move to Trash, plus Open With as a submenu of the file's apps (56488d69abdc, dd018d41b6a2). With them, the check reported 1 inline row in FileExplorerSectionView.swift and 2 in the new FileExplorerOpenWithMenu.swift. All of those rows now go through the registry too.
Fix
-
Menu context. New
ActionMenuContext.fileExplorerRow; its implied context is.fileExplorerFocused. -
Placements. Rows in order:
- Open in cmux, Open With, Reveal in Finder
- New File, New Folder
- Rename
- Copy Path, Copy Relative Path
- Move to Trash
The empty area shows only New File and New Folder.
-
New actions.
fileExplorerNewFile,fileExplorerNewFolder,fileExplorerRenameandfileExplorerMoveToTrashare catalog actions. They are CLI-exempt as live input, like the other explorer actions. Their titles are inActionCatalog.xcstrings, copied from base's 21-localefileExplorer.menu.*strings, which are removed. New File and New Folder then edit the new item's name in its row; Rename edits the selection's. Cmd-Delete runs Move to Trash through the registry. -
Open With apps submenu. The submenu replaces the registry's Open With row. Each app row is a registry row (new
ActionRegistry.makeContextMenuItem(for:in:arguments:title:)) that runsfileExplorerOpenWithwithapp=<path>. Other… runs it with no app; theappargument is now optional. The handler then shows the app chooser and runs the same action with the chosen app. -
How facts reach the run.
ActionMenuPayloadcarries the menu's own implied facts (ActionRegistry.impliedContext(for:)).ActionMenuTargetunions them with the live context into the invocation'skeyContextwhen it validates and runs an item. Facts a call site passes (makeContextMenu(implied:)) only show rows, as before. Otherwise the bookmarks bar, which passesimplied: .browserFocused, would enable Bookmark This Page while a terminal is focused, and the row would then refuse (from review). -
Each row acts on its own tree. The menu's rows carry the id of the tree they were opened in (
explorer,FileExplorerService.explorerArgument), and so do the Open With app rows. The handlers run on that tree: its model, its window's undo stack (Cmd-Z after Move to Trash) and its rename field. Before, every row ran on the active window's tree, so Move to Trash from a back window's menu trashed the front window's selection (review). A run with noexplorerargument still uses the active window's tree. That includescmux action run fileExplorerMoveToTrashand the other explorer ids, which run only while the explorer is focused (fileExplorerFocused). -
Open With with no app opens the chooser only for the person's own run. A CLI or MCP run is refused with
noSuchAppand shows nothing. The chooser opens the file it was shown for, not whatever is selected later. -
Baseline cleanup. The base merge 532b7ac421cf brought in #23467's baseline rows for
FileExplorerOpenWithMenu.swift(2) andFileExplorerSectionView.swift(1), with their comment. They are removed, since neither file has an inline row now.ExtensionsMenu.swift's stale row isn't this PR's and stays.
Verification
-
Row menu test (red at base).
CmuxNextAppTests.FileExplorerTests/theRowMenuRunsTheRegistrysActionsWithoutTheListFocusedchecks, withfileExplorerFocusedremoved from the registry context:- every row is a registry row (
ActionRegistry.menuRun) in the order above, with Open With as the apps submenu; - Copy Path is enabled and copies the selection's path;
- the empty area shows New File and New Folder.
Its first version failed on the test commit 85726018e9f8 (fleet step
f1b5326f800fce6c6cab42dc:runs → [nil, nil, nil, nil, nil]). - every row is a registry row (
-
Open With test.
FileExplorerOpenWithTests/pickingAnAppRunsOpenWithWithThatAppThroughTheRegistry: an app row runsfileExplorerOpenWithwithapp=/Applications/Xcode.appandfileExplorerFocused. Other… runs it with no app. -
Bookmarks test (red at the old head).
CmuxNextActionsTests.ContextMenuImpliedFactsTestschecks two things. A menu's own facts enable and run its rows. A call site's facts don't: Bookmark This Page is disabled and doesn't run with no browser focused. It failed at the previous head 43217d18 plus this test (scratch branch, since deleted; fleet step030ccad3e8916ac6c1f084b2): Bookmark This Page enabled and ran. -
Two-window tests (red at the merge plus tests).
CmuxNextAppTests.FileExplorerWindowsTestscovers two windows with their own trees. New Folder from the back window's menu must make the folder in the back window's tree. An origin.cliOpen With with no app must be refused, with no open panel. Both failed at b99afcf12cdc, the base merge plus these tests (fleet step6950ad6e032efa02eb54725c:inBackfalse,refusedfalse). -
Green at head 4fc7e205da8d. Fleet step
98f50ceb6adc062592d40c24: all 14 suites passed. That is the 12 above plus FileExplorerWindowsTests and base's new FileExplorerWatchTests. -
Compile check at head. https://github.com/manaflow-ai/cmux/actions/runs/39629481095 (success).
-
Green at head bbd07481b5f5. Fleet step
d9d1d4b4f0d32a16fa8623cb: all 12 suites passed (FileExplorerTests, FileExplorerFollowTests, FileExplorerOpenWithTests, FileExplorerEditTests, FileExplorerFocusRingTests, ContextMenuImpliedFactsTests, ContextMenuShapeTests, ActionSurfaceParityTests, ActionContractTests, ContextMenuEssentialsTests, BookmarkManagerMenuTests, RegistryReachabilityTests). -
Compile check at head.
fleet-compile-check.yml: https://github.com/manaflow-ai/cmux/actions/runs/39623177531 (success). -
Static checks.
check-menu-actions.pyexited 1 at the base (the line above) and reportsok: 38 inline menu rows in 29 baselined files, none newat head.check-group-menus.pyandprepush-gate.pyare ok.
Observed / Not run
Observed: the fleet runs, the compile check and the static checks above.
Not run:
- A live right-click in a running app.
- A run of Move to Trash or the Other… chooser (the tests stop at the registry run).
ActionSurfaceExportTests:plans/cmux-next/action-surfaces.jsonandactions.mdwere not regenerated by hand; the PR autofix regenerates them.
Menu order changed from base: base had New File and New Folder first, then the open and copy rows, then Rename and Move to Trash. The order now follows the menu groups listed under Fix.
No capture: the rows are base's rows with base's titles. They come from the catalog now, so they have the actions' icons and the order and separators of the menu groups above. Base's order was New File and New Folder first, then the open and copy rows, then Rename and Move to Trash.
Changelog
Fixed: the Files section's right-click rows run while another view has the keyboard, and from the same actions as the palette and the CLI.
Agent session: cosmic-gray
🤖 Generated with Claude Code