From efed2ae30feaade2eece6595c2d75baae1bd2d74 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 18 Dec 2025 02:05:06 +0000 Subject: [PATCH] Nodes: advertise canvas invoke commands --- .../com/steipete/clawdis/node/NodeRuntime.kt | 42 ++++++---- .../node/bridge/BridgePairingClient.kt | 3 + .../clawdis/node/bridge/BridgeSession.kt | 2 + .../node/bridge/BridgePairingClientTest.kt | 2 + .../clawdis/node/bridge/BridgeSessionTest.kt | 4 + apps/ios/Sources/Bridge/BridgeClient.swift | 21 ++--- .../Bridge/BridgeConnectionController.swift | 22 +++++- apps/ios/Sources/Model/NodeAppModel.swift | 20 ++--- .../ios/Sources/Screen/ScreenController.swift | 4 +- apps/ios/Sources/Settings/SettingsTab.swift | 78 ++++++++++++++++++- apps/ios/Tests/CanvasCommandAliasTests.swift | 38 --------- .../Sources/ClawdisKit/BridgeFrames.swift | 8 +- .../ClawdisKit/CanvasCommandParams.swift | 47 +++++++++++ .../Sources/ClawdisKit/CanvasCommands.swift | 18 ----- .../Sources/ClawdisKit/ScreenCommands.swift | 56 ------------- 15 files changed, 212 insertions(+), 153 deletions(-) delete mode 100644 apps/ios/Tests/CanvasCommandAliasTests.swift create mode 100644 apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommandParams.swift delete mode 100644 apps/shared/ClawdisKit/Sources/ClawdisKit/ScreenCommands.swift diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/NodeRuntime.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/NodeRuntime.kt index b70a55edb..c0cf1bfc9 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/NodeRuntime.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/NodeRuntime.kt @@ -266,6 +266,20 @@ class NodeRuntime(context: Context) { .joinToString(" ") .trim() .ifEmpty { null } + + val invokeCommands = + buildList { + add("canvas.show") + add("canvas.hide") + add("canvas.setMode") + add("canvas.navigate") + add("canvas.eval") + add("canvas.snapshot") + if (cameraEnabled.value) { + add("camera.snap") + add("camera.clip") + } + } val resolved = if (storedToken.isNullOrBlank()) { _statusText.value = "Pairing…" @@ -288,6 +302,7 @@ class NodeRuntime(context: Context) { deviceFamily = "Android", modelIdentifier = modelIdentifier, caps = caps, + commands = invokeCommands, ), ) } else { @@ -311,19 +326,20 @@ class NodeRuntime(context: Context) { platform = "Android", version = "dev", deviceFamily = "Android", - modelIdentifier = modelIdentifier, - caps = - buildList { - add(ClawdisCapability.Canvas.rawValue) - if (cameraEnabled.value) add(ClawdisCapability.Camera.rawValue) - if (voiceWakeMode.value != VoiceWakeMode.Off && hasRecordAudioPermission()) { - add(ClawdisCapability.VoiceWake.rawValue) - } - }, - ), - ) - } - } + modelIdentifier = modelIdentifier, + caps = + buildList { + add(ClawdisCapability.Canvas.rawValue) + if (cameraEnabled.value) add(ClawdisCapability.Camera.rawValue) + if (voiceWakeMode.value != VoiceWakeMode.Off && hasRecordAudioPermission()) { + add(ClawdisCapability.VoiceWake.rawValue) + } + }, + commands = invokeCommands, + ), + ) + } + } private fun hasRecordAudioPermission(): Boolean { return ( diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgePairingClient.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgePairingClient.kt index 9284c69af..c7ac303bc 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgePairingClient.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgePairingClient.kt @@ -28,6 +28,7 @@ class BridgePairingClient { val deviceFamily: String?, val modelIdentifier: String?, val caps: List?, + val commands: List?, ) data class PairResult(val ok: Boolean, val token: String?, val error: String? = null) @@ -62,6 +63,7 @@ class BridgePairingClient { hello.deviceFamily?.let { put("deviceFamily", JsonPrimitive(it)) } hello.modelIdentifier?.let { put("modelIdentifier", JsonPrimitive(it)) } hello.caps?.let { put("caps", JsonArray(it.map(::JsonPrimitive))) } + hello.commands?.let { put("commands", JsonArray(it.map(::JsonPrimitive))) } }, ) @@ -86,6 +88,7 @@ class BridgePairingClient { hello.deviceFamily?.let { put("deviceFamily", JsonPrimitive(it)) } hello.modelIdentifier?.let { put("modelIdentifier", JsonPrimitive(it)) } hello.caps?.let { put("caps", JsonArray(it.map(::JsonPrimitive))) } + hello.commands?.let { put("commands", JsonArray(it.map(::JsonPrimitive))) } }, ) diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeSession.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeSession.kt index bab28bc04..9b44a5aca 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeSession.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeSession.kt @@ -43,6 +43,7 @@ class BridgeSession( val deviceFamily: String?, val modelIdentifier: String?, val caps: List?, + val commands: List?, ) data class InvokeRequest(val id: String, val command: String, val paramsJson: String?) @@ -198,6 +199,7 @@ class BridgeSession( hello.deviceFamily?.let { put("deviceFamily", JsonPrimitive(it)) } hello.modelIdentifier?.let { put("modelIdentifier", JsonPrimitive(it)) } hello.caps?.let { put("caps", JsonArray(it.map(::JsonPrimitive))) } + hello.commands?.let { put("commands", JsonArray(it.map(::JsonPrimitive))) } }, ) diff --git a/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgePairingClientTest.kt b/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgePairingClientTest.kt index 8df358a8d..abb79fd36 100644 --- a/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgePairingClientTest.kt +++ b/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgePairingClientTest.kt @@ -49,6 +49,7 @@ class BridgePairingClientTest { deviceFamily = "Android", modelIdentifier = "SM-X000", caps = null, + commands = null, ), ) assertTrue(res.ok) @@ -97,6 +98,7 @@ class BridgePairingClientTest { deviceFamily = "Android", modelIdentifier = "SM-X000", caps = null, + commands = null, ), ) assertTrue(res.ok) diff --git a/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgeSessionTest.kt b/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgeSessionTest.kt index 2db4d91d1..73458b3a9 100644 --- a/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgeSessionTest.kt +++ b/apps/android/app/src/test/java/com/steipete/clawdis/node/bridge/BridgeSessionTest.kt @@ -72,6 +72,7 @@ class BridgeSessionTest { deviceFamily = null, modelIdentifier = null, caps = null, + commands = null, ), ) @@ -137,6 +138,7 @@ class BridgeSessionTest { deviceFamily = null, modelIdentifier = null, caps = null, + commands = null, ), ) connected.await() @@ -207,6 +209,7 @@ class BridgeSessionTest { deviceFamily = null, modelIdentifier = null, caps = null, + commands = null, ), ) connected.await() @@ -279,6 +282,7 @@ class BridgeSessionTest { deviceFamily = null, modelIdentifier = null, caps = null, + commands = null, ), ) diff --git a/apps/ios/Sources/Bridge/BridgeClient.swift b/apps/ios/Sources/Bridge/BridgeClient.swift index 1493b6480..4604e56aa 100644 --- a/apps/ios/Sources/Bridge/BridgeClient.swift +++ b/apps/ios/Sources/Bridge/BridgeClient.swift @@ -46,16 +46,17 @@ actor BridgeClient { } onStatus?("Requesting approval…") - try await self.send( - BridgePairRequest( - nodeId: hello.nodeId, - displayName: hello.displayName, - platform: hello.platform, - version: hello.version, - deviceFamily: hello.deviceFamily, - modelIdentifier: hello.modelIdentifier, - caps: hello.caps), - over: connection) + try await self.send( + BridgePairRequest( + nodeId: hello.nodeId, + displayName: hello.displayName, + platform: hello.platform, + version: hello.version, + deviceFamily: hello.deviceFamily, + modelIdentifier: hello.modelIdentifier, + caps: hello.caps, + commands: hello.commands), + over: connection) onStatus?("Waiting for approval…") let ok = try await self.withTimeout(seconds: 60, purpose: "pairing approval") { diff --git a/apps/ios/Sources/Bridge/BridgeConnectionController.swift b/apps/ios/Sources/Bridge/BridgeConnectionController.swift index 179098d0b..bd83d2619 100644 --- a/apps/ios/Sources/Bridge/BridgeConnectionController.swift +++ b/apps/ios/Sources/Bridge/BridgeConnectionController.swift @@ -136,7 +136,8 @@ final class BridgeConnectionController { version: self.appVersion(), deviceFamily: self.deviceFamily(), modelIdentifier: self.modelIdentifier(), - caps: self.currentCaps()) + caps: self.currentCaps(), + commands: self.currentCommands()) } private func resolvedDisplayName(defaults: UserDefaults) -> String { @@ -170,6 +171,25 @@ final class BridgeConnectionController { return caps } + private func currentCommands() -> [String] { + var commands: [String] = [ + ClawdisCanvasCommand.show.rawValue, + ClawdisCanvasCommand.hide.rawValue, + ClawdisCanvasCommand.setMode.rawValue, + ClawdisCanvasCommand.navigate.rawValue, + ClawdisCanvasCommand.evalJS.rawValue, + ClawdisCanvasCommand.snapshot.rawValue, + ] + + let caps = Set(self.currentCaps()) + if caps.contains(ClawdisCapability.camera.rawValue) { + commands.append(ClawdisCameraCommand.snap.rawValue) + commands.append(ClawdisCameraCommand.clip.rawValue) + } + + return commands + } + private func platformString() -> String { let v = ProcessInfo.processInfo.operatingSystemVersion let name = switch UIDevice.current.userInterfaceIdiom { diff --git a/apps/ios/Sources/Model/NodeAppModel.swift b/apps/ios/Sources/Model/NodeAppModel.swift index bd3c4e049..367e44670 100644 --- a/apps/ios/Sources/Model/NodeAppModel.swift +++ b/apps/ios/Sources/Model/NodeAppModel.swift @@ -287,30 +287,30 @@ final class NodeAppModel { do { switch command { - case ClawdisScreenCommand.show.rawValue: + case ClawdisCanvasCommand.show.rawValue: return BridgeInvokeResponse(id: req.id, ok: true) - case ClawdisScreenCommand.hide.rawValue: + case ClawdisCanvasCommand.hide.rawValue: return BridgeInvokeResponse(id: req.id, ok: true) - case ClawdisScreenCommand.setMode.rawValue: - let params = try Self.decodeParams(ClawdisScreenSetModeParams.self, from: req.paramsJSON) + case ClawdisCanvasCommand.setMode.rawValue: + let params = try Self.decodeParams(ClawdisCanvasSetModeParams.self, from: req.paramsJSON) self.screen.setMode(params.mode) return BridgeInvokeResponse(id: req.id, ok: true) - case ClawdisScreenCommand.navigate.rawValue: - let params = try Self.decodeParams(ClawdisScreenNavigateParams.self, from: req.paramsJSON) + case ClawdisCanvasCommand.navigate.rawValue: + let params = try Self.decodeParams(ClawdisCanvasNavigateParams.self, from: req.paramsJSON) self.screen.navigate(to: params.url) return BridgeInvokeResponse(id: req.id, ok: true) - case ClawdisScreenCommand.evalJS.rawValue: - let params = try Self.decodeParams(ClawdisScreenEvalParams.self, from: req.paramsJSON) + case ClawdisCanvasCommand.evalJS.rawValue: + let params = try Self.decodeParams(ClawdisCanvasEvalParams.self, from: req.paramsJSON) let result = try await self.screen.eval(javaScript: params.javaScript) let payload = try Self.encodePayload(["result": result]) return BridgeInvokeResponse(id: req.id, ok: true, payloadJSON: payload) - case ClawdisScreenCommand.snapshot.rawValue: - let params = try? Self.decodeParams(ClawdisScreenSnapshotParams.self, from: req.paramsJSON) + case ClawdisCanvasCommand.snapshot.rawValue: + let params = try? Self.decodeParams(ClawdisCanvasSnapshotParams.self, from: req.paramsJSON) let maxWidth = params?.maxWidth.map { CGFloat($0) } let base64 = try await self.screen.snapshotPNGBase64(maxWidth: maxWidth) let payload = try Self.encodePayload(["format": "png", "base64": base64]) diff --git a/apps/ios/Sources/Screen/ScreenController.swift b/apps/ios/Sources/Screen/ScreenController.swift index 915e29341..7f201e739 100644 --- a/apps/ios/Sources/Screen/ScreenController.swift +++ b/apps/ios/Sources/Screen/ScreenController.swift @@ -9,7 +9,7 @@ final class ScreenController { let webView: WKWebView private let navigationDelegate: ScreenNavigationDelegate - var mode: ClawdisScreenMode = .canvas + var mode: ClawdisCanvasMode = .canvas var urlString: String = "" var errorText: String? @@ -36,7 +36,7 @@ final class ScreenController { self.reload() } - func setMode(_ mode: ClawdisScreenMode) { + func setMode(_ mode: ClawdisCanvasMode) { self.mode = mode self.reload() } diff --git a/apps/ios/Sources/Settings/SettingsTab.swift b/apps/ios/Sources/Settings/SettingsTab.swift index bb80c0637..31685bf6d 100644 --- a/apps/ios/Sources/Settings/SettingsTab.swift +++ b/apps/ios/Sources/Settings/SettingsTab.swift @@ -262,6 +262,60 @@ struct SettingsTab: View { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "dev" } + private func deviceFamily() -> String { + switch UIDevice.current.userInterfaceIdiom { + case .pad: + "iPad" + case .phone: + "iPhone" + default: + "iOS" + } + } + + private func modelIdentifier() -> String { + var systemInfo = utsname() + uname(&systemInfo) + let machine = withUnsafeBytes(of: &systemInfo.machine) { ptr in + String(decoding: ptr.prefix { $0 != 0 }, as: UTF8.self) + } + return machine.isEmpty ? "unknown" : machine + } + + private func currentCaps() -> [String] { + var caps = [ClawdisCapability.canvas.rawValue] + + let cameraEnabled = + UserDefaults.standard.object(forKey: "camera.enabled") == nil + ? true + : UserDefaults.standard.bool(forKey: "camera.enabled") + if cameraEnabled { caps.append(ClawdisCapability.camera.rawValue) } + + let voiceWakeEnabled = UserDefaults.standard.bool(forKey: VoiceWakePreferences.enabledKey) + if voiceWakeEnabled { caps.append(ClawdisCapability.voiceWake.rawValue) } + + return caps + } + + private func currentCommands() -> [String] { + var commands: [String] = [ + ClawdisCanvasCommand.show.rawValue, + ClawdisCanvasCommand.hide.rawValue, + ClawdisCanvasCommand.setMode.rawValue, + ClawdisCanvasCommand.navigate.rawValue, + ClawdisCanvasCommand.evalJS.rawValue, + ClawdisCanvasCommand.snapshot.rawValue, + ] + + let caps = Set(self.currentCaps()) + if caps.contains(ClawdisCapability.camera.rawValue) { + commands.append(ClawdisCameraCommand.snap.rawValue) + commands.append(ClawdisCameraCommand.clip.rawValue) + } + + return commands + } + private func connect(_ bridge: BridgeDiscoveryModel.DiscoveredBridge) async { self.connectingBridgeID = bridge.id self.manualBridgeEnabled = false @@ -285,7 +339,11 @@ struct SettingsTab: View { displayName: self.displayName, token: existingToken, platform: self.platformString(), - version: self.appVersion()) + version: self.appVersion(), + deviceFamily: self.deviceFamily(), + modelIdentifier: self.modelIdentifier(), + caps: self.currentCaps(), + commands: self.currentCommands()) let token = try await BridgeClient().pairAndHello( endpoint: bridge.endpoint, hello: hello, @@ -309,7 +367,11 @@ struct SettingsTab: View { displayName: self.displayName, token: token, platform: self.platformString(), - version: self.appVersion())) + version: self.appVersion(), + deviceFamily: self.deviceFamily(), + modelIdentifier: self.modelIdentifier(), + caps: self.currentCaps(), + commands: self.currentCommands())) } catch { self.connectStatus.text = "Failed: \(error.localizedDescription)" @@ -351,7 +413,11 @@ struct SettingsTab: View { displayName: self.displayName, token: existingToken, platform: self.platformString(), - version: self.appVersion()) + version: self.appVersion(), + deviceFamily: self.deviceFamily(), + modelIdentifier: self.modelIdentifier(), + caps: self.currentCaps(), + commands: self.currentCommands()) let token = try await BridgeClient().pairAndHello( endpoint: endpoint, hello: hello, @@ -375,7 +441,11 @@ struct SettingsTab: View { displayName: self.displayName, token: token, platform: self.platformString(), - version: self.appVersion())) + version: self.appVersion(), + deviceFamily: self.deviceFamily(), + modelIdentifier: self.modelIdentifier(), + caps: self.currentCaps(), + commands: self.currentCommands())) } catch { self.connectStatus.text = "Failed: \(error.localizedDescription)" diff --git a/apps/ios/Tests/CanvasCommandAliasTests.swift b/apps/ios/Tests/CanvasCommandAliasTests.swift deleted file mode 100644 index 82f863fa7..000000000 --- a/apps/ios/Tests/CanvasCommandAliasTests.swift +++ /dev/null @@ -1,38 +0,0 @@ -import ClawdisKit -import Testing - -@Suite struct CanvasCommandAliasTests { - @Test func mapsKnownCanvasCommandsToScreen() { - let mappings: [(ClawdisCanvasCommand, ClawdisScreenCommand)] = [ - (.show, .show), - (.hide, .hide), - (.setMode, .setMode), - (.navigate, .navigate), - (.evalJS, .evalJS), - (.snapshot, .snapshot), - ] - - for (canvas, screen) in mappings { - #expect( - ClawdisInvokeCommandAliases.canonicalizeCanvasToScreen(canvas.rawValue) == - screen.rawValue) - } - } - - @Test func mapsUnknownCanvasNamespaceToScreen() { - #expect(ClawdisInvokeCommandAliases.canonicalizeCanvasToScreen("canvas.foo") == "screen.foo") - } - - @Test func leavesNonCanvasCommandsUnchanged() { - #expect( - ClawdisInvokeCommandAliases.canonicalizeCanvasToScreen(ClawdisCameraCommand.snap.rawValue) == - ClawdisCameraCommand.snap.rawValue) - } - - @Test func capabilitiesUseStableStrings() { - #expect(ClawdisCapability.canvas.rawValue == "canvas") - #expect(ClawdisCapability.camera.rawValue == "camera") - #expect(ClawdisCapability.voiceWake.rawValue == "voiceWake") - } -} - diff --git a/apps/shared/ClawdisKit/Sources/ClawdisKit/BridgeFrames.swift b/apps/shared/ClawdisKit/Sources/ClawdisKit/BridgeFrames.swift index 9c0926d2b..af222ecae 100644 --- a/apps/shared/ClawdisKit/Sources/ClawdisKit/BridgeFrames.swift +++ b/apps/shared/ClawdisKit/Sources/ClawdisKit/BridgeFrames.swift @@ -66,6 +66,7 @@ public struct BridgeHello: Codable, Sendable { public let deviceFamily: String? public let modelIdentifier: String? public let caps: [String]? + public let commands: [String]? public init( type: String = "hello", @@ -76,7 +77,8 @@ public struct BridgeHello: Codable, Sendable { version: String?, deviceFamily: String? = nil, modelIdentifier: String? = nil, - caps: [String]? = nil) + caps: [String]? = nil, + commands: [String]? = nil) { self.type = type self.nodeId = nodeId @@ -87,6 +89,7 @@ public struct BridgeHello: Codable, Sendable { self.deviceFamily = deviceFamily self.modelIdentifier = modelIdentifier self.caps = caps + self.commands = commands } } @@ -109,6 +112,7 @@ public struct BridgePairRequest: Codable, Sendable { public let deviceFamily: String? public let modelIdentifier: String? public let caps: [String]? + public let commands: [String]? public let remoteAddress: String? public init( @@ -120,6 +124,7 @@ public struct BridgePairRequest: Codable, Sendable { deviceFamily: String? = nil, modelIdentifier: String? = nil, caps: [String]? = nil, + commands: [String]? = nil, remoteAddress: String? = nil) { self.type = type @@ -130,6 +135,7 @@ public struct BridgePairRequest: Codable, Sendable { self.deviceFamily = deviceFamily self.modelIdentifier = modelIdentifier self.caps = caps + self.commands = commands self.remoteAddress = remoteAddress } } diff --git a/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommandParams.swift b/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommandParams.swift new file mode 100644 index 000000000..6d357f7f0 --- /dev/null +++ b/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommandParams.swift @@ -0,0 +1,47 @@ +import Foundation + +public enum ClawdisCanvasMode: String, Codable, Sendable { + case canvas + case web +} + +public struct ClawdisCanvasNavigateParams: Codable, Sendable, Equatable { + public var url: String + + public init(url: String) { + self.url = url + } +} + +public struct ClawdisCanvasSetModeParams: Codable, Sendable, Equatable { + public var mode: ClawdisCanvasMode + + public init(mode: ClawdisCanvasMode) { + self.mode = mode + } +} + +public struct ClawdisCanvasEvalParams: Codable, Sendable, Equatable { + public var javaScript: String + + public init(javaScript: String) { + self.javaScript = javaScript + } +} + +public enum ClawdisCanvasSnapshotFormat: String, Codable, Sendable { + case png + case jpeg +} + +public struct ClawdisCanvasSnapshotParams: Codable, Sendable, Equatable { + public var maxWidth: Int? + public var quality: Double? + public var format: ClawdisCanvasSnapshotFormat? + + public init(maxWidth: Int? = nil, quality: Double? = nil, format: ClawdisCanvasSnapshotFormat? = nil) { + self.maxWidth = maxWidth + self.quality = quality + self.format = format + } +} diff --git a/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommands.swift b/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommands.swift index 08de9a118..3fe95e7eb 100644 --- a/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommands.swift +++ b/apps/shared/ClawdisKit/Sources/ClawdisKit/CanvasCommands.swift @@ -8,21 +8,3 @@ public enum ClawdisCanvasCommand: String, Codable, Sendable { case evalJS = "canvas.eval" case snapshot = "canvas.snapshot" } - -public enum ClawdisInvokeCommandAliases { - public static func canonicalizeCanvasToScreen(_ command: String) -> String { - if command.hasPrefix(ClawdisCanvasCommand.namespacePrefix) { - return ClawdisScreenCommand.namespacePrefix + - command.dropFirst(ClawdisCanvasCommand.namespacePrefix.count) - } - return command - } -} - -extension ClawdisCanvasCommand { - public static var namespacePrefix: String { "canvas." } -} - -extension ClawdisScreenCommand { - public static var namespacePrefix: String { "screen." } -} diff --git a/apps/shared/ClawdisKit/Sources/ClawdisKit/ScreenCommands.swift b/apps/shared/ClawdisKit/Sources/ClawdisKit/ScreenCommands.swift deleted file mode 100644 index fd9553f38..000000000 --- a/apps/shared/ClawdisKit/Sources/ClawdisKit/ScreenCommands.swift +++ /dev/null @@ -1,56 +0,0 @@ -import Foundation - -public enum ClawdisScreenMode: String, Codable, Sendable { - case canvas - case web -} - -public enum ClawdisScreenCommand: String, Codable, Sendable { - case show = "canvas.show" - case hide = "canvas.hide" - case setMode = "canvas.setMode" - case navigate = "canvas.navigate" - case evalJS = "canvas.eval" - case snapshot = "canvas.snapshot" -} - -public struct ClawdisScreenNavigateParams: Codable, Sendable, Equatable { - public var url: String - - public init(url: String) { - self.url = url - } -} - -public struct ClawdisScreenSetModeParams: Codable, Sendable, Equatable { - public var mode: ClawdisScreenMode - - public init(mode: ClawdisScreenMode) { - self.mode = mode - } -} - -public struct ClawdisScreenEvalParams: Codable, Sendable, Equatable { - public var javaScript: String - - public init(javaScript: String) { - self.javaScript = javaScript - } -} - -public enum ClawdisSnapshotFormat: String, Codable, Sendable { - case png - case jpeg -} - -public struct ClawdisScreenSnapshotParams: Codable, Sendable, Equatable { - public var maxWidth: Int? - public var quality: Double? - public var format: ClawdisSnapshotFormat? - - public init(maxWidth: Int? = nil, quality: Double? = nil, format: ClawdisSnapshotFormat? = nil) { - self.maxWidth = maxWidth - self.quality = quality - self.format = format - } -}