Skip to content

Fix Cmd+T cwd after session restore - #6055

Merged
austinywang merged 9 commits into
mainfrom
issue-6047-cmdt-cwd-restore
Jun 13, 2026
Merged

austinywang merged 9 commits into
mainfrom
issue-6047-cmdt-cwd-restore

Conversation

@austinywang

@austinywang austinywang commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • restore Cmd+T/new-tab cwd resolution to use the same explicit -> panel directory -> requested directory -> workspace currentDirectory order as split/respawn
  • add a Swift Testing regression for a restored focused agent pane with only the workspace cwd restored

Fixes #6047.

Regression proof

  • Commit 1 adds the failing regression test only: test: cover restored agent Cmd+T cwd
  • Commit 2 applies the fix: fix: restore Cmd+T workspace cwd fallback

Local validation

  • git diff --check
  • ./scripts/check-pbxproj.sh
  • ./scripts/lint-pbxproj-test-wiring.sh

Per issue instructions, I did not run local xcodebuild tests or ./scripts/reload.sh.

Localization

No user-facing strings changed; no localization catalog updates required.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Fixes Cmd+T/new-tab cwd after session restore by centralizing cwd resolution and applying it across all terminal-creation paths, including JSON-RPC surface.create. If no pane cwd is available, we use the workspace currentDirectory; “New Terminal to Right” inherits the anchor tab’s cwd even if it isn’t selected.

  • Bug Fixes
    • Centralized cwd resolution in Workspace (order: explicit → panel cwd → panel requested cwd → workspace currentDirectory), ignoring empty/whitespace values. Enabled via inheritWorkingDirectoryFallback (only when no startup command) and optional workingDirectoryFallbackSourcePanelId across new/split/respawn, empty-panel, focused-pane, shell-driven, sidebar new-tab, and v2 surface.create flows (incl. “to the right”).
    • Tests: added WorkspaceTerminalTabWorkingDirectoryTests covering Cmd+T restore uses workspace cwd; remote restore keeps nil; “to the right” inherits anchor; and surface.create inherits workspace cwd from a focused agent pane. Fixes Cmd+T loses workspace cwd after Cmd+Q session restore #6047.

Written for commit 5f2b6fb. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Updated terminal creation flows (including empty-panel, shell-driven, split, and to-the-right) to optionally inherit a fallback working directory from the appropriate anchor or focused pane.
  • Refactor

    • Centralized working-directory resolution by normalizing whitespace/newlines and applying a clear precedence (explicit value, panel-derived intent, then current directory).
  • Tests

    • Added a dedicated test suite covering working-directory inheritance across session restore, remote restore, and “new terminal to the right” scenarios.

@vercel

vercel Bot commented Jun 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 13, 2026 11:23pm
cmux-staging Building Building Preview, Comment Jun 13, 2026 11:23pm

@coderabbitai

coderabbitai Bot commented Jun 13, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Centralizes terminal startup working-directory resolution, adds fallback inheritance to terminal surface creation, updates terminal creation call sites to use it, and adds tests plus Xcode wiring for session-restore cwd behavior.

Changes

Terminal Working-Directory Resolution and Validation

