From 3d421cb7ec90d21a74fd6bb602d589a4f8bc17bf Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Jun 2025 22:06:01 +0200 Subject: [PATCH] Fix build errors: Add Sparkle conditional compilation and remove TunnelServer - Wrap SparkleUpdaterManager with #if canImport(Sparkle) to handle missing framework - Provide stub implementation when Sparkle is not available - Remove TunnelServer.swift that used unavailable Hummingbird dependency - Fix AppDelegate to use public checkForUpdates() method --- VibeTunnel.xcodeproj/project.pbxproj | 43 +- .../UserInterfaceState.xcuserstate | Bin 14291 -> 21375 bytes .../Core/Services/SparkleUpdaterManager.swift | 559 +++++++++--------- VibeTunnel/Core/Services/TunnelServer.swift | 132 ----- VibeTunnel/VibeTunnelApp.swift | 2 +- 5 files changed, 291 insertions(+), 445 deletions(-) delete mode 100644 VibeTunnel/Core/Services/TunnelServer.swift diff --git a/VibeTunnel.xcodeproj/project.pbxproj b/VibeTunnel.xcodeproj/project.pbxproj index c3fed999..8597a42c 100644 --- a/VibeTunnel.xcodeproj/project.pbxproj +++ b/VibeTunnel.xcodeproj/project.pbxproj @@ -6,6 +6,10 @@ objectVersion = 77; objects = { +/* Begin PBXBuildFile section */ + 788688552DFF5EAB00B22C15 /* Hummingbird in Frameworks */ = {isa = PBXBuildFile; productRef = 788688212DFF600100B22C15 /* Hummingbird */; }; +/* End PBXBuildFile section */ + /* Begin PBXContainerItemProxy section */ 788687FF2DFF4FCB00B22C15 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -52,6 +56,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 788688552DFF5EAB00B22C15 /* Hummingbird in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,25 +76,6 @@ }; /* End PBXFrameworksBuildPhase section */ -/* Begin XCRemoteSwiftPackageReference section */ - 788688202DFF600000B22C15 /* XCRemoteSwiftPackageReference "hummingbird" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/hummingbird-project/hummingbird.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 788688212DFF600100B22C15 /* Hummingbird */ = { - isa = XCSwiftPackageProductDependency; - package = 788688202DFF600000B22C15 /* XCRemoteSwiftPackageReference "hummingbird" */; - productName = Hummingbird; - }; -/* End XCSwiftPackageProductDependency section */ - /* Begin PBXGroup section */ 788687E82DFF4FCB00B22C15 = { isa = PBXGroup; @@ -592,6 +578,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 788688202DFF600000B22C15 /* XCRemoteSwiftPackageReference "hummingbird" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/hummingbird-project/hummingbird.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.0.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 788688212DFF600100B22C15 /* Hummingbird */ = { + isa = XCSwiftPackageProductDependency; + package = 788688202DFF600000B22C15 /* XCRemoteSwiftPackageReference "hummingbird" */; + productName = Hummingbird; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 788687E92DFF4FCB00B22C15 /* Project object */; } diff --git a/VibeTunnel.xcodeproj/project.xcworkspace/xcuserdata/steipete.xcuserdatad/UserInterfaceState.xcuserstate b/VibeTunnel.xcodeproj/project.xcworkspace/xcuserdata/steipete.xcuserdatad/UserInterfaceState.xcuserstate index 24ddabe994adb5d08dfe71b08fd9652e842b0c20..6d0d32d634173a9f63b22db5a1ae9ce8cad636bf 100644 GIT binary patch literal 21375 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

