diff --git a/apps/macos/Sources/Clawdis/AppState.swift b/apps/macos/Sources/Clawdis/AppState.swift index e54d98adf..53d81c02d 100644 --- a/apps/macos/Sources/Clawdis/AppState.swift +++ b/apps/macos/Sources/Clawdis/AppState.swift @@ -38,6 +38,7 @@ final class AppState { var debugPaneEnabled: Bool { didSet { self.ifNotPreview { UserDefaults.standard.set(self.debugPaneEnabled, forKey: "clawdis.debugPaneEnabled") } + CanvasManager.shared.refreshDebugStatus() } } diff --git a/apps/macos/Sources/Clawdis/CanvasManager.swift b/apps/macos/Sources/Clawdis/CanvasManager.swift index fc8826dd1..650d63bd3 100644 --- a/apps/macos/Sources/Clawdis/CanvasManager.swift +++ b/apps/macos/Sources/Clawdis/CanvasManager.swift @@ -56,6 +56,7 @@ final class CanvasManager { } controller.presentAnchoredPanel(anchorProvider: anchorProvider) controller.applyPreferredPlacement(placement) + self.refreshDebugStatus() // Existing session: only navigate when an explicit target was provided. if let normalizedTarget { @@ -103,6 +104,7 @@ final class CanvasManager { if normalizedTarget == nil { self.maybeAutoNavigateToA2UIAsync(controller: controller) } + self.refreshDebugStatus() return self.makeShowResult( directory: controller.directoryPath, @@ -177,6 +179,14 @@ final class CanvasManager { return Self.resolveA2UIHostUrl(from: raw) } + func refreshDebugStatus() { + guard let controller = self.panelController else { return } + let enabled = AppStateStore.shared.debugPaneEnabled + let title = GatewayProcessManager.shared.status.label + let subtitle = AppStateStore.shared.connectionMode.rawValue + controller.updateDebugStatus(enabled: enabled, title: title, subtitle: subtitle) + } + private static func resolveA2UIHostUrl(from raw: String?) -> String? { let trimmed = raw?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" guard !trimmed.isEmpty, let base = URL(string: trimmed) else { return nil } diff --git a/apps/macos/Sources/Clawdis/CanvasWindow.swift b/apps/macos/Sources/Clawdis/CanvasWindow.swift index d53a241c3..0a111e9d4 100644 --- a/apps/macos/Sources/Clawdis/CanvasWindow.swift +++ b/apps/macos/Sources/Clawdis/CanvasWindow.swift @@ -44,6 +44,9 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS let presentation: CanvasPresentation private var preferredPlacement: CanvasPlacement? private(set) var currentTarget: String? + private var debugStatusEnabled = false + private var debugStatusTitle: String? + private var debugStatusSubtitle: String? var onVisibilityChanged: ((Bool) -> Void)? @@ -278,6 +281,35 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS self.webView.load(URLRequest(url: url)) } + func updateDebugStatus(enabled: Bool, title: String?, subtitle: String?) { + self.debugStatusEnabled = enabled + self.debugStatusTitle = title + self.debugStatusSubtitle = subtitle + self.applyDebugStatusIfNeeded() + } + + private func applyDebugStatusIfNeeded() { + let enabled = self.debugStatusEnabled + let title = Self.jsOptionalStringLiteral(self.debugStatusTitle) + let subtitle = Self.jsOptionalStringLiteral(self.debugStatusSubtitle) + let js = """ + (() => { + try { + const api = globalThis.__clawdis; + if (!api) return; + if (typeof api.setDebugStatusEnabled === 'function') { + api.setDebugStatusEnabled(\(enabled ? "true" : "false")); + } + if (!\(enabled ? "true" : "false")) return; + if (typeof api.setStatus === 'function') { + api.setStatus(\(title), \(subtitle)); + } + } catch (_) {} + })(); + """ + self.webView.evaluateJavaScript(js) { _, _ in } + } + private func loadFile(_ url: URL) { let fileURL = url.isFileURL ? url : URL(fileURLWithPath: url.path) let accessDir = fileURL.deletingLastPathComponent() @@ -551,6 +583,10 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS decisionHandler(.cancel) } + func webView(_: WKWebView, didFinish _: WKNavigation?) { + self.applyDebugStatusIfNeeded() + } + // MARK: - NSWindowDelegate func windowWillClose(_: Notification) { @@ -585,6 +621,11 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS return data.flatMap { String(data: $0, encoding: .utf8) } ?? "\"\"" } + private static func jsOptionalStringLiteral(_ value: String?) -> String { + guard let value else { return "null" } + return Self.jsStringLiteral(value) + } + private static func storedFrameDefaultsKey(sessionKey: String) -> String { "clawdis.canvas.frame.\(self.sanitizeSessionKey(sessionKey))" } diff --git a/apps/macos/Sources/Clawdis/GatewayProcessManager.swift b/apps/macos/Sources/Clawdis/GatewayProcessManager.swift index 8d711e74a..3b7551aaf 100644 --- a/apps/macos/Sources/Clawdis/GatewayProcessManager.swift +++ b/apps/macos/Sources/Clawdis/GatewayProcessManager.swift @@ -30,7 +30,9 @@ final class GatewayProcessManager { } } - private(set) var status: Status = .stopped + private(set) var status: Status = .stopped { + didSet { CanvasManager.shared.refreshDebugStatus() } + } private(set) var log: String = "" private(set) var environmentStatus: GatewayEnvironmentStatus = .checking private(set) var existingGatewayDetails: String?