Skip to content

Route workspace.last through the Focus Last toggle - #14760

Merged
teamleaderleo merged 2 commits into
mainfrom
workspace-last-focus-last
Sep 25, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
workspace-last-focus-last

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #14700 (Focus Last). The workspace.last socket command, which backs cmux last-window and the tmux -/!/^ window target, called TabManager.navigateBack(). Repeated calls walked further back through focus history, while the app's Focus Last shortcut and History menu item toggle between the two most recent positions.

controlSelectLastWorkspace now calls TabManager.navigateToLastFocused(), the same entry point the app uses, and returns not_found when that navigation fails or leaves the selected workspace unchanged (pane-scoped history can toggle to another pane in the same workspace; tmux - targets must not resolve to the current workspace). The CLI and the app now behave identically: last-window twice returns to where you started.

Test

FocusHistoryScopeTests.workspaceLastSocketCommandTogglesLikeFocusLast selects three workspaces, then drives workspace.last through ControlCommandCoordinator twice. The first call lands on the second workspace, the second returns to the third (the old navigateBack path would have gone to the first).

🤖 Generated with Claude Code


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


Summary by cubic

Routes the workspace.last socket command — which backs cmux last-window and the tmux - target — through the same Focus Last toggle the app uses, so repeated calls flip between the two most recent workspaces instead of walking further back through focus history. not_found is now returned when the toggle can't move or stays in the current workspace (pane-scoped history), so tmux - targets never resolve to the current workspace, matching the app's shortcut and History menu behavior.

Written for commit 8e89466. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • “Last workspace” requests now switch between the two most recently focused workspaces, so successive requests return to the previously focused workspace and then back again. Requests report that no workspace was found when there is no selected workspace or the request cannot change the current selection.

The socket command behind `cmux last-window` and the tmux `-` target
called TabManager.navigateBack(), so repeated calls walked further back
through history, while the app's Focus Last shortcut and History menu
item toggle between the two most recent positions. workspace.last now
calls navigateToLastFocused() and reports not_found only when that
navigation fails, so the CLI and the app behave identically.

Adds a cmuxTests case that drives workspace.last through the control
coordinator twice and expects it to toggle back to the start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 1fc7d066-f4f7-48b9-8c2b-d0b6a05884c9

📥 Commits

Reviewing files that changed from the base of the PR and between 3e5022b and 8e89466.

📒 Files selected for processing (2)
  • Sources/TerminalController+ControlWorkspaceContext.swift
  • cmuxTests/FocusHistoryScopeTests.swift

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The workspace.last control request now toggles between the two most recently focused workspaces. It returns .notFound if navigation fails, no workspace is selected afterward, or the selection does not change. A test checks two successive requests.

Changes

Last workspace toggle

Layer / File(s) Summary
Control toggle and request validation
Sources/TerminalController+ControlWorkspaceContext.swift, cmuxTests/FocusHistoryScopeTests.swift
controlSelectLastWorkspace calls navigateToLastFocused() and returns .notFound if navigation fails, no workspace is selected afterward, or the selection is unchanged. The test sends two workspace.last requests and checks that selection alternates from the third workspace to the second and back.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: austinywang

Merge Risk: ⚪ Minimal · up to 8e894

Workspace history toggles as intended, and pane-only history does not resolve as a different workspace. No actionable merge-blocking risk remains.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 8e894

The command now toggles between recently focused workspaces instead of walking backward through history. It uses the existing workspace routing and does not appear to grant new access. If the last-focused workspace has disappeared, however, the command can fail where it previously could select an older workspace.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed command selects through its already-routed TabManager and returns workspace and window references. The examined change does not add a routing selector, a new state owner, or a new response data category.

Trust Boundaries and Controls

  • observed — workspace.last enters the existing coordinator, which calls the routed controller method. The controller still resolves the manager before requesting focus-history navigation; the changed lines do not alter the remote-relay owner check in that resolver.
