diff --git a/Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift b/Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift index 22312574e6c7..3fb9c05f96b6 100644 --- a/Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift +++ b/Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift @@ -45,4 +45,12 @@ public struct MobileSurfaceKind: RawRepresentable, Codable, Hashable, Sendable { public static let todo = MobileSurfaceKind(rawValue: "todo") /// A transient Cloud VM loading surface. public static let cloudVMLoading = MobileSurfaceKind(rawValue: "cloudVMLoading") + /// A native Apple Simulator surface, rendered as a fallback card on mobile. + public static let simulator = MobileSurfaceKind(rawValue: "simulator") + /// A notifications surface, rendered as a fallback card on mobile. + public static let notifications = MobileSurfaceKind(rawValue: "notifications") + /// A transient iPhone pairing surface, rendered as a fallback card on mobile. + public static let mobilePairing = MobileSurfaceKind(rawValue: "mobilePairing") + /// A transient account sign-in surface, rendered as a fallback card on mobile. + public static let accountSignIn = MobileSurfaceKind(rawValue: "accountSignIn") } diff --git a/Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift b/Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift index 3c693c2800e7..74e28fd2fa3b 100644 --- a/Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift +++ b/Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift @@ -101,6 +101,21 @@ struct MobileStateSyncFrameCodingTests { #expect(try JSONDecoder().decode(MobileSurfaceKind.self, from: data) == kind) } + @Test func knownFallbackKindsUseStableWireValues() { + // These Mac panel kinds intentionally use the open-vocabulary fallback + // renderer on phones until a native mobile renderer is available. + let kinds: [(MobileSurfaceKind, String)] = [ + (.simulator, "simulator"), + (.notifications, "notifications"), + (.mobilePairing, "mobilePairing"), + (.accountSignIn, "accountSignIn"), + ] + + for (kind, expectedRawValue) in kinds { + #expect(kind.rawValue == expectedRawValue) + } + } + @Test func workspaceRecordWithoutSurfacesDecodesAndReencodesWithoutTheField() throws { let json = #"{"id":"ws-old","title":"old","is_selected":false,"is_pinned":false,"last_activity_at":1,"has_unread":false,"sort_index":0,"terminals":[]}"# let decoded = try MobileSyncFrameCoder().decode( diff --git a/Sources/TerminalController+MobileSurfaces.swift b/Sources/TerminalController+MobileSurfaces.swift index 8de9f6cecc06..3d75bdcfece0 100644 --- a/Sources/TerminalController+MobileSurfaces.swift +++ b/Sources/TerminalController+MobileSurfaces.swift @@ -6,43 +6,12 @@ import Foundation /// Mobile surface inventory and focus support kept outside `TerminalController.swift`. extension TerminalController { /// Maps an app panel kind to the shared, open mobile wire vocabulary. + /// + /// ``Workspace.surfaceKind(for:)`` is the canonical mapping used by Mac + /// workspace snapshots. Reusing it here keeps mobile descriptors and Mac + /// persistence on one exhaustive source of truth as panel kinds evolve. func mobileSurfaceKind(for panelType: PanelType) -> MobileSurfaceKind { - switch panelType { - case .terminal: - return .terminal - case .browser: - return .browser - case .markdown: - return .markdown - case .filePreview: - return .filePreview - case .rightSidebarTool: - return .rightSidebarTool - case .customSidebar: - return .customSidebar - case .agentSession: - return .agentSession - case .project: - return .project - case .extensionBrowser: - return .extensionBrowser - case .workspaceTodo: - return .todo - case .notifications: - // Notifications use the open-vocabulary fallback until the phone - // provides a native renderer for this panel kind. - return MobileSurfaceKind(rawValue: "notifications") - case .cloudVMLoading: - return .cloudVMLoading - case .simulator: - // Open wire vocabulary: phones without a native renderer show the - // fallback card for this kind (design: unknown kinds stay cards). - return MobileSurfaceKind(rawValue: "simulator") - case .mobilePairing: - return MobileSurfaceKind(rawValue: "mobilePairing") - case .accountSignIn: - return MobileSurfaceKind(rawValue: "accountSignIn") - } + MobileSurfaceKind(rawValue: Workspace.surfaceKind(for: panelType)) } /// Builds the stable, spatially ordered mobile descriptors for every panel. diff --git a/cmuxTests/MobileSurfaceKindMappingTests.swift b/cmuxTests/MobileSurfaceKindMappingTests.swift index 605d9409686f..f3a35bfdaf19 100644 --- a/cmuxTests/MobileSurfaceKindMappingTests.swift +++ b/cmuxTests/MobileSurfaceKindMappingTests.swift @@ -24,6 +24,10 @@ import Testing .extensionBrowser: "extensionBrowser", .workspaceTodo: "todo", .cloudVMLoading: "cloudVMLoading", + .simulator: "simulator", + .notifications: "notifications", + .mobilePairing: "mobilePairing", + .accountSignIn: "accountSignIn", ] @Test func everyPanelTypeMapsToItsCanonicalWireKind() throws {