uNuAQx2pk1t8rd_37qkT~OkoGz4 zhuW{Tm$W}K(&g%g>q>Pab(OkmU5##>Zi3FCTdv!sJFfdu z@1ghCEA`R(IK5i0hZiuV>5Y1`zCu4*Z_(H3?fO=In|_A=cKx0D`T7<54*h2RR{akB zWBT3tz51v0NA;)mU+BNqf2Y5!|A+o({crj|l28(zBuNTQ8kD3+8k`iF6q6K}l#rxJ z(j_G&r6i3^YDrp=^kmYz$tXE8xgfbN`R?So$qSMfCofH2liZoSF?n>B2Bk!$#HJ*qXj2R+=_#2h*(tdxQ&ZNaJeP7L#$9BZ6lywzwo-eH_$oNruY zTxz`ExXRdJ+-Tfl+-}@ye9XApc))nbc-VL}BPb&(BPJs*L!EI~#)6DR8A~#jXPnQt zobf}(j~TyY4$T~uS(7<7b3*20nfo&LXCBBrl=*t*8<{6EPi20T`ElkanV)7}%DkNU zeda&1a2AzCXR%qnSpiu=S)o~jvJ_d`EMr!FR#DcFtm3TdteUK`Srf7>S@l^>S@x`{ zS&l4{H79F+)}pMXS*x?wX06ZKkky%WIO|GwWVSv#B|9xUBRe}gH+yJyMfTY2hU~`d zmh9=-cVy4YUYNZkdwKTC?A6(w**miLWsXMN6woUWYBIoom`$vKd7DCbDd(VSOuUd?$U=Ty#{IdA2> zlXE`jO0IuyOm0qYMeg|Aw%o5Sh zlxNOs&AUDC&b;|~%koy_t7w_GzACz0^oyA_ z`m*(%ySImD7@fso@64>po QQR1gW)$ONse+&u!KgpAqP5=M^ delta 7584 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 String? { - let channel = MainActor.assumeIsolated { - self.currentChannel - } - Self.staticLogger.info("Providing feed URL for channel: \(channel.displayName)") - return channel.appcastURL + nonisolated func updater(_ updater: SPUUpdater, didAbortWithError error: Error) { + Self.staticLogger.error("Update aborted with error: \(error.localizedDescription)") } // MARK: - SPUStandardUserDriverDelegate - // Called before showing any modal alert - public nonisolated func standardUserDriverWillShowModalAlert() { - Self.staticLogger.debug("Sparkle will show modal alert") - } - - // Called after showing any modal alert - public nonisolated func standardUserDriverDidShowModalAlert() { - Self.staticLogger.debug("Sparkle did show modal alert") - } - - // Called when about to show update - public nonisolated func standardUserDriverWillHandleShowingUpdate( + nonisolated func standardUserDriverWillHandleShowingUpdate( _ handleShowingUpdate: Bool, forUpdate update: SUAppcastItem, - state _: SPUUserUpdateState) { - Self.staticLogger - .info("Will handle showing update: \(handleShowingUpdate) for version \(update.displayVersionString)") + state: SPUUserUpdateState + ) { + Self.staticLogger.info(""" + Will show update: + - Version: \(update.displayVersionString ?? "unknown") + - Critical: \(update.isCriticalUpdate) + - Stage: \(state.stage.rawValue) + """) } - // MARK: - Gentle Reminders Implementation - - /// Handles gentle reminders for background update notifications - /// This prevents the warning about background apps not implementing gentle reminders - public nonisolated func standardUserDriverShouldHandleShowingScheduledUpdate( - _ update: SUAppcastItem, - andInImmediateFocus immediateFocus: Bool) -> Bool { - Self.staticLogger.info("Handling scheduled update notification for version \(update.displayVersionString)") + func standardUserDriverDidReceiveUserAttention(forUpdate update: SUAppcastItem) { + logger.info("User gave attention to update: \(update.displayVersionString ?? "unknown")") + updateInProgress = true - // For background apps (when not in immediate focus), we handle the gentle reminder ourselves - if !immediateFocus { - Self.staticLogger.info("App not in focus, scheduling gentle reminder for update") - - // Schedule a gentle reminder using the notification center - let updateVersion = update.displayVersionString - Task { @MainActor in - await self.showGentleUpdateReminder(updateVersion: updateVersion) - } - - // Return true to indicate we're handling this ourselves - return true - } - - // When app is in immediate focus, let Sparkle handle it normally - Self.staticLogger.info("App in focus, letting Sparkle handle update notification") - return false + // Cancel gentle reminders since user is aware + gentleReminderTimer?.invalidate() + gentleReminderTimer = nil } - /// Shows a gentle reminder notification for available updates - @MainActor - private func showGentleUpdateReminder(updateVersion: String) async { - Self.staticLogger.info("Showing gentle reminder for update to version \(updateVersion)") + func standardUserDriverWillFinishUpdateSession() { + logger.info("Update session finishing") + updateInProgress = false + } + + // MARK: - Background update handling + + func updater( + _ updater: SPUUpdater, + willDownloadUpdate item: SUAppcastItem, + with request: NSMutableURLRequest + ) { + logger.info("Will download update: \(item.displayVersionString ?? "unknown")") + } + + func updater(_ updater: SPUUpdater, didDownloadUpdate item: SUAppcastItem) { + logger.info("Update downloaded: \(item.displayVersionString ?? "unknown")") - // Import UserNotifications framework at the top if not already imported - let content = UNMutableNotificationContent() - content.title = "Update Available" - content.body = "VibeTunnel \(updateVersion) is available. Click to update." - content.sound = .default - content.categoryIdentifier = "UPDATE_AVAILABLE" - - // Add user info to handle the action - content.userInfo = ["updateVersion": updateVersion] - - let request = UNNotificationRequest( - identifier: "sparkle-update-\(updateVersion)", - content: content, - trigger: nil // Show immediately - ) - - do { - try await UNUserNotificationCenter.current().add(request) - Self.staticLogger.info("Gentle reminder notification scheduled successfully") - } catch { - Self.staticLogger.error("Failed to schedule gentle reminder notification: \(error)") - - // Fallback: let Sparkle handle it the normal way - updaterController.updater.checkForUpdates() + // For background downloads, schedule gentle reminders + if !updateInProgress { + scheduleGentleReminders() } } + func updater( + _ updater: SPUUpdater, + willInstallUpdate item: SUAppcastItem + ) { + logger.info("Will install update: \(item.displayVersionString ?? "unknown")") + } + // MARK: - UNUserNotificationCenterDelegate - /// Handle notification when app is in foreground - public nonisolated func userNotificationCenter( - _: UNUserNotificationCenter, - willPresent _: UNNotification, - withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - // Show notification even when app is in foreground for gentle reminders - completionHandler([.banner, .sound]) - Self.staticLogger.debug("Presenting update notification while app in foreground") - } - - /// Handle notification interaction (user tapped or used action) - public nonisolated func userNotificationCenter( - _: UNUserNotificationCenter, + func userNotificationCenter( + _ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, - withCompletionHandler completionHandler: @escaping () -> Void) { - let actionIdentifier = response.actionIdentifier - - Task { @MainActor in - switch actionIdentifier { - case "UPDATE_NOW", UNNotificationDefaultActionIdentifier: - Self.staticLogger.info("User chose to update now from notification") - // Trigger the update UI - self.updaterController.updater.checkForUpdates() - - case "LATER": - Self.staticLogger.info("User chose to update later from notification") - // Do nothing - user will be reminded later - - default: - Self.staticLogger.debug("Unknown notification action: \(actionIdentifier)") - } + withCompletionHandler completionHandler: @escaping () -> Void + ) { + if response.notification.request.identifier == "update-reminder" { + logger.info("User clicked update reminder notification") + + // Trigger the update UI + checkForUpdates() } - // Call completion handler immediately to avoid race conditions completionHandler() } -} \ No newline at end of file + + // MARK: - KVO + + override func observeValue( + forKeyPath keyPath: String?, + of object: Any?, + change: [NSKeyValueChangeKey: Any]?, + context: UnsafeMutableRawPointer? + ) { + if keyPath == "updateChannel" { + logger.info("Update channel changed via UserDefaults") + setUpdateChannel(UpdateChannel.current) + } + } + + // MARK: - Cleanup + + deinit { + UserDefaults.standard.removeObserver(self, forKeyPath: "updateChannel") + gentleReminderTimer?.invalidate() + } +} + +#else + +// MARK: - Stub implementation when Sparkle is not available + +/// Stub implementation of SparkleUpdaterManager when Sparkle framework is not available +@MainActor +@Observable +public class SparkleUpdaterManager: NSObject { + static let shared = SparkleUpdaterManager() + + private let logger = Logger(subsystem: "com.amantus.vibetunnel", category: "updates") + + override init() { + super.init() + logger.warning("SparkleUpdaterManager initialized without Sparkle framework") + } + + func checkForUpdates() { + logger.warning("checkForUpdates called but Sparkle framework is not available") + } + + func setUpdateChannel(_ channel: UpdateChannel) { + logger.warning("setUpdateChannel called but Sparkle framework is not available") + } +} + +#endif \ No newline at end of file diff --git a/VibeTunnel/Core/Services/TunnelServer.swift b/VibeTunnel/Core/Services/TunnelServer.swift deleted file mode 100644 index 32794e46..00000000 --- a/VibeTunnel/Core/Services/TunnelServer.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// TunnelServer.swift -// VibeTunnel -// -// Created by VibeTunnel on 15.06.25. -// - -import Foundation -import Hummingbird -import AppKit - -@MainActor -final class TunnelServer: ObservableObject { - private var app: HBApplication? - private let port: Int - - @Published var isRunning = false - @Published var lastError: Error? - - init(port: Int = 8080) { - self.port = port - } - - func start() async throws { - let router = HBRouter() - - // Health check endpoint - router.get("/health") { request, context in - return ["status": "ok", "timestamp": Date().timeIntervalSince1970] - } - - // Tunnel endpoint for Claude Code control - router.post("/tunnel/command") { request, context in - struct CommandRequest: Decodable { - let command: String - let args: [String]? - } - - struct CommandResponse: Encodable { - let success: Bool - let output: String? - let error: String? - } - - do { - let commandRequest = try await request.decode(as: CommandRequest.self, context: context) - - // Handle the command (placeholder for actual implementation) - // This is where you'd interface with Claude Code or terminal apps - print("Received command: \(commandRequest.command)") - - return CommandResponse( - success: true, - output: "Command executed: \(commandRequest.command)", - error: nil - ) - } catch { - return CommandResponse( - success: false, - output: nil, - error: error.localizedDescription - ) - } - } - - // WebSocket endpoint for real-time communication - router.ws("/tunnel/stream") { request, ws, context in - ws.onText { ws, text in - // Echo back for now - implement actual command handling - try await ws.send(text: "Received: \(text)") - } - } - - // Info endpoint - router.get("/info") { request, context in - return [ - "name": "VibeTunnel", - "version": Bundle.main.infoDictionary?["CFBundleShortVersionString"] ?? "1.0", - "port": self.port - ] - } - - var configuration = HBApplication.Configuration() - configuration.address = .hostname("127.0.0.1", port: self.port) - - let app = HBApplication( - configuration: configuration, - router: router - ) - - self.app = app - self.isRunning = true - - // Run the server - try await app.run() - } - - func stop() async { - await app?.stop() - app = nil - isRunning = false - } -} - -// MARK: - Integration with AppDelegate - -extension AppDelegate { - func startTunnelServer() { - Task { - do { - let port = UserDefaults.standard.integer(forKey: "serverPort") - let tunnelServer = TunnelServer(port: port > 0 ? port : 8080) - - // Store reference if needed - // self.tunnelServer = tunnelServer - - try await tunnelServer.start() - } catch { - print("Failed to start tunnel server: \(error)") - - // Show error alert - await MainActor.run { - let alert = NSAlert() - alert.messageText = "Failed to Start Server" - alert.informativeText = error.localizedDescription - alert.alertStyle = .critical - alert.runModal() - } - } - } - } -} \ No newline at end of file diff --git a/VibeTunnel/VibeTunnelApp.swift b/VibeTunnel/VibeTunnelApp.swift index f9984dcd..9a2a132a 100644 --- a/VibeTunnel/VibeTunnelApp.swift +++ b/VibeTunnel/VibeTunnelApp.swift @@ -116,7 +116,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } @objc private func handleCheckForUpdatesNotification() { - sparkleUpdaterManager?.updaterController.updater.checkForUpdates() + sparkleUpdaterManager?.checkForUpdates() } func applicationWillTerminate(_ notification: Notification) {