Files
openclaw/apps/macos/Sources/OpenClaw/ComputerControlProvider.swift
T
Peter Steinberger 19ace6830b feat(macos): add embedded CUA computer provider (#123635)
* feat(macos): embed CUA computer provider

* fix(macos): clarify embedded CUA trust posture

* fix(macos): contain embedded CUA daemon lifecycle

* fix(macos): reap orphaned CUA daemons

* fix(macos): record the spawned CUA daemon pid so reaping can terminate orphans

* chore(macos): refresh native i18n baseline for the computer control provider picker

* style(macos): satisfy swiftlint on the embedded CUA host and connect params

* refactor(gateway): move optional connect params to GatewayConnectOptions
2026-08-14 10:24:08 -07:00

60 lines
1.7 KiB
Swift

import Foundation
enum ComputerControlProvider: String, CaseIterable, Sendable {
case peekaboo
case cua
static func current(
defaults: UserDefaults = AppDefaults.standard,
cuaAvailable: Bool = CuaDriverArtifact.bundledExecutableURL != nil) -> Self
{
guard let rawValue = defaults.string(forKey: computerControlProviderKey),
let provider = Self(rawValue: rawValue)
else { return .peekaboo }
if provider == .cua, !cuaAvailable { return .peekaboo }
return provider
}
var displayName: String {
switch self {
case .peekaboo: "Peekaboo"
case .cua: "CUA"
}
}
}
struct CuaDriverWorkerEndpoint: Equatable, Sendable {
let socketPath: String
let binaryPath: String
}
enum CuaDriverWorkerEnvironment {
static let socketPath = "OPENCLAW_CUA_DRIVER_SOCKET_PATH"
static let binaryPath = "OPENCLAW_CUA_DRIVER_BINARY_PATH"
}
enum CuaDriverArtifact {
static let resourceName = "cua-driver"
static var bundledExecutableURL: URL? {
self.executableURL(in: Bundle.main.resourceURL)
}
static func executableURL(
in resourceURL: URL?,
fileManager: FileManager = .default) -> URL?
{
guard let resourceURL else { return nil }
let candidate = resourceURL.appendingPathComponent(self.resourceName, isDirectory: false)
guard let values = try? candidate.resourceValues(forKeys: [
.isRegularFileKey,
.isSymbolicLinkKey,
]),
values.isRegularFile == true,
values.isSymbolicLink != true,
fileManager.isExecutableFile(atPath: candidate.path)
else { return nil }
return candidate
}
}