Skip to content

Reopen closed workspaces with sticky repo identity - #8841

Merged
austinywang merged 11 commits into
mainfrom
issue-8772-reopen-closed-workspace
Jul 26, 2026
Merged

austinywang merged 11 commits into
mainfrom
issue-8772-reopen-closed-workspace

Conversation

@austinywang

@austinywang austinywang commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add Reopen Closed Workspace to the History menu and command palette. It defaults to ⌘⇧T, is editable in Settings and cmux.json, and repeated invocations walk backward through workspace-only closed history.
  • Restore directory, panes/layout, label, and color additively into the active/preferred window. Existing windows and workspaces are never replaced.
  • Bound recovery to the 100 most recent workspace records without truncating pre-existing panel/window history.

Persistence design

Closed workspace recovery reuses the existing persisted ClosedItemHistoryStore snapshot pipeline, with an independent workspace-only capacity policy. Capacity trimming uses one-pass removal and is persisted after load, so oversized history is repaired once.

Sticky identity lives in CmuxWorkspaces as an injected WorkspaceDirectoryCustomizationStore. UserDefaults remains the sole source of truth, while a versioned envelope retains the 512 most recently mutated directory records (including explicit-clear tombstones) and migrates the earlier dictionary payload. Session restore batch-reads the map once instead of decoding it per workspace.

Sticky customization semantics

  • The normalized workspace root is captured at creation. Later shell cd changes do not move identity to another directory.
  • Explicit user renames and color changes update their sticky fields. Explicit clears persist as tombstones; automatic/generated titles never update sticky identity.
  • An explicit creation title, including CLI/socket-backed workspace creation, wins over a stored label and becomes the new sticky label. A stored color still applies unless explicitly changed.
  • Sticky state is authoritative during session/history restore. A current eligible snapshot seeds the store only when no record exists; existing records, including tombstones, win over stale snapshots.
  • Snapshots now persist explicit eligibility. Legacy local snapshots infer a root only when that directory already has a sticky record, preventing old generated config/Pro workspaces from poisoning project identity.
  • Config-defined, Pro, Cloud/remote-tmux, and rootless workspaces opt out when they lack an authoritative local project root.
  • Saved-layout, config, UI, and CLI/socket rename/color paths use the shared TabManager mutation path.

The older generalized Reopen Last Closed action remains customizable. Its prior explicit ⌘⇧T binding is preserved for existing profiles; fresh profiles give the familiar browser-style gesture to workspace reopen.

CLI

Recently-closed listing/reopen was skipped. It is not a cheap alias in the current architecture: it would require a new socket protocol operation, cross-window routing contract, CLI parsing/output/help, and localized documentation. Existing CLI workspace creation and customization paths already participate in sticky identity.

Testing and validation

Behavior coverage includes:

  • workspace MRU push/reopen/bound behavior while preserving non-workspace history;
  • repeated workspace-only and additive restore;
  • active destination-window routing;
  • load-time capacity trimming persistence;
  • directory persistence, normalization, bounded retention, and legacy payload migration;
  • apply-on-create, session restore, explicit rename/color updates and clears;
  • stale snapshot/tombstone authority and safe legacy/generated-workspace migration;
  • generated Pro/config exclusion and creation-title precedence; and
  • runtime/Settings/config/command-palette shortcut alignment.

Local static validation covered pbxproj normalization/check, test-target wiring, package lockfile policy, workspace package grouping, deterministic-test lint, warnings-as-errors focused typechecking, Swift parser checks, package manifest parsing, and the English/Japanese localization audit. Per issue instructions, no local app build, xcodebuild, or test execution was run; CI is the execution gate.

python3 scripts/swift_file_length_budget.py is unavailable because the script and .github/swift-file-length-budget.tsv are absent from current origin/main. Every large touched Swift file has zero net line growth, all new Swift files remain under 500 lines, and .github/swift-warning-budget.tsv is unchanged.