Layer / File(s) Summary
Terminal working-directory resolution helpers
Sources/Workspace.swift
Adds normalization and consolidated precedence resolution for terminal startup working directories.
Workspace integration and fallback flags
Sources/Workspace.swift
Adds fallback parameters to terminal surface creation, replaces inline working-directory selection with the shared resolver, and updates workspace terminal creation paths to pass inherited working-directory behavior.
Controller and view call sites
Sources/TerminalController+ControlSidebarContext3.swift, Sources/TerminalController+ControlSystemContext2.swift, Sources/TerminalController+ControlSurfaceContext2.swift, Sources/TerminalController.swift, Sources/WorkspaceContentView.swift
Updates terminal-creation call sites to pass inherited working-directory fallback settings for sidebar, tab-action, mobile, and empty-panel terminal creation.
Tests and Xcode wiring
cmuxTests/WorkspaceTerminalTabWorkingDirectoryTests.swift, cmux.xcodeproj/project.pbxproj
Adds the terminal working-directory test suite and registers the test source in the Xcode project.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped from pane to pane so bright,
And kept the workspace cwd in sight.
No lonely home directory tumble,
Just tidy paths that never mumble. 🥕


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux Cache Substitution Correctness ❌ Error The resolver prioritizes stale panelDirectories cache over fresh currentDirectory for agent panels without handling cache staleness, creating a persistence bug. Add documented graceful-degradation rationale or use event-driven cache updates; OR reverse priority to current Directory first, then panelDirectories as fallback for terminal reports.
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (19 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: Cmd+T working-directory behavior after session restore.
Linked Issues check ✅ Passed The changes restore the cwd fallback order, add the requested regression tests, and cover the related right-of-anchor terminal flow.
Out of Scope Changes check ✅ Passed The diff stays focused on Cmd+T cwd resolution, related terminal-creation paths, and test wiring, with no obvious unrelated changes.
Cmux Swift Actor Isolation ✅ Passed PR introduces well-isolated working directory resolution: new nonisolated static helper, implicit @MainActor instance methods on @MainActor Workspace, simple value-type parameters, and MainActor-co...
Cmux Swift Blocking Runtime ✅ Passed PR adds pure helper functions (normalizedTerminalWorkingDirectory, resolvedTerminalStartupWorkingDirectory) and optional parameters to newTerminalSurface with safe defaults. No new blocking pattern...
Cmux Expensive Synchronous Load ✅ Passed The PR's new working-directory resolution code (resolvedTerminalStartupWorkingDirectory and modified newTerminalSurface) contains only lightweight O(1) dictionary lookups and string operations....
Cmux No Hacky Sleeps ✅ Passed Check is not applicable: PR modifies only Swift code and Xcode project configuration. Runtime-no-hacky-sleeps rule explicitly covers only TypeScript, JavaScript, shell, and non-Swift build/runtime...
Cmux Algorithmic Complexity ✅ Passed The resolvedTerminalStartupWorkingDirectory function (Sources/Workspace.swift) uses a fixed 4-element array with O(1) lookups (dictionary panelDirectories, terminalPanel func). No nested full-colle...
Cmux Swift Concurrency ✅ Passed The PR introduces no new async patterns violating swift-concurrency-modernization.md: helper functions are pure synchronous (no DispatchQueue, Combine, completion handlers, or fire-and-forget Tasks...
Cmux Swift @Concurrent ✅ Passed All Swift changes are synchronous methods on @MainActor-annotated classes; no async functions added; no missing or invalid @concurrent annotations; proper actor isolation throughout.
Cmux Swift File And Package Boundaries ✅ Passed PR refactors cwd fallback logic with net-zero additions to oversized Workspace.swift (19972→19972 lines), extracts helpers to eliminate duplication, and adds focused test coverage. Qualifies as inc...
Cmux Swift Logging ✅ Passed All NSLog additions in Sources/Workspace.swift are properly guarded by #if DEBUG preprocessor directives, meeting the allowed debug-only logging exceptions in the Swift logging rules.
Cmux User-Facing Error Privacy ✅ Passed No user-facing errors, alerts, or sensitive information exposed. Changes are internal working directory resolution logic with safe parameters; new test file is developer-only code.
Cmux Full Internationalization ✅ Passed PR introduces no user-facing text. Changes are private helper functions, method parameters for internal logic (inheritWorkingDirectoryFallback, workingDirectoryFallbackSourcePanelId), and test file...
Cmux Swiftui State Layout ✅ Passed PR adds model-layer helper methods and method parameters only; no new SwiftUI state properties, GeometryReader layout changes, lazy view store refs, or render-time mutations introduced.
Cmux Architecture Rethink ✅ Passed Centralizes cwd resolution in Workspace.resolvedTerminalStartupWorkingDirectory() with clear invariant; adds optional control flags only (no new state); consolidates rather than duplicates logic; t...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR does not add or materially change any NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup. Changes are limited to working directory resolution logic and terminal creation param...
Cmux Source Artifacts ✅ Passed All 8 changed files are hand-written Swift source code, tests, or legitimate Xcode project configuration files in expected source directories; none match artifact patterns (DerivedData, .swiftpm, t...
Description check ✅ Passed The PR description covers the main required content with summary, validation, and localization notes, though it omits some template sections like Demo Video and Checklist.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6047-cmdt-cwd-restore

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 and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes Cmd+T/new-tab cwd resolution after session restore by centralizing working-directory selection in Workspace.swift and opting call sites into the fallback via a new inheritWorkingDirectoryFallback parameter. When the focused pane contains only an agent (or other non-terminal) panel, the new code correctly falls through the explicit → panel cwd → panel requested cwd → workspace currentDirectory chain rather than yielding nil.

  • Extracted the four-step cwd precedence chain into resolvedTerminalStartupWorkingDirectory, replacing three separate inline closures in split, respawn, and new-surface paths with a single canonical helper; also added a nonisolated normalizedTerminalWorkingDirectory to deduplicate the trim-and-nil-coalesce pattern.
  • Added inheritWorkingDirectoryFallback: Bool and workingDirectoryFallbackSourcePanelId: UUID? to newTerminalSurface; the fallback is gated by startupCommand == nil, so remote-terminal and command-driven tabs are unaffected.
  • Added WorkspaceTerminalTabWorkingDirectoryTests with four Swift Testing cases covering the regression scenario, the remote-restore nil-preserving path, "new terminal to right" from a non-selected anchor, and the surface.create RPC path.

Confidence Score: 5/5

Safe to merge — the fix is well-scoped, the fallback is opt-in, and the remote-terminal nil-cwd contract is preserved.

The change centralizes an existing four-step cwd precedence rule that was already correct for split/respawn paths, and applies it consistently to all new-surface paths via an explicit opt-in flag. The gate on startupCommand == nil correctly excludes remote and command-driven terminals. Agent panels fall through cleanly to workspace currentDirectory because they produce no panelDirectories entry and terminalPanel(for:) returns nil for non-terminal panels. The regression is covered by a new Swift Testing suite.

No files require special attention.

Important Files Changed

Filename Overview
Sources/Workspace.swift Centralized cwd resolution into two private helpers; updated split, respawn, new-surface, createTerminalToRight, and BonsplitDelegate paths to use them; behaviour is equivalent for existing callers and correctly extends fallback to agent panes.
Sources/TerminalController+ControlSurfaceContext2.swift Adds inheritWorkingDirectoryFallback: true to the surface.create RPC path; correctly gated by startupCommand == nil inside newTerminalSurface.
Sources/TerminalController+ControlSystemContext2.swift Passes anchor panel's surfaceId (a panel UUID at this call site) as workingDirectoryFallbackSourcePanelId for 'new terminal to right' — correctly uses panel ID, not surface/tab ID.
Sources/TerminalController+ControlSidebarContext3.swift Adds inheritWorkingDirectoryFallback: true to the non-automation sidebar new-terminal call; one-line change, correct.
Sources/TerminalController.swift One-line addition of inheritWorkingDirectoryFallback: true in the internal empty-panel repair path; no other changes.
Sources/WorkspaceContentView.swift Adds inheritWorkingDirectoryFallback: true to the empty-pane New Terminal button path; one-line change, correct.
cmuxTests/WorkspaceTerminalTabWorkingDirectoryTests.swift New Swift Testing suite with four @mainactor tests covering the key regression (agent-only pane to workspace cwd), remote-restore nil preservation, 'to the right' anchor inheritance, and surface.create RPC.
cmux.xcodeproj/project.pbxproj Wires WorkspaceTerminalTabWorkingDirectoryTests.swift into the test target with the repo's standard ID-based pattern; no unrelated changes.

Reviews (8): Last reviewed commit: "test: restore terminal controller manage..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/Workspace.swift`:
- Around line 14745-14751: Update the inline comment above the call to
resolvedTerminalStartupWorkingDirectory so it matches the actual resolver order:
state that an explicit requestedWorkingDirectory (the requestedWorkingDirectory
parameter) is preferred first, then the source panel's reported cwd (identified
by panelId) if present, and finally fall back to the workspace's current
directory; keep the call to resolvedTerminalStartupWorkingDirectory unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 86720799-0e19-45e2-96bb-8b858dd1366d

📥 Commits

Reviewing files that changed from the base of the PR and between 6ceaf2f and 71c86dd.

📒 Files selected for processing (1)
  • Sources/Workspace.swift

Comment thread Sources/Workspace.swift Outdated
@austinywang
austinywang force-pushed the issue-6047-cmdt-cwd-restore branch 3 times, most recently from 008b745 to 97b9824 Compare June 13, 2026 18:18
@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/WorkspaceTerminalTabWorkingDirectoryTests.swift`:
- Around line 189-208: The test uses a hard-reset pattern for
TerminalController.shared state management that can cause state leakage in
parallel test execution. In the
surfaceCreateInheritsWorkspaceCurrentDirectoryForAgentPane function, replace the
defer block that sets activeTabManager to nil at the start with a save/restore
pattern: first call activeTabManagerForCallerNotification() to capture the
previous manager state, then after the setActiveTabManager call with the manager
parameter, add a defer block that restores the previous manager by calling
setActiveTabManager with the saved previousManager value. This ensures tests do
not clobber each other's state and follows the established pattern used
elsewhere in the test suite.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9058f8d0-3830-42aa-ab45-e4ddaebc44bf

📥 Commits

Reviewing files that changed from the base of the PR and between 2a6b378 and 3a52b48.

📒 Files selected for processing (5)
  • Sources/TerminalController+ControlSurfaceContext2.swift
  • Sources/TerminalController.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/WorkspaceTerminalTabWorkingDirectoryTests.swift
👮 Files not reviewed due to content moderation or server errors (1)
  • Sources/TerminalController.swift

Comment thread cmuxTests/WorkspaceTerminalTabWorkingDirectoryTests.swift
@austinywang
austinywang merged commit 2a2d87b into main Jun 13, 2026
24 checks passed
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request Jun 14, 2026
PRs included:
- AppDelegate decomposition: CmuxSession session-snapshot repository (manaflow-ai#6030)
- Fix Cmd+T cwd after session restore (manaflow-ai#6055)
- Speed up iOS terminal scroll rendering (manaflow-ai#6035)
- Preserve Pi sessions across workspace restore (manaflow-ai#5607)
- Scope Biome checks to maintained JS sources (manaflow-ai#6008)
- Fix manaflow-ai#5917: restore OSC 11 pane-local backgrounds (manaflow-ai#5997)
- Expose stable window title templates (manaflow-ai#6059)
- Honor macos-option-as-alt left/right
- Fix macOS 27 SF Symbol rasterization crash (manaflow-ai#5999)
- CmuxRemote* family: extract Workspace remote/cloud-VM connectivity
- Fix iOS workspace swipe-delete confirmation crash (manaflow-ai#6051)
- TabManager decomposition Wave 3+4 sub-models
- Sidebar row cleanups: branchless frame anchor
- CmuxIPCService: extract AppDelegate multi-window CLI routing
- CmuxSidebarGit: extract TabManager git-metadata + PR-polling subsystem
- CmuxTerminalCore: extract terminal core leaf

Fork-side adjustments:
- ghostty submodule: cherry-pick mouse-modifier-state fix onto our renderer-realized branch
- Workspace.swift: take theirs (upstream extracted ~7700 lines into CmuxCore.Remote/CmuxRemoteSession packages); restore fork's renameTopLevelLayoutTabContaining/closeTopLevelLayoutTabContaining + surfaceTmuxClientTTYNames + WorkspaceLayoutTab integration
- TabManager.swift: take theirs; re-add static allocatePortOrdinal()
- BrowserPanelView, RenderableSystemSymbol: keep fork's cmuxSymbolPixelSize extension on top of upstream's cmuxSymbolRasterSize
- Add CmuxWorkspaces / CMUXSessionDaemon / CmuxCommandPalette imports to TerminalController, Workspace, SessionPersistence
- Sources/Workspace+P43Stubs.swift: thin shims for SplitEqualizer, WorkspaceRemoteSessionController.PortScanKickReason, WorkspaceGroupNewWorkspacePlacementSettings (legacy types fork TC still calls; replace with package APIs in P44+)
- Sources/GhosttySurfaceSizeDeferralReason.swift: restore fork-only enum (deleted by upstream)
- Sources/StableLayout/SessionBlueprintExportAction.swift: parked debug action (depends on legacy SessionPersistenceStore, gone)
- Sources/GhosttyTerminalView.swift: stub ghostty_surface_select_cursor_line_compat (needs zig 0.15.2 xcframework rebuild)
- pbxproj: keep-both, drop stale ProcessPipeReader/SplitEqualizer/Panels/BrowserProxyEndpoint refs, fix SurfaceHibernationPolicy UUID collision
- Drop fork's WorkspaceRemoteConfiguration.swift + WorkspaceRemoteSSHBatchCommandBuilder.swift (extracted to CmuxCore package)

This branch was successfully deployed

1 active deployment
Preview – cmux — 5f2b6fb2 Deployed Jun 13, 2026 by vercel[bot]
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.

Cmd+T loses workspace cwd after Cmd+Q session restore

1 participant