🚥 Pre-merge checks | ✅ 23 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description explains the problem, resulting behavior, implementation, and added test. It omits the required Demo Video and Checklist sections, and it does not state an executed test command or tes… Add the Demo Video section with a video or screenshot link. Add the Checklist section and mark each applicable item. Rename Test to Testing and state which command ran, whether it passed, and what remains unverified.
✅ Passed checks (23 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Cloud Persistent Session And Early Input ✅ Passed PASS: The pull request changes only controlSelectLastWorkspace and adds a focus-history test. It does not change Cloud terminal creation, transport, renderer gating, PTY readiness, input ownership, …
Cmux Swift Actor Isolation ✅ Passed The production diff only replaces navigateBack() with navigateToLastFocused() inside TerminalController: ControlWorkspaceContext. TerminalController, TabManager, ControlWorkspaceContext, a…
Cmux Swift Blocking Runtime ✅ Passed The production diff only replaces navigateBack() with navigateToLastFocused() and adds a result guard plus documentation. It adds no semaphore, blocking wait, sleep, delayed dispatch, polling loop…
Cmux Browser Automation Off-Main ✅ Passed PASS. The diff changes workspace.last workspace focus behavior and adds a focus-history test. It does not add or move any browser.* socket command, WebKit/page wait, worker-lane browser route, or …
Cmux Expensive Synchronous Load ✅ Passed The production diff only replaces tabManager.navigateBack() with tabManager.navigateToLastFocused() in the existing socket handler. The handler is @MainActor, but `FocusHistoryModel.navigateToLa…
Cmux Cache Substitution Correctness ✅ Passed PASS: The diff does not replace an authoritative persistence read with a cache. It changes one in-memory focus-history operation (navigateBack() to navigateToLastFocused()). FocusHistoryModel up…
Cmux No Hacky Sleeps ✅ Passed PASS. The PR changes only Swift production code and Swift tests. The production change calls TabManager.navigateToLastFocused() and introduces no sleep, timer, polling loop, delay, or wall-clock wai…
Cmux Algorithmic Complexity ✅ Passed The production diff replaces navigateBack() with navigateToLastFocused() in Sources/TerminalController+ControlWorkspaceContext.swift. It adds no loop, batch rescan, repeated sort, or filter. `Fo…
Cmux Swift Concurrency ✅ Passed PASS. The diff changes synchronous workspace navigation from navigateBack() to navigateToLastFocused() and adds a synchronous XCTest-style test. It adds no Task, background DispatchQueue, Comb…
Cmux Swift @Concurrent ✅ Passed PASS: The PR adds no async, nonisolated async, or @concurrent declaration or call site. controlSelectLastWorkspace remains synchronous and calls synchronous `TabManager.navigateToLastFocused()…
Cmux Swift Package Boundaries ✅ Passed The production diff changes only the app-side TerminalController control adapter: it resolves the app TabManager, focuses the window, calls the existing navigateToLastFocused() API, and maps the…
Cmux Swiftpm Lockfiles ✅ Passed The authoritative PR diff changes only Sources/TerminalController+ControlWorkspaceContext.swift and cmuxTests/FocusHistoryScopeTests.swift. It changes no Package.swift, Package.resolved, `.git…
Cmux Swift Logging ✅ Passed The PR adds no production logging. The changed runtime code only replaces navigateBack() with navigateToLastFocused(), and the added test contains no print, debugPrint, dump, NSLog, ad hoc…
Cmux User-Facing Error Privacy ✅ Passed PASS. The production diff changes navigation behavior and returns the existing generic .notFound result; it adds no user-facing error, alert, command-output text, API error body, or recovery copy co…
Cmux Full Internationalization ✅ Passed PASS: The PR changes workspace navigation logic and adds a test. The only new prose is developer-only Swift comments and test text, which the rule allows. No user-facing Swift text, localization key, …
Cmux Swiftui State Layout ✅ Passed PASS: The pull request changes only workspace navigation logic and a focus-history test. The diff adds no SwiftUI view boundary, ObservableObject/@published state, GeometryReader, lazy/list row store …
Cmux Architecture Rethink ✅ Passed The PR passes the architectural check. The only production change replaces navigateBack() with the existing TabManager.navigateToLastFocused() owner and preserves the workspace-change invariant be…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The diff changes workspace focus navigation in controlSelectLastWorkspace and adds a test-only socket-command fixture. It does not add or materially change an NSWindow, NSPanel, `NSWindowControl…
Cmux Source Artifacts ✅ Passed The PR changes only two tracked text files: Sources/TerminalController+ControlWorkspaceContext.swift and cmuxTests/FocusHistoryScopeTests.swift. The diff contains hand-written product source and a…
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR changes one production Swift method, controlSelectLastWorkspace, to call the existing TabManager.navigateToLastFocused() API. The added production lines contain no test-build guard, test-on…
Title check ✅ Passed The title clearly identifies the main change: routing the workspace.last command through the Focus Last toggle.
Full details: Description check

Explanation

The description explains the problem, resulting behavior, implementation, and added test. It omits the required Demo Video and Checklist sections, and it does not state an executed test command or test result.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Pane-scoped history can make the toggle land on another pane in the
current workspace; keep reporting not_found there so tmux - targets never
resolve to the current workspace. Also fix the test's JSONValue.int
argument type (Int64).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit 8ea76f8 into main Sep 25, 2026
59 of 61 checks passed
@teamleaderleo
teamleaderleo deleted the workspace-last-focus-last branch September 25, 2026 23:18
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 8e89466a0a, merged 2026-09-25 23:18:31 UTC

  • Not verified at merge: CI fast guards (failure)
  • Verified: app-host unit tests, ci-status, macOS compile admission, Web complexity, web-validation, Fast static checks, GhosttyKit release check, guards (17), late-placement, linux-preflight, macOS admission gate, macOS status, and 2 more
  • Skipped by policy: browser, Claude wrapper regressions, CLI product tests, release-admission, release-build, remote-daemon, suite-coverage, swift-package-tests, tests-build-and-lag, web, web-build, web-database-tests, and 1 more
  • Full suite: runs on main after merge.

teamleaderleo added a commit that referenced this pull request Sep 25, 2026
git 2.55 starts `git maintenance run --auto --detach` after commit, fetch,
and clone. The detached child can still be writing into a fixture repo's
.git when TemporaryDirectory removes it, which failed CI fast guards on
#14760 with "Directory not empty: '.git'". Set maintenance.auto=false through
GIT_CONFIG_COUNT for every git child of test_ci_change_areas.py.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 26, 2026
e196ab6 Fix spontaneous Computer Use onboarding during permission refresh (manaflow-ai#14752)
6ba2583 ci: stop git auto maintenance in CI routing test fixture repos (manaflow-ai#14765)
db9580b ci: let a refused owned job's siblings finish instead of cancelling them (manaflow-ai#14766)
8ea76f8 Route workspace.last through the Focus Last toggle (manaflow-ai#14760)

# Conflicts:
#	.github/workflows/ci-macos.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant