diff --git a/apps/macos/Sources/Clawdis/ToolsSettings.swift b/apps/macos/Sources/Clawdis/ToolsSettings.swift index f05376d24..06a24fe74 100644 --- a/apps/macos/Sources/Clawdis/ToolsSettings.swift +++ b/apps/macos/Sources/Clawdis/ToolsSettings.swift @@ -147,11 +147,11 @@ struct ToolsSettings: View { method: .brew(formula: "openhue/cli/openhue-cli", binary: "openhue"), kind: .tool), ToolEntry( - id: "openai-whisper", - name: "OpenAI Whisper", - url: URL(string: "https://github.com/openai/whisper")!, - description: "On-device speech-to-text for quick note taking or voicemail transcription.", - method: .brew(formula: "openai-whisper", binary: "whisper"), + id: "gog", + name: "gog", + url: URL(string: "https://github.com/steipete/gog")!, + description: "Unified Google CLI for Gmail, Calendar, Drive, and Contacts. Replaces MCP servers.", + method: .brew(formula: "steipete/tap/gog", binary: "gog"), kind: .tool), ToolEntry( id: "gemini-cli", @@ -179,26 +179,6 @@ struct ToolsSettings: View { url: "https://github.com/badlogic/agent-tools.git", destination: "\(NSHomeDirectory())/agent-tools"), kind: .tool), - ToolEntry( - id: "gmail-mcp", - name: "Gmail MCP", - url: URL(string: "https://www.npmjs.com/package/@gongrzhe/server-gmail-autoauth-mcp")!, - description: "Model Context Protocol server that exposes Gmail search, read, and send tools.", - method: .mcporter( - name: "gmail", - command: "npx -y @gongrzhe/server-gmail-autoauth-mcp", - summary: "Adds Gmail MCP via mcporter (stdio transport, auto-auth)."), - kind: .mcp), - ToolEntry( - id: "google-calendar-mcp", - name: "Google Calendar MCP", - url: URL(string: "https://www.npmjs.com/package/@cocal/google-calendar-mcp")!, - description: "MCP server to list, create, and update calendar events for scheduling automations.", - method: .mcporter( - name: "google-calendar", - command: "npx -y @cocal/google-calendar-mcp", - summary: "Adds Google Calendar MCP via mcporter (stdio transport)."), - kind: .mcp), ] @AppStorage("tools.packageManager") private var packageManagerRaw = NodePackageManager.npm.rawValue diff --git a/apps/macos/Sources/Clawdis/WebChatWindow.swift b/apps/macos/Sources/Clawdis/WebChatWindow.swift index f0d4e366f..5bf8640e3 100644 --- a/apps/macos/Sources/Clawdis/WebChatWindow.swift +++ b/apps/macos/Sources/Clawdis/WebChatWindow.swift @@ -538,8 +538,10 @@ final class WebChatManager { static let shared = WebChatManager() private var windowController: WebChatWindowController? private var panelController: WebChatWindowController? + private var panelSessionKey: String? private var swiftWindowController: WebChatSwiftUIWindowController? private var swiftPanelController: WebChatSwiftUIWindowController? + private var swiftPanelSessionKey: String? private var browserTunnel: WebChatTunnel? var onPanelVisibilityChanged: ((Bool) -> Void)? @@ -575,12 +577,18 @@ final class WebChatManager { func togglePanel(sessionKey: String, anchorProvider: @escaping () -> NSRect?) { if AppStateStore.webChatSwiftUIEnabled { if let controller = self.swiftPanelController { - if controller.isVisible { + if self.swiftPanelSessionKey != sessionKey { controller.close() + self.swiftPanelController = nil + self.swiftPanelSessionKey = nil } else { - controller.presentAnchored(anchorProvider: anchorProvider) + if controller.isVisible { + controller.close() + } else { + controller.presentAnchored(anchorProvider: anchorProvider) + } + return } - return } let controller = WebChatSwiftUIWindowController( sessionKey: sessionKey, @@ -592,21 +600,30 @@ final class WebChatManager { self?.onPanelVisibilityChanged?(visible) } self.swiftPanelController = controller + self.swiftPanelSessionKey = sessionKey controller.presentAnchored(anchorProvider: anchorProvider) } else { if let controller = self.panelController { - if controller.window?.isVisible == true { - controller.closePanel() + if self.panelSessionKey != sessionKey { + controller.shutdown() + controller.close() + self.panelController = nil + self.panelSessionKey = nil } else { - controller.presentAnchoredPanel(anchorProvider: anchorProvider) + if controller.window?.isVisible == true { + controller.closePanel() + } else { + controller.presentAnchoredPanel(anchorProvider: anchorProvider) + } + return } - return } let controller = WebChatWindowController( sessionKey: sessionKey, presentation: .panel(anchorProvider: anchorProvider)) self.panelController = controller + self.panelSessionKey = sessionKey controller.onPanelClosed = { [weak self] in self?.panelHidden() } @@ -656,10 +673,12 @@ final class WebChatManager { self.panelController?.shutdown() self.panelController?.close() self.panelController = nil + self.panelSessionKey = nil self.swiftWindowController?.close() self.swiftWindowController = nil self.swiftPanelController?.close() self.swiftPanelController = nil + self.swiftPanelSessionKey = nil } @MainActor @@ -712,17 +731,18 @@ final class WebChatManager { self.panelController?.shutdown() self.panelController?.close() self.panelController = nil + self.panelSessionKey = nil self.swiftWindowController?.close() self.swiftWindowController = nil self.swiftPanelController?.close() self.swiftPanelController = nil + self.swiftPanelSessionKey = nil } private func panelHidden() { self.onPanelVisibilityChanged?(false) - self.panelController = nil - self.swiftPanelController = nil + // Keep panel controllers cached so reopening doesn't re-bootstrap. } }