Skip to content

Organize SPM packages into Packages/{Shared,iOS,macOS}/ so the folder tree mirrors the Xcode workspace groups - #6278

Merged
azooz2003-bit merged 1 commit into
mainfrom
task-spm-package-groups
Jun 17, 2026
Merged

azooz2003-bit merged 1 commit into
mainfrom
task-spm-package-groups

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

Summary

The root cmux.xcworkspace grouped packages into Shared / iOS / macOS columns, but on disk every package sat flat under Packages/, so the group structure wasn't visible as folders in the repo. This makes the folder tree the source of truth and the same shape as the workspace: every Swift package now lives physically under exactly one group directory, and the workspace mirrors it one-to-one.

  • Packages/Shared/<pkg> — used by both the macOS and iOS apps
  • Packages/iOS/<pkg> — iOS app only
  • Packages/macOS/<pkg> — macOS app only

All 74 packages were git mvd into their group folder (Shared 5 / iOS 15 / macOS 54). The three workspace groups now have container:Packages/Shared|iOS|macOS locations, so opening the workspace shows each package under the group matching the folder it lives in. Classification (which folder) was computed from app dependency closures: reachable from both apps → Shared, iOS-app-only → iOS, macOS-app-only → macOS, orphans by declared platforms.

Every relative path that crosses the package boundary was rewritten so the build is unaffected:

  • inter-package deps: same group ../Name, cross group ../../<Group>/Name
  • escaping paths gain one directory level: vendor ../../../vendor/..., GhosttyKit binary target ../../../GhosttyKit.xcframework
  • macOS cmux.xcodeproj relativePaths, ios/cmuxPackage + Examples package deps and their .xcodeproj relativePaths, .github/swift-file-length-budget.tsv, the lint-ios-package-conventions.sh scopes, lint-namespace-types-baseline.txt, the test-ios.yml change-detection globs, and doc/skill references all point at the nested paths.

