Skip to content

cmux NEXT: the workspace row copies its link before its ID, and a test that the link opens it - #27564

Merged
teamleaderleo merged 1 commit into
feat-cmux-nextfrom
leo/workspace-copy-link
Oct 30, 2026
Merged

teamleaderleo merged 1 commit into
feat-cmux-nextfrom
leo/workspace-copy-link

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Leo, 2026-10-29:

in the more area of the right-click for the workspaces, that needs to have... Yeah, these, like, pain links, pain IDs, whatever the hell. Okay, we did add those links, and it's nice, these UUIDs and stuff, but we, um, yeah, I don't know. I don't know. I feel like there's a much better way of doing things than just all of these menus. Because, like, more importantly, the workspaces, you know, in this case, you don't, like, there's no link to workspace, which is, I mean, that seems pretty important, doesn't it?

This PR is the first part: the workspace link. The "much better way than all these menus" part (one Copy ▸ submenu on the workspace, tab and pane menus) is the follow-up PR.

While this was in review, #27709 landed Copy Workspace ID and Copy Workspace Link in the workspace row's More › Copy, ID first. This PR now carries what that one doesn't:

What

  • Link first. In the workspace row's More › Copy, Copy Workspace Link now comes before Copy Workspace ID, the order the tab and pane menus use (link, then ID). Only the two ranks in ActionSurfaceCatalog+Menus.swift swap. ContextMenuEssentialsTests.theWorkspaceRowMenuCopiesItsLinkThenItsID checks the order.
  • Opening the link shows the workspace, tested end to end. link.open → DeepLinkNavigator → windows.reveal(workspaceID:) already handled <scheme>://workspace/ws_…, but nothing tested it. WorkspaceLinkTests (app tests, same-tree daemon):
    • It makes a second workspace that its window isn't showing.
    • It runs Copy Workspace Link on that workspace's row target and checks the link is <scheme>://workspace/<ws_ id>.
    • It opens that link through link.open the way a clicked link does (origin .user; a CLI run never moves this client's view), then waits until the window that lists the workspace shows it.
    • A link to a workspace that doesn't exist refuses with linkTargetGone.
    • The test checks the link text through services.link(workspace:) rather than the clipboard: the fleet's headless test workers have no usable pasteboard (an earlier version failed there).
  • Capture tooling. debug.object_menu (DEBUG only) opens the workspace, tab or pane right-click menu, then folders in it, for before/after shots. tour:object-menu-workspace, -tab and -pane run it.
    • The workspace menu comes from a synthesized right-click on its sidebar row (debug.mouse). Its folders open by type-select, after a Down arrow that takes the keys back from the menu's name field, so the workspace isn't renamed.
    • The tab and pane menus open with NSMenu.popUp from a main run-loop perform (a small @MainActor NSObject, no assumeIsolated), so the menu's tracking doesn't hold the main queue and the next call can run. Their folders open with arrow keys over the menu's enabled rows.

Overlaps:

plans/cmux-next/ exports are left to the PR autofix, as its workflow says ("no person regenerates them").

Captures

The workspace row's right-click › More, from tour:object-menu-workspace on a fleet mini (whole-host display shot, cropped to the app window). The before is the current base plus the capture tooling alone (96aa11a), the after is this PR at 1e6967b (the menu rows are the same at the head).

Before (ID, then link) After (link, then ID)
before: Copy Workspace ID above Copy Workspace Link after: Copy Workspace Link above Copy Workspace ID

Menus still open on the click; nothing here adds an animation.

Tests

On the fleet at this head (package-test-lane.sh): ContextMenuEssentialsTests, WorkspaceLinkTests, ActionSurfaceParityTests, LinkExportTests, ContextMenuIconTests.

Timers and observers

None. debug.object_menu (DEBUG only) schedules one run-loop perform (perform(_:with:afterDelay:inModes:)) per tab or pane menu it opens; it fires once, and the menu it opens closes with Escape (dismiss).

Risk

Low. Two existing rows swap places. The rest is a test and DEBUG-only capture tooling.

🤖 Generated with Claude Code

Agent session: agent session

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 65135ef: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr27564 -f ref=leo/workspace-copy-link -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 7665b87 to compare; do not merge until green; see lane-rules

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 29, 2026
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Default changes

This pull request changes 5 defaults at 65135ef355c8 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextActions/ActionSurfaceCatalog+Menus.swift:layoutPlacements: "087aba83afdc9cea1daf878ab7433f5e25c39f4d73a9decef89e8f89feddf9d3" -> "b9f133b451f39b9bfb55abb1c16beb2947dc7ca25d86d53c36e24d4123a6d6c9"
  • tunable-source.CmuxNextApp/Control/DebugObjectMenu.swift:arrow: (none) -> "db2e6a88e24d72f32a44fa05c0328f3bd78eb7247edbfe78ea02649793881f74"
  • tunable-source.CmuxNextApp/Control/DebugObjectMenu.swift:arrowKeys: (none) -> "14bbf63479c5563ea7e1b528e915b9744dd2408f74524628f105f0efa056e377"
  • tunable-source.CmuxNextApp/Control/DebugObjectMenu.swift:failure: (none) -> "020b983e3120cb633109514f628f8ceaac443bac9047c8c2801030efd976247f"
  • tunable-source.CmuxNextApp/Control/DebugObjectMenu.swift:run: (none) -> "d0881a493bd2b73f53801232b61556268bdabbee601becbae5f2ef2842dc1139"

Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Review (<reviewer>): SHIP at 65135ef355c8c872171d36159b2b3265c66cb15a, from a member, not a self-review (the newest verdict naming the head decides; a later BLOCK beats an earlier SHIP), or with an approving review on this commit from @lawrencecchen or @austinywang (the call owners in .github/defaults-call-owners.json, never the author). A receipt posted as a review re-runs this check; after a plain comment, re-run it. The needs a call label alone does not pass, and a new push needs a new receipt.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

@blacksmith-sh

This comment has been minimized.

@cursor

cursor Bot commented Oct 29, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo
teamleaderleo force-pushed the leo/workspace-copy-link branch from c3e146e to ac3de4d Compare October 29, 2026 21:07
@teamleaderleo
teamleaderleo force-pushed the leo/workspace-copy-link branch from e71756b to 00cda77 Compare October 29, 2026 21:20
@teamleaderleo
teamleaderleo force-pushed the leo/workspace-copy-link branch from 5de18c1 to c82c6ae Compare October 30, 2026 00:05
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (Codex gpt-6-astra, high, independent): SHIP at 74ebf24

  • Delta review of the rebase onto c673b52: the PR's code is byte-identical to the reviewed 6053d36 (an empty diff of diffs). The regenerated plans only move Copy Workspace Link, then Copy Workspace ID, into the workspace row's More and out of pointerMenuTrim (right-click 594 → 596).
  • The full review at 5de18c1 and the delta at 6053d36 were both SHIP.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (Codex gpt-6-astra, high, independent): SHIP at 15dc9bb

@teamleaderleo teamleaderleo changed the title cmux NEXT: Copy Workspace Link and Copy Workspace ID in the workspace row's menu cmux NEXT: the workspace row copies its link before its ID, and a test that the link opens it Oct 30, 2026
… the link opens it

Leo 2026-10-29: "the workspaces, you know, in this case, you don't, like,
there's no link to workspace, which is, I mean, that seems pretty important,
doesn't it?"

#27709 put Copy Workspace ID and Copy Workspace Link in the workspace row's
More > Copy. This puts the link first, as on the tab and pane menus, and
WorkspaceLinkTests copies a workspace's link through the action and opens it
through link.open, which shows that workspace; a gone workspace's link refuses.

debug.object_menu (DEBUG only) and tour:object-menu-workspace, -tab and -pane
open the workspace, tab and pane right-click menus and their folders for
captures.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-fb75b7af9902231028aa
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (Codex gpt-6-astra, high, independent): SHIP at 65135ef

  • Delta from the SHIP at 15dc9bb: debug.object_menu (DEBUG only) now pops up the tab or pane menu from a small @MainActor NSObject through perform(_:with:afterDelay:inModes:) on the main run loop. That removes the MainActor.assumeIsolated and nonisolated(unsafe) the crash ratchet refused. Base changed none of the PR's files.
  • Fleet at this head: ContextMenuEssentialsTests, WorkspaceLinkTests, ActionSurfaceParityTests, LinkExportTests and ContextMenuIconTests passed. A whole-host tour:object-menu-tab capture opened the tab menu and its More folder.

@teamleaderleo
teamleaderleo merged commit ec98305 into feat-cmux-next Oct 30, 2026
162 of 173 checks passed
@teamleaderleo
teamleaderleo deleted the leo/workspace-copy-link branch October 30, 2026 05:14
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 30, 2026
…8106)

