Skip to content

Extract sidebar drag state machine from ContentView into CmuxSidebarDragCoordinator - #6172

Closed
azooz2003-bit wants to merge 1 commit into
mainfrom
feat-sidebar-drag-orchestration
Closed

azooz2003-bit wants to merge 1 commit into
mainfrom
feat-sidebar-drag-orchestration

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 15, 2026 •

Copy link
Copy Markdown
Collaborator

What moved

The sidebar drag/drop state machine moves out of the ContentView.swift god file into a new domain package Packages/CmuxSidebarDragCoordinator (depends only on CmuxFoundation):

  • SidebarDragState — @MainActor @Observable Coordinator owning transient drag state (draggedTabId, dropIndicator, isSimulated, foreignDraggedIsPinned; beginDragging/setDropIndicator/clearDrag). Its former static reach into the cross-window registry is inverted via a constructor-injected any SidebarWorkspaceDragRegistering.
  • SidebarWorkspaceDragRegistry — the process-wide cross-window dragged-workspace identity, converted from a caseless static-namespace enum into a real @MainActor final class behind a protocol seam, owned by AppDelegate (the composition root) and injected.
  • SidebarDragStateRegistry (#if DEBUG) — the windowId -> SidebarDragState map read by the debug.sidebar.simulate_drag profiling handler, likewise converted from a static-namespace enum to an AppDelegate-owned instance.

Seams inverted

  • SidebarTabDropDelegate's former SidebarWorkspaceDragRegistry.currentWorkspaceId reads now go through the injected coordinator (dragState.currentWorkspaceDragId).
  • The DEBUG SidebarDragStateRegistry.{register,unregister,state} calls in ContentView/TerminalController forward to AppDelegate.shared?.sidebar*Registry.
  • An app-side SidebarDragState.convenience init() keeps the @State var dragState = SidebarDragState() call site byte-identical by injecting AppDelegate's shared registry (fresh-registry fallback only if AppDelegate.shared is nil, never the case once a sidebar has mounted).

Byte-identical notes

No Defaults keys, NotificationCenter names, wire formats, or logic changed. The only change is the declaration site of these types plus injection of an already-process-wide value (a singleton in all but name). clearDrag's originated-vs-foreign guard, the end() stale-clear no-op, and the simulate-drag flow are preserved exactly.

Scope decision

The pure drop predicates/planner (SidebarTabDropIndicatorPredicate, SidebarDropPlanner, SidebarDropIndicator, SidebarWorkspaceSelectionSyncPolicy in CmuxFoundation) and the autoscroll service (SidebarDragAutoScroll* in CmuxAppKitSupportUI) were already extracted by prior refactor waves, so this PR takes the remaining clean subset: the state machine + cross-window identity. The SwiftUI SidebarTabDropDelegate is a DropDelegate welded to TabManager, AppDelegate.shared cross-window methods, @Bindings, and DropInfo; moving it would require inverting ~10 collaborator methods at high behavior-drift risk, so it is intentionally left in the app target (it now consumes the package types).

Tests

6 behavior unit tests with a fake SidebarWorkspaceDragRegistering seam covering begin/clear, originating-vs-mirrored-foreign clear semantics, the top-level indicator flag, and the registry stale-clear no-op. swift build + swift test pass in the package.

Verification

  • scripts/lint-ios-package-conventions.sh: OK, zero new lint:allow.
  • Packages/CmuxSidebarDragCoordinator swift build + swift test: pass.
  • .github/swift-file-length-budget.tsv reconciled (ContentView.swift ratcheted down ~112 lines).
  • Package wired into cmux.xcodeproj (6 pbxproj entries mirroring CmuxSidebarGit) and added as an app-target dependency.

Est. lines removed from the ContentView giant: ~112.

NOTE: the full app build + XCUITests are validated by GitHub CI; per refactor protocol they were not run locally.

🤖 Generated with Claude Code


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


Summary by cubic

Extracted the sidebar drag/drop state machine into a new CmuxSidebarDragCoordinator package and replaced static globals with injected registries for better modularity and cross-window drag handling. Behavior is unchanged.

  • Refactors

    • Moved SidebarDragState, SidebarWorkspaceDragRegistry, and DEBUG SidebarDragStateRegistry to CmuxSidebarDragCoordinator.
    • Introduced SidebarWorkspaceDragRegistering and SidebarWorkspaceDragRegistry (@MainActor); owned by AppDelegate and injected.
    • SidebarTabDropDelegate now reads cross-window drag via dragState.currentWorkspaceDragId.
    • Added app-side SidebarDragState convenience init to keep @State var dragState = SidebarDragState() call sites unchanged.
    • Trimmed ContentView.swift by ~112 lines.
  • Dependencies

    • Added Packages/CmuxSidebarDragCoordinator (depends on CmuxFoundation) and wired it into cmux.xcodeproj.
    • Added 6 unit tests in the new package; swift build and swift test pass.

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

Review in cubic

Summary by CodeRabbit

  • Refactor

    • Extracted sidebar drag-and-drop coordination logic into a dedicated package for improved code maintainability and cross-window functionality.
  • Tests

    • Added comprehensive test coverage for drag-and-drop state management and cross-window workspace coordination.

Moves the sidebar drag/drop state machine out of ContentView.swift into a new
domain package, CmuxSidebarDragCoordinator (depends only on CmuxFoundation):

- SidebarDragState: @mainactor @observable Coordinator (begin/clear drag,
  drop-indicator state). Inverts its former static reach into the cross-window
  registry via a constructor-injected `any SidebarWorkspaceDragRegistering`.
- SidebarWorkspaceDragRegistry: the process-wide cross-window drag identity,
  converted from a caseless static-namespace enum into a real @mainactor class
  behind a protocol seam, owned by AppDelegate (composition root) and injected.
- SidebarDragStateRegistry (#if DEBUG): the windowId->SidebarDragState map used
  by the debug.sidebar.simulate_drag profiling handler, likewise converted from
  a static-namespace enum to an AppDelegate-owned instance.

Seams inverted: the former `SidebarWorkspaceDragRegistry.currentWorkspaceId`
reads in SidebarTabDropDelegate now go through the injected coordinator
(`dragState.currentWorkspaceDragId`); the DEBUG registry calls in
ContentView/TerminalController forward to `AppDelegate.shared?.sidebar*Registry`.
An app-side `SidebarDragState.convenience init()` keeps the `@State` call site
byte-identical by injecting AppDelegate's shared registry.

Byte-identical: no Defaults keys, NotificationCenter names, wire formats, or
logic changed; only declaration site + injection of an already-process-wide
value. The pure drop predicates/planner (CmuxFoundation) and autoscroll service
(CmuxAppKitSupportUI) were already extracted by prior waves; the entangled
SwiftUI SidebarTabDropDelegate (welded to TabManager/AppDelegate/@binding) is
left in the app target intentionally.

Adds behavior unit tests with a fake registry seam (6 tests). New package wired
into cmux.xcodeproj (6 pbxproj entries mirroring CmuxSidebarGit) and added as an
app-target dependency. Budget ratcheted: ContentView.swift -112 lines.

NOTE: app build validated by CI (not run locally per refactor protocol).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 15, 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 15, 2026 7:51pm
cmux-staging Building Building Preview, Comment Jun 15, 2026 7:51pm

@coderabbitai

coderabbitai Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A new local Swift package CmuxSidebarDragCoordinator is introduced containing SidebarWorkspaceDragRegistering/SidebarWorkspaceDragRegistry, SidebarDragState, and a debug-only SidebarDragStateRegistry. These types are extracted from the main app target; AppDelegate takes ownership of the singletons, and ContentView, TerminalController, and SidebarWorkspaceGroupHeaderView are updated to consume them via AppDelegate.shared.

Changes

CmuxSidebarDragCoordinator Package Extraction and App Wiring

Layer / File(s) Summary
Package manifest and Xcode project wiring
Packages/CmuxSidebarDragCoordinator/Package.swift, cmux.xcodeproj/project.pbxproj
Package.swift declares the library with macOS 14+, Swift 6, and a local CmuxFoundation dependency. The Xcode project gains PBXBuildFile, framework phase, and local package reference entries for CmuxSidebarDragCoordinator.
Cross-window SidebarWorkspaceDragRegistering protocol and registry
Packages/CmuxSidebarDragCoordinator/Sources/.../SidebarWorkspaceDragRegistry.swift
SidebarWorkspaceDragRegistering defines the @MainActor protocol for the process-wide active workspace drag ID. SidebarWorkspaceDragRegistry implements it in memory, clearing only when end(workspaceId:) matches the stored active ID to prevent stale drag termination.
Per-window SidebarDragState observable class
Packages/CmuxSidebarDragCoordinator/Sources/.../SidebarDragState.swift
SidebarDragState is a @MainActor @Observable`` class holding per-window transient drag/drop state. beginDragging registers globally; `clearDrag` ends the registry entry only when this window originated the drag. `currentWorkspaceDragId` forwards the registry value for cross-window rendering.
Debug-only SidebarDragStateRegistry and AppDelegate ownership
Packages/CmuxSidebarDragCoordinator/Sources/.../SidebarDragStateRegistry.swift, Sources/AppDelegate.swift
SidebarDragStateRegistry (#if DEBUG) stores live SidebarDragState per window UUID. AppDelegate gains sidebarWorkspaceDragRegistry (always) and sidebarDragStateRegistry (#if DEBUG) as process-wide owned instances.
Unit tests for SidebarDragState and SidebarWorkspaceDragRegistry
Packages/CmuxSidebarDragCoordinator/Tests/.../SidebarDragStateTests.swift
FakeWorkspaceDragRegistry supports assertion-based testing. SidebarDragStateTests covers beginDragging, clearDrag origin vs. foreign guard, drop-indicator usesTopLevelRows tracking, and currentWorkspaceDragId forwarding. SidebarWorkspaceDragRegistryTests verifies stale-ID no-op behavior.
App-side wiring
Sources/ContentView.swift, Sources/TerminalController.swift, Sources/SidebarWorkspaceGroupHeaderView.swift
ContentView adds a SidebarDragState convenience initializer using AppDelegate.shared?.sidebarWorkspaceDragRegistry, switches debug lifecycle hooks to AppDelegate.shared?.sidebarDragStateRegistry, and updates effectiveDraggedTabId/activateForeignDragIfNeeded to read dragState.currentWorkspaceDragId. TerminalController's v2DebugSidebarSimulateDrag lookups are updated to use AppDelegate.shared?.sidebarDragStateRegistry.

Sequence Diagram(s)

sequenceDiagram
  participant Sidebar as VerticalTabsSidebar (ContentView)
  participant State as SidebarDragState
  participant AppRegistry as SidebarWorkspaceDragRegistry (AppDelegate)
  participant DropDelegate as SidebarTabDropDelegate

  Sidebar->>State: SidebarDragState() [convenience init]
  State->>AppRegistry: injects AppDelegate.shared?.sidebarWorkspaceDragRegistry

  Sidebar->>State: beginDragging(tabId:)
  State->>AppRegistry: begin(workspaceId: tabId)

  DropDelegate->>State: currentWorkspaceDragId
  State->>AppRegistry: currentWorkspaceId
  AppRegistry-->>State: UUID?
  State-->>DropDelegate: UUID? (used as effectiveDraggedTabId)

  Sidebar->>State: clearDrag()
  alt originatedActiveDrag == true
    State->>AppRegistry: end(workspaceId: tabId)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • manaflow-ai/cmux#5399: Implements the cross-window sidebar workspace move/drop behavior in ContentView.swift and AppDelegate.swift using the same SidebarWorkspaceDragRegistry and SidebarDragState types that this PR extracts into the coordinator package.
  • manaflow-ai/cmux#4771: Implements v2DebugSidebarSimulateDrag using SidebarDragStateRegistry and SidebarDragState.isSimulated, the exact code paths updated in TerminalController.swift by this PR.

Poem

🐇 Hop, hop! I tidied the drag,
Into a package neatly bagged.
No more globals scattered wide,
AppDelegate holds them all inside.
Swift 6 strict, the registries sing—
A cleaner warren, just the thing! 🎉


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 Source Artifacts ❌ Error PR adds runtime/generated artifacts: .claude/scheduled_tasks.lock (session lock with PID/timestamp) and .greptile/files.json (generated file cache), violating source-control-artifacts.md rules. Remove .claude/scheduled_tasks.lock and .greptile/files.json from the commit, or add narrow .gitignore patterns to exclude Greptile/Claude cache/lock files.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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 and concisely summarizes the main change: extracting the sidebar drag state machine from ContentView into a new coordinator package, which aligns perfectly with the PR's primary objective.
Description check ✅ Passed The PR description comprehensively covers all template sections with detailed technical context, testing information, and verification steps, though it lacks a demo video link and explicit checklist completion markers.
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 Swift Actor Isolation ✅ Passed All new types properly marked with @MainActor: SidebarDragState (@MainActor @Observable), SidebarWorkspaceDragRegistering (@MainActor protocol), SidebarWorkspaceDragRegistry (@MainActor class), Sid...
Cmux Swift Blocking Runtime ✅ Passed New CmuxSidebarDragCoordinator package contains zero blocking primitives, sleep operations, or locks. All synchronization uses @MainActor isolation. No blocking patterns introduced in app-side modi...
Cmux Expensive Synchronous Load ✅ Passed PR introduces lightweight in-memory registries (SidebarDragState, SidebarWorkspaceDragRegistry, SidebarDragStateRegistry) with only simple property assignments and dictionary operations—no expensiv...
Cmux Cache Substitution Correctness ✅ Passed The PR does not introduce cache substitution issues. The sidebar drag registries are transient in-memory state holders with no persistence or undo/history dependency, explicitly allowed by the rule...
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift source and Xcode project changes; the rule explicitly covers TypeScript, JavaScript, shell, and non-Swift build/runtime scripts. Swift is out of scope for this rule.
Cmux Algorithmic Complexity ✅ Passed The PR introduces no algorithmic complexity violations per .github/review-bot-rules/algorithmic-complexity.md. All new code (SidebarDragState, SidebarWorkspaceDragRegistry, SidebarDragStateRegistry...
Cmux Swift Concurrency ✅ Passed PR introduces no new DispatchQueue background work, Combine state, completion handlers, or fire-and-forget Tasks. Uses modern @MainActor actors and @Observable patterns instead.
Cmux Swift @Concurrent ✅ Passed PR adds new @MainActor synchronous methods across SidebarDragState, SidebarWorkspaceDragRegistry, and SidebarDragStateRegistry; no async functions or improper @concurrent annotations introduced. Al...
Cmux Swift File And Package Boundaries ✅ Passed PR properly extracts sidebar drag state machine from ContentView.swift into small, focused package files (101/55/39 lines) with clear single responsibilities. No mixing of UI/state/persistence/netw...
Cmux Swift Logging ✅ Passed PR adds no logging statements. All new package code is logging-free; modified app files add no logging. Three pre-existing NSLog calls in AppDelegate are unrelated to the sidebar drag refactor.
Cmux User-Facing Error Privacy ✅ Passed PR adds no user-facing error messages. New CmuxSidebarDragCoordinator package contains only internal types (classes/protocols) with doc comments. Errors in v2DebugSidebarSimulateDrag are DEBUG-only...
Cmux Full Internationalization ✅ Passed PR adds only internal state machine types, registries, and test code with no user-facing text, localization keys, or string catalog modifications.
Cmux Swiftui State Layout ✅ Passed SidebarDragState uses modern @Observable (not ObservableObject). All state mutations occur in lifecycle/event handlers, not render. LazyVStack rows receive value snapshots, not store references. No...
Cmux Architecture Rethink ✅ Passed PR follows Swift architectural guidelines: no timing/blocking repairs, duplicate ownership, split lifecycle, or symptom patches. Clear state owners, injectable seams, and preserved invariants.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR extracts sidebar drag state into a new package but introduces no NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup code; only state/registry management classes.
✨ 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 feat-sidebar-drag-orchestration

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 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts the sidebar drag/drop state machine from ContentView.swift into a new CmuxSidebarDragCoordinator SwiftPM package, converting two static-namespace enum globals into proper @MainActor final class instances owned by AppDelegate and injected via a protocol seam.

  • SidebarDragState, SidebarWorkspaceDragRegistry, and (DEBUG) SidebarDragStateRegistry move to the new package; all actor isolation, the originatedActiveDrag guard, and the stale-clear no-op are preserved byte-identical.
  • An app-side convenience init() extension on SidebarDragState keeps every @State var dragState = SidebarDragState() call site unchanged by reading the shared registry from AppDelegate; the fallback to a fresh registry when AppDelegate.shared is nil silently creates an orphaned instance not shared across windows.

Confidence Score: 4/5

Safe to merge; the extraction is clean, all semantics are preserved, and the only concern is a silent fallback path in the convenience init that isn't expected to fire in production.

The refactor is well-scoped and correct: actor isolation, the originating-vs-mirrored-foreign guard, and the stale-clear no-op are all preserved. The one gap is the convenience init() fallback — if AppDelegate.shared happens to be nil at @State initialization time, the new SidebarDragState gets a private orphaned registry rather than the shared one, silently breaking cross-window drag detection for that window with no diagnostic. The previous static enum never had this failure mode. In practice this path doesn't fire once a sidebar has mounted, but there is no assertion to enforce that invariant.

The app-side convenience init() extension in Sources/ContentView.swift is the only place that needs attention.

Important Files Changed

Filename Overview
Sources/ContentView.swift ~112 lines removed; app-side convenience init() extension injects AppDelegate's shared registry but silently falls back to an orphaned registry if AppDelegate is nil.
Packages/CmuxSidebarDragCoordinator/Sources/CmuxSidebarDragCoordinator/SidebarDragState.swift New @MainActor @Observable coordinator; clean actor isolation, injected seam, originatedActiveDrag guard preserved correctly.
Packages/CmuxSidebarDragCoordinator/Sources/CmuxSidebarDragCoordinator/SidebarWorkspaceDragRegistry.swift Protocol seam and concrete registry class; stale-clear guard preserved, @MainActor throughout, clean conversion from static enum.
Sources/AppDelegate.swift Adds sidebarWorkspaceDragRegistry and (DEBUG) sidebarDragStateRegistry as let composition-root properties; correct ownership pattern.
Sources/TerminalController.swift Four SidebarDragStateRegistry static calls updated to AppDelegate.shared?.sidebarDragStateRegistry; semantics preserved, all guarded by existing nil checks.

Sequence Diagram

sequenceDiagram
    participant AD as AppDelegate (composition root)
    participant CV as ContentView (@State dragState)
    participant SDS as SidebarDragState
    participant SWDR as SidebarWorkspaceDragRegistry
    participant SDD as SidebarTabDropDelegate

    AD->>AD: init sidebarWorkspaceDragRegistry
    AD->>CV: create window / ContentView
    CV->>SDS: SidebarDragState() [convenience init]
    SDS->>AD: AppDelegate.shared?.sidebarWorkspaceDragRegistry
    AD-->>SDS: shared SidebarWorkspaceDragRegistry instance
    SDS->>SDS: store workspaceDragRegistry

    Note over CV,SDS: Drag begins in originating window
    CV->>SDS: beginDragging(tabId:)
    SDS->>SWDR: begin(workspaceId:)
    SWDR->>SWDR: "activeWorkspaceId = tabId"

    Note over SDD: Drop in destination window
    SDD->>SDS: dragState.currentWorkspaceDragId
    SDS->>SWDR: currentWorkspaceId
    SWDR-->>SDS: tabId (cross-window identity)
    SDS-->>SDD: foreignId resolved

    Note over CV,SDS: Drag ends
    CV->>SDS: clearDrag()
    SDS->>SWDR: end(workspaceId:) [only if originated]
    SWDR->>SWDR: "activeWorkspaceId = nil"
Loading

Reviews (1): Last reviewed commit: "Extract sidebar drag state machine into ..." | Re-trigger Greptile

Comment thread Sources/ContentView.swift
Comment on lines +10072 to 10077
convenience init() {
self.init(
workspaceDragRegistry: AppDelegate.shared?.sidebarWorkspaceDragRegistry
?? SidebarWorkspaceDragRegistry()
)
}

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 The convenience init() falls back to a brand-new SidebarWorkspaceDragRegistry() when AppDelegate.shared is nil. That orphaned instance is not the same object stored in AppDelegate.sidebarWorkspaceDragRegistry, so any SidebarDragState created through this path would have cross-window drag detection silently broken: currentWorkspaceDragId would always return nil when a drag originates in another window. The original static enum never had this failure mode. Adding an assertionFailure in DEBUG guards against this regressing silently in future test harnesses or early-lifecycle code paths.

Suggested change
convenience init() {
self.init(
workspaceDragRegistry: AppDelegate.shared?.sidebarWorkspaceDragRegistry
?? SidebarWorkspaceDragRegistry()
)
}
convenience init() {
let registry: any SidebarWorkspaceDragRegistering
if let shared = AppDelegate.shared {
registry = shared.sidebarWorkspaceDragRegistry
} else {
assertionFailure("SidebarDragState() called before AppDelegate is available; cross-window drag detection will be broken for this instance")
registry = SidebarWorkspaceDragRegistry()
}
self.init(workspaceDragRegistry: registry)
}

@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/ContentView.swift`:
- Around line 10068-10077: The convenience initializer for SidebarDragState
silently falls back to creating an isolated SidebarWorkspaceDragRegistry when
AppDelegate.shared is unavailable, which masks cross-window drag coordination
bugs rather than surfacing the unexpected state. Since the code comment asserts
this should never happen after a sidebar mounts, add a defensive assertion
before the fallback to catch any unexpected early initialization scenarios and
alert developers to this problematic condition, while keeping the fallback for
safety.
🪄 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: 8e90e795-2645-4a35-9903-b6adeac777cf

📥 Commits

Reviewing files that changed from the base of the PR and between 5321bec and 8f2fe27.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (10)
  • Packages/CmuxSidebarDragCoordinator/Package.swift
  • Packages/CmuxSidebarDragCoordinator/Sources/CmuxSidebarDragCoordinator/SidebarDragState.swift
  • Packages/CmuxSidebarDragCoordinator/Sources/CmuxSidebarDragCoordinator/SidebarDragStateRegistry.swift
  • Packages/CmuxSidebarDragCoordinator/Sources/CmuxSidebarDragCoordinator/SidebarWorkspaceDragRegistry.swift
  • Packages/CmuxSidebarDragCoordinator/Tests/CmuxSidebarDragCoordinatorTests/SidebarDragStateTests.swift
  • Sources/AppDelegate.swift
  • Sources/ContentView.swift
  • Sources/SidebarWorkspaceGroupHeaderView.swift
  • Sources/TerminalController.swift
  • cmux.xcodeproj/project.pbxproj

Comment thread Sources/ContentView.swift
Comment on lines +10068 to 10077
extension SidebarDragState {
/// Builds a drag state wired to the app's process-wide cross-window drag
/// registry. Falls back to a fresh registry only if `AppDelegate.shared` is
/// not yet available (never the case once a sidebar has mounted).
convenience init() {
self.init(
workspaceDragRegistry: AppDelegate.shared?.sidebarWorkspaceDragRegistry
?? SidebarWorkspaceDragRegistry()
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Silent fallback to isolated registry could mask cross-window drag bugs.

The fallback ?? SidebarWorkspaceDragRegistry() creates an isolated registry if AppDelegate.shared is unavailable. This silently breaks cross-window drag coordination rather than surfacing the unexpected state. Since the comment claims this is "never the case once a sidebar has mounted," consider an assertion to catch any unexpected early initialization:

Proposed defensive assertion
 extension SidebarDragState {
     /// Builds a drag state wired to the app's process-wide cross-window drag
     /// registry. Falls back to a fresh registry only if `AppDelegate.shared` is
     /// not yet available (never the case once a sidebar has mounted).
     convenience init() {
+        let registry = AppDelegate.shared?.sidebarWorkspaceDragRegistry
+        `#if` DEBUG
+        if registry == nil {
+            assertionFailure("SidebarDragState initialized before AppDelegate.shared available")
+        }
+        `#endif`
         self.init(
-            workspaceDragRegistry: AppDelegate.shared?.sidebarWorkspaceDragRegistry
-                ?? SidebarWorkspaceDragRegistry()
+            workspaceDragRegistry: registry ?? SidebarWorkspaceDragRegistry()
         )
     }
 }
🤖 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 10068 - 10077, The convenience
initializer for SidebarDragState silently falls back to creating an isolated
SidebarWorkspaceDragRegistry when AppDelegate.shared is unavailable, which masks
cross-window drag coordination bugs rather than surfacing the unexpected state.
Since the code comment asserts this should never happen after a sidebar mounts,
add a defensive assertion before the fallback to catch any unexpected early
initialization scenarios and alert developers to this problematic condition,
while keeping the fallback for safety.

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Superseded by #6226 — consolidated into the existing CmuxSidebar package (no new micro-package) per over-engineering review. The extraction is preserved there.

This branch was successfully deployed

1 active deployment
Preview – cmux — 8f2fe278 Deployed Jun 15, 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.

1 participant