scripts/check-workspace-package-groups.py now mirrors the folders directly (a package's group is its parent directory). --write regenerates contents.xcworkspacedata; --check is wired into the CI lint job and fails on drift. The rule is documented in CLAUDE.md/AGENTS.md: to regroup a package, git mv its folder and re-run --write; never hand-edit the workspace.

Testing

Metadata/path-only change (no app/runtime behavior), so no tagged reload.

  • python3 scripts/check-workspace-package-groups.py --check → OK; re-running --write is idempotent. All 74 packages covered, 0 missing, 0 dangling.
  • swift package dump-package resolves a package closure crossing Shared↔iOS boundaries (../../<group>/... paths), confirming the rewrites resolve through SwiftPM, not just on disk.
  • A structural check confirms every path: in every manifest and every pbxproj relativePath resolves to an existing directory.
  • xcodebuild -list -workspace cmux.xcworkspace finds every package at its new nested path; the only remaining errors are the pre-existing environmental ones (uninitialized vendor/bonsplit submodule + unbuilt GhosttyKit binary target + an existing GhosttyRuntimeTestStubs target-name clash), byte-identical to the pre-change baseline. A full Xcode resolve needs scripts/setup.sh (submodule init + zig GhosttyKit build) and isn't possible in a fresh worktree.
  • ./scripts/check-pbxproj.sh (pbxproj normalized), python3 scripts/swift_file_length_budget.py (budget paths), and ./scripts/lint-ios-package-conventions.sh (scopes resolve) all pass.

A source-shape test asserting specific FileRefs would just restate the generator output, so the generator's deterministic --check in CI is the right behavior-level proof.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 16, 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 17, 2026 1:04am
cmux-staging Building Building Preview, Comment Jun 17, 2026 1:04am

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Too many files!

This PR contains 299 files, which is 149 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 31523fac-4178-4183-ac40-d7a8ad81e5d7

📥 Commits

Reviewing files that changed from the base of the PR and between dae0e84 and eff93a4.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (299)
  • .github/workflows/ci.yml
  • .github/workflows/test-ios.yml
  • CLAUDE.md
  • Examples/CmuxExtensionSidebarExamples/Package.swift
  • Examples/SampleSidebarExtensionApp/SampleSidebarExtensionApp.xcodeproj/project.pbxproj
  • Examples/StubAgentSidebarExtension/Package.swift
  • Examples/TabsVisibleSidebar/TabsVisibleSidebar.xcodeproj/project.pbxproj
  • Packages/Shared/CMUXAuthCore/Package.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthAutoLoginCredentials.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthConfig.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthEnvironment.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthMagicLinkCode.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthState.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthTeam.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthUser+UITestFixture.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Models/CMUXAuthUser.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Persistence/CMUXAuthIdentityStore.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Persistence/CMUXAuthKeyValueStore.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Persistence/CMUXAuthSessionCache.swift
  • Packages/Shared/CMUXAuthCore/Sources/CMUXAuthCore/Persistence/CMUXAuthTeamSelectionStore.swift
  • Packages/Shared/CMUXAuthCore/Tests/CMUXAuthCoreTests/CMUXAuthStateTests.swift
  • Packages/Shared/CMUXAuthCore/Tests/CMUXAuthCoreTests/CMUXAuthTeamSelectionStoreTests.swift
  • Packages/Shared/CMUXMobileCore/Package.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/AnalyticsEmitting.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/AnalyticsValue.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxAttachTicketCompactCoder.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxLoopbackHost.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxManualPairingEntry.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxPairingQRBitmap.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxPairingQRCode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxPairingURLScheme.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxTransport.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CompactAttachEndpoint.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CompactAttachRoute.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CompactAttachTicket.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/ComposerDockIntent.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/ComposerDockReducer.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/ConnectionOutageThrottle.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEvent.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventCode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/InputResponderIdentity.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSyncProtocol.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileTerminalRenderGrid.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileTerminalRenderGridReplay.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/NoopAnalytics.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TerminalGridSize.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxAttachTicketCodingTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxAttachTicketCompactCoderTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxLoopbackHostTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxManualPairingEntryTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxPairingQRBitmapTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxPairingQRCodeTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxPairingURLSchemeTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxTransportTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/ComposerDockReducerTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/ConnectionOutageThrottleTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileSyncProtocolTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileTerminalRenderGridTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/TerminalGridSizeTests.swift
  • Packages/Shared/CmuxAgentChat/Package.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatAgentKind.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatAgentState.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatAttachment.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatFileEdit.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatMessage.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatMessageKind.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatOutboundAttachment.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatPermissionRequest.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatProse.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatQuestion.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatRole.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatSessionDescriptor.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatSessionKind.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatStatusTransition.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatTerminalCapture.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatThought.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatToolUse.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/ChatUnsupportedPayload.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Model/TerminalCommandBlock.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/ChatTranscriptParseResult.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/ChatTranscriptParseState.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/ClaudeTranscriptParser.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/CodexTranscriptParser.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/OSC133CommandParser.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/TranscriptBatchAssembler.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/TranscriptDiffBuilder.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/TranscriptJSONValue.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/TranscriptTextBudget.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/TranscriptTimestampParser.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/TranscriptToolCompletion.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Source/ChatEventSource.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Source/FixtureChatEventSource.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatConversationStore.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatDeliveryState.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatGroupPosition.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatMessageRowSnapshot.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatPendingOutbound.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatSessionListReducer.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatTranscriptProjector.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatTranscriptRow.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Wire/ChatHistoryPage.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Wire/ChatSessionEvent.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Wire/ChatSessionEventFrame.swift
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Wire/ChatWireCoding.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ChatConversationStoreTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ChatMessageCodableTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ChatSessionListReducerTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ChatSessionOrderingTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ChatTranscriptProjectorTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ClaudeTranscriptParserTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/CodexTranscriptParserTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/OSC133CommandParserTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/TerminalCommandRowTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/TerminalConversationStoreTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/TerminalWireCodableTests.swift
  • Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/TranscriptBatchAssemblerTests.swift
  • Packages/Shared/CmuxAuthRuntime/.gitignore
  • Packages/Shared/CmuxAuthRuntime/Package.swift
  • Packages/Shared/CmuxAuthRuntime/README.md
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/ASWebBrowserAuthSessionFactory.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/AuthCallbackPayload.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/AuthCallbackRouter.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserAuthSession.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/BrowserSignIn/HostBrowserSignInFlow.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Client/AuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Client/StackAuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthConfig.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthCoordinator+SessionPriming.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthCoordinator+Tokens.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthCoordinator.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthError+DisplaySafe.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthError.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthLaunchOptions.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthPhase.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthPhaseTimeout.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthTimeouts.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/CachedSessionValidationFailureAction.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/TokenProviding.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Diagnostics/AuthDebugLog.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Presentation/AuthPresentationAnchoring.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Presentation/AuthPresentationContextProvider.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Push/PushRegistering.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Push/PushRegistrationService.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/TokenStores/AuthTokenSnapshot.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/TokenStores/FallbackTokenStore.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/TokenStores/FileStackTokenStore.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/TokenStores/KeychainStackTokenStore.swift
  • Packages/Shared/CmuxAuthRuntime/Sources/CmuxAuthRuntime/TokenStores/StackAuthTokenStoreProtocol.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/ASWebBrowserAuthSessionFactoryTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorCancellationTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorSessionValidityTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorSignOutOfflineTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorStaleClearTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorStaleRevalidationTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthCoordinatorTimeoutTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthDebugLogTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/AuthErrorDisplaySafeTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/Fakes.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/GateableValidationAuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HangingMagicLinkAuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HangingOAuthAuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HangingSignOutAuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HangingTokenMintAuthClient.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowFakes.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/HostBrowserSignInFlowTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/ManualTestClock.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/PushRegistrationServiceTests.swift
  • Packages/Shared/CmuxAuthRuntime/Tests/CmuxAuthRuntimeTests/TestPhaseSignal.swift
  • Packages/Shared/CmuxSyncStore/Package.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/CmuxSyncStore+RowDecode.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/CmuxSyncStore.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/CmuxSyncStoreError.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/CmuxSyncStoring.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/DeviceSyncFacade.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/MobileDeviceListLocalFirst.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/PairedMacMigration.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/SyncClient.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/SyncDatabase.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/SyncFrameApplier.swift
  • Packages/Shared/CmuxSyncStore/Sources/CmuxSyncStore/SyncProtocol.swift
  • Packages/Shared/CmuxSyncStore/Tests/CmuxSyncStoreTests/CmuxSyncStoreTests.swift
  • Packages/Shared/CmuxSyncStore/Tests/CmuxSyncStoreTests/SyncFrameAndProtocolTests.swift
  • Packages/iOS/CmuxAgentChatUI/Package.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Composer/ChatAccessoryChipRow.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Composer/ChatComposerAttachment.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Composer/ChatComposerView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Markdown/ChatANSISanitizer.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Markdown/ChatContentCache.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Markdown/ChatMarkdownRenderer.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Markdown/ChatProseSegment.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Markdown/ChatProseSegmenter.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Markdown/ChatTextBlock.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Previews/ChatFixtureConversation.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Previews/ChatScreenPreviews.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Resources/Localizable.xcstrings
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Screen/ChatScreen.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Screen/KeyboardDismissTap.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Theme/ChatBubbleMaxWidthKey.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Theme/ChatTheme.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Theme/Color+ChatAdaptive.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatMessageRowView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatRowActions.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatScrollToBottomButton.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatTranscriptListView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatTranscriptRowView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatTranscriptTableView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatTypingIndicatorView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatAttachmentBubbleView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatDateHeaderView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatFileEditCardView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatPendingBubbleView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatPermissionCardView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatProseBubbleView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatQuestionCardView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatSessionHeaderView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatStatusRowView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatTerminalCardView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatThoughtRowView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatToolUseRowView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatUnreadSeparatorView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatUnsupportedRowView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/TerminalCommandBlockView.swift
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/TerminalInteractiveCardView.swift
  • Packages/iOS/CmuxAgentChatUI/Tests/CmuxAgentChatUITests/ChatANSISanitizerTests.swift
  • Packages/iOS/CmuxAgentChatUI/Tests/CmuxAgentChatUITests/ChatProseSegmenterTests.swift
  • Packages/iOS/CmuxAgentChatUI/Tests/CmuxAgentChatUITests/ChatTextBlockParserTests.swift
  • Packages/iOS/CmuxMobileAnalytics/Package.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsConsentProviding.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsEmitter.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsEvent.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsSessionStore.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsSessionizer.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsTokenProviding.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/AnalyticsUploading.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/HTTPAnalyticsUploader.swift
  • Packages/iOS/CmuxMobileAnalytics/Sources/CmuxMobileAnalytics/RecordingAnalyticsUploader.swift
  • Packages/iOS/CmuxMobileAnalytics/Tests/CmuxMobileAnalyticsTests/AnalyticsEmitterTests.swift
  • Packages/iOS/CmuxMobileAnalytics/Tests/CmuxMobileAnalyticsTests/AnalyticsSessionStoreTests.swift
  • Packages/iOS/CmuxMobileAnalytics/Tests/CmuxMobileAnalyticsTests/AnalyticsSessionizerTests.swift
  • Packages/iOS/CmuxMobileBrowser/Package.swift
  • Packages/iOS/CmuxMobileBrowser/Sources/CmuxMobileBrowser/BrowserSurfaceState.swift
  • Packages/iOS/CmuxMobileBrowser/Sources/CmuxMobileBrowser/BrowserSurfaceStore.swift
  • Packages/iOS/CmuxMobileBrowser/Sources/CmuxMobileBrowser/BrowserURLResolver.swift
  • Packages/iOS/CmuxMobileBrowser/Sources/CmuxMobileBrowser/MobileBrowserPane.swift
  • Packages/iOS/CmuxMobileBrowser/Sources/CmuxMobileBrowser/MobileBrowserView.swift
  • Packages/iOS/CmuxMobileBrowser/Tests/CmuxMobileBrowserTests/BrowserSurfaceStateTests.swift
  • Packages/iOS/CmuxMobileBrowser/Tests/CmuxMobileBrowserTests/BrowserSurfaceStoreTests.swift
  • Packages/iOS/CmuxMobileBrowser/Tests/CmuxMobileBrowserTests/BrowserURLResolverTests.swift
  • Packages/iOS/CmuxMobileCamera/Package.swift
  • Packages/iOS/CmuxMobileCamera/README.md
  • Packages/iOS/CmuxMobileCamera/Sources/CmuxMobileCamera/CameraAuthorization.swift
  • Packages/iOS/CmuxMobileCamera/Sources/CmuxMobileCamera/QRCodeCaptureController.swift
  • Packages/iOS/CmuxMobileCamera/Sources/CmuxMobileCamera/QRCodeFrameCandidate.swift
  • Packages/iOS/CmuxMobileCamera/Sources/CmuxMobileCamera/QRCodeFrameSelection.swift
  • Packages/iOS/CmuxMobileCamera/Sources/CmuxMobileCamera/QRCodeMetadataReceiver.swift
  • Packages/iOS/CmuxMobileCamera/Sources/CmuxMobileCamera/QRCodeScanStream.swift
  • Packages/iOS/CmuxMobileCamera/Tests/CmuxMobileCameraTests/QRCodeFrameSelectionTests.swift
  • Packages/iOS/CmuxMobileCamera/Tests/CmuxMobileCameraTests/QRCodeScanStreamTests.swift
  • Packages/iOS/CmuxMobileDiagnostics/Package.swift
  • Packages/iOS/CmuxMobileDiagnostics/Sources/CmuxMobileDiagnostics/MobileDebugLog+Anchormux.swift
  • Packages/iOS/CmuxMobileDiagnostics/Sources/CmuxMobileDiagnostics/MobileDebugLog.swift
  • Packages/iOS/CmuxMobileDiagnostics/Sources/CmuxMobileDiagnostics/MobileDebugLogSink.swift
  • Packages/iOS/CmuxMobileDiagnostics/Tests/CmuxMobileDiagnosticsTests/MobileDebugLogSinkTests.swift
  • Packages/iOS/CmuxMobilePairedMac/Package.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMac.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMacStore.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMacStoreError.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMacStoring.swift
  • Packages/iOS/CmuxMobilePairedMac/Tests/CmuxMobilePairedMacTests/MobilePairedMacStoreTests.swift
  • Packages/iOS/CmuxMobileRPC/Package.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/CmxAttachEndpoint+LogDescription.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/CmxAttachTicketInput.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCAttachTicketCoverage.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCSession.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileEventEnvelope.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileEventSubscribeResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileHostStatusResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileNotificationBadgeEvent.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileNotificationDismissedEvent.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileNotificationReconcileResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileShellConnectionError.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileSyncRuntime.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileSyncWorkspaceListResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileSyncing.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileTerminalBytesEvent.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileTerminalInputResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileTerminalRenderGridEvent.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileTerminalReplayResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileTerminalViewportResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileWorkspacePreview+RemoteMapping.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/PreviewMobileHost.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/CmxAttachTicketInputTests.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/MobileCoreRPCClientTests.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/MobileTerminalDTODecodeTests.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/TransportTestDoubles.swift

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces scripts/check-workspace-package-groups.py, a Python tool that scans Packages/, classifies each SPM package into Shared, iOS, or macOS via transitive reachability from app roots, and deterministically rewrites cmux.xcworkspace/contents.xcworkspacedata. The workspace file is updated to this generated output. A CI step and a CLAUDE.md note enforce the grouping going forward.

Changes

Workspace SPM Package Grouping Enforcement

Layer / File(s) Summary
Package grouping script: discovery, classification, rendering, and CLI
scripts/check-workspace-package-groups.py
New 240-line Python CLI: discovers packages under Packages/, extracts local .package(path:) deps and platforms, computes transitive reachability from macOS and iOS project.pbxproj roots via closure(), classifies each package to Shared/iOS/macOS, renders deterministic workspace XML, and supports --check (diff + exit 1) or --write (overwrite) modes.
Workspace file updated to script-generated output
cmux.xcworkspace/contents.xcworkspacedata
Rewrites the workspace groupings to match script output: adds CmuxAgentChat, CmuxSyncStore, CmuxAgentChatUI, CmuxMobileAnalytics, CmuxMobileBrowser in shared/iOS sections; inserts ~50 new macOS package FileRef entries; removes five stale entries (CmuxFoundation, CMUXPasteboardFidelity, CmuxSettings, CmuxSettingsUI, CmuxSocketControl).
CI guard step and developer documentation
.github/workflows/ci.yml, CLAUDE.md
Adds a workflow-guard-tests step running check-workspace-package-groups.py --check to fail on drift; documents the grouping rule and --write regeneration command in CLAUDE.md.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • manaflow-ai/cmux#4834: Also modifies cmux.xcworkspace/contents.xcworkspacedata to control how local Packages/* appear in the workspace navigator; this PR expands and normalizes those same package-group references and adds a script to enforce them.
  • manaflow-ai/cmux#5111: Also updates CLAUDE.md with Swift package wiring and workspace layout guidance; this PR adds the SPM grouping mirroring rule and script regeneration note to the same document.

Poem

🐇 Hoppity-hop through Packages galore,
Each module sorted — Shared, iOS, macOS in store.
A Python script scurries, classifies with care,
Transitive closures computed right there!
CI shall guard lest the workspace go astray,
No drift shall escape this deterministic day. 🌿

🚥 Pre-merge checks | ✅ 20 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (20 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 Swift Actor Isolation ✅ Passed This PR makes only metadata/configuration changes (workspace XML grouping, CI YAML, Python script, documentation) with no Swift source file modifications, so Swift 6 actor isolation issues cannot b...
Cmux Swift Blocking Runtime ✅ Passed PR contains no Swift code changes: only YAML workflow config, markdown docs, XML workspace file, and Python tooling script. Check is for production Swift blocking runtime patterns.
Cmux Expensive Synchronous Load ✅ Passed PR contains no production Swift code changes (only YAML workflow, Markdown docs, Python scripts, and XML workspace config), so expensive synchronous load check does not apply.
Cmux Cache Substitution Correctness ✅ Passed This PR does not involve cache substitution. It introduces a deterministic workspace grouping generator that reads fresh authoritative state from disk (Package.swift files, project.pbxproj) and gen...
Cmux No Hacky Sleeps ✅ Passed PR modifies Python, YAML, XML, and documentation files only. The check applies only to TypeScript, JavaScript, shell, or build/runtime scripts; Python is not in scope. The Python script contains no...
Cmux Algorithmic Complexity ✅ Passed PR adds only build-time validation script and metadata. Algorithmic complexity rule applies to production code on user-data collections; this script operates on ~74 repository packages (tiny fixed...
Cmux Swift Concurrency ✅ Passed PR's stated changes are metadata-only (Python script for workspace validation, YAML workflow config, documentation, XML workspace reorganization) with no new Swift code introducing legacy async pat...
Cmux Swift @Concurrent ✅ Passed PR contains no Swift code changes (only YAML CI config, Markdown docs, XML workspace config, and Python script), so the @concurrent annotation rule does not apply.
Cmux Swift File And Package Boundaries ✅ Passed PR contains no Swift source file changes: only CI workflow (YAML), documentation (Markdown), workspace config (XML), and Python automation tool. Swift boundary rules do not apply.
Cmux Swift Logging ✅ Passed No Swift code changes in PR; only YAML, markdown, XML, and Python CLI script modified. Python print statements are appropriate CLI output, which the check permits.
Cmux User-Facing Error Privacy ✅ Passed All user-facing messages use product terms, no vendor names/credentials/secrets/internal details; messages state what happened and provide concrete next actions per the rule.
Cmux Full Internationalization ✅ Passed All changes are dev-only: CI config, developer docs, workspace metadata tokens, and developer tool output—no user-facing text requiring localization.
Cmux Swiftui State Layout ✅ Passed No SwiftUI changes present. PR modifies CI configuration, documentation, Xcode workspace metadata, and adds a Python utility script—not SwiftUI code.
Cmux Architecture Rethink ✅ Passed PR is metadata-only (workspace XML, CI config, Python build tool, docs); makes no Swift architecture changes and contains none of the flagged anti-patterns (sleeps, polling, locks, observers, split...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains no Swift changes—only Python script, YAML workflow, XML workspace config, and documentation. No auxiliary window code added or modified.
Cmux Source Artifacts ✅ Passed All changed files are intentional source control content per source-control-artifacts.md: .github/workflows/ci.yml (CI config), CLAUDE.md (durable documentation), cmux.xcworkspace/contents.xcworksp...
Title check ✅ Passed The title accurately summarizes the main change: organizing SPM packages into grouped folders (Shared/iOS/macOS) so the folder structure mirrors the workspace organization.
Description check ✅ Passed The description comprehensively covers the summary, detailed implementation, testing approach, and verification steps, though it doesn't follow the exact template structure with all checklist items marked.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-spm-package-groups

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

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a long-standing drift in cmux.xcworkspace where only 26 of 74 Packages/* packages were visible. A new deterministic generator script (check-workspace-package-groups.py) classifies every package as Shared/iOS/macOS based on reachability from the two app projects, then rewrites contents.xcworkspacedata; CI enforces no further drift via --check.

  • scripts/check-workspace-package-groups.py: New Python script that reads project.pbxproj and Package.swift files to compute a transitive closure of package reachability, classifies all 74 packages, and renders a deterministic workspace XML; --write regenerates, --check enforces in CI.
  • cmux.xcworkspace/contents.xcworkspacedata: Adds the ~48 previously-absent package FileRef entries across the three named groups; verified idempotent and XML-valid.
  • CLAUDE.md / .github/workflows/ci.yml: Documents the --write workflow for future package additions and wires --check into the existing lint job.

Confidence Score: 4/5

The workspace data change itself is metadata-only and safe to merge. The new generator script has one design gap worth addressing before the next example project is added.

The classification logic, idempotency, and CI wiring are all well-constructed. The one concrete defect is that EXAMPLES_GROUP is hardcoded in the generator: if anyone adds a new example project to the workspace and then gets a CI --check failure, the error guidance ('run --write') will silently drop their new entry rather than preserving it. This is not a current breakage — the constant matches the workspace today — but it is a predictable workflow trap the next time an example is added.

scripts/check-workspace-package-groups.py — the EXAMPLES_GROUP constant and the --check error message both need attention before an example is next added to the workspace.

Important Files Changed

Filename Overview
scripts/check-workspace-package-groups.py New deterministic generator for workspace SPM groups. Core classification and rendering logic is solid, but EXAMPLES_GROUP is hardcoded — following the --write guidance after manually adding a new example will silently drop the new entry.
.github/workflows/ci.yml Adds a CI lint step to run --check on the workspace grouping; correctly positioned, uses python3, no issues.
CLAUDE.md Documents the workspace grouping rule and --write workflow for package additions; accurate for the Packages case but doesn't mention that adding an example also requires updating EXAMPLES_GROUP in the script.
cmux.xcworkspace/contents.xcworkspacedata Adds the ~48 previously-missing package FileRefs across the three groups; output matches the generator's deterministic format and verified idempotent.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[discover_packages\nPackages/*/Package.swift] --> B[build deps map\nlocal .package path edges]
    B --> C1[pbx_local_roots\ncmux.xcodeproj]
    B --> C2[pbx_local_roots\nios/cmux-ios.xcodeproj\n+ ios/cmuxPackage]
    C1 --> D1[closure mac]
    C2 --> D2[closure ios]
    D1 --> E{in mac?\nin ios?}
    D2 --> E
    E -->|both| F[Shared]
    E -->|ios only| G[iOS]
    E -->|mac only| H[macOS]
    E -->|neither| I[declared_platforms\nfallback]
    I -->|iOS only| G
    I -->|macOS only| H
    I -->|both or neither| F
    F --> J[render + write\ncontents.xcworkspacedata]
    G --> J
    H --> J
    J --> K{--write or --check?}
    K -->|--write| L[overwrite file]
    K -->|--check| M{actual == expected?}
    M -->|yes| N[OK exit 0]
    M -->|no| O[error + diff exit 1]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[discover_packages\nPackages/*/Package.swift] --> B[build deps map\nlocal .package path edges]
    B --> C1[pbx_local_roots\ncmux.xcodeproj]
    B --> C2[pbx_local_roots\nios/cmux-ios.xcodeproj\n+ ios/cmuxPackage]
    C1 --> D1[closure mac]
    C2 --> D2[closure ios]
    D1 --> E{in mac?\nin ios?}
    D2 --> E
    E -->|both| F[Shared]
    E -->|ios only| G[iOS]
    E -->|mac only| H[macOS]
    E -->|neither| I[declared_platforms\nfallback]
    I -->|iOS only| G
    I -->|macOS only| H
    I -->|both or neither| F
    F --> J[render + write\ncontents.xcworkspacedata]
    G --> J
    H --> J
    J --> K{--write or --check?}
    K -->|--write| L[overwrite file]
    K -->|--check| M{actual == expected?}
    M -->|yes| N[OK exit 0]
    M -->|no| O[error + diff exit 1]
Loading

Reviews (1): Last reviewed commit: "Group every SPM package in the root work..." | Re-trigger Greptile

Comment on lines +53 to +61
EXAMPLES_GROUP = (
'container:Examples',
'Examples',
[
"group:TabsVisibleSidebar/TabsVisibleSidebar.xcodeproj",
"group:SampleSidebarExtensionApp/SampleSidebarExtensionApp.xcodeproj",
"group:CmuxExtensionSidebarExamples",
],
)

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 Hardcoded EXAMPLES_GROUP creates a data-loss trap for future example additions

render() always regenerates the Examples group from the hardcoded constant on line 53–61. If a developer adds a new example project to the workspace manually and then gets a --check failure in CI, the failure message instructs them to "Run --write" — but --write will silently drop their new entry because the constant no longer matches the workspace. The developer must also update EXAMPLES_GROUP in this script, but nothing in the error message or the CLAUDE.md doc tells them that. The safest fix is to parse the existing Examples group from the current workspace file rather than hardcoding its children, or at minimum make the --check error message explicitly warn that Examples changes also require updating EXAMPLES_GROUP in the script.

],
)

PACKAGE_DEP_RE = re.compile(r'\.package\(\s*path:\s*"([^"]+)"')

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 PACKAGE_DEP_RE regex matches .package(path: "...") anywhere in the file, including inside Swift line comments. A commented-out dependency whose package still exists on disk would be incorrectly included in the reachability closure and change the group classification for that package.

Suggested change
PACKAGE_DEP_RE = re.compile(r'\.package\(\s*path:\s*"([^"]+)"')
# Strip line comments before matching to avoid false positives from commented-out deps.
_STRIP_COMMENT_RE = re.compile(r"//[^\n]*")
PACKAGE_DEP_RE = re.compile(r'\.package\(\s*path:\s*"([^"]+)"')

Comment on lines +216 to +217
actual = open(WORKSPACE_DATA, encoding="utf-8").read()
if actual == expected:

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 open(WORKSPACE_DATA) in --check mode will raise FileNotFoundError (unhandled, raw Python traceback) if the workspace file is absent, rather than printing a clean actionable message. This could happen in a fresh sparse checkout or if someone renames the file.

Suggested change
actual = open(WORKSPACE_DATA, encoding="utf-8").read()
if actual == expected:
try:
actual = open(WORKSPACE_DATA, encoding="utf-8").read()
except FileNotFoundError:
print(
f"::error file={os.path.relpath(WORKSPACE_DATA, ROOT)}::"
f"workspace file not found. Run: python3 scripts/check-workspace-package-groups.py --write",
file=sys.stderr,
)
return 1
if actual == expected:

@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 `@scripts/check-workspace-package-groups.py`:
- Around line 94-97: In the pbx_local_roots() function, restrict pbx root
discovery to only consider relativePath entries that are under the `Packages/`
directory. The current code in the loop iterating through PBX_RELPATH_RE.findall
results adds any basename found in names to the roots set, but it should first
verify that the raw path contains or starts with the `Packages/` directory
prefix before adding to roots. This prevents unrelated relativePath entries from
being incorrectly marked as SwiftPM roots.
🪄 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: 92db4548-418e-4474-8aab-f286ee34ddc3

📥 Commits

Reviewing files that changed from the base of the PR and between f1553aa and dae0e84.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • CLAUDE.md
  • cmux.xcworkspace/contents.xcworkspacedata
  • scripts/check-workspace-package-groups.py

Comment on lines +94 to +97
for raw in PBX_RELPATH_RE.findall(txt):
base = os.path.basename(raw.strip().rstrip("/"))
if base in names:
roots.add(base)

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 | 🟠 Major | ⚡ Quick win

Restrict pbx root discovery to Packages/ paths only.

pbx_local_roots() currently treats any relativePath basename as a package root. That can incorrectly mark unrelated entries as SwiftPM roots and skew Shared/iOS/macOS classification.

Suggested fix
 def pbx_local_roots(pbxproj: str, names: set[str]) -> set[str]:
     if not os.path.exists(pbxproj):
         return set()
     txt = open(pbxproj, encoding="utf-8").read()
     roots = set()
     for raw in PBX_RELPATH_RE.findall(txt):
-        base = os.path.basename(raw.strip().rstrip("/"))
+        rel = raw.strip().rstrip("/")
+        if not rel.startswith("Packages/"):
+            continue
+        base = os.path.basename(rel)
         if base in names:
             roots.add(base)
     return roots
🤖 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 `@scripts/check-workspace-package-groups.py` around lines 94 - 97, In the
pbx_local_roots() function, restrict pbx root discovery to only consider
relativePath entries that are under the `Packages/` directory. The current code
in the loop iterating through PBX_RELPATH_RE.findall results adds any basename
found in names to the roots set, but it should first verify that the raw path
contains or starts with the `Packages/` directory prefix before adding to roots.
This prevents unrelated relativePath entries from being incorrectly marked as
SwiftPM roots.

@azooz2003-bit azooz2003-bit changed the title Group every SPM package in the root workspace by Shared/iOS/macOS, derived from the Packages/ folder layout Organize SPM packages into Packages/{Shared,iOS,macOS}/ so the folder tree mirrors the Xcode workspace groups Jun 16, 2026
@azooz2003-bit
azooz2003-bit force-pushed the task-spm-package-groups branch from bd8417a to 9217d11 Compare June 16, 2026 23:08
@azooz2003-bit
azooz2003-bit force-pushed the task-spm-package-groups branch 3 times, most recently from bc1add9 to 3353d80 Compare June 16, 2026 23:45
… tree mirrors the workspace groups

Every Swift package now lives physically under exactly one group directory
(Packages/Shared, Packages/iOS, Packages/macOS), so the repo's directory
tree and the root workspace's group columns are the same shape. Opening
cmux.xcworkspace shows each package under the Shared / iOS / macOS group
matching the folder it lives in.

Folder is the source of truth. Group = which app(s) consume the package:
both apps -> Shared, iOS app only -> iOS, macOS app only -> macOS.
check-workspace-package-groups.py mirrors the folders directly; --write
regenerates the workspace, --check (in CI, beside check-pbxproj) fails on drift.

All boundary-crossing relative paths were rewritten to keep the build intact:
inter-package deps same group `../Name` / cross group `../../<Group>/Name`;
escaping paths gain one level (vendor `../../../vendor/...`, GhosttyKit
`../../../GhosttyKit.xcframework`); macOS project relativePaths, ios/cmuxPackage
and Examples deps + project relativePaths, the file-length budget, the iOS
conventions lint scopes, the namespace-type baseline, the test-ios change
globs, the ci.yml per-package `swift test` loop (now resolves the group dir),
and doc/skill references all updated to the nested paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview – cmux — eff93a42 Deployed Jun 17, 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