The cmux-next checks job's menu-metrics item fails on base:
DebugObjectMenu.swift:52 `NSPoint(x: 80, ...)` "places a row part at its
own x". DebugObjectMenu (#27564) reads as a menu surface by its type name,
but that point is where the DEBUG `debug.object_menu` command pops the
pane's own menu up when the pane's tab bar is hidden: a click location, not
a row of a menu it draws. No MenuMetrics value is 80, so taking one would
move the capture's menu. List the file in NOT_MENUS with why, as the lint
does for MacScreenButtons.swift.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Oct 31, 2026
…s are instances AppServices owns (#28267)

The arch-ratchet tip rise (audit-rh): fourteen globals and two assumeIsolated sites that landed with
no reviewed exception now live on instances the composition root constructs and passes.

- AppServices.DebugFixtures (DEBUG only): the capture fixtures of one app. It holds
  debug.cloud_machine_fixture's cloudWorkspace (was DebugCloudMachineFixture.holders, #26274),
  debug.add_device's listing (DebugAddDevice.listing, #27229), debug.join_consent's status and
  person line (DebugJoinConsent.status and .line, #27223), debug.object_menu's menu
  (DebugObjectMenu.popped, #27564), and debug.joined_machines' service (was
  AppServices.debugJoinedMachines).
- DebugWindowRecord is an instance (AppServices.windowRecord): running, launchRecorders,
  launchSeen and launchWatch (#23680) are its properties. The app delegate starts
  --record-launch right after it makes the services, before the first window, as before. A launch
  recording's window-close observer is a MainActorObservation, not a raw queue: .main observer
  with MainActor.assumeIsolated.
- RoomDefaultsUpdates is an instance (AppServices.roomDefaults): its per-space serial tails (#23461).
- JoinConsentModel.fixtureActive: the app sets it in DEBUG from its fixtures; it is false in
  Release, as the removed static was. The Mac Screen gate reads it before and after its read.
- The grant gate is invalidated by SettingsController.onEveryLoad, which runs on the main actor in
  the load itself, before the load changes snapshot or loadCount. This replaces an observation
  that re-armed itself through Thread.isMainThread plus assumeIsolated or a Task (#27223). Those
  two properties change only in that main-actor load, so the Task branch never ran.
- PageID.fixtureRoots (#26109) is gone. A test gives its fixture root to the page host it builds
  (PageWebView and AgentPaneView testRoot: true; DEBUG only, Release ignores it).

Behavior does not change. Tests that set the statics now set their own instances.

arch_counts delta: stateful_singletons -4, global_mutable_statics -7, assume_isolated_outside_adapters -2,
assume_isolated_total -2, app_lines -11; no row rises. Owner: Performance Lead.
Not compiled or tested on this VM (fleet compile-check after push).

This branch was previously deployed

3 inactive (2 outdated) deployments
ci-routing-agent — 65135ef3 Deployed Oct 30, 2026 by teamleaderleo via wait for same-key tree publisher #80566
artifacts — 74ebf245 Deployed Oct 30, 2026 by teamleaderleo via add the Windows daemon to the tree #79680
sentry-dsyms — 74ebf245 Deployed Oct 30, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #79680
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant