diff --git a/ios/VibeTunnel/Services/LivePreviewManager.swift b/ios/VibeTunnel/Services/LivePreviewManager.swift index 0a02906a..25d3159f 100644 --- a/ios/VibeTunnel/Services/LivePreviewManager.swift +++ b/ios/VibeTunnel/Services/LivePreviewManager.swift @@ -89,7 +89,7 @@ final class LivePreviewManager { } } - case .exit(_): + case .exit: subscription.isSessionActive = false default: @@ -190,4 +190,4 @@ extension View { func livePreview(for sessionId: String, enabled: Bool = true) -> some View { modifier(LivePreviewModifier(sessionId: sessionId, isEnabled: enabled)) } -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Services/ReconnectionManager.swift b/ios/VibeTunnel/Services/ReconnectionManager.swift index 4ab966d0..0629741d 100644 --- a/ios/VibeTunnel/Services/ReconnectionManager.swift +++ b/ios/VibeTunnel/Services/ReconnectionManager.swift @@ -121,4 +121,4 @@ extension ReconnectionManager { extension NetworkMonitor { static let statusChangedNotification = Notification.Name("NetworkStatusChanged") -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Utils/ErrorHandling.swift b/ios/VibeTunnel/Utils/ErrorHandling.swift index 70c415d0..e22ac960 100644 --- a/ios/VibeTunnel/Utils/ErrorHandling.swift +++ b/ios/VibeTunnel/Utils/ErrorHandling.swift @@ -163,4 +163,4 @@ extension Task where Failure == Error { } } } -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Utils/MacCatalystWindow.swift b/ios/VibeTunnel/Utils/MacCatalystWindow.swift index a9d88f65..b4059aac 100644 --- a/ios/VibeTunnel/Utils/MacCatalystWindow.swift +++ b/ios/VibeTunnel/Utils/MacCatalystWindow.swift @@ -276,4 +276,4 @@ extension View { } } -#endif \ No newline at end of file +#endif diff --git a/ios/VibeTunnel/Views/Connection/EnhancedConnectionView.swift b/ios/VibeTunnel/Views/Connection/EnhancedConnectionView.swift index 0d1d42fc..b6159078 100644 --- a/ios/VibeTunnel/Views/Connection/EnhancedConnectionView.swift +++ b/ios/VibeTunnel/Views/Connection/EnhancedConnectionView.swift @@ -57,7 +57,7 @@ struct EnhancedConnectionView: View { Spacer(minLength: 50) } .padding() - } + } .scrollBounceBehavior(.basedOnSize) } .toolbar(.hidden, for: .navigationBar) @@ -438,4 +438,4 @@ struct ServerProfileEditView: View { #Preview { EnhancedConnectionView() .environment(ConnectionManager()) -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Views/Sessions/SessionCreateView.swift b/ios/VibeTunnel/Views/Sessions/SessionCreateView.swift index 1008126a..1c148be1 100644 --- a/ios/VibeTunnel/Views/Sessions/SessionCreateView.swift +++ b/ios/VibeTunnel/Views/Sessions/SessionCreateView.swift @@ -116,11 +116,10 @@ struct SessionCreateView: View { // Error Message if presentedError != nil { ErrorBanner( - message: presentedError?.error.localizedDescription ?? "An error occurred", - onDismiss: { + message: presentedError?.error.localizedDescription ?? "An error occurred" + ) { presentedError = nil } - ) .overlay( RoundedRectangle(cornerRadius: Theme.CornerRadius.small) .stroke(Theme.Colors.errorAccent.opacity(0.3), lineWidth: 1) diff --git a/ios/VibeTunnel/Views/Sessions/SessionListView.swift b/ios/VibeTunnel/Views/Sessions/SessionListView.swift index 8724c343..5697386e 100644 --- a/ios/VibeTunnel/Views/Sessions/SessionListView.swift +++ b/ios/VibeTunnel/Views/Sessions/SessionListView.swift @@ -388,7 +388,6 @@ struct SessionListView: View { } } - /// View model for managing session list state and operations. @MainActor @Observable @@ -463,8 +462,8 @@ struct SessionHeaderView: View { let onKillAll: () -> Void let onCleanupAll: () -> Void - private var runningCount: Int { sessions.count { $0.isRunning }} - private var exitedCount: Int { sessions.count { !$0.isRunning }} + private var runningCount: Int { sessions.count { $0.isRunning } } + private var exitedCount: Int { sessions.count { !$0.isRunning } } var body: some View { VStack(spacing: Theme.Spacing.medium) { diff --git a/ios/VibeTunnel/Views/Settings/SettingsView.swift b/ios/VibeTunnel/Views/Settings/SettingsView.swift index fd39789e..338f4f70 100644 --- a/ios/VibeTunnel/Views/Settings/SettingsView.swift +++ b/ios/VibeTunnel/Views/Settings/SettingsView.swift @@ -293,8 +293,8 @@ struct AdvancedSettingsView: View { windowManager.setWindowStyle(style) } - Text(macWindowStyle == .inline ? - "Traffic light buttons appear inline with content" : + Text(macWindowStyle == .inline ? + "Traffic light buttons appear inline with content" : "Standard macOS title bar with traffic lights") .font(Theme.Typography.terminalSystem(size: 12)) .foregroundColor(Theme.Colors.terminalForeground.opacity(0.6)) diff --git a/ios/VibeTunnel/Views/Terminal/CtrlKeyGrid.swift b/ios/VibeTunnel/Views/Terminal/CtrlKeyGrid.swift index 8ea6f9cc..4897d80f 100644 --- a/ios/VibeTunnel/Views/Terminal/CtrlKeyGrid.swift +++ b/ios/VibeTunnel/Views/Terminal/CtrlKeyGrid.swift @@ -69,9 +69,8 @@ struct CtrlKeyGrid: View { ForEach(currentKeys, id: \.0) { key, description in CtrlGridKeyButton( key: key, - description: description, - onPress: { sendCtrlKey(key) } - ) + description: description + ) { sendCtrlKey(key) } } } .padding() @@ -144,7 +143,7 @@ struct CtrlGridKeyButton: View { @State private var showingTooltip = false var body: some View { - Button(action: onPress, label: { + Button(action: onPress) { VStack(spacing: 4) { Text("^" + key) .font(Theme.Typography.terminalSystem(size: 20, weight: .bold)) @@ -171,7 +170,7 @@ struct CtrlGridKeyButton: View { color: isPressed ? Theme.Colors.primaryAccent.opacity(0.3) : .clear, radius: isPressed ? 8 : 0 ) - }) + } .buttonStyle(PlainButtonStyle()) .scaleEffect(isPressed ? 0.95 : 1.0) .animation(.easeInOut(duration: 0.1), value: isPressed) @@ -213,4 +212,4 @@ struct CtrlGridKeyButton: View { CtrlKeyGrid(isPresented: .constant(true)) { key in logger.debug("Ctrl key pressed: \(key)") } -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Views/Terminal/FullscreenTextInput.swift b/ios/VibeTunnel/Views/Terminal/FullscreenTextInput.swift index e624817a..394cdabf 100644 --- a/ios/VibeTunnel/Views/Terminal/FullscreenTextInput.swift +++ b/ios/VibeTunnel/Views/Terminal/FullscreenTextInput.swift @@ -211,4 +211,4 @@ struct FullscreenTextInput: View { FullscreenTextInput(isPresented: .constant(true)) { text in logger.debug("Submitted: \(text)") } -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Views/Terminal/QuickFontSizeButtons.swift b/ios/VibeTunnel/Views/Terminal/QuickFontSizeButtons.swift index 8725b524..1a722081 100644 --- a/ios/VibeTunnel/Views/Terminal/QuickFontSizeButtons.swift +++ b/ios/VibeTunnel/Views/Terminal/QuickFontSizeButtons.swift @@ -73,4 +73,4 @@ struct QuickFontSizeButtons: View { QuickFontSizeButtons(fontSize: .constant(14)) .padding() .background(Theme.Colors.terminalBackground) -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Views/Terminal/TerminalBufferPreview.swift b/ios/VibeTunnel/Views/Terminal/TerminalBufferPreview.swift index b9b15edf..828b9fcf 100644 --- a/ios/VibeTunnel/Views/Terminal/TerminalBufferPreview.swift +++ b/ios/VibeTunnel/Views/Terminal/TerminalBufferPreview.swift @@ -14,7 +14,7 @@ struct TerminalBufferPreview: View { } var body: some View { - GeometryReader { geometry in + GeometryReader { _ in ScrollViewReader { scrollProxy in ScrollView([.horizontal, .vertical], showsIndicators: false) { VStack(alignment: .leading, spacing: 0) { @@ -185,4 +185,4 @@ struct CompactTerminalPreview: View { return lines } -} \ No newline at end of file +} diff --git a/ios/VibeTunnel/Views/Terminal/TerminalView.swift b/ios/VibeTunnel/Views/Terminal/TerminalView.swift index 3df3379c..9c9f56c4 100644 --- a/ios/VibeTunnel/Views/Terminal/TerminalView.swift +++ b/ios/VibeTunnel/Views/Terminal/TerminalView.swift @@ -523,12 +523,11 @@ struct TerminalView: View { .focused($isInputFocused) .overlay( ScrollToBottomButton( - isVisible: showScrollToBottom, - action: { + isVisible: showScrollToBottom + ) { viewModel.scrollToBottom() showScrollToBottom = false } - ) .padding(.bottom, Theme.Spacing.large) .padding(.leading, Theme.Spacing.large), alignment: .bottomLeading diff --git a/mac/VibeTunnel/Core/Services/BunServer.swift b/mac/VibeTunnel/Core/Services/BunServer.swift index 34f3c2ec..21b06851 100644 --- a/mac/VibeTunnel/Core/Services/BunServer.swift +++ b/mac/VibeTunnel/Core/Services/BunServer.swift @@ -230,15 +230,14 @@ final class BunServer { } } catch { // Log more detailed error information - let errorMessage: String - if let bunError = error as? BunServerError { - errorMessage = bunError.localizedDescription + let errorMessage: String = if let bunError = error as? BunServerError { + bunError.localizedDescription } else if let urlError = error as? URLError { - errorMessage = "Network error: \(urlError.localizedDescription) (Code: \(urlError.code.rawValue))" + "Network error: \(urlError.localizedDescription) (Code: \(urlError.code.rawValue))" } else if let posixError = error as? POSIXError { - errorMessage = "System error: \(posixError.localizedDescription) (Code: \(posixError.code.rawValue))" + "System error: \(posixError.localizedDescription) (Code: \(posixError.code.rawValue))" } else { - errorMessage = error.localizedDescription + error.localizedDescription } logger.error("Failed to start Bun server: \(errorMessage)") diff --git a/mac/VibeTunnel/Core/Services/NgrokService.swift b/mac/VibeTunnel/Core/Services/NgrokService.swift index cb4becae..90c1a7d7 100644 --- a/mac/VibeTunnel/Core/Services/NgrokService.swift +++ b/mac/VibeTunnel/Core/Services/NgrokService.swift @@ -69,7 +69,7 @@ protocol NgrokTunnelProtocol { @MainActor final class NgrokService: NgrokTunnelProtocol { static let shared = NgrokService() - + /// Current tunnel status private(set) var tunnelStatus: NgrokTunnelStatus? diff --git a/mac/VibeTunnel/Core/Services/ServerManager.swift b/mac/VibeTunnel/Core/Services/ServerManager.swift index dc245dad..8fae7c75 100644 --- a/mac/VibeTunnel/Core/Services/ServerManager.swift +++ b/mac/VibeTunnel/Core/Services/ServerManager.swift @@ -8,37 +8,37 @@ enum ServerError: LocalizedError { case repeatedCrashes(count: Int) case portInUse(port: Int) case startupFailed(String) - + var errorDescription: String? { switch self { case .repeatedCrashes: - return "Server keeps crashing" + "Server keeps crashing" case .portInUse(let port): - return "Port \(port) is already in use" + "Port \(port) is already in use" case .startupFailed(let reason): - return "Server startup failed: \(reason)" + "Server startup failed: \(reason)" } } - + var failureReason: String? { switch self { case .repeatedCrashes(let count): - return "The server crashed \(count) times in a row" + "The server crashed \(count) times in a row" case .portInUse(let port): - return "Another process is using port \(port)" + "Another process is using port \(port)" case .startupFailed: - return nil + nil } } - + var recoverySuggestion: String? { switch self { case .repeatedCrashes: - return "Check the logs for errors or try a different port" + "Check the logs for errors or try a different port" case .portInUse: - return "Stop the other process or choose a different port" + "Stop the other process or choose a different port" case .startupFailed: - return "Check the server configuration and try again" + "Check the server configuration and try again" } } } @@ -52,7 +52,7 @@ enum ServerError: LocalizedError { @Observable class ServerManager { static let shared = ServerManager() - + var port: String { get { UserDefaults.standard.string(forKey: "serverPort") ?? "4020" } set { UserDefaults.standard.set(newValue, forKey: "serverPort") } @@ -504,32 +504,32 @@ class ServerManager { enum ServerManagerError: LocalizedError { case portInUseByApp(appName: String, port: Int, alternatives: [Int]) - + var errorDescription: String? { switch self { case .portInUseByApp(let appName, let port, _): - return "Port \(port) is in use by \(appName)" + "Port \(port) is in use by \(appName)" } } - + var failureReason: String? { switch self { case .portInUseByApp: - return "The port is being used by another application" + "The port is being used by another application" } } - + var recoverySuggestion: String? { switch self { case .portInUseByApp(_, _, let alternatives): - return "Try one of these ports: \(alternatives.map(String.init).joined(separator: ", "))" + "Try one of these ports: \(alternatives.map(String.init).joined(separator: ", "))" } } - + var helpAnchor: String? { switch self { case .portInUseByApp: - return "port-conflict" + "port-conflict" } } } diff --git a/mac/VibeTunnel/Core/Services/SessionMonitor.swift b/mac/VibeTunnel/Core/Services/SessionMonitor.swift index f892bab2..d802884f 100644 --- a/mac/VibeTunnel/Core/Services/SessionMonitor.swift +++ b/mac/VibeTunnel/Core/Services/SessionMonitor.swift @@ -22,7 +22,7 @@ struct ServerSessionInfo: Codable { @Observable final class SessionMonitor { static let shared = SessionMonitor() - + private(set) var sessions: [String: ServerSessionInfo] = [:] private(set) var lastError: Error? diff --git a/mac/VibeTunnel/Core/Utilities/ErrorHandling.swift b/mac/VibeTunnel/Core/Utilities/ErrorHandling.swift index f35e95cf..6dc6bdd1 100644 --- a/mac/VibeTunnel/Core/Utilities/ErrorHandling.swift +++ b/mac/VibeTunnel/Core/Utilities/ErrorHandling.swift @@ -7,7 +7,7 @@ struct ErrorAlertModifier: ViewModifier { @Binding var error: Error? let title: String let onDismiss: (() -> Void)? - + func body(content: Content) -> some View { content .alert( @@ -31,7 +31,9 @@ extension View { _ title: String = "Error", error: Binding, onDismiss: (() -> Void)? = nil - ) -> some View { + ) + -> some View + { modifier(ErrorAlertModifier(error: error, title: title, onDismiss: onDismiss)) } } @@ -46,7 +48,9 @@ extension Task where Failure == Error { priority: TaskPriority? = nil, errorBinding: Binding, operation: @escaping () async throws -> T - ) -> Task { + ) + -> Task + { Task(priority: priority) { do { return try await operation() @@ -77,26 +81,26 @@ struct ErrorRecoveryAction { struct ErrorToast: View { let error: Error let onDismiss: () -> Void - + @State private var opacity: Double = 0 - + var body: some View { HStack(spacing: 12) { Image(systemName: "exclamationmark.triangle.fill") .foregroundColor(.red) - + VStack(alignment: .leading, spacing: 4) { Text("Error") .font(.headline) - + Text(error.localizedDescription) .font(.subheadline) .foregroundColor(.secondary) .lineLimit(2) } - + Spacer() - + Button(action: onDismiss) { Image(systemName: "xmark.circle.fill") .foregroundColor(.secondary) @@ -129,7 +133,7 @@ struct ErrorToast: View { struct AsyncErrorBoundary: View { @State private var error: Error? let content: () -> Content - + var body: some View { content() .environment(\.asyncErrorHandler, AsyncErrorHandler { error in @@ -142,7 +146,7 @@ struct AsyncErrorBoundary: View { // MARK: - Environment Values private struct AsyncErrorHandlerKey: EnvironmentKey { - nonisolated(unsafe) static let defaultValue = AsyncErrorHandler(handler: { _ in }) + nonisolated(unsafe) static let defaultValue = AsyncErrorHandler { _ in } } extension EnvironmentValues { @@ -154,8 +158,8 @@ extension EnvironmentValues { struct AsyncErrorHandler { let handler: (Error) -> Void - + func handle(_ error: Error) { handler(error) } -} \ No newline at end of file +} diff --git a/mac/VibeTunnel/Presentation/Views/MenuBarView.swift b/mac/VibeTunnel/Presentation/Views/MenuBarView.swift index 9838ff22..9f01dedf 100644 --- a/mac/VibeTunnel/Presentation/Views/MenuBarView.swift +++ b/mac/VibeTunnel/Presentation/Views/MenuBarView.swift @@ -205,7 +205,7 @@ struct ServerStatusView: View { .foregroundColor(.primary) .lineLimit(1) } - + if isRunning { Text(accessText) .font(.system(size: 11)) @@ -219,12 +219,12 @@ struct ServerStatusView: View { private var statusText: String { if isRunning { - return "Server running" + "Server running" } else { - return "Server stopped" + "Server stopped" } } - + private var accessText: String { let bindAddress = serverManager.bindAddress if bindAddress == "127.0.0.1" { diff --git a/mac/VibeTunnel/Presentation/Views/SessionDetailView.swift b/mac/VibeTunnel/Presentation/Views/SessionDetailView.swift index b9cfcdd0..1b94bd1e 100644 --- a/mac/VibeTunnel/Presentation/Views/SessionDetailView.swift +++ b/mac/VibeTunnel/Presentation/Views/SessionDetailView.swift @@ -1,11 +1,11 @@ -import SwiftUI import os +import SwiftUI /// View displaying detailed information about a specific terminal session struct SessionDetailView: View { let session: ServerSessionInfo @State private var windowTitle = "" - + private let logger = Logger(subsystem: "sh.vibetunnel.vibetunnel", category: "SessionDetailView") var body: some View { diff --git a/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift b/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift index 18873581..482e49dd 100644 --- a/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift +++ b/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift @@ -210,11 +210,11 @@ struct DashboardSettingsView: View { } else { // Just password change, no network mode switch await updateServerForPasswordChange(action: .apply, logger: logger) - + // Restart server to apply new password logger.info("Restarting server to apply new password") await serverManager.restart() - + // Wait for server to be ready try? await Task.sleep(for: .seconds(1)) } @@ -372,11 +372,11 @@ private struct SecuritySection: View { // Go server handles authentication internally logger.info("Clearing auth cache to remove password") await serverManager.clearAuthCache() - + // Restart server to remove password protection logger.info("Restarting server to remove password protection") await serverManager.restart() - + // Wait for server to be ready try? await Task.sleep(for: .seconds(1)) } @@ -685,82 +685,82 @@ private struct PortConfigurationView: View { // Port conflict warning if let conflict = portConflict { - VStack(alignment: .leading, spacing: 6) { - HStack(spacing: 4) { - Image(systemName: "exclamationmark.triangle.fill") - .foregroundColor(.orange) - .font(.caption) + VStack(alignment: .leading, spacing: 6) { + HStack(spacing: 4) { + Image(systemName: "exclamationmark.triangle.fill") + .foregroundColor(.orange) + .font(.caption) - Text("Port \(conflict.port) is used by \(conflict.process.name)") - .font(.caption) - .foregroundColor(.orange) - } + Text("Port \(conflict.port) is used by \(conflict.process.name)") + .font(.caption) + .foregroundColor(.orange) + } - HStack(spacing: 8) { - if !conflict.alternativePorts.isEmpty { - HStack(spacing: 4) { - Text("Try port:") - .font(.caption) - .foregroundStyle(.secondary) + HStack(spacing: 8) { + if !conflict.alternativePorts.isEmpty { + HStack(spacing: 4) { + Text("Try port:") + .font(.caption) + .foregroundStyle(.secondary) - ForEach(conflict.alternativePorts.prefix(3), id: \.self) { port in - Button(String(port)) { - serverPort = String(port) - portNumber = port - restartServerWithNewPort(port) + ForEach(conflict.alternativePorts.prefix(3), id: \.self) { port in + Button(String(port)) { + serverPort = String(port) + portNumber = port + restartServerWithNewPort(port) + } + .buttonStyle(.link) + .font(.caption) + } + + Button("Choose...") { + showPortPicker() } .buttonStyle(.link) .font(.caption) } + } - Button("Choose...") { - showPortPicker() + Spacer() + + Button { + Task { + await forceQuitConflictingProcess(conflict) + } + } label: { + HStack(spacing: 4) { + Image(systemName: "xmark.circle.fill") + .font(.caption) + Text("Kill Process") + .font(.caption) } - .buttonStyle(.link) - .font(.caption) } + .buttonStyle(.borderedProminent) + .controlSize(.small) + .tint(.red) } - - Spacer() - - Button { - Task { - await forceQuitConflictingProcess(conflict) - } - } label: { - HStack(spacing: 4) { - Image(systemName: "xmark.circle.fill") - .font(.caption) - Text("Kill Process") - .font(.caption) - } - } - .buttonStyle(.borderedProminent) - .controlSize(.small) - .tint(.red) } - } - .padding(.vertical, 8) - .padding(.horizontal, 12) - .frame(maxWidth: .infinity, alignment: .leading) - .background(Color.orange.opacity(0.1)) - .cornerRadius(6) - } else if !serverManager.isRunning && serverManager.lastError != nil { - // Show general server error if no specific port conflict - HStack(spacing: 4) { - Image(systemName: "exclamationmark.circle.fill") - .foregroundColor(.red) - .font(.caption) + .padding(.vertical, 8) + .padding(.horizontal, 12) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color.orange.opacity(0.1)) + .cornerRadius(6) + } else if !serverManager.isRunning && serverManager.lastError != nil { + // Show general server error if no specific port conflict + HStack(spacing: 4) { + Image(systemName: "exclamationmark.circle.fill") + .foregroundColor(.red) + .font(.caption) - Text("Server failed to start") + Text("Server failed to start") + .font(.caption) + .foregroundColor(.red) + } + } else { + Text("The server will automatically restart when the port is changed.") .font(.caption) - .foregroundColor(.red) - } - } else { - Text("The server will automatically restart when the port is changed.") - .font(.caption) - .foregroundStyle(.secondary) - .padding(.top, 4) + .foregroundStyle(.secondary) + .padding(.top, 4) } } } diff --git a/mac/VibeTunnel/Presentation/Views/Shared/GlowingAppIcon.swift b/mac/VibeTunnel/Presentation/Views/Shared/GlowingAppIcon.swift index 6ca89ae8..ed370864 100644 --- a/mac/VibeTunnel/Presentation/Views/Shared/GlowingAppIcon.swift +++ b/mac/VibeTunnel/Presentation/Views/Shared/GlowingAppIcon.swift @@ -1,5 +1,5 @@ -import SwiftUI import os +import SwiftUI /// Shared glowing app icon component with configurable animation and effects. /// @@ -7,9 +7,9 @@ import os /// floating animation, and interactive behaviors. It can be used in both the Welcome /// and About views with different configurations. struct GlowingAppIcon: View { - // Configuration + /// Configuration let size: CGFloat - + private let logger = Logger(subsystem: "sh.vibetunnel.vibetunnel", category: "GlowingAppIcon") let enableFloating: Bool let enableInteraction: Bool diff --git a/mac/VibeTunnel/Utilities/TerminalLauncher.swift b/mac/VibeTunnel/Utilities/TerminalLauncher.swift index 5590ae20..5b3ce02f 100644 --- a/mac/VibeTunnel/Utilities/TerminalLauncher.swift +++ b/mac/VibeTunnel/Utilities/TerminalLauncher.swift @@ -1,8 +1,8 @@ import AppKit import Foundation +import Observation import os.log import SwiftUI -import Observation /// Terminal launch result with window/tab information struct TerminalLaunchResult { @@ -689,7 +689,7 @@ final class TerminalLauncher { let fullCommand: String // Check if we have a Bun executable (it would be bundled as vibetunnel) let bunServerActive = Bundle.main.path(forResource: "vibetunnel", ofType: nil) != nil && - !command.contains("TTY_SESSION_ID=") // If command already has session ID, it's from Go server + !command.contains("TTY_SESSION_ID=") // If command already has session ID, it's from Go server if bunServerActive { // For Bun server, use fwd command logger.info("Using Bun server session creation via fwd") diff --git a/mac/VibeTunnel/VibeTunnelApp.swift b/mac/VibeTunnel/VibeTunnelApp.swift index 36107a73..ed2eec9c 100644 --- a/mac/VibeTunnel/VibeTunnelApp.swift +++ b/mac/VibeTunnel/VibeTunnelApp.swift @@ -163,6 +163,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, @preconcurrency UNUser } // Initialize dock icon visibility through DockIconManager + DockIconManager.initialize() DockIconManager.shared.updateDockVisibility() // Show welcome screen when version changes @@ -320,7 +321,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, @preconcurrency UNUser @objc private func openDashboard() { if let serverManager = app?.serverManager, - let url = URL(string: "http://localhost:\(serverManager.port)") { + let url = URL(string: "http://localhost:\(serverManager.port)") + { NSWorkspace.shared.open(url) } }