chore(swift): run swiftformat and clear swiftlint
This commit is contained in:
@@ -51,8 +51,7 @@ actor BridgeClient {
|
|||||||
nodeId: hello.nodeId,
|
nodeId: hello.nodeId,
|
||||||
displayName: hello.displayName,
|
displayName: hello.displayName,
|
||||||
platform: hello.platform,
|
platform: hello.platform,
|
||||||
version: hello.version
|
version: hello.version),
|
||||||
),
|
|
||||||
over: connection)
|
over: connection)
|
||||||
|
|
||||||
onStatus?("Waiting for approval…")
|
onStatus?("Waiting for approval…")
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
|
import ClawdisKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private final class ConnectStatusStore: ObservableObject {
|
||||||
|
@Published var text: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ConnectStatusStore: @unchecked Sendable {}
|
||||||
|
|
||||||
struct SettingsTab: View {
|
struct SettingsTab: View {
|
||||||
@EnvironmentObject private var appModel: NodeAppModel
|
@EnvironmentObject private var appModel: NodeAppModel
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
@@ -8,7 +16,7 @@ struct SettingsTab: View {
|
|||||||
@AppStorage("voiceWake.enabled") private var voiceWakeEnabled: Bool = false
|
@AppStorage("voiceWake.enabled") private var voiceWakeEnabled: Bool = false
|
||||||
@AppStorage("bridge.preferredStableID") private var preferredBridgeStableID: String = ""
|
@AppStorage("bridge.preferredStableID") private var preferredBridgeStableID: String = ""
|
||||||
@StateObject private var discovery = BridgeDiscoveryModel()
|
@StateObject private var discovery = BridgeDiscoveryModel()
|
||||||
@State private var connectStatus: String?
|
@StateObject private var connectStatus = ConnectStatusStore()
|
||||||
@State private var connectingBridgeID: String?
|
@State private var connectingBridgeID: String?
|
||||||
@State private var didAutoConnect = false
|
@State private var didAutoConnect = false
|
||||||
|
|
||||||
@@ -47,8 +55,8 @@ struct SettingsTab: View {
|
|||||||
self.bridgeList(showing: .all)
|
self.bridgeList(showing: .all)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let connectStatus {
|
if let text = self.connectStatus.text {
|
||||||
Text(connectStatus)
|
Text(text)
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
@@ -86,13 +94,11 @@ struct SettingsTab: View {
|
|||||||
displayName: self.displayName,
|
displayName: self.displayName,
|
||||||
token: existing,
|
token: existing,
|
||||||
platform: self.platformString(),
|
platform: self.platformString(),
|
||||||
version: self.appVersion()
|
version: self.appVersion()))
|
||||||
)
|
self.connectStatus.text = nil
|
||||||
)
|
|
||||||
self.connectStatus = nil
|
|
||||||
}
|
}
|
||||||
.onChange(of: self.appModel.bridgeServerName) { _, _ in
|
.onChange(of: self.appModel.bridgeServerName) { _, _ in
|
||||||
self.connectStatus = nil
|
self.connectStatus.text = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,17 +184,16 @@ struct SettingsTab: View {
|
|||||||
displayName: self.displayName,
|
displayName: self.displayName,
|
||||||
token: existingToken,
|
token: existingToken,
|
||||||
platform: self.platformString(),
|
platform: self.platformString(),
|
||||||
version: self.appVersion()
|
version: self.appVersion())
|
||||||
)
|
|
||||||
let token = try await BridgeClient().pairAndHello(
|
let token = try await BridgeClient().pairAndHello(
|
||||||
endpoint: bridge.endpoint,
|
endpoint: bridge.endpoint,
|
||||||
hello: hello,
|
hello: hello,
|
||||||
onStatus: { status in
|
onStatus: { status in
|
||||||
|
let store = self.connectStatus
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
self.connectStatus = status
|
store.text = status
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
if !token.isEmpty, token != existingToken {
|
if !token.isEmpty, token != existingToken {
|
||||||
_ = KeychainStore.saveString(
|
_ = KeychainStore.saveString(
|
||||||
@@ -204,12 +209,10 @@ struct SettingsTab: View {
|
|||||||
displayName: self.displayName,
|
displayName: self.displayName,
|
||||||
token: token,
|
token: token,
|
||||||
platform: self.platformString(),
|
platform: self.platformString(),
|
||||||
version: self.appVersion()
|
version: self.appVersion()))
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
self.connectStatus = "Failed: \(error.localizedDescription)"
|
self.connectStatus.text = "Failed: \(error.localizedDescription)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import SwiftUI
|
|||||||
struct ConfigSettings: View {
|
struct ConfigSettings: View {
|
||||||
private let isPreview = ProcessInfo.processInfo.isPreview
|
private let isPreview = ProcessInfo.processInfo.isPreview
|
||||||
private let labelColumnWidth: CGFloat = 120
|
private let labelColumnWidth: CGFloat = 120
|
||||||
|
private static let browserAttachOnlyHelp =
|
||||||
|
"When enabled, the browser server will only connect if the clawd browser is already running."
|
||||||
|
private static let browserProfileNote =
|
||||||
|
"Clawd uses a separate Chrome profile and ports (default 18791/18792) "
|
||||||
|
+ "so it won’t interfere with your daily browser."
|
||||||
@State private var configModel: String = ""
|
@State private var configModel: String = ""
|
||||||
@State private var customModel: String = ""
|
@State private var customModel: String = ""
|
||||||
@State private var configSaving = false
|
@State private var configSaving = false
|
||||||
@@ -203,16 +208,12 @@ struct ConfigSettings: View {
|
|||||||
.toggleStyle(.checkbox)
|
.toggleStyle(.checkbox)
|
||||||
.disabled(!self.browserEnabled)
|
.disabled(!self.browserEnabled)
|
||||||
.onChange(of: self.browserAttachOnly) { _, _ in self.autosaveConfig() }
|
.onChange(of: self.browserAttachOnly) { _, _ in self.autosaveConfig() }
|
||||||
.help(
|
.help(Self.browserAttachOnlyHelp)
|
||||||
"When enabled, the browser server will only connect if the clawd browser is already running."
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
GridRow {
|
GridRow {
|
||||||
Color.clear
|
Color.clear
|
||||||
.frame(width: self.labelColumnWidth, height: 1)
|
.frame(width: self.labelColumnWidth, height: 1)
|
||||||
Text(
|
Text(Self.browserProfileNote)
|
||||||
"Clawd uses a separate Chrome profile and ports (default 18791/18792) so it won’t interfere with your daily browser."
|
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
|||||||
@@ -71,8 +71,7 @@ struct CronSettings: View {
|
|||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
"Jobs are saved, but they will not run automatically until `cron.enabled` is set to `true` " +
|
"Jobs are saved, but they will not run automatically until `cron.enabled` is set to `true` " +
|
||||||
"and the Gateway restarts."
|
"and the Gateway restarts.")
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
@@ -497,6 +496,21 @@ private struct CronJobEditor: View {
|
|||||||
let onSave: ([String: Any]) -> Void
|
let onSave: ([String: Any]) -> Void
|
||||||
|
|
||||||
private let labelColumnWidth: CGFloat = 160
|
private let labelColumnWidth: CGFloat = 160
|
||||||
|
private static let introText =
|
||||||
|
"Create a schedule that wakes clawd via the Gateway. "
|
||||||
|
+ "Use an isolated session for agent turns so your main chat stays clean."
|
||||||
|
private static let sessionTargetNote =
|
||||||
|
"Main jobs post a system event into the current main session. "
|
||||||
|
+ "Isolated jobs run clawd in a dedicated session and can deliver results (WhatsApp/Telegram/etc)."
|
||||||
|
private static let scheduleKindNote =
|
||||||
|
"“At” runs once, “Every” repeats with a duration, “Cron” uses a 5-field Unix expression."
|
||||||
|
private static let isolatedPayloadNote =
|
||||||
|
"Isolated jobs always run an agent turn. The result can be delivered to a surface, "
|
||||||
|
+ "and a short summary is posted back to your main chat."
|
||||||
|
private static let mainPayloadNote =
|
||||||
|
"System events are injected into the current main session. Agent turns require an isolated session target."
|
||||||
|
private static let mainSummaryNote =
|
||||||
|
"Controls the label used when posting the completion summary back to the main session."
|
||||||
|
|
||||||
@State private var name: String = ""
|
@State private var name: String = ""
|
||||||
@State private var enabled: Bool = true
|
@State private var enabled: Bool = true
|
||||||
@@ -527,9 +541,7 @@ private struct CronJobEditor: View {
|
|||||||
VStack(alignment: .leading, spacing: 6) {
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
Text(self.job == nil ? "New cron job" : "Edit cron job")
|
Text(self.job == nil ? "New cron job" : "Edit cron job")
|
||||||
.font(.title3.weight(.semibold))
|
.font(.title3.weight(.semibold))
|
||||||
Text(
|
Text(Self.introText)
|
||||||
"Create a schedule that wakes clawd via the Gateway. Use an isolated session for agent turns so your main chat stays clean."
|
|
||||||
)
|
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
@@ -575,8 +587,7 @@ private struct CronJobEditor: View {
|
|||||||
Color.clear
|
Color.clear
|
||||||
.frame(width: self.labelColumnWidth, height: 1)
|
.frame(width: self.labelColumnWidth, height: 1)
|
||||||
Text(
|
Text(
|
||||||
"Main jobs post a system event into the current main session. Isolated jobs run clawd in a dedicated session and can deliver results (WhatsApp/Telegram/etc)."
|
Self.sessionTargetNote)
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
@@ -601,8 +612,7 @@ private struct CronJobEditor: View {
|
|||||||
Color.clear
|
Color.clear
|
||||||
.frame(width: self.labelColumnWidth, height: 1)
|
.frame(width: self.labelColumnWidth, height: 1)
|
||||||
Text(
|
Text(
|
||||||
"“At” runs once, “Every” repeats with a duration, “Cron” uses a 5-field Unix expression."
|
Self.scheduleKindNote)
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
@@ -646,9 +656,7 @@ private struct CronJobEditor: View {
|
|||||||
GroupBox("Payload") {
|
GroupBox("Payload") {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
if self.sessionTarget == .isolated {
|
if self.sessionTarget == .isolated {
|
||||||
Text(
|
Text(Self.isolatedPayloadNote)
|
||||||
"Isolated jobs always run an agent turn. The result can be delivered to a surface, and a short summary is posted back to your main chat."
|
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
@@ -669,8 +677,7 @@ private struct CronJobEditor: View {
|
|||||||
Color.clear
|
Color.clear
|
||||||
.frame(width: self.labelColumnWidth, height: 1)
|
.frame(width: self.labelColumnWidth, height: 1)
|
||||||
Text(
|
Text(
|
||||||
"System events are injected into the current main session. Agent turns require an isolated session target."
|
Self.mainPayloadNote)
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
@@ -703,8 +710,7 @@ private struct CronJobEditor: View {
|
|||||||
Color.clear
|
Color.clear
|
||||||
.frame(width: self.labelColumnWidth, height: 1)
|
.frame(width: self.labelColumnWidth, height: 1)
|
||||||
Text(
|
Text(
|
||||||
"Controls the label used when posting the completion summary back to the main session."
|
Self.mainSummaryNote)
|
||||||
)
|
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
|||||||
@@ -149,8 +149,7 @@ struct DebugSettings: View {
|
|||||||
.help(
|
.help(
|
||||||
"When enabled in local mode, the mac app will only connect " +
|
"When enabled in local mode, the mac app will only connect " +
|
||||||
"to an already-running gateway " +
|
"to an already-running gateway " +
|
||||||
"and will not start one itself."
|
"and will not start one itself.")
|
||||||
)
|
|
||||||
}
|
}
|
||||||
GridRow {
|
GridRow {
|
||||||
self.gridLabel("Deep links")
|
self.gridLabel("Deep links")
|
||||||
@@ -237,8 +236,7 @@ struct DebugSettings: View {
|
|||||||
.toggleStyle(.checkbox)
|
.toggleStyle(.checkbox)
|
||||||
.help(
|
.help(
|
||||||
"Writes a rotating, local-only diagnostics log under ~/Library/Logs/Clawdis/. " +
|
"Writes a rotating, local-only diagnostics log under ~/Library/Logs/Clawdis/. " +
|
||||||
"Enable only while actively debugging."
|
"Enable only while actively debugging.")
|
||||||
)
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
Button("Open folder") {
|
Button("Open folder") {
|
||||||
NSWorkspace.shared.open(DiagnosticsFileLog.logDirectoryURL())
|
NSWorkspace.shared.open(DiagnosticsFileLog.logDirectoryURL())
|
||||||
@@ -490,8 +488,7 @@ struct DebugSettings: View {
|
|||||||
.toggleStyle(.checkbox)
|
.toggleStyle(.checkbox)
|
||||||
.help(
|
.help(
|
||||||
"When off, agent Canvas requests return “Canvas disabled by user”. " +
|
"When off, agent Canvas requests return “Canvas disabled by user”. " +
|
||||||
"Manual debug actions still work."
|
"Manual debug actions still work.")
|
||||||
)
|
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
TextField("Session", text: self.$canvasSessionKey)
|
TextField("Session", text: self.$canvasSessionKey)
|
||||||
@@ -593,8 +590,7 @@ struct DebugSettings: View {
|
|||||||
.toggleStyle(.checkbox)
|
.toggleStyle(.checkbox)
|
||||||
.help(
|
.help(
|
||||||
"When enabled, the menu bar chat window/panel uses the native SwiftUI UI instead of the " +
|
"When enabled, the menu bar chat window/panel uses the native SwiftUI UI instead of the " +
|
||||||
"bundled WKWebView."
|
"bundled WKWebView.")
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -757,7 +753,7 @@ struct DebugSettings: View {
|
|||||||
.appendingPathComponent(".clawdis")
|
.appendingPathComponent(".clawdis")
|
||||||
.appendingPathComponent("clawdis.json")
|
.appendingPathComponent("clawdis.json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension DebugSettings {
|
extension DebugSettings {
|
||||||
// MARK: - Canvas debug actions
|
// MARK: - Canvas debug actions
|
||||||
@@ -854,8 +850,7 @@ extension DebugSettings {
|
|||||||
let session = self.canvasSessionKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
let session = self.canvasSessionKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let result = try await CanvasManager.shared.eval(
|
let result = try await CanvasManager.shared.eval(
|
||||||
sessionKey: session.isEmpty ? "main" : session,
|
sessionKey: session.isEmpty ? "main" : session,
|
||||||
javaScript: self.canvasEvalJS
|
javaScript: self.canvasEvalJS)
|
||||||
)
|
|
||||||
self.canvasEvalResult = result
|
self.canvasEvalResult = result
|
||||||
} catch {
|
} catch {
|
||||||
self.canvasError = error.localizedDescription
|
self.canvasError = error.localizedDescription
|
||||||
@@ -870,8 +865,7 @@ extension DebugSettings {
|
|||||||
let session = self.canvasSessionKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
let session = self.canvasSessionKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let path = try await CanvasManager.shared.snapshot(
|
let path = try await CanvasManager.shared.snapshot(
|
||||||
sessionKey: session.isEmpty ? "main" : session,
|
sessionKey: session.isEmpty ? "main" : session,
|
||||||
outPath: nil
|
outPath: nil)
|
||||||
)
|
|
||||||
self.canvasSnapshotPath = path
|
self.canvasSnapshotPath = path
|
||||||
} catch {
|
} catch {
|
||||||
self.canvasError = error.localizedDescription
|
self.canvasError = error.localizedDescription
|
||||||
@@ -879,7 +873,7 @@ extension DebugSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct PlainSettingsGroupBoxStyle: GroupBoxStyle {
|
private struct PlainSettingsGroupBoxStyle: GroupBoxStyle {
|
||||||
func makeBody(configuration: Configuration) -> some View {
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
configuration.label
|
configuration.label
|
||||||
@@ -889,10 +883,10 @@ extension DebugSettings {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
struct DebugSettings_Previews: PreviewProvider {
|
struct DebugSettings_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
DebugSettings()
|
DebugSettings()
|
||||||
.frame(width: SettingsTab.windowWidth, height: SettingsTab.windowHeight)
|
.frame(width: SettingsTab.windowWidth, height: SettingsTab.windowHeight)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct GeneralSettings: View {
|
struct GeneralSettings: View {
|
||||||
@ObservedObject var state: AppState
|
@ObservedObject var state: AppState
|
||||||
@ObservedObject private var healthStore = HealthStore.shared
|
@ObservedObject private var healthStore = HealthStore.shared
|
||||||
@ObservedObject private var gatewayManager = GatewayProcessManager.shared
|
@ObservedObject private var gatewayManager = GatewayProcessManager.shared
|
||||||
|
|||||||
@@ -121,8 +121,7 @@ struct OnboardingView: View {
|
|||||||
.font(.largeTitle.weight(.semibold))
|
.font(.largeTitle.weight(.semibold))
|
||||||
Text(
|
Text(
|
||||||
"Your macOS menu bar companion for notifications, screenshots, and agent automation — " +
|
"Your macOS menu bar companion for notifications, screenshots, and agent automation — " +
|
||||||
"setup takes just a few minutes."
|
"setup takes just a few minutes.")
|
||||||
)
|
|
||||||
.font(.body)
|
.font(.body)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
@@ -167,8 +166,7 @@ struct OnboardingView: View {
|
|||||||
.font(.largeTitle.weight(.semibold))
|
.font(.largeTitle.weight(.semibold))
|
||||||
Text(
|
Text(
|
||||||
"Clawdis has one primary Gateway (“master”) that runs continuously. " +
|
"Clawdis has one primary Gateway (“master”) that runs continuously. " +
|
||||||
"Connect locally or over SSH/Tailscale so the agent can work on any Mac."
|
"Connect locally or over SSH/Tailscale so the agent can work on any Mac.")
|
||||||
)
|
|
||||||
.font(.body)
|
.font(.body)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
@@ -303,8 +301,7 @@ struct OnboardingView: View {
|
|||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
"Uses \"npm install -g clawdis@<version>\" on your PATH. " +
|
"Uses \"npm install -g clawdis@<version>\" on your PATH. " +
|
||||||
"We keep the gateway on port 18789."
|
"We keep the gateway on port 18789.")
|
||||||
)
|
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.lineLimit(2)
|
.lineLimit(2)
|
||||||
|
|||||||
@@ -20,17 +20,17 @@ enum PermissionManager {
|
|||||||
private static func ensureCapability(_ cap: Capability, interactive: Bool) async -> Bool {
|
private static func ensureCapability(_ cap: Capability, interactive: Bool) async -> Bool {
|
||||||
switch cap {
|
switch cap {
|
||||||
case .notifications:
|
case .notifications:
|
||||||
return await self.ensureNotifications(interactive: interactive)
|
await self.ensureNotifications(interactive: interactive)
|
||||||
case .appleScript:
|
case .appleScript:
|
||||||
return await self.ensureAppleScript(interactive: interactive)
|
await self.ensureAppleScript(interactive: interactive)
|
||||||
case .accessibility:
|
case .accessibility:
|
||||||
return await self.ensureAccessibility(interactive: interactive)
|
await self.ensureAccessibility(interactive: interactive)
|
||||||
case .screenRecording:
|
case .screenRecording:
|
||||||
return await self.ensureScreenRecording(interactive: interactive)
|
await self.ensureScreenRecording(interactive: interactive)
|
||||||
case .microphone:
|
case .microphone:
|
||||||
return await self.ensureMicrophone(interactive: interactive)
|
await self.ensureMicrophone(interactive: interactive)
|
||||||
case .speechRecognition:
|
case .speechRecognition:
|
||||||
return await self.ensureSpeechRecognition(interactive: interactive)
|
await self.ensureSpeechRecognition(interactive: interactive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,8 @@ enum PermissionManager {
|
|||||||
guard interactive else { return false }
|
guard interactive else { return false }
|
||||||
let granted = await (try? center.requestAuthorization(options: [.alert, .sound, .badge])) ?? false
|
let granted = await (try? center.requestAuthorization(options: [.alert, .sound, .badge])) ?? false
|
||||||
let updated = await center.notificationSettings()
|
let updated = await center.notificationSettings()
|
||||||
return granted && (updated.authorizationStatus == .authorized || updated.authorizationStatus == .provisional)
|
return granted &&
|
||||||
|
(updated.authorizationStatus == .authorized || updated.authorizationStatus == .provisional)
|
||||||
case .denied:
|
case .denied:
|
||||||
if interactive {
|
if interactive {
|
||||||
NotificationPermissionHelper.openSettings()
|
NotificationPermissionHelper.openSettings()
|
||||||
|
|||||||
@@ -451,8 +451,7 @@ struct WebChatView: View {
|
|||||||
Text(
|
Text(
|
||||||
self.viewModel.healthOK
|
self.viewModel.healthOK
|
||||||
? "This is the native SwiftUI debug chat."
|
? "This is the native SwiftUI debug chat."
|
||||||
: "Connecting to the gateway…"
|
: "Connecting to the gateway…")
|
||||||
)
|
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ enum BrowserCLI {
|
|||||||
sub: String,
|
sub: String,
|
||||||
options: RunOptions,
|
options: RunOptions,
|
||||||
baseURL: URL,
|
baseURL: URL,
|
||||||
jsonOutput: Bool
|
jsonOutput: Bool) async throws -> Int32
|
||||||
) async throws -> Int32 {
|
{
|
||||||
switch sub {
|
switch sub {
|
||||||
case "status":
|
case "status":
|
||||||
return try await self.handleStatus(baseURL: baseURL, jsonOutput: jsonOutput)
|
return try await self.handleStatus(baseURL: baseURL, jsonOutput: jsonOutput)
|
||||||
@@ -172,8 +172,7 @@ enum BrowserCLI {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
url: url,
|
url: url,
|
||||||
body: ["url": urlString],
|
body: ["url": urlString],
|
||||||
timeoutInterval: 15.0
|
timeoutInterval: 15.0)
|
||||||
)
|
|
||||||
self.printResult(jsonOutput: jsonOutput, res: res)
|
self.printResult(jsonOutput: jsonOutput, res: res)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -188,8 +187,7 @@ enum BrowserCLI {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
url: url,
|
url: url,
|
||||||
body: ["targetId": id],
|
body: ["targetId": id],
|
||||||
timeoutInterval: 5.0
|
timeoutInterval: 5.0)
|
||||||
)
|
|
||||||
self.printResult(jsonOutput: jsonOutput, res: res)
|
self.printResult(jsonOutput: jsonOutput, res: res)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -250,8 +248,7 @@ enum BrowserCLI {
|
|||||||
"targetId": options.targetId ?? "",
|
"targetId": options.targetId ?? "",
|
||||||
"await": options.awaitPromise,
|
"await": options.awaitPromise,
|
||||||
],
|
],
|
||||||
timeoutInterval: 15.0
|
timeoutInterval: 15.0)
|
||||||
)
|
|
||||||
|
|
||||||
if jsonOutput {
|
if jsonOutput {
|
||||||
self.printJSON(ok: true, result: res)
|
self.printJSON(ok: true, result: res)
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ struct ClawdisCLI {
|
|||||||
guard let t = title, let b = body else { throw CLIError.help }
|
guard let t = title, let b = body else { throw CLIError.help }
|
||||||
return ParsedCLIRequest(
|
return ParsedCLIRequest(
|
||||||
request: .notify(title: t, body: b, sound: sound, priority: priority, delivery: delivery),
|
request: .notify(title: t, body: b, sound: sound, priority: priority, delivery: delivery),
|
||||||
kind: .generic
|
kind: .generic)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func parseEnsurePermissions(args: inout [String]) -> ParsedCLIRequest {
|
private static func parseEnsurePermissions(args: inout [String]) -> ParsedCLIRequest {
|
||||||
@@ -174,10 +173,8 @@ struct ClawdisCLI {
|
|||||||
cwd: cwd,
|
cwd: cwd,
|
||||||
env: env.isEmpty ? nil : env,
|
env: env.isEmpty ? nil : env,
|
||||||
timeoutSec: timeout,
|
timeoutSec: timeout,
|
||||||
needsScreenRecording: needsSR
|
needsScreenRecording: needsSR),
|
||||||
),
|
kind: .generic)
|
||||||
kind: .generic
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func parseEnvPair(_ pair: String, into env: inout [String: String]) {
|
private static func parseEnvPair(_ pair: String, into env: inout [String: String]) {
|
||||||
@@ -212,8 +209,7 @@ struct ClawdisCLI {
|
|||||||
guard let message else { throw CLIError.help }
|
guard let message else { throw CLIError.help }
|
||||||
return ParsedCLIRequest(
|
return ParsedCLIRequest(
|
||||||
request: .agent(message: message, thinking: thinking, session: session, deliver: deliver, to: to),
|
request: .agent(message: message, thinking: thinking, session: session, deliver: deliver, to: to),
|
||||||
kind: .generic
|
kind: .generic)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func parseNode(args: inout [String]) throws -> ParsedCLIRequest {
|
private static func parseNode(args: inout [String]) throws -> ParsedCLIRequest {
|
||||||
@@ -237,8 +233,7 @@ struct ClawdisCLI {
|
|||||||
guard let nodeId, let command else { throw CLIError.help }
|
guard let nodeId, let command else { throw CLIError.help }
|
||||||
return ParsedCLIRequest(
|
return ParsedCLIRequest(
|
||||||
request: .nodeInvoke(nodeId: nodeId, command: command, paramsJSON: paramsJSON),
|
request: .nodeInvoke(nodeId: nodeId, command: command, paramsJSON: paramsJSON),
|
||||||
kind: .generic
|
kind: .generic)
|
||||||
)
|
|
||||||
default:
|
default:
|
||||||
throw CLIError.help
|
throw CLIError.help
|
||||||
}
|
}
|
||||||
@@ -253,8 +248,7 @@ struct ClawdisCLI {
|
|||||||
let placement = self.parseCanvasPlacement(args: &args, session: &session, path: &path)
|
let placement = self.parseCanvasPlacement(args: &args, session: &session, path: &path)
|
||||||
return ParsedCLIRequest(
|
return ParsedCLIRequest(
|
||||||
request: .canvasShow(session: session, path: path, placement: placement),
|
request: .canvasShow(session: session, path: path, placement: placement),
|
||||||
kind: .generic
|
kind: .generic)
|
||||||
)
|
|
||||||
case "hide":
|
case "hide":
|
||||||
var session = "main"
|
var session = "main"
|
||||||
while !args.isEmpty {
|
while !args.isEmpty {
|
||||||
@@ -272,8 +266,7 @@ struct ClawdisCLI {
|
|||||||
guard let path else { throw CLIError.help }
|
guard let path else { throw CLIError.help }
|
||||||
return ParsedCLIRequest(
|
return ParsedCLIRequest(
|
||||||
request: .canvasGoto(session: session, path: path, placement: placement),
|
request: .canvasGoto(session: session, path: path, placement: placement),
|
||||||
kind: .generic
|
kind: .generic)
|
||||||
)
|
|
||||||
case "eval":
|
case "eval":
|
||||||
var session = "main"
|
var session = "main"
|
||||||
var js: String?
|
var js: String?
|
||||||
@@ -307,8 +300,8 @@ struct ClawdisCLI {
|
|||||||
private static func parseCanvasPlacement(
|
private static func parseCanvasPlacement(
|
||||||
args: inout [String],
|
args: inout [String],
|
||||||
session: inout String,
|
session: inout String,
|
||||||
path: inout String?
|
path: inout String?) -> CanvasPlacement?
|
||||||
) -> CanvasPlacement? {
|
{
|
||||||
var x: Double?
|
var x: Double?
|
||||||
var y: Double?
|
var y: Double?
|
||||||
var width: Double?
|
var width: Double?
|
||||||
|
|||||||
Reference in New Issue
Block a user