Closes #8772

@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai

coderabbitai Bot commented Jul 24, 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

Adds reopening of closed workspaces through history, command palette, menu, and keyboard shortcuts. Persists workspace title/color customizations by normalized directory across creation and session restoration, with capacity policies and recovery tests.

Changes

Workspace recovery and customization

Layer / File(s) Summary
Shortcut contracts and configuration
Packages/macOS/CmuxSettings/..., Sources/KeyboardShortcutSettings*.swift, Sources/ContentView*.swift, web/data/*, Resources/Localizable.xcstrings
Adds the reopen-closed-workspace action, Cmd+Shift+T default, legacy conflict handling, localization, command-palette and History menu integration, and configuration metadata.
Closed workspace restoration flow
Sources/ClosedItemHistory*.swift, Sources/ClosedWorkspaceHistory.swift
Filters workspace history entries, enforces total and workspace capacities, and restores the newest matching workspace.
Directory customization persistence
Packages/macOS/CmuxWorkspaces/Sources/..., Sources/SessionPersistence.swift, Sources/Workspace.swift
Adds normalized directory-keyed title/color storage and persists customization-directory metadata in workspace snapshots.
Workspace customization lifecycle
Sources/TabManager*, Sources/cmuxApp.swift, Sources/AppDelegate*.swift, Sources/CmuxConfigExecutor+WorkspaceLaunch.swift, Sources/RemoteTmuxController.swift
Applies and reconciles stored customization during workspace creation and restoration, records user changes, routes tab colors, and injects the customization store.
Validation and project wiring
cmuxTests/*, Packages/macOS/CmuxWorkspaces/Tests/..., cmux.xcodeproj/project.pbxproj
Adds persistence, restoration, customization, shortcut, and project-build coverage for the new behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

  • manaflow-ai/cmux#8695 — Both changes modify closed-workspace restoration and related workspace identity handling.

Suggested reviewers: lawrencecchen


Important

Pre-merge checks failed

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

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Cache Substitution Correctness ❌ Error The new workspace-reopen path trusts ClosedItemHistoryStore.shared’s async-loaded in-memory records, with no cold-load or freshness gate before restore. Gate reopen on didFinishPersistedRecordsLoad or synchronously load/flush the history store before any history-based restore.
Cmux Swift Package Boundaries ❌ Error Sources/ClosedItemHistoryCapacityPolicy.swift adds pure trimming/capacity logic in the app target; it’s testable/reusable domain code that should live in a SwiftPM package. Extract a small package target (e.g. CmuxClosedHistoryCore) and expose ClosedItemHistoryCapacityPolicy there; keep only AppDelegate/TabManager wiring in the app.
Cmux Full Internationalization ❌ Error FAIL: web/data/cmux-shortcuts.ts adds reopenClosedWorkspace only in en/ja while web/i18n/routing.ts lists 20 locales, and no matching web/messages updates were added. Add translations for every routed locale (or move the shortcut copy into next-intl) and keep the matching message files in sync.
Docstring Coverage ⚠️ Warning Docstring coverage is 15.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (21 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement a reopen-closed-workspace history flow and sticky per-directory customization as requested in #8772.
Out of Scope Changes check ✅ Passed The added files and edits appear directly related to workspace reopening, customization persistence, shortcut wiring, and tests.
Cmux Swift Actor Isolation ✅ Passed PASS: The new store/history helpers are explicitly @MainActor and only wired through main-actor TabManager/AppDelegate paths; pure value types stay nonisolated.
Cmux Swift Blocking Runtime ✅ Passed No new blocking sync appears in the PR hunks; diff scans found no waits/sleeps/locks, and the only DispatchQueue.main.sync is pre-existing DEBUG-only code.
Cmux Browser Automation Off-Main ✅ Passed The PR only touches workspace/history/shortcut and persistence files; it does not modify TerminalController, ControlCommandExecutionPolicy, or any browser.* worker-routing path.
Cmux Expensive Synchronous Load ✅ Passed No new agent-history load was added to the menu/shortcut paths; the new actions call closed-item history restore only, and existing RestorableAgentSessionIndex.load() sites are untouched.
Cmux No Hacky Sleeps ✅ Passed The only non-Swift TS/JSON changes are static shortcut data/schema docs; no sleeps, timers, polling, or fixed waits were introduced.
Cmux Algorithmic Complexity ✅ Passed The diff uses explicit bounds (100 workspace history, 128 restore workspaces) and one-pass Set/dedup batching; the only O(n^2) trim path is test-only/unused in production.
Cmux Swift Concurrency ✅ Passed PASS: The modified workspace-recovery and sticky-customization code is synchronous; it adds no new DispatchQueue/Combine/completion-handler or fire-and-forget Task patterns.
Cmux Swift @Concurrent ✅ Passed The patch adds only synchronous/UI-bound helpers and tests; no new @concurrent, invalid @concurrent, or nonisolated async changes appear in the diff.
Cmux Swiftpm Lockfiles ✅ Passed No .gitignore, Package.swift, workflow, or Package.resolved files changed; the Xcode project edit only registers sources/tests, not SwiftPM package references.
Cmux Swift Logging ✅ Passed No new or changed runtime logging appears in the PR hunks; the touched code only adjusts workspace/shortcut logic, and existing loggers predate the diff.
Cmux User-Facing Error Privacy ✅ Passed Only new user-facing copy is a generic workspace-exists confirmation; no vendor/internal names, raw messages, or sensitive details are exposed.
Cmux Swiftui State Layout ✅ Passed The diff only adds menu/command wiring and a TabManager dependency; no new ObservableObject/@published, GeometryReader, lazy-row store refs, or render-time state writes were introduced.
Cmux Architecture Rethink ✅ Passed PASS: New workspace-reopen and sticky-identity flows are centralized in MainActor stores/TabManager; no new timing hacks, observers, or split lifecycle ownership.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR only adds menu/command actions and workspace recovery logic; no new NSWindow/NSPanel/WindowGroup or identifier changes were introduced, so the auxiliary-window rule isn’t implicated.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/docs/config/test assets; no temp, cache, build-output, DerivedData, or scratch directories appear in the diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Changed production files add only workspace/shortcut logic; the diff shows no new #if DEBUG/test-only members, no test-hook names, and no visibility widening for tests.
Cmux No Ambient Global State ✅ Passed The actual diff only adds method-level logic and a private static helper; it introduces no new top-level APIs, globals, or singleton/app-delegate state.
Title check ✅ Passed The title clearly matches the main change: reopening closed workspaces with sticky per-directory identity.
Description check ✅ Passed The description covers summary, persistence, semantics, CLI, and testing, but omits the demo video, review trigger, and checklist sections.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8772-reopen-closed-workspace

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.

@greptile-apps

greptile-apps Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a "Reopen Closed Workspace" action (⌘⇧T default) surfaced in the History menu, command palette, and settings. It introduces an independent 100-record workspace-only capacity policy for the shared closed-item history store, and a new WorkspaceDirectoryCustomizationStore that persists up to 512 directory→title/color mappings in UserDefaults with no in-memory mirror, so independently constructed window TabManager instances stay consistent.

  • Reopen workspace flow: ClosedWorkspaceHistory adds a matching: predicate to restoreFirstRestorable to filter workspace-only records; AppDelegate.reopenMostRecentlyClosedWorkspace resolves the target window, routes to TabManager.restoreClosedWorkspace, and handles focus. The restore path explicitly passes shouldApplyWorkspaceDirectoryCustomization: false to addWorkspace, then calls reconcileWorkspaceDirectoryCustomization after restoreSessionSnapshot so stored sticky values remain authoritative over stale snapshots.
  • Sticky identity: WorkspaceDirectoryCustomizationStore is injected into TabManager; applyWorkspaceDirectoryCustomization is called on every eligible addWorkspace path, and recordWorkspaceCustomTitle/applyWorkspaceColor write back on explicit user renames and color changes. Session restore uses cachedWorkspaceDirectoryCustomizations for a single batch decode instead of one decode per workspace.
  • Shortcut migration: ⌘⇧T moves to reopenClosedWorkspace; existing profiles that had it bound to reopenClosedBrowserPanel are detected via defaultShortcutResolvingLegacyConflicts and the workspace action falls back to unbound for those users.

Confidence Score: 4/5

The core reopen/restore/sticky-identity flows are well-structured and the previous issues were addressed. One existing concern about the remote tmux workspace label not being applied remains unresolved in the diff.

The RemoteTmuxController path passes shouldApplyWorkspaceDirectoryCustomization: false (correct — remote mirrors opt out), but unlike the CmuxConfigExecutor path there is no compensating setCustomTitle call after addWorkspace. The sessionName title argument is silently discarded, so remote tmux workspaces appear in the sidebar without their session name. This issue was noted in the previous outside-diff review and remains present in the current diff.

Files Needing Attention: Sources/RemoteTmuxController.swift — the sessionName title passed to addWorkspace is never applied to the workspace when shouldApplyWorkspaceDirectoryCustomization is false and no compensating setCustomTitle call follows.

Important Files Changed

Filename Overview
Sources/ClosedItemHistoryCapacityPolicy.swift New struct implementing independent total/workspace capacity policies; one-pass trimming via Set-based removal; workspace trim sorts by closedAt then array offset for deterministic oldest-first removal.
Sources/ClosedWorkspaceHistory.swift New file adding workspace-only reopen extensions on ClosedItemHistoryStore, AppDelegate, and TabManager; delegates window focus to AppDelegate path and restores additively without replacing live workspaces.
Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Customization/WorkspaceDirectoryCustomizationStore.swift New @mainactor struct persisting sticky directory→(title,color) in UserDefaults with no in-memory mirror; performs full JSONDecoder.decode on every read. Design is intentional to prevent window-graph drift; bounded to 512 entries.
Sources/TabManager+WorkspaceDirectoryCustomization.swift New extension wiring applyWorkspaceDirectoryCustomization, reconcileWorkspaceDirectoryCustomization (with/without batch cache), recordWorkspaceCustomTitle, and applyWorkspaceColor through the store.
Sources/TabManager.swift Adds workspaceDirectoryCustomizationStore injection; addWorkspace routes through applyWorkspaceDirectoryCustomization; restoreClosedWorkspace passes shouldApplyWorkspaceDirectoryCustomization:false to avoid pre-snapshot sticky writes.
Sources/ClosedItemHistory.swift Shared store now has independent workspaceCapacity=100 while panel/window history remains unbounded; adds matching: predicate to restoreFirstRestorable.
Sources/RemoteTmuxController.swift Adds shouldApplyWorkspaceDirectoryCustomization:false (correct for remote mirrors), but unlike CmuxConfigExecutor there is no compensating setCustomTitle call, so sessionName is silently discarded.
Sources/KeyboardShortcutSettingsLookup.swift Adds defaultShortcutResolvingLegacyConflicts to detect existing profiles with reopenClosedBrowserPanel bound to ⌘⇧T and yield nil for reopenClosedWorkspace to avoid a conflict on upgrade.
Sources/CmuxConfigExecutor+WorkspaceLaunch.swift Config-defined workspaces opt out of sticky customization via shouldApplyWorkspaceDirectoryCustomization:false, then apply title/color via compensating setCustomTitle/setTabColor calls.
Resources/Localizable.xcstrings Adds menu.history.reopenClosedWorkspace with both en and ja translations, matching all usage sites.

Sequence Diagram

sequenceDiagram
    participant U as User (⌘⇧T)
    participant AD as AppDelegate
    participant CIHS as ClosedItemHistoryStore
    participant TM as TabManager
    participant WS as Workspace
    participant WDCS as WorkspaceDirectoryCustomizationStore

    U->>AD: reopenMostRecentlyClosedWorkspace()
    AD->>CIHS: restoreMostRecentlyClosedWorkspace()
    CIHS-->>CIHS: restoreFirstRestorable(matching: .workspace)
    CIHS->>AD: workspaceEntry (restore closure)
    AD->>TM: restoreClosedWorkspace(workspaceEntry)
    TM->>TM: addWorkspace(shouldApplyWorkspaceDirectoryCustomization: false)
    TM->>WS: restoreSessionSnapshot(snapshot)
    WS-->>TM: panelIds restored
    TM->>WDCS: customizations(forDirectories:[directoryKey])
    WDCS-->>TM: stored or nil
    alt stored record exists
        TM->>WS: setCustomTitle(stored.customTitle)
        TM->>WS: setCustomColor(stored.customColor)
    else no record + snapshot has user-owned title/color
        TM->>WDCS: updateCustomization(for: directoryKey)
    end
    TM-->>AD: "restored = true"
    AD->>AD: focusMainWindow(windowId)
Loading

Reviews (11): Last reviewed commit: "Construct customization store on main ac..." | Re-trigger Greptile

Comment thread Sources/ClosedItemHistory.swift Outdated
Comment on lines 129 to 133
static let defaultCapacity = 100
static let shared = ClosedItemHistoryStore(
capacity: nil,
capacity: defaultCapacity,
fileURL: defaultHistoryFileURL()
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Shared history cap silently removes older reopen history for all item types

ClosedItemHistoryStore.shared previously had capacity: nil (unbounded). Bounding it to 100 affects the existing "Reopen Last Closed" action for browser panels and tabs — items beyond the 100-item budget are permanently dropped. A user who closes many browser panels in a session could find their older "Reopen Last Closed" history gone, with no warning. The workspace-only filter inside reopenMostRecentlyClosedWorkspace makes the cap feel even tighter: every closed panel or tab eats into the same 100-item budget.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in bc8f3bc. The shared store now has an independent 100-record workspace capacity while the pre-existing panel/window history remains unbounded. Coverage pushes a panel plus three workspaces through a two-workspace bound and verifies the panel survives.

— Claude Code

Comment thread Sources/ClosedWorkspaceHistory.swift Outdated
Comment on lines +42 to +61
if historyStore === ClosedItemHistoryStore.shared,
let appDelegate = AppDelegate.shared {
return appDelegate.reopenMostRecentlyClosedWorkspace(preferredTabManager: self)
}

return historyStore.restoreFirstRestorable(
newerThan: nil,
matching: { entry in
if case .workspace = entry {
return true
}
return false
},
using: { entry in
guard case .workspace(let workspaceEntry) = entry else { return false }
return self.restoreClosedWorkspace(workspaceEntry)
}
)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Test-path behavior diverges from production path on window focus

TabManager.reopenMostRecentlyClosedWorkspace delegates to AppDelegate (which includes window focus) when historyStore === .shared, but falls through to a local implementation — without focus — when an injected non-shared store is used. Any test driving the fallback path validates restoration but never exercises the window-focus logic, so coverage of the production flow is incomplete. The workspace-matching lambda is also duplicated between this fallback and AppDelegate.reopenMostRecentlyClosedWorkspace. Extracting a shared helper for the predicate and moving the focus responsibility to the call site (rather than the store-identity check) would make both paths exercise the same code.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in bc8f3bc. AppDelegate and TabManager now share one workspace-only history helper, TabManager no longer branches on singleton identity, and behavior coverage exercises active-destination routing while proving the source window remains unchanged.

— Claude Code

@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: 3

🤖 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
`@Packages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction.swift`:
- Around line 194-198: Move reopenClosedWorkspace out of the switch branch
returning .navigation and into the preceding .workspace branch alongside the
other workspace actions, so its shortcut is categorized as .workspace while all
other cases retain their existing categories.

In `@Sources/ClosedWorkspaceHistory.swift`:
- Around line 20-23: Update the tab-manager selection in the workspace
restoration flow to prioritize preferredTabManager before the
workspaceEntry.windowId lookup. Preserve self.tabManager as the final fallback
so history-menu and shortcut callers restore additively in the selected
destination window.

In `@web/data/cmux-shortcuts.ts`:
- Line 252: Update the reopenClosedWorkspace shortcut entry’s localized
description to include translations for all supported next-intl locales, rather
than only en and ja. Use the existing LocalizedText locale keys and preserve
localizedShortcutText() fallback behavior; do not change fallback logic unless
intentionally expanding it for the supported locales.
🪄 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 Plus

Run ID: 998ce2d8-d789-4e88-a5fc-f93b61c68290

📥 Commits

Reviewing files that changed from the base of the PR and between 0efce0d and f5af960.

📒 Files selected for processing (26)
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction+Defaults.swift
  • Packages/macOS/CmuxSettings/Sources/CmuxSettings/Values/ShortcutAction.swift
  • Resources/Localizable.xcstrings
  • Sources/AppDelegate.swift
  • Sources/ClosedItemHistory.swift
  • Sources/ClosedWorkspaceHistory.swift
  • Sources/CmuxConfigExecutor+WorkspaceLaunch.swift
  • Sources/ContentView+RightSidebarCommandPalette.swift
  • Sources/ContentView.swift
  • Sources/KeyboardShortcutSettings.swift
  • Sources/SessionPersistence.swift
  • Sources/TabManager+DetachedWorkspace.swift
  • Sources/TabManager+SavedLayouts.swift
  • Sources/TabManager+WorkspaceCustomTitle.swift
  • Sources/TabManager+WorkspaceDirectoryCustomization.swift
  • Sources/TabManager.swift
  • Sources/Workspace.swift
  • Sources/WorkspaceDirectoryCustomization.swift
  • Sources/WorkspaceDirectoryCustomizationStore.swift
  • Sources/cmuxApp+HistoryMenu.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/WorkspaceRecoveryTests.swift
  • skills/cmux-settings/references/shortcut-actions.md
  • web/data/cmux-shortcuts.ts
  • web/data/cmux.schema.json

Comment thread Sources/ClosedWorkspaceHistory.swift Outdated
Comment thread web/data/cmux-shortcuts.ts
…sed-workspace

# Conflicts:
#	Sources/TabManager.swift
@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/ContentView.swift (1)

7015-7022: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the palette submenu translation coverage.

menu.history.reopenClosedWorkspace is localized only for en and ja, while the nearby history palette items cover the full supported catalog. Add matching translations for the remaining supported locales in Resources/Localizable.xcstrings.

🤖 Prompt for 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.

In `@Sources/ContentView.swift` around lines 7015 - 7022, Extend the
menu.history.reopenClosedWorkspace entry in Resources/Localizable.xcstrings with
translations for every supported locale currently missing, matching the coverage
and established wording of the nearby history palette items while preserving the
existing en and ja translations.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@Sources/ContentView.swift`:
- Around line 7015-7022: Extend the menu.history.reopenClosedWorkspace entry in
Resources/Localizable.xcstrings with translations for every supported locale
currently missing, matching the coverage and established wording of the nearby
history palette items while preserving the existing en and ja translations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 145f92d7-7562-4f40-91ad-6aa5fa93bcf8

📥 Commits

Reviewing files that changed from the base of the PR and between f5af960 and 787b8a5.

📒 Files selected for processing (7)
  • Resources/Localizable.xcstrings
  • Sources/AppDelegate.swift
  • Sources/ContentView.swift
  • Sources/SessionPersistence.swift
  • Sources/TabManager.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/AppDelegate.swift (1)

7469-7512: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Disable directory customization for the Cloud VM synthetic workspace.

context.tabManager.addWorkspace(...) for .cloudVMLoading still uses the default shouldApplyWorkspaceDirectoryCustomization: true. With inheritWorkingDirectory: false and no explicit workingDirectory, this workspace can resolve to a fallback directory and inherit stored workspace customization meant for a real directory-based workspace, like the Remote tmux mirror workspace does.

🐛 Proposed fix
             workspace = context.tabManager.addWorkspace(
                 title: workspaceTitle,
                 titleSource: .auto,
                 initialSurface: .cloudVMLoading,
                 inheritWorkingDirectory: false,
                 select: true,
-                autoWelcomeIfNeeded: false
+                autoWelcomeIfNeeded: false,
+                shouldApplyWorkspaceDirectoryCustomization: false
             )
🤖 Prompt for 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.

In `@Sources/AppDelegate.swift` around lines 7469 - 7512, Update the addWorkspace
call in performCloudVMAction for the .cloudVMLoading synthetic workspace to
disable directory customization by passing
shouldApplyWorkspaceDirectoryCustomization: false. Preserve the existing
inheritWorkingDirectory: false behavior and all other workspace setup options.
🤖 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.

Outside diff comments:
In `@Sources/AppDelegate.swift`:
- Around line 7469-7512: Update the addWorkspace call in performCloudVMAction
for the .cloudVMLoading synthetic workspace to disable directory customization
by passing shouldApplyWorkspaceDirectoryCustomization: false. Preserve the
existing inheritWorkingDirectory: false behavior and all other workspace setup
options.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ae7e6847-2a21-479d-86f0-21cff75ec51e

📥 Commits

Reviewing files that changed from the base of the PR and between bc8f3bc and 227b81d.

📒 Files selected for processing (12)
  • Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Customization/WorkspaceDirectoryCustomization.swift
  • Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Customization/WorkspaceDirectoryCustomizationStore.swift
  • Packages/macOS/CmuxWorkspaces/Tests/CmuxWorkspacesTests/Customization/WorkspaceDirectoryCustomizationStoreTests.swift
  • Sources/AppDelegate+MoveTabToNewWorkspace.swift
  • Sources/AppDelegate.swift
  • Sources/ClosedWorkspaceHistory.swift
  • Sources/ContentView.swift
  • Sources/RemoteTmuxController.swift
  • Sources/TabManager+DetachedWorkspace.swift
  • Sources/TabManager+WorkspaceDirectoryCustomization.swift
  • Sources/TabManager.swift
  • cmuxTests/WorkspaceRecoveryTests.swift
💤 Files with no reviewable changes (1)
  • Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Customization/WorkspaceDirectoryCustomization.swift

Comment on lines 303 to 307
let workspace = tabManager.addWorkspace(
title: sessionName,
title: sessionName, titleSource: .auto,
select: false,
autoWelcomeIfNeeded: false
autoWelcomeIfNeeded: false, shouldApplyWorkspaceDirectoryCustomization: false
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Remote tmux workspace label silently dropped

The title: sessionName argument is now a no-op. In addWorkspace, the title is only applied inside applyWorkspaceDirectoryCustomization, which is gated on shouldApplyWorkspaceDirectoryCustomization. When that flag is false, the workspace's customTitle is never set and the session name never appears in the sidebar. The CmuxConfigExecutor path that also passes shouldApplyWorkspaceDirectoryCustomization: false works around this by calling tabManager.setCustomTitle(tabId: newWorkspace.id, title: workspaceName, source: .auto) immediately after — there is no equivalent compensating call here.

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.

Reopen closed workspace + persist per-repo color/label: closing a workspace permanently loses its customization

1 participant