diff --git a/Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/BrowserStackSidebar.swift b/Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/BrowserStackSidebar.swift index cf31db8003ff..9f82977a42e0 100644 --- a/Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/BrowserStackSidebar.swift +++ b/Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/BrowserStackSidebar.swift @@ -26,7 +26,14 @@ public struct BrowserStackSidebar: CmuxExtensionSidebarMutableProvider { } public static func postStateDidLoadNotification() { - NotificationCenter.default.post(name: stateDidLoadNotification, object: nil) + // Dispatch async so SwiftUI views that subscribed to this notification + // inside `body` are guaranteed to have their .onReceive subscription + // installed before the post arrives. Without this, a small persisted + // state file can finish loading during the same render pass and the + // notification gets missed. + DispatchQueue.main.async { + NotificationCenter.default.post(name: stateDidLoadNotification, object: nil) + } } public func render(snapshot: CmuxExtensionSidebarSnapshot) -> CmuxExtensionSidebarRenderModel { diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 9b3bc3b9b8a7..18aef5332a69 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -2,6 +2,7 @@ import AppKit import Bonsplit import Combine import CmuxExtensionKit +import CmuxExtensionSidebarExamples import ImageIO import Observation import SwiftUI @@ -9682,8 +9683,15 @@ enum CmuxExtensionSidebarSelection { static let defaultsKey = "cmuxExtensionSidebar.providerId" static let defaultProviderId = CmuxExtensionSidebarProviderID.defaultWorkspaces + // User-vibe-coded sidebar providers. To add your own: + // 1. Implement `CmuxExtensionSidebarProvider` in a new file under + // Examples/CmuxExtensionSidebarExamples/Sources/CmuxExtensionSidebarExamples/ + // (or any Swift Package depended on by the cmux target). + // 2. Append your provider to `SidebarExamples.providers`. + // 3. Rebuild with `./scripts/reload.sh --tag ` and pick it from the + // sidebar provider menu. static var providers: [any CmuxExtensionSidebarProvider] { - [] + SidebarExamples.providers } static var descriptors: [CmuxExtensionSidebarProviderDescriptor] { @@ -10493,6 +10501,12 @@ struct VerticalTabsSidebar: View { ) { _ in refreshExtensionSidebarSnapshot() } + .onReceive( + NotificationCenter.default.publisher(for: BrowserStackSidebar.stateDidLoadNotification) + .receive(on: RunLoop.main) + ) { _ in + refreshExtensionSidebarSnapshot() + } } } diff --git a/cmux.xcodeproj/project.pbxproj b/cmux.xcodeproj/project.pbxproj index dd5a6a2bf20f..e733488a8aee 100644 --- a/cmux.xcodeproj/project.pbxproj +++ b/cmux.xcodeproj/project.pbxproj @@ -139,6 +139,7 @@ E7E000000000000000000007 /* CmuxEventPublishing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7E000000000000000000008 /* CmuxEventPublishing.swift */; }; E7E000000000000000000001 /* CmuxEventStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7E000000000000000000002 /* CmuxEventStream.swift */; }; C0DE45000000000000000001 /* CmuxExtensionKit in Frameworks */ = {isa = PBXBuildFile; productRef = C0DE45000000000000000002 /* CmuxExtensionKit */; }; + C0DE45000000000000000004 /* CmuxExtensionSidebarExamples in Frameworks */ = {isa = PBXBuildFile; productRef = C0DE45000000000000000005 /* CmuxExtensionSidebarExamples */; }; C0DE34020000000000000001 /* CmuxHelpCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0DE34020000000000000003 /* CmuxHelpCommands.swift */; }; C0DE34020000000000000002 /* CmuxHelpResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0DE34020000000000000004 /* CmuxHelpResource.swift */; }; E7E00000000000000000000B /* CmuxLifecycleEventPublishing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7E00000000000000000000C /* CmuxLifecycleEventPublishing.swift */; }; @@ -1120,6 +1121,7 @@ F53000A0A1B2C3D4E5F60718 /* CMUXAgentVault in Frameworks */, 5EDB6027B346C46521A93C74 /* CMUXAuthCore in Frameworks */, C0DE45000000000000000001 /* CmuxExtensionKit in Frameworks */, + C0DE45000000000000000004 /* CmuxExtensionSidebarExamples in Frameworks */, 3069F1D10000000000000005 /* CMUXPasteboardFidelity in Frameworks */, A5354303A5354303A5354303 /* CMUXSocketPathDomain in Frameworks */, AA11BB22CC33DD44EE550001 /* CMUXWorkstream in Frameworks */, @@ -1787,6 +1789,7 @@ 29813FE5A6CBC1019289A251 /* CMUXAuthCore */, AA11BB22CC33DD44EE550002 /* CMUXWorkstream */, C0DE45000000000000000002 /* CmuxExtensionKit */, + C0DE45000000000000000005 /* CmuxExtensionSidebarExamples */, 3069F1D10000000000000006 /* CMUXPasteboardFidelity */, F53000A2A1B2C3D4E5F60718 /* CMUXAgentVault */, A5B00002A1B2C3D4E5F60718 /* CMUXAgentLaunch */, @@ -1920,6 +1923,7 @@ 40B63BB4A170F0BD2D1DEFD1 /* XCLocalSwiftPackageReference "CMUXAuthCore" */, AA11BB22CC33DD44EE550003 /* XCLocalSwiftPackageReference "CMUXWorkstream" */, C0DE45000000000000000003 /* XCLocalSwiftPackageReference "CmuxExtensionKit" */, + C0DE45000000000000000006 /* XCLocalSwiftPackageReference "CmuxExtensionSidebarExamples" */, 3069F1D10000000000000007 /* XCLocalSwiftPackageReference "CMUXPasteboardFidelity" */, F53000A1A1B2C3D4E5F60718 /* XCLocalSwiftPackageReference "CMUXAgentVault" */, A5B00001A1B2C3D4E5F60718 /* XCLocalSwiftPackageReference "CMUXAgentLaunch" */, @@ -2975,6 +2979,10 @@ isa = XCLocalSwiftPackageReference; relativePath = Packages/CmuxExtensionKit; }; + C0DE45000000000000000006 /* XCLocalSwiftPackageReference "CmuxExtensionSidebarExamples" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Examples/CmuxExtensionSidebarExamples; + }; 3069F1D10000000000000007 /* XCLocalSwiftPackageReference "CMUXPasteboardFidelity" */ = { isa = XCLocalSwiftPackageReference; relativePath = Packages/CMUXPasteboardFidelity; @@ -3052,6 +3060,11 @@ package = C0DE45000000000000000003 /* XCLocalSwiftPackageReference "CmuxExtensionKit" */; productName = CmuxExtensionKit; }; + C0DE45000000000000000005 /* CmuxExtensionSidebarExamples */ = { + isa = XCSwiftPackageProductDependency; + package = C0DE45000000000000000006 /* XCLocalSwiftPackageReference "CmuxExtensionSidebarExamples" */; + productName = CmuxExtensionSidebarExamples; + }; 3069F1D10000000000000006 /* CMUXPasteboardFidelity */ = { isa = XCSwiftPackageProductDependency; package = 3069F1D10000000000000007 /* XCLocalSwiftPackageReference "CMUXPasteboardFidelity" */;