chore(swift): restore compact conditional bodies (#103832)

* style(swift): restore compact conditional bodies

* fix(ios): remove redundant startup timeout await

* chore(swift): sync native i18n inventory
This commit is contained in:
Peter Steinberger
2026-07-10 18:12:00 +01:00
committed by GitHub
parent 906f1b816f
commit 091584b197
204 changed files with 1391 additions and 3023 deletions
File diff suppressed because it is too large Load Diff
@@ -88,15 +88,9 @@ struct OpenClawLiveActivity: Widget {
}
private func dotColor(state: OpenClawActivityAttributes.ContentState) -> Color {
if state.isDisconnected {
return OpenClawActivityStyle.danger
}
if state.isConnecting {
return OpenClawActivityStyle.info
}
if state.isIdle {
return OpenClawActivityStyle.ok
}
if state.isDisconnected { return OpenClawActivityStyle.danger }
if state.isConnecting { return OpenClawActivityStyle.info }
if state.isIdle { return OpenClawActivityStyle.ok }
return OpenClawActivityStyle.warn
}
}
@@ -352,15 +352,9 @@ final class ShareViewController: UIViewController {
let text = self.sanitizeDraftFragment(payload.text)
let url = payload.url?.absoluteString.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if let title, !title.isEmpty {
lines.append(title)
}
if let text, !text.isEmpty {
lines.append(text)
}
if !url.isEmpty {
lines.append(url)
}
if let title, !title.isEmpty { lines.append(title) }
if let text, !text.isEmpty { lines.append(text) }
if !url.isEmpty { lines.append(url) }
return lines.joined(separator: "\n\n")
}
@@ -483,9 +477,7 @@ final class ShareViewController: UIViewController {
quality -= 0.1
}
guard let fallback = image.jpegData(compressionQuality: 0.35) else { return nil }
if fallback.count <= maxBytes {
return fallback
}
if fallback.count <= maxBytes { return fallback }
return nil
}
@@ -233,24 +233,12 @@ struct IOSGatewayChatTransport: OpenClawChatTransport {
unread: Bool? = nil) throws -> String
{
var params: [String: Any] = ["key": key]
if let agentId {
params["agentId"] = agentId
}
if let label {
params["label"] = label ?? NSNull()
}
if let category {
params["category"] = category ?? NSNull()
}
if let pinned {
params["pinned"] = pinned
}
if let archived {
params["archived"] = archived
}
if let unread {
params["unread"] = unread
}
if let agentId { params["agentId"] = agentId }
if let label { params["label"] = label ?? NSNull() }
if let category { params["category"] = category ?? NSNull() }
if let pinned { params["pinned"] = pinned }
if let archived { params["archived"] = archived }
if let unread { params["unread"] = unread }
return try self.encodeJSONObject(params)
}
@@ -806,9 +794,7 @@ struct IOSGatewayChatTransport: OpenClawChatTransport {
let task = Task {
let stream = await self.gateway.subscribeServerEvents()
for await evt in stream {
if Task.isCancelled {
return
}
if Task.isCancelled { return }
if let mapped = Self.mapEventFrame(evt) {
continuation.yield(mapped)
}
@@ -515,9 +515,7 @@ struct AgentProDreamingDestination: View {
}
private func dreamingPhaseState(_ phase: DreamingPhaseStatusLite) -> String {
if phase.enabled == false {
return "off"
}
if phase.enabled == false { return "off" }
return phase.managedCronPresent == true ? "scheduled" : "setup"
}
@@ -621,15 +619,9 @@ struct AgentProDreamingDestination: View {
let id = markerDay ?? Self.dayID(title)
let bodyLines = rawLines.enumerated().compactMap { offset, line -> String? in
let trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines)
if offset == dateLineIndex {
return nil
}
if trimmed.hasPrefix("<!--") && trimmed.hasSuffix("-->") {
return nil
}
if trimmed == "#" || trimmed == "# Dream Diary" {
return nil
}
if offset == dateLineIndex { return nil }
if trimmed.hasPrefix("<!--") && trimmed.hasSuffix("-->") { return nil }
if trimmed == "#" || trimmed == "# Dream Diary" { return nil }
return line
}
let body = bodyLines
@@ -124,9 +124,7 @@ struct AgentProNodesDestination: View {
private var sortedPresenceEntries: [PresenceEntry] {
(self.overview?.presence ?? [])
.sorted { lhs, rhs in
if lhs.ts != rhs.ts {
return lhs.ts > rhs.ts
}
if lhs.ts != rhs.ts { return lhs.ts > rhs.ts }
return (Self.presenceLabel(lhs) ?? lhs.presenceKey)
.localizedCaseInsensitiveCompare(Self.presenceLabel(rhs) ?? rhs.presenceKey) == .orderedAscending
}
@@ -343,15 +341,9 @@ struct AgentProNodesDestination: View {
private static func presenceIcon(_ entry: PresenceEntry) -> String {
let family = Self.normalized(entry.devicefamily)?.lowercased()
if family?.contains("phone") == true {
return "iphone"
}
if family?.contains("tablet") == true || family?.contains("pad") == true {
return "ipad"
}
if family?.contains("desktop") == true || family?.contains("mac") == true {
return "desktopcomputer"
}
if family?.contains("phone") == true { return "iphone" }
if family?.contains("tablet") == true || family?.contains("pad") == true { return "ipad" }
if family?.contains("desktop") == true || family?.contains("mac") == true { return "desktopcomputer" }
return "display"
}
@@ -23,9 +23,7 @@ extension AgentProTab {
}
func agentTint(for agent: AgentSummary, state: AgentRosterState) -> Color {
if agent.id == self.activeAgentID {
return OpenClawBrand.accent
}
if agent.id == self.activeAgentID { return OpenClawBrand.accent }
return state.color.opacity(0.62)
}
@@ -49,9 +47,7 @@ extension AgentProTab {
func agentRosterState(for agent: AgentSummary) -> AgentRosterState {
guard self.gatewayConnected else { return .ready }
if agent.id == self.activeAgentID {
return .online
}
if agent.id == self.activeAgentID { return .online }
return .ready
}
@@ -208,17 +204,11 @@ extension AgentProTab {
static func duration(milliseconds: Int) -> String {
let seconds = max(0, milliseconds / 1000)
if seconds < 60 {
return "\(seconds)s"
}
if seconds < 60 { return "\(seconds)s" }
let minutes = seconds / 60
if minutes < 60 {
return "\(minutes)m"
}
if minutes < 60 { return "\(minutes)m" }
let hours = minutes / 60
if hours < 24 {
return "\(hours)h"
}
if hours < 24 { return "\(hours)h" }
return "\(hours / 24)d"
}
@@ -491,12 +491,8 @@ extension AgentProTab {
var sortedAgents: [AgentSummary] {
appModel.gatewayAgents.sorted { lhs, rhs in
if lhs.id == self.activeAgentID {
return true
}
if rhs.id == self.activeAgentID {
return false
}
if lhs.id == self.activeAgentID { return true }
if rhs.id == self.activeAgentID { return false }
return self.agentName(for: lhs)
.localizedCaseInsensitiveCompare(self.agentName(for: rhs)) == .orderedAscending
}
@@ -545,28 +541,18 @@ extension AgentProTab {
}
var emptyAgentsTitle: String {
if !self.gatewayConnected {
return "Agents unavailable"
}
if !agentSearchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
return "No matches"
}
if agentRosterFilter != .all {
return "No \(agentRosterFilter.title.lowercased()) agents"
}
if !self.gatewayConnected { return "Agents unavailable" }
if !agentSearchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { return "No matches" }
if agentRosterFilter != .all { return "No \(agentRosterFilter.title.lowercased()) agents" }
return "No agents reported"
}
var emptyAgentsDetail: String {
if !self.gatewayConnected {
return "Connect a gateway to load the live agent roster."
}
if !self.gatewayConnected { return "Connect a gateway to load the live agent roster." }
if !agentSearchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
return "Try another search or clear the agent filters."
}
if agentRosterFilter != .all {
return "Clear the filter to view the full roster."
}
if agentRosterFilter != .all { return "Clear the filter to view the full roster." }
return "The connected gateway did not return an agent list."
}
@@ -226,9 +226,7 @@ extension AgentProTab {
}
var skillPolicySummary: String {
if appModel.isAppleReviewDemoModeEnabled {
return "Demo mode keeps live skill changes disabled."
}
if appModel.isAppleReviewDemoModeEnabled { return "Demo mode keeps live skill changes disabled." }
guard gatewayConnected else { return "Connect a gateway to edit skills." }
guard let filter = agentSkillFilter else {
return "All available skills are allowed for this agent."
@@ -282,9 +280,7 @@ extension AgentProTab {
func sortSkills(_ lhs: SkillStatusEntryLite, _ rhs: SkillStatusEntryLite) -> Bool {
let lhsEnabled = self.isSkillAllowed(lhs)
let rhsEnabled = self.isSkillAllowed(rhs)
if lhsEnabled != rhsEnabled {
return lhsEnabled && !rhsEnabled
}
if lhsEnabled != rhsEnabled { return lhsEnabled && !rhsEnabled }
return lhs.name.localizedCaseInsensitiveCompare(rhs.name) == .orderedAscending
}
@@ -246,11 +246,7 @@ struct CommandSessionActionsModifier: ViewModifier {
private var editorBinding: Binding<Bool> {
Binding(
get: { self.editor != nil },
set: {
if !$0 {
self.editor = nil
}
})
set: { if !$0 { self.editor = nil } })
}
private var editorTitle: String {
+4 -16
View File
@@ -626,9 +626,7 @@ struct CommandCenterTab: View {
nonisolated static func isRecentChatSession(_ key: String, defaultSessionKey: String) -> Bool {
let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return false }
if trimmed == defaultSessionKey {
return false
}
if trimmed == defaultSessionKey { return false }
let normalized = trimmed.lowercased()
let defaultBase = self.sessionBaseKey(defaultSessionKey)
if !normalized.contains(":"),
@@ -636,9 +634,7 @@ struct CommandCenterTab: View {
{
return false
}
if self.isHiddenInternalSession(trimmed) {
return false
}
if self.isHiddenInternalSession(trimmed) { return false }
return !self.isAgentDeviceSession(trimmed, defaultSessionKey: defaultSessionKey)
}
@@ -953,21 +949,13 @@ struct CommandSessionsScreen: View {
private var groupEditorBinding: Binding<Bool> {
Binding(
get: { self.groupEditor != nil },
set: {
if !$0 {
self.groupEditor = nil
}
})
set: { if !$0 { self.groupEditor = nil } })
}
private var groupDeleteBinding: Binding<Bool> {
Binding(
get: { self.groupPendingDelete != nil },
set: {
if !$0 {
self.groupPendingDelete = nil
}
})
set: { if !$0 { self.groupPendingDelete = nil } })
}
private func commitGroupEditor() {
@@ -1223,16 +1223,10 @@ struct IPadSkillProposal: Identifiable {
var ageLabel: String {
let diff = max(0, Date().timeIntervalSince1970 * 1000 - self.updatedAtMs)
let minutes = Int(diff / 60000)
if minutes < 1 {
return "now"
}
if minutes < 60 {
return "\(minutes)m"
}
if minutes < 1 { return "now" }
if minutes < 60 { return "\(minutes)m" }
let hours = minutes / 60
if hours < 24 {
return "\(hours)h"
}
if hours < 24 { return "\(hours)h" }
return "\(hours / 24)d"
}
@@ -705,9 +705,7 @@ struct IPadWorkboardScreen: View {
self.errorText = nil
return
}
if self.isLoading {
return
}
if self.isLoading { return }
self.isLoading = true
self.errorText = nil
@@ -136,9 +136,7 @@ struct SettingsChannelsDestination: View {
}
private var headerValue: String? {
if self.isLoading {
return "Loading"
}
if self.isLoading { return "Loading" }
guard self.canRead else { return "Offline" }
return "\(self.channelEntries.count)"
}
@@ -155,21 +153,15 @@ struct SettingsChannelsDestination: View {
private var summaryValue: String {
guard self.canRead else { return "offline" }
if self.isLoading {
return "loading"
}
if self.errorText != nil {
return "error"
}
if self.isLoading { return "loading" }
if self.errorText != nil { return "error" }
let configured = self.channelEntries.count(where: { $0.configured })
return "\(configured)/\(self.channelEntries.count)"
}
private var summaryColor: Color {
guard self.canRead else { return .secondary }
if self.errorText != nil {
return OpenClawBrand.warn
}
if self.errorText != nil { return OpenClawBrand.warn }
return self.channelEntries.contains(where: { $0.running || $0.connected }) ? OpenClawBrand.ok : OpenClawBrand
.accent
}
@@ -241,9 +233,7 @@ struct SettingsChannelsDestination: View {
self.errorText = nil
return
}
if self.isLoading {
return
}
if self.isLoading { return }
self.isLoading = true
self.errorText = nil
@@ -328,16 +318,10 @@ struct SettingsChannelsDestination: View {
private static func relativeTime(_ milliseconds: Int) -> String {
let age = max(0, Int(Date().timeIntervalSince1970 * 1000) - milliseconds)
let minutes = age / 60000
if minutes < 1 {
return "now"
}
if minutes < 60 {
return "\(minutes)m ago"
}
if minutes < 1 { return "now" }
if minutes < 60 { return "\(minutes)m ago" }
let hours = minutes / 60
if hours < 24 {
return "\(hours)h ago"
}
if hours < 24 { return "\(hours)h ago" }
return "\(hours / 24)d ago"
}
@@ -475,28 +459,16 @@ private struct SettingsChannelEntry: Identifiable {
let accounts: [SettingsChannelAccount]
var color: Color {
if self.connected || self.running {
return OpenClawBrand.ok
}
if self.lastError != nil {
return OpenClawBrand.warn
}
if self.connected || self.running { return OpenClawBrand.ok }
if self.lastError != nil { return OpenClawBrand.warn }
return self.configured ? OpenClawBrand.accent : .secondary
}
var statusValue: String {
if self.connected {
return "connected"
}
if self.running {
return "running"
}
if self.linked {
return "linked"
}
if self.configured {
return "configured"
}
if self.connected { return "connected" }
if self.running { return "running" }
if self.linked { return "linked" }
if self.configured { return "configured" }
return "not set"
}
@@ -557,12 +529,8 @@ private struct SettingsChannelAccount: Identifiable {
}
var color: Color {
if self.connected || self.running {
return OpenClawBrand.ok
}
if self.lastError != nil {
return OpenClawBrand.warn
}
if self.connected || self.running { return OpenClawBrand.ok }
if self.lastError != nil { return OpenClawBrand.warn }
return self.configured ? OpenClawBrand.accent : .secondary
}
}
@@ -961,9 +961,7 @@ extension SettingsProTab {
}
var manualPortIsValid: Bool {
if self.manualGatewayPortText.isEmpty {
return true
}
if self.manualGatewayPortText.isEmpty { return true }
return self.manualGatewayPort >= 1 && self.manualGatewayPort <= 65535
}
@@ -980,24 +978,16 @@ extension SettingsProTab {
}
let trimmedSetup = self.setupStatusText?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let gatewayStatus = self.appModel.gatewayStatusText.trimmingCharacters(in: .whitespacesAndNewlines)
if let friendly = self.friendlyGatewayMessage(from: gatewayStatus) {
return friendly
}
if let friendly = self.friendlyGatewayMessage(from: trimmedSetup) {
return friendly
}
if let friendly = self.friendlyGatewayMessage(from: gatewayStatus) { return friendly }
if let friendly = self.friendlyGatewayMessage(from: trimmedSetup) { return friendly }
if self.isTransientSetupStatus(trimmedSetup),
!gatewayStatus.isEmpty,
gatewayStatus != "Offline"
{
return gatewayStatus
}
if !trimmedSetup.isEmpty {
return trimmedSetup
}
if gatewayStatus.isEmpty || gatewayStatus == "Offline" {
return nil
}
if !trimmedSetup.isEmpty { return trimmedSetup }
if gatewayStatus.isEmpty || gatewayStatus == "Offline" { return nil }
return gatewayStatus
}
@@ -1084,12 +1074,8 @@ extension SettingsProTab {
let title = self.appModel.talkMode.gatewayTalkActiveModeTitle.trimmingCharacters(in: .whitespacesAndNewlines)
let subtitle = (self.appModel.talkMode.gatewayTalkActiveModeSubtitle ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
if title.isEmpty {
return "Not active"
}
if subtitle.isEmpty {
return title
}
if title.isEmpty { return "Not active" }
if subtitle.isEmpty { return title }
return "\(title)\(subtitle)"
}
@@ -1101,12 +1087,8 @@ extension SettingsProTab {
func gatewayDetailLines(_ gateway: GatewayDiscoveryModel.DiscoveredGateway) -> [String] {
var lines: [String] = []
if let lanHost = gateway.lanHost {
lines.append("LAN: \(lanHost)")
}
if let tailnet = gateway.tailnetDns {
lines.append("Tailnet: \(tailnet)")
}
if let lanHost = gateway.lanHost { lines.append("LAN: \(lanHost)") }
if let tailnet = gateway.tailnetDns { lines.append("Tailnet: \(tailnet)") }
let gw = gateway.gatewayPort.map(String.init)
let canvas = gateway.canvasPort.map(String.init)
if gw != nil || canvas != nil {
@@ -1121,23 +1103,17 @@ extension SettingsProTab {
}
var gatewayStatusDetail: String {
if self.appModel.isAppleReviewDemoModeEnabled {
return "Apple Review demo mode"
}
if self.appModel.isAppleReviewDemoModeEnabled { return "Apple Review demo mode" }
return self.gatewayConnected ? "Connected" : self.appModel.gatewayDisplayStatusText
}
var gatewayStatusValue: String {
if self.appModel.isAppleReviewDemoModeEnabled {
return "demo"
}
if self.appModel.isAppleReviewDemoModeEnabled { return "demo" }
return self.gatewayConnected ? "online" : "offline"
}
var gatewayStatusColor: Color {
if self.appModel.isAppleReviewDemoModeEnabled {
return OpenClawBrand.accent
}
if self.appModel.isAppleReviewDemoModeEnabled { return OpenClawBrand.accent }
return self.gatewayConnected ? OpenClawBrand.ok : .secondary
}
@@ -1160,23 +1136,17 @@ extension SettingsProTab {
}
var gatewayTalkConfigDetail: String {
if self.appModel.isAppleReviewDemoModeEnabled {
return "Demo mode only"
}
if self.appModel.isAppleReviewDemoModeEnabled { return "Demo mode only" }
return self.appModel.talkMode.gatewayTalkTransportLabel
}
var gatewayTalkConfigValue: String {
if self.appModel.isAppleReviewDemoModeEnabled {
return "demo"
}
if self.appModel.isAppleReviewDemoModeEnabled { return "demo" }
return self.appModel.talkMode.gatewayTalkConfigLoaded ? "loaded" : "missing"
}
var gatewayTalkConfigColor: Color {
if self.appModel.isAppleReviewDemoModeEnabled {
return .secondary
}
if self.appModel.isAppleReviewDemoModeEnabled { return .secondary }
return self.appModel.talkMode.gatewayTalkConfigLoaded ? OpenClawBrand.ok : .secondary
}
@@ -1217,28 +1187,16 @@ extension SettingsProTab {
}
var voiceDetail: String {
if self.talkEnabled, self.voiceWakeEnabled {
return "Talk + Wake"
}
if self.talkEnabled {
return "Talk on"
}
if self.voiceWakeEnabled {
return "Wake on"
}
if self.talkEnabled, self.voiceWakeEnabled { return "Talk + Wake" }
if self.talkEnabled { return "Talk on" }
if self.voiceWakeEnabled { return "Wake on" }
return "Off"
}
var diagnosticsHealthValue: String {
if self.appModel.isAppleReviewDemoModeEnabled {
return "demo"
}
if self.gatewayConnected {
return "ready"
}
if self.gatewayController.gateways.isEmpty {
return "check"
}
if self.appModel.isAppleReviewDemoModeEnabled { return "demo" }
if self.gatewayConnected { return "ready" }
if self.gatewayController.gateways.isEmpty { return "check" }
return "partial"
}
@@ -343,18 +343,10 @@ enum SettingsDiagnostics {
notificationsAllowed: Bool) -> [SettingsDiagnosticIssue]
{
var issues: [SettingsDiagnosticIssue] = []
if !gatewayConnected {
issues.append(.gatewayOffline)
}
if discoveredGatewayCount == 0 {
issues.append(.discoveryUnavailable)
}
if gatewayConnected, !talkConfigLoaded {
issues.append(.talkConfigMissing)
}
if !notificationsAllowed {
issues.append(.notificationsUnavailable)
}
if !gatewayConnected { issues.append(.gatewayOffline) }
if discoveredGatewayCount == 0 { issues.append(.discoveryUnavailable) }
if gatewayConnected, !talkConfigLoaded { issues.append(.talkConfigMissing) }
if !notificationsAllowed { issues.append(.notificationsUnavailable) }
return issues
}
@@ -387,9 +379,7 @@ extension SettingsProTab {
let isLoopback = (flags & IFF_LOOPBACK) != 0
guard let addrPtr = ptr.pointee.ifa_addr else { continue }
let family = addrPtr.pointee.sa_family
if !isUp || isLoopback || family != UInt8(AF_INET) {
continue
}
if !isUp || isLoopback || family != UInt8(AF_INET) { continue }
var addr = addrPtr.pointee
var buffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let result = getnameinfo(
@@ -403,18 +393,14 @@ extension SettingsProTab {
guard result == 0 else { continue }
let bytes = buffer.prefix { $0 != 0 }.map { UInt8(bitPattern: $0) }
guard let ip = String(bytes: bytes, encoding: .utf8) else { continue }
if self.isTailnetIPv4(ip) {
return true
}
if self.isTailnetIPv4(ip) { return true }
}
return false
}
static func isTailnetHostOrIP(_ host: String) -> Bool {
let trimmed = host.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if trimmed.hasSuffix(".ts.net") || trimmed.hasSuffix(".ts.net.") {
return true
}
if trimmed.hasSuffix(".ts.net") || trimmed.hasSuffix(".ts.net.") { return true }
return self.isTailnetIPv4(trimmed)
}
+27 -82
View File
@@ -215,36 +215,23 @@ struct TalkProTab: View {
private var heroSubtitle: String {
if self.state
.prefersPermissionCopy
{
return "Gateway approval is required before this phone can capture voice."
}
if self.appModel.isAppleReviewDemoModeEnabled {
return "Voice is disabled in Apple Review demo mode."
}
if !self.gatewayConnected {
return "Connect to your gateway to start a voice conversation."
}
.prefersPermissionCopy { return "Gateway approval is required before this phone can capture voice." }
if self.appModel.isAppleReviewDemoModeEnabled { return "Voice is disabled in Apple Review demo mode." }
if !self.gatewayConnected { return "Connect to your gateway to start a voice conversation." }
if !self.appModel.talkMode.gatewayTalkConfigLoaded {
return "Open Voice settings after the gateway loads Talk configuration."
}
let subtitle = (appModel.talkMode.gatewayTalkVoiceModeSubtitle ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
if !subtitle.isEmpty {
return subtitle
}
if !subtitle.isEmpty { return subtitle }
return "Routes voice to \(self.appModel.chatAgentName)."
}
private var transportText: String {
let provider = self.appModel.talkMode.gatewayTalkProviderLabel.trimmingCharacters(in: .whitespacesAndNewlines)
let transport = self.appModel.talkMode.gatewayTalkTransportLabel.trimmingCharacters(in: .whitespacesAndNewlines)
if provider.isEmpty || provider == "Not loaded" {
return transport.isEmpty ? "Not loaded" : transport
}
if transport.isEmpty || transport == "Not loaded" {
return provider
}
if provider.isEmpty || provider == "Not loaded" { return transport.isEmpty ? "Not loaded" : transport }
if transport.isEmpty || transport == "Not loaded" { return provider }
return "\(provider)\(transport)"
}
@@ -252,12 +239,8 @@ struct TalkProTab: View {
let title = self.appModel.talkMode.gatewayTalkActiveModeTitle.trimmingCharacters(in: .whitespacesAndNewlines)
let subtitle = (appModel.talkMode.gatewayTalkActiveModeSubtitle ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
if title.isEmpty {
return "Not active"
}
if subtitle.isEmpty {
return title
}
if title.isEmpty { return "Not active" }
if subtitle.isEmpty { return title }
return "\(title)\(subtitle)"
}
@@ -275,9 +258,7 @@ struct TalkProTab: View {
}
private var speechLocaleText: String {
if self.talkSpeechLocale == TalkSpeechLocale.automaticID {
return "Automatic"
}
if self.talkSpeechLocale == TalkSpeechLocale.automaticID { return "Automatic" }
return self.talkSpeechLocale
}
@@ -381,12 +362,8 @@ struct TalkProState: Equatable {
}
var title: String {
if self.isDemoMode {
return "Demo mode only"
}
if !self.gatewayConnected {
return "Gateway offline"
}
if self.isDemoMode { return "Demo mode only" }
if !self.gatewayConnected { return "Gateway offline" }
switch self.permissionState {
case .missingScope, .requestFailed:
return "Gateway permission required"
@@ -401,54 +378,32 @@ struct TalkProState: Equatable {
default:
break
}
if !self.isConfigLoaded {
return "Voice config unavailable"
}
if self.isSpeaking {
return "Speaking"
}
if self.isListening {
return "Listening"
}
if self.normalizedStatus.contains("connecting") {
return "Connecting"
}
if self.normalizedStatus.contains("thinking") {
return "Asking OpenClaw"
}
if self.isEnabled {
return "Ready to talk"
}
if !self.isConfigLoaded { return "Voice config unavailable" }
if self.isSpeaking { return "Speaking" }
if self.isListening { return "Listening" }
if self.normalizedStatus.contains("connecting") { return "Connecting" }
if self.normalizedStatus.contains("thinking") { return "Asking OpenClaw" }
if self.isEnabled { return "Ready to talk" }
return "Talk is off"
}
var color: Color {
if self.isDemoMode {
return .secondary
}
if !self.gatewayConnected {
return .secondary
}
if self.isDemoMode { return .secondary }
if !self.gatewayConnected { return .secondary }
switch self.permissionState {
case .requestFailed, .loadFailed:
return OpenClawBrand.danger
case .missingScope, .requestingUpgrade, .upgradeRequested, .apiKeyMissing:
return OpenClawBrand.warn
default:
if !self.isConfigLoaded {
return OpenClawBrand.warn
}
if !self.isConfigLoaded { return OpenClawBrand.warn }
return self.isEnabled ? OpenClawBrand.ok : OpenClawBrand.accentHot
}
}
var primaryAction: TalkProPrimaryAction {
if self.isDemoMode {
return .waiting
}
if !self.gatewayConnected {
return .openSettings
}
if self.isDemoMode { return .waiting }
if !self.gatewayConnected { return .openSettings }
switch self.permissionState {
case .missingScope, .requestFailed:
return .enablePermission
@@ -491,12 +446,8 @@ struct TalkProState: Equatable {
}
func waveformPhase(micLevel: Double, playbackLevel: Double?) -> TalkWaveformPhase {
if self.isDemoMode {
return .idle
}
if !self.gatewayConnected {
return .idle
}
if self.isDemoMode { return .idle }
if !self.gatewayConnected { return .idle }
switch self.permissionState {
case .requestingUpgrade, .upgradeRequested:
return .thinking
@@ -505,15 +456,9 @@ struct TalkProState: Equatable {
default:
break
}
if !self.isConfigLoaded {
return .idle
}
if self.isSpeaking {
return .speaking(level: playbackLevel)
}
if self.isListening {
return .listening(level: micLevel, speechActive: self.isUserSpeechDetected)
}
if !self.isConfigLoaded { return .idle }
if self.isSpeaking { return .speaking(level: playbackLevel) }
if self.isListening { return .listening(level: micLevel, speechActive: self.isUserSpeechDetected) }
if self.normalizedStatus.contains("connecting") || self.normalizedStatus.contains("thinking") {
return .thinking
}
@@ -34,18 +34,10 @@ final class NetworkStatusService: @unchecked Sendable {
}
var interfaces: [OpenClawNetworkInterfaceType] = []
if path.usesInterfaceType(.wifi) {
interfaces.append(.wifi)
}
if path.usesInterfaceType(.cellular) {
interfaces.append(.cellular)
}
if path.usesInterfaceType(.wiredEthernet) {
interfaces.append(.wired)
}
if interfaces.isEmpty {
interfaces.append(.other)
}
if path.usesInterfaceType(.wifi) { interfaces.append(.wifi) }
if path.usesInterfaceType(.cellular) { interfaces.append(.cellular) }
if path.usesInterfaceType(.wiredEthernet) { interfaces.append(.wired) }
if interfaces.isEmpty { interfaces.append(.other) }
return OpenClawNetworkStatusPayload(
status: status,
@@ -70,9 +62,7 @@ private final class NetworkStatusState: @unchecked Sendable {
func markCompleted() -> Bool {
self.lock.lock()
defer { self.lock.unlock() }
if self.completed {
return false
}
if self.completed { return false }
self.completed = true
return true
}
@@ -22,9 +22,7 @@ struct GatewayConnectConfig {
/// If the caller doesn't provide a stableID, fall back to URL identity.
var effectiveStableID: String {
let trimmed = self.stableID.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty {
return self.url.absoluteString
}
if trimmed.isEmpty { return self.url.absoluteString }
return trimmed
}
@@ -117,20 +117,14 @@ extension GatewayConnectionController {
UserDefaults.standard.object(forKey: "camera.enabled") == nil
? true
: UserDefaults.standard.bool(forKey: "camera.enabled")
if cameraEnabled {
caps.append(OpenClawCapability.camera.rawValue)
}
if cameraEnabled { caps.append(OpenClawCapability.camera.rawValue) }
let voiceWakeEnabled = UserDefaults.standard.bool(forKey: VoiceWakePreferences.enabledKey)
if voiceWakeEnabled {
caps.append(OpenClawCapability.voiceWake.rawValue)
}
if voiceWakeEnabled { caps.append(OpenClawCapability.voiceWake.rawValue) }
let locationModeRaw = UserDefaults.standard.string(forKey: "location.enabledMode") ?? "off"
let locationMode = OpenClawLocationMode(rawValue: locationModeRaw) ?? .off
if locationMode != .off {
caps.append(OpenClawCapability.location.rawValue)
}
if locationMode != .off { caps.append(OpenClawCapability.location.rawValue) }
caps.append(OpenClawCapability.device.rawValue)
caps.append(OpenClawCapability.talk.rawValue)
@@ -1028,9 +1028,7 @@ extension GatewayConnectionController {
.max { lhs, rhs in
let lhsConnected = lhs.lastConnectedAtMs ?? Int.min
let rhsConnected = rhs.lastConnectedAtMs ?? Int.min
if lhsConnected != rhsConnected {
return lhsConnected < rhsConnected
}
if lhsConnected != rhsConnected { return lhsConnected < rhsConnected }
return lhs.stableID > rhs.stableID
}
}
@@ -26,9 +26,7 @@ enum GatewayConnectionIssue: Equatable {
}
var needsPairing: Bool {
if case .pairingRequired = self {
return true
}
if case .pairingRequired = self { return true }
return false
}
@@ -52,9 +52,7 @@ final class GatewayDiscoveryModel {
}
func start() {
if !self.browsers.isEmpty {
return
}
if !self.browsers.isEmpty { return }
self.appendDebugLog("start()")
for domain in OpenClawBonjour.gatewayServiceDomains {
@@ -44,9 +44,7 @@ final class GatewayHealthMonitor {
}
}
if Task.isCancelled {
break
}
if Task.isCancelled { break }
let interval = max(0.0, config.intervalSeconds)
let nanos = UInt64(interval * 1_000_000_000)
if nanos > 0 {
@@ -464,9 +464,7 @@ enum GatewaySettingsStore {
service: self.talkService,
account: account)?
.trimmingCharacters(in: .whitespacesAndNewlines)
if value?.isEmpty == false {
return value
}
if value?.isEmpty == false { return value }
return nil
}
@@ -586,9 +584,7 @@ enum GatewaySettingsStore {
.compactMap(self.normalizedGatewayRegistryEntry)
.filter { seen.insert($0.stableID).inserted }
.sorted { lhs, rhs in
if lhs.name != rhs.name {
return lhs.name < rhs.name
}
if lhs.name != rhs.name { return lhs.name < rhs.name }
return lhs.stableID < rhs.stableID
}
let activeStableID = registry.activeStableID.flatMap { activeID in
@@ -715,9 +711,7 @@ enum GatewaySettingsStore {
let key = self.clientIdOverrideDefaultsPrefix + trimmedID
let value = UserDefaults.standard.string(forKey: key)?
.trimmingCharacters(in: .whitespacesAndNewlines)
if value?.isEmpty == false {
return value
}
if value?.isEmpty == false { return value }
return nil
}
@@ -739,9 +733,7 @@ enum GatewaySettingsStore {
let key = self.selectedAgentDefaultsPrefix + trimmedID
let value = UserDefaults.standard.string(forKey: key)?
.trimmingCharacters(in: .whitespacesAndNewlines)
if value?.isEmpty == false {
return value
}
if value?.isEmpty == false { return value }
return nil
}
+1 -3
View File
@@ -28,9 +28,7 @@ enum KeychainStore {
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
if status == errSecItemNotFound {
return true
}
if status == errSecItemNotFound { return true }
guard status == errSecSuccess else { return false }
let matches = item as? [[String: Any]] ?? []
let accounts = matches
+1 -3
View File
@@ -15,9 +15,7 @@ enum TCPProbe {
let finished = OSAllocatedUnfairLock(initialState: false)
let finish: @Sendable (Bool) -> Void = { ok in
let shouldResume = finished.withLock { flag -> Bool in
if flag {
return false
}
if flag { return false }
flag = true
return true
}
@@ -44,9 +44,7 @@ final class LocationService: NSObject, CLLocationManagerDelegate, ConcurrentLoca
let updated = await self.requestAuthorization(requiresDeterminedStatus: true) {
self.manager.requestWhenInUseAuthorization()
}
if mode != .always {
return updated
}
if mode != .always { return updated }
}
if mode == .always {
@@ -67,9 +67,7 @@ extension NodeAppModel {
_ risk: OpenClawWatchRisk?,
priority: OpenClawNotificationPriority?) -> OpenClawWatchRisk?
{
if let risk {
return risk
}
if let risk { return risk }
switch priority {
case .passive:
return .low
@@ -86,9 +84,7 @@ extension NodeAppModel {
_ priority: OpenClawNotificationPriority?,
risk: OpenClawWatchRisk?) -> OpenClawNotificationPriority?
{
if let priority {
return priority
}
if let priority { return priority }
switch risk {
case .low:
return .passive
+16 -50
View File
@@ -237,11 +237,7 @@ final class NodeAppModel {
// value equality alone cannot tell the UI to re-surface or shake the toast.
private(set) var gatewayProblemReportCount = 0
private(set) var lastGatewayProblem: GatewayConnectionProblem? {
didSet {
if self.lastGatewayProblem != nil {
self.gatewayProblemReportCount &+= 1
}
}
didSet { if self.lastGatewayProblem != nil { self.gatewayProblemReportCount &+= 1 } }
}
private var operatorGatewayProblem: GatewayConnectionProblem?
@@ -366,12 +362,8 @@ final class NodeAppModel {
}
var localChatFixture: LocalChatFixture? {
if self.isScreenshotFixtureModeEnabled {
return .appScreenshots
}
if self.isAppleReviewDemoModeEnabled {
return .appleReviewDemo
}
if self.isScreenshotFixtureModeEnabled { return .appScreenshots }
if self.isAppleReviewDemoModeEnabled { return .appleReviewDemo }
return nil
}
@@ -384,12 +376,8 @@ final class NodeAppModel {
}
var chatTransportModeID: String {
if self.isScreenshotFixtureModeEnabled {
return "screenshots"
}
if self.isAppleReviewDemoModeEnabled {
return "apple-review-demo"
}
if self.isScreenshotFixtureModeEnabled { return "screenshots" }
if self.isAppleReviewDemoModeEnabled { return "apple-review-demo" }
return self.isOperatorGatewayConnected ? "operator" : "offline"
}
@@ -707,9 +695,7 @@ final class NodeAppModel {
private func handleCanvasA2UIAction(body: [String: Any]) async {
let userActionAny = body["userAction"] ?? body
let userAction: [String: Any] = {
if let dict = userActionAny as? [String: Any] {
return dict
}
if let dict = userActionAny as? [String: Any] { return dict }
if let dict = userActionAny as? [AnyHashable: Any] {
return dict.reduce(into: [String: Any]()) { acc, pair in
guard let key = pair.key as? String else { return }
@@ -1297,9 +1283,7 @@ final class NodeAppModel {
guard let operatorRoute = await self.operatorGateway.currentRoute(), shouldContinue() else { return }
let stream = await self.operatorGateway.subscribeServerEvents(bufferingNewest: 200)
for await evt in stream {
if Task.isCancelled || !shouldContinue() {
return
}
if Task.isCancelled || !shouldContinue() { return }
guard evt.payload != nil else { continue }
await self.handleOperatorGatewayServerEvent(
evt,
@@ -1386,9 +1370,7 @@ final class NodeAppModel {
self.gatewayHealthMonitor.start(
check: { [weak self] in
guard let self else { return false }
if await MainActor.run(body: { self.isGatewayHealthMonitorDisabled() }) {
return true
}
if await MainActor.run(body: { self.isGatewayHealthMonitorDisabled() }) { return true }
do {
let data = try await self.operatorGateway.request(
method: "health",
@@ -1599,9 +1581,7 @@ final class NodeAppModel {
let params = try? Self.decodeParams(OpenClawCanvasSnapshotParams.self, from: req.paramsJSON)
let format = params?.format ?? .jpeg
let maxWidth: CGFloat? = {
if let raw = params?.maxWidth, raw > 0 {
return CGFloat(raw)
}
if let raw = params?.maxWidth, raw > 0 { return CGFloat(raw) }
// Keep default snapshots comfortably below the gateway client's maxPayload.
// For full-res, clients should explicitly request a larger maxWidth.
return switch format {
@@ -2640,9 +2620,7 @@ extension NodeAppModel {
private func isCameraEnabled() -> Bool {
// Default-on: if the key doesn't exist yet, treat it as enabled.
if UserDefaults.standard.object(forKey: "camera.enabled") == nil {
return true
}
if UserDefaults.standard.object(forKey: "camera.enabled") == nil { return true }
return UserDefaults.standard.bool(forKey: "camera.enabled")
}
@@ -2702,9 +2680,7 @@ extension NodeAppModel {
let base = SessionKey.normalizeMainKey(self.mainSessionBaseKey)
let agentId = (selectedAgentId ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
let defaultId = (gatewayDefaultAgentId ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
if agentId.isEmpty || (!defaultId.isEmpty && agentId == defaultId) {
return base
}
if agentId.isEmpty || (!defaultId.isEmpty && agentId == defaultId) { return base }
return SessionKey.makeAgentSessionKey(agentId: agentId, baseKey: base)
}
@@ -2807,9 +2783,7 @@ extension NodeAppModel {
return sessionAgentId.lowercased()
}
let selected = (self.selectedAgentId ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
if !selected.isEmpty {
return selected.lowercased()
}
if !selected.isEmpty { return selected.lowercased() }
let defaultId = (self.gatewayDefaultAgentId ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
return defaultId.isEmpty ? nil : defaultId.lowercased()
}
@@ -2845,9 +2819,7 @@ extension NodeAppModel {
private func agentDisplayName(for agentId: String, fallback: String) -> String {
let resolvedId = agentId.trimmingCharacters(in: .whitespacesAndNewlines)
if resolvedId.isEmpty {
return fallback
}
if resolvedId.isEmpty { return fallback }
if let match = gatewayAgents.first(where: { $0.id == resolvedId }) {
let name = (match.name ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
return name.isEmpty ? match.id : name
@@ -6432,17 +6404,13 @@ extension NodeAppModel {
let kind = payload["kind"] as? String
{
let trimmed = kind.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
}
if !trimmed.isEmpty { return trimmed }
}
if let payload = userInfo["openclaw"] as? [AnyHashable: Any],
let kind = payload["kind"] as? String
{
let trimmed = kind.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
}
if !trimmed.isEmpty { return trimmed }
}
return "unknown"
}
@@ -7434,9 +7402,7 @@ extension NodeAppModel {
let trimmed = (key ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }
let current = self.mainSessionBaseKey.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed == current {
return
}
if trimmed == current { return }
self.mainSessionBaseKey = trimmed
self.synchronizeTalkSessionKey()
}
@@ -30,14 +30,10 @@ enum OnboardingStateStore {
hasSavedGatewayConnection: Bool? = nil)
-> Bool
{
if defaults.bool(forKey: self.completedDefaultsKey) {
return false
}
if defaults.bool(forKey: self.completedDefaultsKey) { return false }
let hasSavedGatewayConnection =
hasSavedGatewayConnection ?? (GatewaySettingsStore.activeGatewayEntry() != nil)
if hasSavedGatewayConnection {
return false
}
if hasSavedGatewayConnection { return false }
return appModel.gatewayServerName == nil
}
@@ -192,9 +192,7 @@ struct OnboardingWizardView: View {
.alert("QR Scanner Unavailable", isPresented: Binding(
get: { self.scannerError != nil },
set: {
if !$0 {
self.scannerError = nil
}
if !$0 { self.scannerError = nil }
})) {
Button(role: .cancel) {} label: {
Text("OK")
@@ -1395,29 +1393,17 @@ extension OnboardingWizardView {
switch mode {
case .homeNetwork:
if hostIsDefaultLike {
self.manualHost = "openclaw.local"
}
if hostIsDefaultLike { self.manualHost = "openclaw.local" }
self.manualTLS = true
if self.manualPort <= 0 || self.manualPort > 65535 {
self.manualPort = 18789
}
if self.manualPort <= 0 || self.manualPort > 65535 { self.manualPort = 18789 }
case .remoteDomain:
if host == "openclaw.local" || host == "localhost" {
self.manualHost = ""
}
if host == "openclaw.local" || host == "localhost" { self.manualHost = "" }
self.manualTLS = true
if self.manualPort <= 0 || self.manualPort > 65535 {
self.manualPort = 18789
}
if self.manualPort <= 0 || self.manualPort > 65535 { self.manualPort = 18789 }
case .developerLocal:
if hostIsDefaultLike {
self.manualHost = "localhost"
}
if hostIsDefaultLike { self.manualHost = "localhost" }
self.manualTLS = false
if self.manualPort <= 0 || self.manualPort > 65535 {
self.manualPort = 18789
}
if self.manualPort <= 0 || self.manualPort > 65535 { self.manualPort = 18789 }
}
}
@@ -25,9 +25,7 @@ struct GatewayPendingTargetSuppression {
mutating func take(ifOwnedBy owner: Owner? = nil) -> GatewayConnectionController.AutoConnectSuppressionLease? {
guard let value = self.value else { return nil }
if let owner, value.owner != owner {
return nil
}
if let owner, value.owner != owner { return nil }
self.value = nil
return value.lease
}
@@ -96,9 +96,7 @@ enum PushRelayRegistrationStore {
service: self.service,
account: self.scopedAccount(self.appAttestKeyIDAccount, scope: scope))?
.trimmingCharacters(in: .whitespacesAndNewlines)
if value?.isEmpty == false {
return value
}
if value?.isEmpty == false { return value }
return nil
}
@@ -122,9 +120,7 @@ enum PushRelayRegistrationStore {
service: self.service,
account: self.scopedAccount(self.appAttestedKeyIDAccount, scope: scope))?
.trimmingCharacters(in: .whitespacesAndNewlines)
if value?.isEmpty == false {
return value
}
if value?.isEmpty == false { return value }
return nil
}
+3 -9
View File
@@ -1290,17 +1290,11 @@ extension RootTabs {
}
private func hasExistingGatewayConfig() -> Bool {
if self.appModel.activeGatewayConnectConfig != nil {
return true
}
if GatewaySettingsStore.activeGatewayEntry() != nil {
return true
}
if self.appModel.activeGatewayConnectConfig != nil { return true }
if GatewaySettingsStore.activeGatewayEntry() != nil { return true }
let preferredStableID = self.preferredGatewayStableID.trimmingCharacters(in: .whitespacesAndNewlines)
if !preferredStableID.isEmpty {
return true
}
if !preferredStableID.isEmpty { return true }
let manualHost = self.manualGatewayHost.trimmingCharacters(in: .whitespacesAndNewlines)
return self.manualGatewayEnabled && !manualHost.isEmpty
+4 -12
View File
@@ -163,9 +163,7 @@ final class ScreenController {
})()
""")
let trimmed = res.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if trimmed == "true" || trimmed == "1" {
return true
}
if trimmed == "true" || trimmed == "1" { return true }
} catch {
// ignore; page likely still loading
}
@@ -285,9 +283,7 @@ final class ScreenController {
}
nonisolated static func parseA2UIActionBody(_ body: Any) -> [String: Any]? {
if let dict = body as? [String: Any] {
return dict.isEmpty ? nil : dict
}
if let dict = body as? [String: Any] { return dict.isEmpty ? nil : dict }
if let str = body as? String,
let data = str.data(using: .utf8),
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
@@ -317,12 +313,8 @@ final class ScreenController {
extension Double {
fileprivate func clamped(to range: ClosedRange<Double>) -> Double {
if self < range.lowerBound {
return range.lowerBound
}
if self > range.upperBound {
return range.upperBound
}
if self < range.lowerBound { return range.lowerBound }
if self > range.upperBound { return range.upperBound }
return self
}
}
+1 -3
View File
@@ -9,9 +9,7 @@ enum SessionKey {
static func makeAgentSessionKey(agentId: String, baseKey: String) -> String {
let trimmedAgent = agentId.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedBase = baseKey.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmedAgent.isEmpty {
return trimmedBase.isEmpty ? "main" : trimmedBase
}
if trimmedAgent.isEmpty { return trimmedBase.isEmpty ? "main" : trimmedBase }
let normalizedBase = trimmedBase.isEmpty ? "main" : trimmedBase
return "agent:\(trimmedAgent):\(normalizedBase)"
}
@@ -22,12 +22,8 @@ enum GatewayStatusBuilder {
lastGatewayProblem: GatewayConnectionProblem?,
gatewayStatusText: String) -> GatewayDisplayState
{
if gatewayServerName != nil {
return .connected
}
if let lastGatewayProblem, lastGatewayProblem.pauseReconnect {
return .error
}
if gatewayServerName != nil { return .connected }
if let lastGatewayProblem, lastGatewayProblem.pauseReconnect { return .error }
let text = gatewayStatusText.trimmingCharacters(in: .whitespacesAndNewlines)
if text.localizedCaseInsensitiveContains("connecting") ||
@@ -391,9 +391,7 @@ final class RealtimeTalkRelaySession {
self.eventTask?.cancel()
self.eventTask = Task { [weak self] in
for await event in stream {
if Task.isCancelled {
return
}
if Task.isCancelled { return }
await self?.handleGatewayEvent(event, lifecycleGeneration: lifecycleGeneration)
}
}
@@ -482,15 +480,9 @@ final class RealtimeTalkRelaySession {
timeoutSeconds: Int,
lifecycleGeneration: UInt64) async -> StartupWaitResult
{
if self.isClosed {
return .cancelled
}
if self.hasReceivedReady {
return .ready
}
if let startupIssue {
return .failed(startupIssue)
}
if self.isClosed { return .cancelled }
if self.hasReceivedReady { return .ready }
if let startupIssue { return .failed(startupIssue) }
return await withCheckedContinuation { continuation in
if self.isClosed {
continuation.resume(returning: .cancelled)
@@ -499,7 +491,7 @@ final class RealtimeTalkRelaySession {
self.startupWaiter = continuation
Task { [weak self] in
try? await Task.sleep(nanoseconds: UInt64(max(0, timeoutSeconds)) * 1_000_000_000)
await self?.timeoutStartupWaiterIfNeeded(lifecycleGeneration: lifecycleGeneration)
self?.timeoutStartupWaiterIfNeeded(lifecycleGeneration: lifecycleGeneration)
}
}
}
@@ -39,9 +39,7 @@ struct TalkRuntimeIssue: Equatable {
}
var displayMessage: String {
if !self.message.isEmpty {
return self.message
}
if !self.message.isEmpty { return self.message }
return "Realtime voice did not start."
}
@@ -66,35 +64,19 @@ struct TalkRuntimeIssue: Equatable {
"code: \(code.rawValue)",
"message: \(self.displayMessage)",
]
if let provider, !provider.isEmpty {
lines.append("provider: \(provider)")
}
if let model, !model.isEmpty {
lines.append("model: \(model)")
}
if let transport, !transport.isEmpty {
lines.append("transport: \(transport)")
}
if let phase, !phase.isEmpty {
lines.append("phase: \(phase)")
}
if let provider, !provider.isEmpty { lines.append("provider: \(provider)") }
if let model, !model.isEmpty { lines.append("model: \(model)") }
if let transport, !transport.isEmpty { lines.append("transport: \(transport)") }
if let phase, !phase.isEmpty { lines.append("phase: \(phase)") }
return lines.joined(separator: "\n")
}
var diagnosticSummary: String {
var parts = [displayMessage]
if let provider, !provider.isEmpty {
parts.append("provider: \(provider)")
}
if let model, !model.isEmpty {
parts.append("model: \(model)")
}
if let transport, !transport.isEmpty {
parts.append("transport: \(transport)")
}
if let phase, !phase.isEmpty {
parts.append("phase: \(phase)")
}
if let provider, !provider.isEmpty { parts.append("provider: \(provider)") }
if let model, !model.isEmpty { parts.append("model: \(model)") }
if let transport, !transport.isEmpty { parts.append("transport: \(transport)") }
if let phase, !phase.isEmpty { parts.append("phase: \(phase)") }
return parts.joined(separator: "")
}
@@ -466,9 +448,7 @@ enum TalkModeGatewayConfigParser {
guard let config else { return nil }
for key in keys {
let value = config[key]?.stringValue?.trimmingCharacters(in: .whitespacesAndNewlines)
if value?.isEmpty == false {
return value
}
if value?.isEmpty == false { return value }
}
return nil
}
+12 -36
View File
@@ -476,9 +476,7 @@ final class TalkModeManager: NSObject {
func updateMainSessionKey(_ sessionKey: String?) -> Bool {
let trimmed = (sessionKey ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return false }
if trimmed == self.mainSessionKey {
return false
}
if trimmed == self.mainSessionKey { return false }
let shouldRestartTalk = self.isEnabled &&
(self.hasRealtimeOwnerOrStart || self.hasContinuousTalkOwner)
if let captureId = self.activePTTCaptureId {
@@ -837,9 +835,7 @@ final class TalkModeManager: NSObject {
func resumeAfterBackground(wasKeptActive: Bool = false) {
self.foregroundPushToTalkAllowed = true
self.foregroundAudioCaptureAllowed = true
if wasKeptActive, self.hasContinuousTalkOwner {
return
}
if wasKeptActive, self.hasContinuousTalkOwner { return }
guard self.isEnabled else { return }
Task { @MainActor [weak self] in
await self?.start()
@@ -1486,9 +1482,7 @@ final class TalkModeManager: NSObject {
private func restartRecognitionAfterError(expectedGeneration: UInt64) async {
guard self.canRestartNativeRecognition(expectedGeneration: expectedGeneration) else { return }
// Avoid thrashing the audio engine if its already running.
if self.recognitionTask != nil, self.audioEngine.isRunning {
return
}
if self.recognitionTask != nil, self.audioEngine.isRunning { return }
try? await Task.sleep(nanoseconds: 250_000_000)
guard self.canRestartNativeRecognition(expectedGeneration: expectedGeneration) else { return }
do {
@@ -1625,9 +1619,7 @@ final class TalkModeManager: NSObject {
guard !transcript.isEmpty else { return }
let lastActivity = [lastHeard, lastAudioActivity].compactMap(\.self).max()
guard let lastActivity else { return }
if Date().timeIntervalSince(lastActivity) < self.silenceWindow {
return
}
if Date().timeIntervalSince(lastActivity) < self.silenceWindow { return }
await self.processTranscript(transcript, restartAfter: true)
return
}
@@ -1641,9 +1633,7 @@ final class TalkModeManager: NSObject {
guard !transcript.isEmpty else { return }
let lastActivity = [lastHeard, lastAudioActivity].compactMap(\.self).max()
guard let lastActivity else { return }
if Date().timeIntervalSince(lastActivity) < self.silenceWindow {
return
}
if Date().timeIntervalSince(lastActivity) < self.silenceWindow { return }
if let pttCaptureId {
_ = self.endPushToTalk(captureId: pttCaptureId)
} else {
@@ -2416,9 +2406,7 @@ final class TalkModeManager: NSObject {
guard let content = msg["content"] as? [[String: Any]] else { continue }
let text = content.compactMap { $0["text"] as? String }.joined(separator: "\n")
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
}
if !trimmed.isEmpty { return trimmed }
}
return nil
}
@@ -3463,9 +3451,7 @@ extension TalkModeManager {
let trimmed = (value ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return nil }
let normalized = trimmed.lowercased()
if let mapped = voiceAliases[normalized] {
return mapped
}
if let mapped = voiceAliases[normalized] { return mapped }
if self.voiceAliases.values.contains(where: { $0.caseInsensitiveCompare(trimmed) == .orderedSame }) {
return trimmed
}
@@ -3484,14 +3470,10 @@ extension TalkModeManager {
if Self.isLikelyVoiceId(trimmed) {
return trimmed
}
if let resolved = resolveVoiceAlias(trimmed) {
return resolved
}
if let resolved = resolveVoiceAlias(trimmed) { return resolved }
self.logger.warning("unknown voice alias \(trimmed, privacy: .public)")
}
if let fallbackVoiceId {
return fallbackVoiceId
}
if let fallbackVoiceId { return fallbackVoiceId }
do {
let voices = try await ElevenLabsTTSClient(apiKey: apiKey).listVoices()
@@ -3527,9 +3509,7 @@ extension TalkModeManager {
guard !trimmed.isEmpty else { return nil }
guard trimmed != Self.redactedConfigSentinel else { return nil }
// Config values may be env placeholders (for example `${ELEVENLABS_API_KEY}`).
if trimmed.hasPrefix("${"), trimmed.hasSuffix("}") {
return nil
}
if trimmed.hasPrefix("${"), trimmed.hasSuffix("}") { return nil }
return trimmed
}
@@ -4128,13 +4108,9 @@ private final class AudioTapDiagnostics: @unchecked Sendable {
let resolvedRms = Float(TalkAudioLevel.rms(buffer: buffer))
self.lock.lock()
self.lastRms = resolvedRms
if resolvedRms > self.maxRmsWindow {
self.maxRmsWindow = resolvedRms
}
if resolvedRms > self.maxRmsWindow { self.maxRmsWindow = resolvedRms }
let maxRms = self.maxRmsWindow
if shouldLog {
self.maxRmsWindow = 0
}
if shouldLog { self.maxRmsWindow = 0 }
self.lock.unlock()
if shouldEmitLevel, let onLevel {
@@ -168,9 +168,7 @@ struct TalkPermissionPromptView: View {
private func pollUntilReady() async {
while !Task.isCancelled {
try? await Task.sleep(nanoseconds: 3_000_000_000)
if Task.isCancelled {
return
}
if Task.isCancelled { return }
await self.appModel.pollTalkPermissionUpgrade()
if !self.appModel.talkMode.gatewayTalkPermissionState.requiresTalkPermissionAction {
return
@@ -199,12 +199,8 @@ final class TalkRealtimeWebRTCSession: NSObject {
else { continue }
// Per the WebRTC stats spec audioLevel is linear 0...1:
// media-source is the local mic, inbound-rtp the remote voice.
if stat.type == "media-source" {
input = level.doubleValue
}
if stat.type == "inbound-rtp" {
output = level.doubleValue
}
if stat.type == "media-source" { input = level.doubleValue }
if stat.type == "inbound-rtp" { output = level.doubleValue }
}
continuation.resume(returning: (input, output))
}
@@ -514,17 +510,13 @@ final class TalkRealtimeWebRTCSession: NSObject {
stream: stream,
since: historySince,
timeoutSeconds: Self.toolResultTimeoutSeconds)
if Task.isCancelled || self.stopped {
return
}
if Task.isCancelled || self.stopped { return }
self.trace("tool call chat result ready callId=\(callId) runId=\(runId) chars=\(result.count)")
self.submitToolResult(callId: callId, result: ["result": result])
} catch is CancellationError {
return
} catch {
if Task.isCancelled || self.stopped {
return
}
if Task.isCancelled || self.stopped { return }
Self.logger.error("realtime tool call failed: \(error.localizedDescription, privacy: .public)")
self.trace("tool call failed callId=\(callId) error=\(error.localizedDescription)")
if let runId = activeToolRunIds[callId] {
@@ -567,9 +559,7 @@ final class TalkRealtimeWebRTCSession: NSObject {
} catch is CancellationError {
return
} catch {
if Task.isCancelled || self.stopped {
return
}
if Task.isCancelled || self.stopped { return }
Self.logger.error("realtime control tool failed: \(error.localizedDescription, privacy: .public)")
self.trace("control tool failed callId=\(callId) error=\(error.localizedDescription)")
self.submitToolResult(callId: callId, result: [
@@ -703,9 +693,7 @@ final class TalkRealtimeWebRTCSession: NSObject {
private nonisolated static func matchesSessionKey(_ incoming: String, _ current: String) -> Bool {
let incoming = incoming.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
let current = current.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if incoming == current {
return true
}
if incoming == current { return true }
return (incoming == "agent:main:main" && current == "main") ||
(incoming == "main" && current == "agent:main:main")
}
+4 -12
View File
@@ -255,12 +255,8 @@ final class VoiceWakeManager: NSObject {
func start() async {
guard self.isEnabled else { return }
if self.isListening {
return
}
if self.isStarting {
return
}
if self.isListening { return }
if self.isStarting { return }
self.isStarting = true
defer { self.isStarting = false }
@@ -377,9 +373,7 @@ final class VoiceWakeManager: NSObject {
while !Task.isCancelled {
try? await Task.sleep(nanoseconds: 40_000_000)
let drained = queue.drain()
if drained.isEmpty {
continue
}
if drained.isEmpty { continue }
for buf in drained {
request.append(buf)
}
@@ -453,9 +447,7 @@ final class VoiceWakeManager: NSObject {
guard let transcript else { return }
guard let cmd = self.extractCommand(from: transcript, segments: segments) else { return }
if cmd == self.lastDispatched {
return
}
if cmd == self.lastDispatched { return }
self.lastDispatched = cmd
self.lastTriggeredCommand = cmd
self.statusText = "Triggered"
@@ -152,9 +152,7 @@ struct OpenClawWatchApp: App {
self.execApprovalRefreshTask = Task { @MainActor in
self.inboxStore.beginExecApprovalReviewLoading()
for attempt in 0..<5 {
if Task.isCancelled {
return
}
if Task.isCancelled { return }
await receiver.requestExecApprovalSnapshot()
if !self.inboxStore.execApprovals.isEmpty
|| self.inboxStore.hasCompletedExecApprovalSnapshotRefresh
@@ -398,9 +398,7 @@ private struct WatchControlSurfaceView: View {
}
private var primaryLabel: String {
if self.store.activeExecApproval != nil {
return "Next up"
}
if self.store.activeExecApproval != nil { return "Next up" }
return self.store.appSnapshot?.gatewayConnected == true ? "Running" : "Pairing"
}
@@ -505,12 +503,8 @@ private struct WatchControlSurfaceView: View {
return greetingTextOverride
}
let hour = Calendar.current.component(.hour, from: Date())
if hour < 12 {
return "Good morning"
}
if hour < 18 {
return "Good afternoon"
}
if hour < 12 { return "Good morning" }
if hour < 18 { return "Good afternoon" }
return "Good evening"
}
@@ -7,23 +7,11 @@ func age(from date: Date, now: Date = .init()) -> String {
let hours = minutes / 60
let days = hours / 24
if seconds < 60 {
return "just now"
}
if minutes == 1 {
return "1 minute ago"
}
if minutes < 60 {
return "\(minutes)m ago"
}
if hours == 1 {
return "1 hour ago"
}
if hours < 24 {
return "\(hours)h ago"
}
if days == 1 {
return "yesterday"
}
if seconds < 60 { return "just now" }
if minutes == 1 { return "1 minute ago" }
if minutes < 60 { return "\(minutes)m ago" }
if hours == 1 { return "1 hour ago" }
if hours < 24 { return "\(hours)h ago" }
if days == 1 { return "yesterday" }
return "\(days)d ago"
}
@@ -30,9 +30,7 @@ enum AgentWorkspace {
static func displayPath(for url: URL) -> String {
let home = FileManager().homeDirectoryForCurrentUser.path
let path = url.path
if path == home {
return "~"
}
if path == home { return "~" }
if path.hasPrefix(home + "/") {
return "~/" + String(path.dropFirst(home.count + 1))
}
@@ -41,9 +39,7 @@ enum AgentWorkspace {
static func resolveWorkspaceURL(from userInput: String?) -> URL {
let trimmed = userInput?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if trimmed.isEmpty {
return OpenClawConfigFile.defaultWorkspaceURL()
}
if trimmed.isEmpty { return OpenClawConfigFile.defaultWorkspaceURL() }
let expanded = (trimmed as NSString).expandingTildeInPath
return URL(fileURLWithPath: expanded, isDirectory: true)
}
@@ -80,9 +76,7 @@ enum AgentWorkspace {
if !fm.fileExists(atPath: workspaceURL.path, isDirectory: &isDir) {
return .safe
}
if !isDir.boolValue {
return .blocked("Workspace path points to a file.")
}
if !isDir.boolValue { return .blocked("Workspace path points to a file.") }
let agentsURL = self.agentsURL(workspaceURL: workspaceURL)
if fm.fileExists(atPath: agentsURL.path) {
return .safe
@@ -15,9 +15,7 @@ enum CLIInstaller {
case incompatible(location: String, found: String, required: String)
var isReady: Bool {
if case .ready = self {
return true
}
if case .ready = self { return true }
return false
}
@@ -44,9 +44,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
}
let body: [String: Any] = {
if let dict = message.body as? [String: Any] {
return dict
}
if let dict = message.body as? [String: Any] { return dict }
if let dict = message.body as? [AnyHashable: Any] {
return dict.reduce(into: [String: Any]()) { acc, pair in
guard let key = pair.key as? String else { return }
@@ -59,9 +57,7 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
let userActionAny = body["userAction"] ?? body
let userAction: [String: Any] = {
if let dict = userActionAny as? [String: Any] {
return dict
}
if let dict = userActionAny as? [String: Any] { return dict }
if let dict = userActionAny as? [AnyHashable: Any] {
return dict.reduce(into: [String: Any]()) { acc, pair in
guard let key = pair.key as? String else { return }
@@ -137,24 +133,12 @@ final class CanvasA2UIActionMessageHandler: NSObject, WKScriptMessageHandler {
private static func isLocalNetworkIPv4(_ ip: (UInt8, UInt8, UInt8, UInt8)) -> Bool {
let (a, b, _, _) = ip
if a == 10 {
return true
}
if a == 172, (16...31).contains(Int(b)) {
return true
}
if a == 192, b == 168 {
return true
}
if a == 127 {
return true
}
if a == 169, b == 254 {
return true
}
if a == 100, (64...127).contains(Int(b)) {
return true
}
if a == 10 { return true }
if a == 172, (16...31).contains(Int(b)) { return true }
if a == 192, b == 168 { return true }
if a == 127 { return true }
if a == 169, b == 254 { return true }
if a == 100, (64...127).contains(Int(b)) { return true }
return false
}
// Formatting helpers live in OpenClawKit (`OpenClawCanvasA2UIAction`).
@@ -206,15 +206,9 @@ final class HoverChromeContainerView: NSView {
// When the chrome is hidden, do not intercept any mouse events (let the WKWebView receive them).
guard self.alphaValue > 0.02 else { return nil }
if self.closeButton.frame.contains(point) {
return self.closeButton
}
if self.dragHandle.frame.contains(point) {
return self.dragHandle
}
if self.resizeHandle.frame.contains(point) {
return self.resizeHandle
}
if self.closeButton.frame.contains(point) { return self.closeButton }
if self.dragHandle.frame.contains(point) { return self.dragHandle }
if self.resizeHandle.frame.contains(point) { return self.resizeHandle }
return nil
}
@@ -255,9 +255,7 @@ final class CanvasManager {
guard !trimmed.isEmpty else { return nil }
if let url = URL(string: trimmed), let scheme = url.scheme?.lowercased() {
if scheme == "https" || scheme == "http" || scheme == "file" {
return url
}
if scheme == "https" || scheme == "http" || scheme == "file" { return url }
}
// Convenience: existing absolute *file* paths resolve as local files.
@@ -304,18 +302,14 @@ final class CanvasManager {
let withoutQuery = trimmed.split(separator: "?", maxSplits: 1, omittingEmptySubsequences: false).first
.map(String.init) ?? trimmed
var path = withoutQuery
if path.hasPrefix("/") {
path.removeFirst()
}
if path.hasPrefix("/") { path.removeFirst() }
path = path.removingPercentEncoding ?? path
// Root special-case: built-in scaffold page when no index exists.
if path.isEmpty {
let a = sessionDir.appendingPathComponent("index.html", isDirectory: false)
let b = sessionDir.appendingPathComponent("index.htm", isDirectory: false)
if fm.fileExists(atPath: a.path) || fm.fileExists(atPath: b.path) {
return .ok
}
if fm.fileExists(atPath: a.path) || fm.fileExists(atPath: b.path) { return .ok }
return .welcome
}
@@ -343,9 +337,7 @@ final class CanvasManager {
private static func indexExists(in dir: URL) -> Bool {
let fm = FileManager()
let a = dir.appendingPathComponent("index.html", isDirectory: false)
if fm.fileExists(atPath: a.path) {
return true
}
if fm.fileExists(atPath: a.path) { return true }
let b = dir.appendingPathComponent("index.htm", isDirectory: false)
return fm.fileExists(atPath: b.path)
}
@@ -61,12 +61,8 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
// Path mapping: request path maps directly into the session dir.
var path = url.path
if let qIdx = path.firstIndex(of: "?") {
path = String(path[..<qIdx])
}
if path.hasPrefix("/") {
path.removeFirst()
}
if let qIdx = path.firstIndex(of: "?") { path = String(path[..<qIdx]) }
if path.hasPrefix("/") { path.removeFirst() }
path = path.removingPercentEncoding ?? path
// Special-case: welcome page when root index is missing.
@@ -117,9 +113,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
var isDir: ObjCBool = false
if fm.fileExists(atPath: candidate.path, isDirectory: &isDir) {
if isDir.boolValue {
if let idx = self.resolveIndex(in: candidate) {
return idx
}
if let idx = self.resolveIndex(in: candidate) { return idx }
return nil
}
return candidate
@@ -130,9 +124,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
if !requestPath.isEmpty, !requestPath.hasSuffix("/") {
candidate = sessionRoot.appendingPathComponent(requestPath, isDirectory: true)
if fm.fileExists(atPath: candidate.path, isDirectory: &isDir), isDir.boolValue {
if let idx = self.resolveIndex(in: candidate) {
return idx
}
if let idx = self.resolveIndex(in: candidate) { return idx }
}
}
@@ -148,13 +140,9 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
private func resolveIndex(in dir: URL) -> URL? {
let fm = FileManager()
let a = dir.appendingPathComponent("index.html", isDirectory: false)
if fm.fileExists(atPath: a.path) {
return a
}
if fm.fileExists(atPath: a.path) { return a }
let b = dir.appendingPathComponent("index.htm", isDirectory: false)
if fm.fileExists(atPath: b.path) {
return b
}
if fm.fileExists(atPath: b.path) { return b }
return nil
}
@@ -229,9 +217,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
private func loadBundledResourceData(relativePath: String) -> Data? {
let trimmed = relativePath.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return nil }
if trimmed.contains("..") || trimmed.contains("\\") {
return nil
}
if trimmed.contains("..") || trimmed.contains("\\") { return nil }
let parts = trimmed.split(separator: "/")
guard let filename = parts.last else { return nil }
@@ -251,9 +237,7 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
}
private func textEncodingName(forMimeType mimeType: String) -> String? {
if mimeType.hasPrefix("text/") {
return "utf-8"
}
if mimeType.hasPrefix("text/") { return "utf-8" }
switch mimeType {
case "application/javascript", "application/json", "image/svg+xml":
return "utf-8"
@@ -25,9 +25,7 @@ enum CanvasPresentation {
case panel(anchorProvider: () -> NSRect?)
var isPanel: Bool {
if case .panel = self {
return true
}
if case .panel = self { return true }
return false
}
}
@@ -6,9 +6,7 @@ extension CanvasWindowController {
static func sanitizeSessionKey(_ key: String) -> String {
let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty {
return "main"
}
if trimmed.isEmpty { return "main" }
let allowed = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+")
let scalars = trimmed.unicodeScalars.map { allowed.contains($0) ? Character($0) : "_" }
return String(scalars)
@@ -32,9 +30,7 @@ extension CanvasWindowController {
let key = self.storedFrameDefaultsKey(sessionKey: sessionKey)
guard let arr = UserDefaults.standard.array(forKey: key) as? [Double], arr.count == 4 else { return nil }
let rect = NSRect(x: arr[0], y: arr[1], width: arr[2], height: arr[3])
if rect.width < CanvasLayout.minPanelSize.width || rect.height < CanvasLayout.minPanelSize.height {
return nil
}
if rect.width < CanvasLayout.minPanelSize.width || rect.height < CanvasLayout.minPanelSize.height { return nil }
return rect
}
@@ -34,24 +34,12 @@ extension CanvasWindowController {
static func _testIsLocalNetworkIPv4(_ ip: (UInt8, UInt8, UInt8, UInt8)) -> Bool {
let (a, b, _, _) = ip
if a == 10 {
return true
}
if a == 172, (16...31).contains(Int(b)) {
return true
}
if a == 192, b == 168 {
return true
}
if a == 127 {
return true
}
if a == 169, b == 254 {
return true
}
if a == 100, (64...127).contains(Int(b)) {
return true
}
if a == 10 { return true }
if a == 172, (16...31).contains(Int(b)) { return true }
if a == 192, b == 168 { return true }
if a == 127 { return true }
if a == 169, b == 254 { return true }
if a == 100, (64...127).contains(Int(b)) { return true }
return false
}
@@ -79,18 +79,10 @@ extension CanvasWindowController {
// - If agent provides width/height, override size.
// - If agent provides only size, keep the remembered origin.
if let placement = self.preferredPlacement {
if let x = placement.x {
frame.origin.x = x
}
if let y = placement.y {
frame.origin.y = y
}
if let w = placement.width {
frame.size.width = max(CanvasLayout.minPanelSize.width, CGFloat(w))
}
if let h = placement.height {
frame.size.height = max(CanvasLayout.minPanelSize.height, CGFloat(h))
}
if let x = placement.x { frame.origin.x = x }
if let y = placement.y { frame.origin.y = y }
if let w = placement.width { frame.size.width = max(CanvasLayout.minPanelSize.width, CGFloat(w)) }
if let h = placement.height { frame.size.height = max(CanvasLayout.minPanelSize.height, CGFloat(h)) }
}
self.setPanelFrame(frame, on: targetScreen)
@@ -136,9 +128,7 @@ extension CanvasWindowController {
}
static func constrainFrame(_ frame: NSRect, toVisibleFrame bounds: NSRect) -> NSRect {
if bounds == .zero {
return frame
}
if bounds == .zero { return frame }
var next = frame
next.size.width = min(max(CanvasLayout.minPanelSize.width, next.size.width), bounds.width)
@@ -323,12 +323,8 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, WK
func shouldAutoNavigateToA2UI(lastAutoTarget: String?, candidateTarget: String) -> Bool {
let current = (self.currentTarget ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
let candidate = candidateTarget.trimmingCharacters(in: .whitespacesAndNewlines)
if current.isEmpty || current == "/" {
return true
}
if !candidate.isEmpty, current == candidate {
return false
}
if current.isEmpty || current == "/" { return true }
if !candidate.isEmpty, current == candidate { return false }
if let lastAuto = lastAutoTarget?.trimmingCharacters(in: .whitespacesAndNewlines),
!lastAuto.isEmpty,
current == lastAuto
@@ -121,9 +121,7 @@ struct ConfigSchemaForm: View {
}
return AnyView(
VStack(alignment: .leading, spacing: 6) {
if let label {
Text(label).font(.callout.weight(.semibold))
}
if let label { Text(label).font(.callout.weight(.semibold)) }
Text("Unsupported field type.")
.font(.caption)
.foregroundStyle(.secondary)
@@ -154,9 +152,7 @@ struct ConfigSchemaForm: View {
let sortedKeys = properties.keys.sorted { lhs, rhs in
let orderA = hintForPath(path + [.key(lhs)], hints: store.configUiHints)?.order ?? 0
let orderB = hintForPath(path + [.key(rhs)], hints: store.configUiHints)?.order ?? 0
if orderA != orderB {
return orderA < orderB
}
if orderA != orderB { return orderA < orderB }
return lhs < rhs
}
@@ -210,9 +206,7 @@ struct ConfigSchemaForm: View {
value: Any?) -> Bool
{
guard schema.allowsAdditionalProperties else { return false }
if self.mode != .channelQuick {
return true
}
if self.mode != .channelQuick { return true }
guard let dict = value as? [String: Any] else { return false }
let reserved = Set(schema.properties.keys)
return dict.keys.contains { !reserved.contains($0) }
@@ -341,9 +335,7 @@ struct ConfigSchemaForm: View {
}
} else {
VStack(alignment: .leading, spacing: 6) {
if let label {
Text(label).font(.callout.weight(.semibold))
}
if let label { Text(label).font(.callout.weight(.semibold)) }
if let help {
Text(help)
.font(.caption)
@@ -379,9 +371,7 @@ struct ConfigSchemaForm: View {
}
} else {
VStack(alignment: .leading, spacing: 6) {
if let label {
Text(label).font(.callout.weight(.semibold))
}
if let label { Text(label).font(.callout.weight(.semibold)) }
if let help {
Text(help)
.font(.caption)
@@ -420,9 +410,7 @@ struct ConfigSchemaForm: View {
}
} else {
VStack(alignment: .leading, spacing: 6) {
if let label {
Text(label).font(.callout.weight(.semibold))
}
if let label { Text(label).font(.callout.weight(.semibold)) }
if let help {
Text(help)
.font(.caption)
@@ -450,9 +438,7 @@ struct ConfigSchemaForm: View {
let items = value as? [Any] ?? []
let itemSchema = schema.items
VStack(alignment: .leading, spacing: 10) {
if let label {
Text(label).font(.callout.weight(.semibold))
}
if let label { Text(label).font(.callout.weight(.semibold)) }
if let help {
Text(help)
.font(.caption)
@@ -544,9 +530,7 @@ struct ConfigSchemaForm: View {
private func stringBinding(_ path: ConfigPath, defaultValue: String?) -> Binding<String> {
Binding(
get: {
if let value = store.configValue(at: path) as? String {
return value
}
if let value = store.configValue(at: path) as? String { return value }
return defaultValue ?? ""
},
set: { newValue in
@@ -558,9 +542,7 @@ struct ConfigSchemaForm: View {
private func boolBinding(_ path: ConfigPath, defaultValue: Bool?) -> Binding<Bool> {
Binding(
get: {
if let value = store.configValue(at: path) as? Bool {
return value
}
if let value = store.configValue(at: path) as? Bool { return value }
return defaultValue ?? false
},
set: { newValue in
@@ -575,9 +557,7 @@ struct ConfigSchemaForm: View {
{
Binding(
get: {
if let value = store.configValue(at: path) {
return String(describing: value)
}
if let value = store.configValue(at: path) { return String(describing: value) }
guard let defaultValue else { return "" }
return isInteger ? String(Int(defaultValue)) : String(defaultValue)
},
@@ -10,28 +10,16 @@ extension ChannelsSettings {
}
private func configuredChannelTint(configured: Bool, running: Bool, hasError: Bool, probeOk: Bool?) -> Color {
if !configured {
return .secondary
}
if hasError {
return .orange
}
if probeOk == false {
return .orange
}
if running {
return .green
}
if !configured { return .secondary }
if hasError { return .orange }
if probeOk == false { return .orange }
if running { return .green }
return .orange
}
private func configuredChannelSummary(configured: Bool, running: Bool) -> String {
if !configured {
return "Not configured"
}
if running {
return "Running"
}
if !configured { return "Not configured" }
if running { return "Running" }
return "Configured"
}
@@ -108,21 +96,11 @@ extension ChannelsSettings {
var whatsAppTint: Color {
guard let status = self.channelStatus("whatsapp", as: ChannelsStatusSnapshot.WhatsAppStatus.self)
else { return .secondary }
if !status.configured {
return .secondary
}
if !status.linked {
return .red
}
if status.lastError != nil {
return .orange
}
if status.connected {
return .green
}
if status.running {
return .orange
}
if !status.configured { return .secondary }
if !status.linked { return .red }
if status.lastError != nil { return .orange }
if status.connected { return .green }
if status.running { return .orange }
return .orange
}
@@ -179,15 +157,9 @@ extension ChannelsSettings {
var whatsAppSummary: String {
guard let status = self.channelStatus("whatsapp", as: ChannelsStatusSnapshot.WhatsAppStatus.self)
else { return "Checking…" }
if !status.linked {
return "Not linked"
}
if status.connected {
return "Connected"
}
if status.running {
return "Running"
}
if !status.linked { return "Not linked" }
if status.connected { return "Connected" }
if status.running { return "Running" }
return "Linked"
}
@@ -372,9 +344,7 @@ extension ChannelsSettings {
return channels.sorted { lhs, rhs in
let lhsEnabled = self.channelEnabled(lhs)
let rhsEnabled = self.channelEnabled(rhs)
if lhsEnabled != rhsEnabled {
return lhsEnabled && !rhsEnabled
}
if lhsEnabled != rhsEnabled { return lhsEnabled && !rhsEnabled }
return lhs.sortOrder < rhs.sortOrder
}
}
@@ -435,12 +405,8 @@ extension ChannelsSettings {
case "imessage":
return self.imessageTint
default:
if self.channelHasError(channel) {
return .orange
}
if self.channelEnabled(channel) {
return .green
}
if self.channelHasError(channel) { return .orange }
if self.channelEnabled(channel) { return .green }
return .secondary
}
}
@@ -460,12 +426,8 @@ extension ChannelsSettings {
case "imessage":
return self.imessageSummary
default:
if self.channelHasError(channel) {
return "Error"
}
if self.channelEnabled(channel) {
return "Active"
}
if self.channelHasError(channel) { return "Error" }
if self.channelEnabled(channel) { return "Active" }
return "Not configured"
}
}
@@ -570,9 +532,7 @@ extension ChannelsSettings {
private func resolveChannelTitle(_ id: String) -> String {
let label = self.store.resolveChannelLabel(id)
if label != id {
return label
}
if label != id { return label }
return id.prefix(1).uppercased() + id.dropFirst()
}
@@ -99,9 +99,7 @@ extension CoalescingFSEventsWatcher {
guard self.shouldNotify(numEvents, eventPaths) else { return }
// Coalesce rapid changes (common during builds/atomic saves).
if self.pending {
return
}
if self.pending { return }
self.pending = true
self.queue.asyncAfter(deadline: .now() + self.coalesceDelay) { [weak self] in
guard let self else { return }
@@ -6,17 +6,11 @@ enum CommandResolver {
static func gatewayEntrypoint(in root: URL) -> String? {
let distEntry = root.appendingPathComponent("dist/index.js").path
if FileManager().isReadableFile(atPath: distEntry) {
return distEntry
}
if FileManager().isReadableFile(atPath: distEntry) { return distEntry }
let openclawEntry = root.appendingPathComponent("openclaw.mjs").path
if FileManager().isReadableFile(atPath: openclawEntry) {
return openclawEntry
}
if FileManager().isReadableFile(atPath: openclawEntry) { return openclawEntry }
let binEntry = root.appendingPathComponent("bin/openclaw.js").path
if FileManager().isReadableFile(atPath: binEntry) {
return binEntry
}
if FileManager().isReadableFile(atPath: binEntry) { return binEntry }
return nil
}
@@ -207,9 +201,7 @@ enum CommandResolver {
for i in 0..<maxCount {
let ai = i < va.count ? va[i] : 0
let bi = i < vb.count ? vb[i] : 0
if ai != bi {
return ai > bi
}
if ai != bi { return ai > bi }
}
// If identical numerically, keep stable ordering.
return a > b
@@ -263,12 +255,8 @@ enum CommandResolver {
}
static func hasAnyOpenClawInvoker(searchPaths: [String]? = nil) -> Bool {
if self.openclawExecutable(searchPaths: searchPaths) != nil {
return true
}
if self.findExecutable(named: "pnpm", searchPaths: searchPaths) != nil {
return true
}
if self.openclawExecutable(searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "pnpm", searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "node", searchPaths: searchPaths) != nil,
self.nodeCliPath() != nil
{
@@ -599,9 +587,7 @@ enum CommandResolver {
}
private static func shellQuote(_ text: String) -> String {
if text.isEmpty {
return "''"
}
if text.isEmpty { return "''" }
let escaped = text.replacingOccurrences(of: "'", with: "'\\''")
return "'\(escaped)'"
}
@@ -625,12 +611,8 @@ enum CommandResolver {
}
private static func isValidSSHComponent(_ value: String, allowLeadingDash: Bool = false) -> Bool {
if value.isEmpty {
return false
}
if !allowLeadingDash, value.hasPrefix("-") {
return false
}
if value.isEmpty { return false }
if !allowLeadingDash, value.hasPrefix("-") { return false }
let invalid = CharacterSet.whitespacesAndNewlines.union(.controlCharacters)
return value.rangeOfCharacter(from: invalid) == nil
}
@@ -22,15 +22,9 @@ final class ConfigFileWatcher: @unchecked Sendable, SimpleFileWatcherOwner {
guard let eventPaths else { return true }
let paths = unsafeBitCast(eventPaths, to: NSArray.self)
for case let path as String in paths {
if path == targetPath {
return true
}
if path.hasSuffix("/\(targetName)") {
return true
}
if path == watchedDirPath {
return true
}
if path == targetPath { return true }
if path.hasSuffix("/\(targetName)") { return true }
if path == watchedDirPath { return true }
}
return false
},
@@ -64,20 +64,14 @@ struct ConfigSchemaNode {
}
var typeList: [String] {
if let type = self.raw["type"] as? String {
return [type]
}
if let types = self.raw["type"] as? [String] {
return types
}
if let type = self.raw["type"] as? String { return [type] }
if let types = self.raw["type"] as? [String] { return types }
return []
}
var schemaType: String? {
let filtered = self.typeList.filter { $0 != "null" }
if let first = filtered.first {
return first
}
if let first = filtered.first { return first }
return self.typeList.first
}
@@ -102,12 +96,8 @@ struct ConfigSchemaNode {
}
var literalValue: Any? {
if let constValue {
return constValue
}
if let enumValues, enumValues.count == 1 {
return enumValues[0]
}
if let constValue { return constValue }
if let enumValues, enumValues.count == 1 { return enumValues[0] }
return nil
}
@@ -129,16 +119,12 @@ struct ConfigSchemaNode {
}
var allowsAdditionalProperties: Bool {
if let allow = self.raw["additionalProperties"] as? Bool {
return allow
}
if let allow = self.raw["additionalProperties"] as? Bool { return allow }
return self.additionalProperties != nil
}
var defaultValue: Any {
if let value = self.raw["default"] {
return value
}
if let value = self.raw["default"] { return value }
switch self.schemaType {
case "object":
return [String: Any]()
@@ -194,9 +180,7 @@ func decodeUiHints(_ raw: [String: Any]) -> [String: ConfigUiHint] {
func hintForPath(_ path: ConfigPath, hints: [String: ConfigUiHint]) -> ConfigUiHint? {
let key = pathKey(path)
if let direct = hints[key] {
return direct
}
if let direct = hints[key] { return direct }
let segments = key.split(separator: ".").map(String.init)
for (hintKey, hint) in hints {
guard hintKey.contains("*") else { continue }
@@ -210,9 +194,7 @@ func hintForPath(_ path: ConfigPath, hints: [String: ConfigUiHint]) -> ConfigUiH
break
}
}
if match {
return hint
}
if match { return hint }
}
return nil
}
@@ -419,9 +419,7 @@ extension ConfigSettings {
private func sortLookupChildren(_ lhs: ConfigSchemaLookupChild, _ rhs: ConfigSchemaLookupChild) -> Bool {
let orderA = lhs.hint?.order ?? 0
let orderB = rhs.hint?.order ?? 0
if orderA != orderB {
return orderA < orderB
}
if orderA != orderB { return orderA < orderB }
return lhs.key < rhs.key
}
@@ -444,9 +442,7 @@ extension ConfigSettings {
}
private static func shouldRenderFormEditor(for schema: ConfigSchemaNode) -> Bool {
if schema.schemaType == "array" {
return true
}
if schema.schemaType == "array" { return true }
return schema.additionalProperties != nil
}
@@ -49,9 +49,7 @@ struct ContextMenuCardView: View {
private var subtitle: String {
let count = self.rows.count
if count == 1 {
return "1 session · 24h"
}
if count == 1 { return "1 session · 24h" }
return "\(count) sessions · 24h"
}
@@ -9,25 +9,19 @@ struct ContextUsageBar: View {
private static let okGreen: NSColor = .init(name: nil) { appearance in
let base = NSColor.systemGreen
let match = appearance.bestMatch(from: [.aqua, .darkAqua])
if match == .darkAqua {
return base
}
if match == .darkAqua { return base }
return base.blended(withFraction: 0.24, of: .black) ?? base
}
private static let trackFill: NSColor = .init(name: nil) { appearance in
let match = appearance.bestMatch(from: [.aqua, .darkAqua])
if match == .darkAqua {
return NSColor.white.withAlphaComponent(0.14)
}
if match == .darkAqua { return NSColor.white.withAlphaComponent(0.14) }
return NSColor.black.withAlphaComponent(0.12)
}
private static let trackStroke: NSColor = .init(name: nil) { appearance in
let match = appearance.bestMatch(from: [.aqua, .darkAqua])
if match == .darkAqua {
return NSColor.white.withAlphaComponent(0.22)
}
if match == .darkAqua { return NSColor.white.withAlphaComponent(0.22) }
return NSColor.black.withAlphaComponent(0.2)
}
@@ -43,15 +37,9 @@ struct ContextUsageBar: View {
private var tint: Color {
guard let pct = self.percentUsed else { return .secondary }
if pct >= 95 {
return Color(nsColor: .systemRed)
}
if pct >= 80 {
return Color(nsColor: .systemOrange)
}
if pct >= 60 {
return Color(nsColor: .systemYellow)
}
if pct >= 95 { return Color(nsColor: .systemRed) }
if pct >= 80 { return Color(nsColor: .systemOrange) }
if pct >= 60 { return Color(nsColor: .systemYellow) }
return Color(nsColor: Self.okGreen)
}
@@ -74,9 +62,7 @@ struct ContextUsageBar: View {
}
private var accessibilityValue: String {
if self.contextTokens <= 0 {
return "Unknown context window"
}
if self.contextTokens <= 0 { return "Unknown context window" }
let pct = Int(round(self.clampedFractionUsed * 100))
return "\(pct) percent used"
}
@@ -343,9 +343,7 @@ final class ControlChannel {
let detail = nsError.localizedDescription.isEmpty ? "unknown gateway error" : nsError.localizedDescription
let trimmed = detail.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.lowercased().hasPrefix("gateway error:") {
return trimmed
}
if trimmed.lowercased().hasPrefix("gateway error:") { return trimmed }
return "Gateway error: \(trimmed)"
}
@@ -367,9 +365,7 @@ final class ControlChannel {
private func scheduleRecovery(reason: String) {
let now = Date()
if let last = self.lastRecoveryAt, now.timeIntervalSince(last) < 10 {
return
}
if let last = self.lastRecoveryAt, now.timeIntervalSince(last) < 10 { return }
guard self.recoveryTask == nil else { return }
self.lastRecoveryAt = now
@@ -99,9 +99,7 @@ extension CritterStatusLabel {
deadlines: [Date]) -> TimeInterval
{
// Working motion needs a steady cadence; idle motion only wakes for its next visible event.
if isWorking {
return 0.35
}
if isWorking { return 0.35 }
guard let nextDeadline = deadlines.min() else { return 1 }
return max(0.05, nextDeadline.timeIntervalSince(now))
}
@@ -248,9 +246,7 @@ extension CritterStatusLabel {
}
private var gatewayNeedsAttention: Bool {
if self.isSleeping {
return false
}
if self.isSleeping { return false }
switch self.gatewayStatus {
case .failed, .stopped:
return !self.isPaused
@@ -110,9 +110,7 @@ extension CronJobEditor {
"payload": payload,
]
self.applyDeleteAfterRun(to: &root)
if !description.isEmpty {
root["description"] = description
}
if !description.isEmpty { root["description"] = description }
if !agentId.isEmpty {
root["agentId"] = agentId
} else if self.job?.agentId != nil {
@@ -133,9 +131,7 @@ extension CronJobEditor {
let trimmed = self.channel.trimmingCharacters(in: .whitespacesAndNewlines)
delivery["channel"] = trimmed.isEmpty ? "last" : trimmed
let to = self.to.trimmingCharacters(in: .whitespacesAndNewlines)
if !to.isEmpty {
delivery["to"] = to
}
if !to.isEmpty { delivery["to"] = to }
if self.bestEffortDeliver {
delivery["bestEffort"] = true
} else if self.job?.delivery?.bestEffort == true {
@@ -189,9 +185,7 @@ extension CronJobEditor {
}
func buildSelectedPayload() throws -> [String: Any] {
if self.isIsolatedLikeSessionTarget {
return self.buildAgentTurnPayload()
}
if self.isIsolatedLikeSessionTarget { return self.buildAgentTurnPayload() }
switch self.payloadKind {
case .systemEvent:
let text = self.trimmed(self.systemEventText)
@@ -257,20 +251,14 @@ extension CronJobEditor {
let msg = self.agentMessage.trimmingCharacters(in: .whitespacesAndNewlines)
var payload: [String: Any] = ["kind": "agentTurn", "message": msg]
let thinking = self.thinking.trimmingCharacters(in: .whitespacesAndNewlines)
if !thinking.isEmpty {
payload["thinking"] = thinking
}
if let n = Int(self.timeoutSeconds), n > 0 {
payload["timeoutSeconds"] = n
}
if !thinking.isEmpty { payload["thinking"] = thinking }
if let n = Int(self.timeoutSeconds), n > 0 { payload["timeoutSeconds"] = n }
return payload
}
static func parseDurationMs(_ input: String) -> Int? {
let raw = input.trimmingCharacters(in: .whitespacesAndNewlines)
if raw.isEmpty {
return nil
}
if raw.isEmpty { return nil }
let rx = try? NSRegularExpression(pattern: "^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d)$", options: [.caseInsensitive])
guard let match = rx?.firstMatch(in: raw, range: NSRange(location: 0, length: raw.utf16.count)) else {
@@ -282,9 +270,7 @@ extension CronJobEditor {
return String(raw[r])
}
let n = Double(group(1)) ?? 0
if !n.isFinite || n <= 0 {
return nil
}
if !n.isFinite || n <= 0 { return nil }
let unit = group(2).lowercased()
let factor: Double = switch unit {
case "ms": 1
@@ -85,9 +85,7 @@ struct CronJobEditor: View {
}
func channelLabel(for id: String) -> String {
if id == "last" {
return "last"
}
if id == "last" { return "last" }
return self.channelsStore.resolveChannelLabel(id)
}
+2 -6
View File
@@ -139,12 +139,8 @@ enum CronSchedule: Codable, Equatable {
static func parseAtDate(_ value: String) -> Date? {
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty {
return nil
}
if let date = makeIsoFormatter(withFractional: true).date(from: trimmed) {
return date
}
if trimmed.isEmpty { return nil }
if let date = makeIsoFormatter(withFractional: true).date(from: trimmed) { return date }
return self.makeIsoFormatter(withFractional: false).date(from: trimmed)
}
@@ -25,14 +25,10 @@ extension CronSettings {
case let .every(everyMs, _):
return "every \(self.formatDuration(ms: everyMs))"
case let .cron(expr, tz):
if let tz, !tz.isEmpty {
return "cron \(expr) (\(tz))"
}
if let tz, !tz.isEmpty { return "cron \(expr) (\(tz))" }
return "cron \(expr)"
case let .onExit(command, cwd):
if let cwd, !cwd.isEmpty {
return "on exit: \(command) (cwd: \(cwd))"
}
if let cwd, !cwd.isEmpty { return "on exit: \(command) (cwd: \(cwd))" }
return "on exit: \(command)"
}
}
@@ -43,20 +39,12 @@ extension CronSettings {
func nextRunLabel(_ date: Date, now: Date = .init()) -> String {
let delta = date.timeIntervalSince(now)
if delta <= 0 {
return "due"
}
if delta < 60 {
return "in <1m"
}
if delta <= 0 { return "due" }
if delta < 60 { return "in <1m" }
let minutes = Int(round(delta / 60))
if minutes < 60 {
return "in \(minutes)m"
}
if minutes < 60 { return "in \(minutes)m" }
let hours = Int(round(Double(minutes) / 60))
if hours < 48 {
return "in \(hours)h"
}
if hours < 48 { return "in \(hours)h" }
let days = Int(round(Double(hours) / 24))
return "in \(days)d"
}
@@ -39,9 +39,7 @@ extension CronSettings {
.alert("Delete cron job?", isPresented: Binding(
get: { self.confirmDelete != nil },
set: {
if !$0 {
self.confirmDelete = nil
}
if !$0 { self.confirmDelete = nil }
})) {
Button("Cancel", role: .cancel) { self.confirmDelete = nil }
Button("Delete", role: .destructive) {
@@ -222,12 +222,8 @@ extension CronSettings {
.font(.callout)
.textSelection(.enabled)
HStack(spacing: 8) {
if let thinking, !thinking.isEmpty {
StatusPill(text: "think \(thinking)", tint: .secondary)
}
if let timeoutSeconds {
StatusPill(text: "\(timeoutSeconds)s", tint: .secondary)
}
if let thinking, !thinking.isEmpty { StatusPill(text: "think \(thinking)", tint: .secondary) }
if let timeoutSeconds { StatusPill(text: "\(timeoutSeconds)s", tint: .secondary) }
if job.supportsAnnounceDelivery {
let delivery = job.delivery
if let delivery {
@@ -236,9 +232,7 @@ extension CronSettings {
if let channel = delivery.channel, !channel.isEmpty {
StatusPill(text: channel, tint: .secondary)
}
if let to = delivery.to, !to.isEmpty {
StatusPill(text: to, tint: .secondary)
}
if let to = delivery.to, !to.isEmpty { StatusPill(text: to, tint: .secondary) }
} else {
StatusPill(text: "no delivery", tint: .secondary)
}
@@ -236,13 +236,9 @@ enum DebugActions {
static func killProcess(_ pid: Int) async -> Result<Void, DebugActionError> {
let primary = await ShellExecutor.run(command: ["kill", "-TERM", "\(pid)"], cwd: nil, env: nil, timeout: 2)
if primary.ok {
return .success(())
}
if primary.ok { return .success(()) }
let force = await ShellExecutor.run(command: ["kill", "-KILL", "\(pid)"], cwd: nil, env: nil, timeout: 2)
if force.ok {
return .success(())
}
if force.ok { return .success(()) }
let detail = force.message ?? primary.message ?? "kill failed"
return .failure(.message(detail))
}
@@ -318,9 +318,7 @@ struct DebugSettings: View {
HStack(spacing: 8) {
Text("Port diagnostics")
.font(.caption.weight(.semibold))
if self.portCheckInFlight {
ProgressView().controlSize(.small)
}
if self.portCheckInFlight { ProgressView().controlSize(.small) }
Spacer()
Button("Check gateway ports") {
Task { await self.runPortCheck() }
@@ -29,9 +29,7 @@ enum DeviceModelCatalog {
""
}
if title.isEmpty {
return nil
}
if title.isEmpty { return nil }
return DevicePresentation(title: title, symbol: symbol)
}
@@ -52,54 +50,26 @@ enum DeviceModelCatalog {
guard !modelIdentifier.isEmpty else { return nil }
let lower = modelIdentifier.lowercased()
if lower.hasPrefix("ipad") {
return "ipad"
}
if lower.hasPrefix("iphone") {
return "iphone"
}
if lower.hasPrefix("ipod") {
return "iphone"
}
if lower.hasPrefix("watch") {
return "applewatch"
}
if lower.hasPrefix("appletv") {
return "appletv"
}
if lower.hasPrefix("audio") || lower.hasPrefix("homepod") {
return "speaker"
}
if lower.hasPrefix("ipad") { return "ipad" }
if lower.hasPrefix("iphone") { return "iphone" }
if lower.hasPrefix("ipod") { return "iphone" }
if lower.hasPrefix("watch") { return "applewatch" }
if lower.hasPrefix("appletv") { return "appletv" }
if lower.hasPrefix("audio") || lower.hasPrefix("homepod") { return "speaker" }
if lower.hasPrefix("macbook") || lower.hasPrefix("macbookpro") || lower.hasPrefix("macbookair") {
return "laptopcomputer"
}
if lower.hasPrefix("macstudio") {
return "macstudio"
}
if lower.hasPrefix("macmini") {
return "macmini"
}
if lower.hasPrefix("imac") || lower.hasPrefix("macpro") {
return "desktopcomputer"
}
if lower.hasPrefix("macstudio") { return "macstudio" }
if lower.hasPrefix("macmini") { return "macmini" }
if lower.hasPrefix("imac") || lower.hasPrefix("macpro") { return "desktopcomputer" }
if lower.hasPrefix("mac"), let friendlyNameLower = friendlyName?.lowercased() {
if friendlyNameLower.contains("macbook") {
return "laptopcomputer"
}
if friendlyNameLower.contains("imac") {
return "desktopcomputer"
}
if friendlyNameLower.contains("mac mini") {
return "macmini"
}
if friendlyNameLower.contains("mac studio") {
return "macstudio"
}
if friendlyNameLower.contains("mac pro") {
return "desktopcomputer"
}
if friendlyNameLower.contains("macbook") { return "laptopcomputer" }
if friendlyNameLower.contains("imac") { return "desktopcomputer" }
if friendlyNameLower.contains("mac mini") { return "macmini" }
if friendlyNameLower.contains("mac studio") { return "macstudio" }
if friendlyNameLower.contains("mac pro") { return "desktopcomputer" }
}
return nil
@@ -107,9 +77,7 @@ enum DeviceModelCatalog {
private static func fallbackSymbol(for familyRaw: String, modelIdentifier: String) -> String? {
let family = familyRaw.trimmingCharacters(in: .whitespacesAndNewlines)
if family.isEmpty {
return nil
}
if family.isEmpty { return nil }
switch family.lowercased() {
case "ipad":
return "ipad"
@@ -96,9 +96,7 @@ actor DiagnosticsFileLog {
let size = attrs[.size] as? NSNumber
else { return }
if size.int64Value < self.maxBytes {
return
}
if size.int64Value < self.maxBytes { return }
let fm = FileManager()
@@ -2,21 +2,13 @@ import Foundation
enum DurationFormattingSupport {
static func conciseDuration(ms: Int) -> String {
if ms < 1000 {
return "\(ms)ms"
}
if ms < 1000 { return "\(ms)ms" }
let s = Double(ms) / 1000.0
if s < 60 {
return "\(Int(round(s)))s"
}
if s < 60 { return "\(Int(round(s)))s" }
let m = s / 60.0
if m < 60 {
return "\(Int(round(m)))m"
}
if m < 60 { return "\(Int(round(m)))m" }
let h = m / 60.0
if h < 48 {
return "\(Int(round(h)))h"
}
if h < 48 { return "\(Int(round(h)))h" }
let d = h / 24.0
return "\(Int(round(d)))d"
}
@@ -11,9 +11,7 @@ enum ExecAllowlistMatcher {
case let .valid(pattern):
if ExecApprovalHelpers.patternHasPathSelector(pattern) {
let target = resolvedPath ?? rawExecutable
if self.matches(pattern: pattern, target: target) {
return entry
}
if self.matches(pattern: pattern, target: target) { return entry }
} else if pattern != "*",
!ExecApprovalHelpers.patternHasPathSelector(rawExecutable),
self.matchesExecutableBasename(pattern: pattern, resolution: resolution)
+12 -36
View File
@@ -301,9 +301,7 @@ enum ExecApprovalsStore {
private static func isLegacyDefaultSocketPath(_ raw: String, legacyFileURL: URL) -> Bool {
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty {
return true
}
if trimmed.isEmpty { return true }
let expanded = self.expandPath(trimmed)
let legacySocket = legacyFileURL.deletingLastPathComponent()
.appendingPathComponent("exec-approvals.sock", isDirectory: false)
@@ -323,9 +321,7 @@ enum ExecApprovalsStore {
}
}
let parent = cursor.deletingLastPathComponent()
if parent.path == cursor.path {
return false
}
if parent.path == cursor.path { return false }
cursor = parent
}
}
@@ -349,9 +345,7 @@ enum ExecApprovalsStore {
}
var closed = false
defer {
if !closed {
close(fd)
}
if !closed { close(fd) }
}
do {
try data.withUnsafeBytes { rawBuffer in
@@ -411,9 +405,7 @@ enum ExecApprovalsStore {
let rawSocketPath = file.socket?.path?
.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if self.isLegacyDefaultSocketPath(rawSocketPath, legacyFileURL: legacyURL) {
if file.socket == nil {
file.socket = ExecApprovalsSocketConfig(path: nil, token: nil)
}
if file.socket == nil { file.socket = ExecApprovalsSocketConfig(path: nil, token: nil) }
file.socket?.path = self.socketPath()
}
let encoder = JSONEncoder()
@@ -423,13 +415,9 @@ enum ExecApprovalsStore {
try FileManager().createDirectory(
at: targetURL.deletingLastPathComponent(),
withIntermediateDirectories: true)
if FileManager().fileExists(atPath: targetURL.path) {
return .notNeeded
}
if FileManager().fileExists(atPath: targetURL.path) { return .notNeeded }
let created = try self.writeMigratedFileExclusively(migrated, to: targetURL)
if !created {
return .notNeeded
}
if !created { return .notNeeded }
try? FileManager().setAttributes(
[.posixPermissions: 0o600],
ofItemAtPath: targetURL.path)
@@ -598,9 +586,7 @@ enum ExecApprovalsStore {
let loadedHash = self.hashFile(loaded)
var file = self.normalizeIncoming(loaded)
if file.socket == nil {
file.socket = ExecApprovalsSocketConfig(path: nil, token: nil)
}
if file.socket == nil { file.socket = ExecApprovalsSocketConfig(path: nil, token: nil) }
let path = file.socket?.path?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if path.isEmpty {
file.socket?.path = self.socketPath()
@@ -609,9 +595,7 @@ enum ExecApprovalsStore {
if token.isEmpty {
file.socket?.token = self.generateToken()
}
if file.agents == nil {
file.agents = [:]
}
if file.agents == nil { file.agents = [:] }
if !existed || loadedHash != self.hashFile(file) {
self.saveFile(file)
}
@@ -715,9 +699,7 @@ enum ExecApprovalsStore {
var agents = file.agents ?? [:]
var entry = agents[key] ?? ExecApprovalsAgent()
var allowlist = entry.allowlist ?? []
if allowlist.contains(where: { $0.pattern == normalizedPattern }) {
return
}
if allowlist.contains(where: { $0.pattern == normalizedPattern }) { return }
allowlist.append(ExecAllowlistEntry(
pattern: normalizedPattern,
lastUsedAt: Date().timeIntervalSince1970 * 1000))
@@ -1020,12 +1002,8 @@ enum ExecApprovalHelpers {
allowlistMatch: ExecAllowlistEntry?,
skillAllow: Bool) -> Bool
{
if ask == .always {
return true
}
if ask == .onMiss, security == .allowlist, allowlistMatch == nil, !skillAllow {
return true
}
if ask == .always { return true }
if ask == .onMiss, security == .allowlist, allowlistMatch == nil, !skillAllow { return true }
return false
}
@@ -1053,9 +1031,7 @@ struct ExecEventPayload: Codable {
static func truncateOutput(_ raw: String, maxChars: Int = 20000) -> String? {
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return nil }
if trimmed.count <= maxChars {
return trimmed
}
if trimmed.count <= maxChars { return trimmed }
let suffix = trimmed.suffix(maxChars)
return "... (truncated) \(suffix)"
}
@@ -31,9 +31,7 @@ final class ExecApprovalsGatewayPrompter {
private func run() async {
let stream = await GatewayConnection.shared.subscribe(bufferingNewest: 200)
for await push in stream {
if Task.isCancelled {
return
}
if Task.isCancelled { return }
await self.handle(push: push)
}
}
@@ -199,9 +197,7 @@ final class ExecApprovalsGatewayPrompter {
private static func lastInputSeconds() -> Int? {
let anyEvent = CGEventType(rawValue: UInt32.max) ?? .null
let seconds = CGEventSource.secondsSinceLastEventType(.combinedSessionState, eventType: anyEvent)
if seconds.isNaN || seconds.isInfinite || seconds < 0 {
return nil
}
if seconds.isNaN || seconds.isInfinite || seconds < 0 { return nil }
return Int(seconds.rounded())
}
}
@@ -169,13 +169,9 @@ private func readLineFromHandle(_ handle: FileHandle, maxBytes: Int) throws -> S
var buffer = Data()
while buffer.count < maxBytes {
let chunk = try handle.read(upToCount: 4096) ?? Data()
if chunk.isEmpty {
break
}
if chunk.isEmpty { break }
buffer.append(chunk)
if buffer.contains(0x0A) {
break
}
if buffer.contains(0x0A) { break }
}
guard let newlineIndex = buffer.firstIndex(of: 0x0A) else {
guard !buffer.isEmpty else { return nil }
@@ -619,9 +615,7 @@ private enum ExecHostExecutor {
guard needsScreenRecording == true else { return nil }
let authorized = await PermissionManager
.status([.screenRecording])[.screenRecording] ?? false
if authorized {
return nil
}
if authorized { return nil }
return self.errorResponse(
code: "UNAVAILABLE",
message: "PERMISSION_MISSING: screenRecording",
@@ -734,15 +728,9 @@ enum ExecApprovalsSocketPathGuard {
}
let fileType = status.st_mode & mode_t(S_IFMT)
if fileType == mode_t(S_IFDIR) {
return .directory
}
if fileType == mode_t(S_IFSOCK) {
return .socket
}
if fileType == mode_t(S_IFLNK) {
return .symlink
}
if fileType == mode_t(S_IFDIR) { return .directory }
if fileType == mode_t(S_IFSOCK) { return .socket }
if fileType == mode_t(S_IFLNK) { return .symlink }
return .other
}
@@ -856,9 +844,7 @@ private final class ExecApprovalsSocketServer: @unchecked Sendable {
}
}
if client < 0 {
if errno == EINTR {
continue
}
if errno == EINTR { continue }
break
}
Task.detached { [weak self] in
@@ -332,9 +332,7 @@ struct ExecCommandResolution {
current.append(ch)
}
if escaped {
current.append("\\")
}
if escaped { current.append("\\") }
appendCurrent()
return tokens
}
@@ -443,9 +441,7 @@ struct ExecCommandResolution {
idx += 1
}
if escaped || inSingle || inDouble {
return nil
}
if escaped || inSingle || inDouble { return nil }
guard appendCurrent() else { return nil }
return segments
}
@@ -519,9 +515,7 @@ enum ExecCommandFormatter {
let trimmed = arg.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return "\"\"" }
let needsQuotes = trimmed.contains { $0.isWhitespace || $0 == "\"" }
if !needsQuotes {
return trimmed
}
if !needsQuotes { return trimmed }
let escaped = trimmed.replacingOccurrences(of: "\"", with: "\\\"")
return "\"\(escaped)\""
}.joined(separator: " ")
@@ -529,9 +523,7 @@ enum ExecCommandFormatter {
static func displayString(for argv: [String], rawCommand: String?) -> String {
let trimmed = rawCommand?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if !trimmed.isEmpty {
return trimmed
}
if !trimmed.isEmpty { return trimmed }
return self.displayString(for: argv)
}
}
@@ -165,9 +165,7 @@ enum ExecInlineCommandParser {
idx += 1
continue
}
if token == "--" {
break
}
if token == "--" { break }
let comparableToken = allowCombinedC ? token : token.lowercased()
if flags.contains(comparableToken) {
return Match(tokenIndex: idx, inlineCommand: nil)
@@ -190,12 +190,8 @@ enum ExecShellWrapperParser {
private static func extractPowerShellInlineCommand(_ command: [String]) -> String? {
for idx in 1..<command.count {
let token = command[idx].trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if token.isEmpty {
continue
}
if token == "--" {
break
}
if token.isEmpty { continue }
if token == "--" { break }
if self.powershellInlineFlags.contains(token) {
return ExecInlineCommandParser.extractInlineCommand(
command,
@@ -492,16 +492,12 @@ actor GatewayConnection {
}
if let deviceToken = lastSnapshot?.auth["deviceToken"]?.value as? String {
let trimmed = deviceToken.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
}
if !trimmed.isEmpty { return trimmed }
}
let identity = DeviceIdentityStore.loadOrCreate()
if let entry = DeviceAuthStore.loadToken(deviceId: identity.deviceId, role: "operator") {
let trimmed = entry.token.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
return trimmed
}
if !trimmed.isEmpty { return trimmed }
}
return nil
}
@@ -880,9 +876,7 @@ extension GatewayConnection {
func healthSnapshot(timeoutMs: Double? = nil) async throws -> HealthSnapshot {
let data = try await requestRaw(method: .health, timeoutMs: timeoutMs)
if let snap = decodeHealthSnapshot(from: data) {
return snap
}
if let snap = decodeHealthSnapshot(from: data) { return snap }
throw GatewayDecodingError(method: Method.health.rawValue, message: "failed to decode health snapshot")
}
@@ -925,15 +919,9 @@ extension GatewayConnection {
var params: [String: AnyCodable] = [
"skillKey": AnyCodable(skillKey),
]
if let enabled {
params["enabled"] = AnyCodable(enabled)
}
if let apiKey {
params["apiKey"] = AnyCodable(apiKey)
}
if let env, !env.isEmpty {
params["env"] = AnyCodable(env)
}
if let enabled { params["enabled"] = AnyCodable(enabled) }
if let apiKey { params["apiKey"] = AnyCodable(apiKey) }
if let env, !env.isEmpty { params["env"] = AnyCodable(env) }
return try await self.requestDecoded(method: .skillsUpdate, params: params)
}
@@ -952,12 +940,8 @@ extension GatewayConnection {
return OpenClawSessionsPreviewPayload(ts: 0, previews: [])
}
var params: [String: AnyCodable] = ["keys": AnyCodable(resolvedKeys)]
if let limit {
params["limit"] = AnyCodable(limit)
}
if let maxChars {
params["maxChars"] = AnyCodable(maxChars)
}
if let limit { params["limit"] = AnyCodable(limit) }
if let maxChars { params["maxChars"] = AnyCodable(maxChars) }
let timeout = timeoutMs.map { Double($0) }
return try await self.requestDecoded(
method: .sessionsPreview,
@@ -980,12 +964,8 @@ extension GatewayConnection {
if let agentID = agentID?.trimmingCharacters(in: .whitespacesAndNewlines), !agentID.isEmpty {
params["agentId"] = AnyCodable(agentID)
}
if let limit {
params["limit"] = AnyCodable(limit)
}
if let maxChars {
params["maxChars"] = AnyCodable(maxChars)
}
if let limit { params["limit"] = AnyCodable(limit) }
if let maxChars { params["maxChars"] = AnyCodable(maxChars) }
let timeout = timeoutMs.map { Double($0) }
if let route {
let data = try await request(
@@ -1070,9 +1050,7 @@ extension GatewayConnection {
func talkMode(enabled: Bool, phase: String? = nil) async {
var params: [String: AnyCodable] = ["enabled": AnyCodable(enabled)]
if let phase {
params["phase"] = AnyCodable(phase)
}
if let phase { params["phase"] = AnyCodable(phase) }
try? await self.requestVoid(method: .talkMode, params: params)
}
@@ -57,9 +57,7 @@ final class GatewayConnectivityCoordinator {
private static func hostLabel(for url: URL) -> String {
let host = url.host ?? url.absoluteString
if let port = url.port {
return "\(host):\(port)"
}
if let port = url.port { return "\(host):\(port)" }
return host
}
}
@@ -13,12 +13,8 @@ struct Semver: Comparable, CustomStringConvertible {
}
static func < (lhs: Semver, rhs: Semver) -> Bool {
if lhs.major != rhs.major {
return lhs.major < rhs.major
}
if lhs.minor != rhs.minor {
return lhs.minor < rhs.minor
}
if lhs.major != rhs.major { return lhs.major < rhs.major }
if lhs.minor != rhs.minor { return lhs.minor < rhs.minor }
return lhs.patch < rhs.patch
}
@@ -80,9 +76,7 @@ enum GatewayEnvironment {
static func gatewayPort() -> Int {
if let raw = ProcessInfo.processInfo.environment["OPENCLAW_GATEWAY_PORT"] {
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if let parsed = Int(trimmed), parsed > 0 {
return parsed
}
if let parsed = Int(trimmed), parsed > 0 { return parsed }
}
if let configPort = OpenClawConfigFile.gatewayPort(), configPort > 0 {
return configPort
@@ -24,9 +24,7 @@ enum GatewayLaunchAgentManager {
}
static func isLaunchAgentWriteDisabled() -> Bool {
if FileManager().fileExists(atPath: self.disableLaunchAgentMarkerURL.path) {
return true
}
if FileManager().fileExists(atPath: self.disableLaunchAgentMarkerURL.path) { return true }
return false
}
@@ -155,9 +153,7 @@ extension GatewayLaunchAgentManager {
quiet: Bool = false) async -> String?
{
let result = await self.runDaemonCommandResult(args, timeout: timeout, quiet: quiet)
if result.success {
return nil
}
if result.success { return nil }
return result.message ?? "Gateway daemon command failed"
}
@@ -206,9 +202,7 @@ extension GatewayLaunchAgentManager {
}
private static func withJsonFlag(_ args: [String]) -> [String] {
if args.contains("--json") {
return args
}
if args.contains("--json") { return args }
return args + ["--json"]
}
@@ -18,9 +18,7 @@ final class GatewayProcessManager {
case .stopped: return "Stopped"
case .starting: return "Starting…"
case let .running(details):
if let details, !details.isEmpty {
return "Running (\(details))"
}
if let details, !details.isEmpty { return "Running (\(details))" }
return "Running"
case let .attachedExisting(details):
if let details, !details.isEmpty {
@@ -151,9 +149,7 @@ final class GatewayProcessManager {
func refreshEnvironmentStatus(force: Bool = false) {
let now = Date()
if !force {
if self.environmentRefreshTask != nil {
return
}
if self.environmentRefreshTask != nil { return }
if let last = self.lastEnvironmentRefresh,
now.timeIntervalSince(last) < self.environmentRefreshMinInterval
{
@@ -297,9 +293,7 @@ final class GatewayProcessManager {
return true
}
let ns = error as NSError
if ns.domain == "Gateway", ns.code == 1008 {
return true
}
if ns.domain == "Gateway", ns.code == 1008 { return true }
let lower = ns.localizedDescription.lowercased()
return lower.contains("unauthorized") || lower.contains("auth")
}
@@ -342,9 +336,7 @@ final class GatewayProcessManager {
// Best-effort: wait for the gateway to accept connections.
let deadline = Date().addingTimeInterval(6)
while Date() < deadline {
if !self.desiredActive {
return
}
if !self.desiredActive { return }
do {
_ = try await self.connection.requestRaw(method: .health, timeoutMs: 1500)
let instance = await PortGuardian.shared.describe(port: port)
@@ -392,9 +384,7 @@ final class GatewayProcessManager {
func waitForGatewayReady(timeout: TimeInterval = 6) async -> Bool {
let deadline = Date().addingTimeInterval(timeout)
while Date() < deadline {
if !self.desiredActive {
return false
}
if !self.desiredActive { return false }
do {
_ = try await self.connection.requestRaw(method: .health, timeoutMs: 1500)
self.clearLastFailure()
@@ -426,9 +416,7 @@ final class GatewayProcessManager {
guard FileManager().fileExists(atPath: path) else { return "" }
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { return "" }
let text = String(data: data, encoding: .utf8) ?? ""
if text.count <= limit {
return text
}
if text.count <= limit { return text }
return String(text.suffix(limit))
}
}
@@ -13,9 +13,7 @@ enum GatewayPushSubscription {
}
for await push in stream {
if Task.isCancelled {
return
}
if Task.isCancelled { return }
await MainActor.run {
onPush(push)
}
@@ -248,9 +248,7 @@ enum GatewayRemoteConfig {
}
static func defaultPort(for url: URL) -> Int? {
if let port = url.port {
return port
}
if let port = url.port { return port }
let scheme = url.scheme?.lowercased() ?? ""
switch scheme {
case "wss":
+10 -30
View File
@@ -129,9 +129,7 @@ final class HealthStore {
}
} else {
self.lastError = "health output not JSON"
if onDemand {
self.snapshot = nil
}
if onDemand { self.snapshot = nil }
if previousError != self.lastError {
Self.logger.warning("health refresh failed: output not JSON")
}
@@ -139,9 +137,7 @@ final class HealthStore {
} catch {
let desc = error.localizedDescription
self.lastError = desc
if onDemand {
self.snapshot = nil
}
if onDemand { self.snapshot = nil }
if previousError != desc {
Self.logger.error("health refresh failed \(desc, privacy: .public)")
}
@@ -157,16 +153,12 @@ final class HealthStore {
private static func describeProbeFailure(_ probe: HealthSnapshot.ChannelSummary.Probe) -> String {
let elapsed = probe.elapsedMs.map { "\(Int($0))ms" }
if let error = probe.error, error.lowercased().contains("timeout") || probe.status == nil {
if let elapsed {
return "Health check timed out (\(elapsed))"
}
if let elapsed { return "Health check timed out (\(elapsed))" }
return "Health check timed out"
}
let code = probe.status.map { "status \($0)" } ?? "status unknown"
let reason = probe.error?.isEmpty == false ? probe.error! : "health probe failed"
if let elapsed {
return "\(reason) (\(code), \(elapsed))"
}
if let elapsed { return "\(reason) (\(code), \(elapsed))" }
return "\(reason) (\(code))"
}
@@ -193,9 +185,7 @@ final class HealthStore {
{
let order = snap.channelOrder ?? Array(snap.channels.keys)
for channelId in order {
if channelId == id {
continue
}
if channelId == id { continue }
guard let summary = snap.channels[channelId] else { continue }
if Self.isChannelHealthy(summary) {
return (id: channelId, summary: summary)
@@ -223,12 +213,8 @@ final class HealthStore {
}
var summaryLine: String {
if self.isRefreshing {
return "Health check running…"
}
if let error = self.lastError {
return "Health check failed: \(error)"
}
if self.isRefreshing { return "Health check running…" }
if let error = self.lastError { return "Health check failed: \(error)" }
guard let snap = self.snapshot else { return "Health check pending" }
guard let link = self.resolveLinkChannel(snap) else { return "Health check pending" }
if link.summary.linked != true {
@@ -291,16 +277,10 @@ final class HealthStore {
func msToAge(_ ms: Double) -> String {
let minutes = Int(round(ms / 60000))
if minutes < 1 {
return "just now"
}
if minutes < 60 {
return "\(minutes)m"
}
if minutes < 1 { return "just now" }
if minutes < 60 { return "\(minutes)m" }
let hours = Int(round(Double(minutes) / 60))
if hours < 48 {
return "\(hours)h"
}
if hours < 48 { return "\(hours)h" }
let days = Int(round(Double(hours) / 24))
return "\(days)d"
}
@@ -34,8 +34,6 @@ final class HeartbeatStore {
@MainActor
deinit {
if let observer {
NotificationCenter.default.removeObserver(observer)
}
if let observer { NotificationCenter.default.removeObserver(observer) }
}
}
@@ -37,23 +37,17 @@ enum HostEnvSanitizer {
]
private static func isBlocked(_ upperKey: String) -> Bool {
if self.blockedKeys.contains(upperKey) {
return true
}
if self.blockedKeys.contains(upperKey) { return true }
return self.blockedPrefixes.contains(where: { upperKey.hasPrefix($0) })
}
private static func isBlockedInherited(_ upperKey: String) -> Bool {
if self.blockedInheritedKeys.contains(upperKey) {
return true
}
if self.blockedInheritedKeys.contains(upperKey) { return true }
return self.blockedInheritedPrefixes.contains(where: { upperKey.hasPrefix($0) })
}
private static func isBlockedOverride(_ upperKey: String) -> Bool {
if self.blockedOverrideKeys.contains(upperKey) {
return true
}
if self.blockedOverrideKeys.contains(upperKey) { return true }
if upperKey.range(
of: self.cargoTargetExecutableOverridePattern,
options: .regularExpression) != nil
@@ -117,9 +111,7 @@ enum HostEnvSanitizer {
private static func sanitizeInheritedGitAllowProtocolValue(_ value: String) -> String {
let normalized = value.trimmingCharacters(in: .whitespacesAndNewlines)
if normalized.isEmpty {
return ""
}
if normalized.isEmpty { return "" }
let safeProtocols = normalized
.split(separator: ":", omittingEmptySubsequences: false)
.filter { self.gitDefaultAlwaysAllowedProtocols.contains(String($0)) }
@@ -180,9 +172,7 @@ enum HostEnvSanitizer {
}
continue
}
if self.isBlockedInherited(upper) {
continue
}
if self.isBlockedInherited(upper) { continue }
merged[key] = value
}
@@ -196,15 +186,9 @@ enum HostEnvSanitizer {
let upper = key.uppercased()
// PATH is part of the security boundary (command resolution + safe-bin checks). Never
// allow request-scoped PATH overrides from agents/gateways.
if upper == "PATH" {
continue
}
if self.isBlockedOverride(upper) {
continue
}
if self.isBlocked(upper) {
continue
}
if upper == "PATH" { continue }
if self.isBlockedOverride(upper) { continue }
if self.isBlocked(upper) { continue }
merged[key] = value
}
return merged
+6 -18
View File
@@ -113,9 +113,7 @@ final class HoverHUDController {
try? await Task.sleep(nanoseconds: 250_000_000)
await MainActor.run {
guard let self else { return }
if self.model.hoveringStatusItem || self.model.hoveringPanel {
return
}
if self.model.hoveringStatusItem || self.model.hoveringPanel { return }
self.dismiss(reason: "hoverExit")
}
}
@@ -141,9 +139,7 @@ final class HoverHUDController {
}
private func ensureWindow() {
if self.window != nil {
return
}
if self.window != nil { return }
let panel = OverlayPanelFactory.makePanel(
contentRect: NSRect(x: 0, y: 0, width: self.width, height: self.height),
level: .statusBar,
@@ -180,9 +176,7 @@ final class HoverHUDController {
}
private func installDismissMonitor() {
if ProcessInfo.processInfo.isRunningTests {
return
}
if ProcessInfo.processInfo.isRunningTests { return }
guard self.dismissMonitor == nil, let window else { return }
self.dismissMonitor = NSEvent.addGlobalMonitorForEvents(matching: [
.leftMouseDown,
@@ -207,19 +201,13 @@ private struct HoverHUDView: View {
private let activityStore = WorkActivityStore.shared
private var statusTitle: String {
if self.activityStore.iconState.isWorking {
return "Working"
}
if self.activityStore.iconState.isWorking { return "Working" }
return "Idle"
}
private var detail: String {
if let current = self.activityStore.current?.label, !current.isEmpty {
return current
}
if let last = self.activityStore.lastToolLabel, !last.isEmpty {
return last
}
if let current = self.activityStore.current?.label, !current.isEmpty { return current }
if let last = self.activityStore.lastToolLabel, !last.isEmpty { return last }
return "No recent activity"
}
@@ -84,9 +84,7 @@ struct InstancesSettings: View {
HStack(spacing: 8) {
Text(inst.host ?? "unknown host").font(.subheadline.bold())
self.presenceIndicator(inst)
if let ip = inst.ip {
Text("(") + Text(ip).monospaced() + Text(")")
}
if let ip = inst.ip { Text("(") + Text(ip).monospaced() + Text(")") }
}
HStack(spacing: 8) {
@@ -111,9 +109,7 @@ struct InstancesSettings: View {
self.label(icon: self.platformIcon(platform), text: prettyPlatform)
}
if let mode = inst.mode {
self.label(icon: "network", text: mode)
}
if let mode = inst.mode { self.label(icon: "network", text: mode) }
}
.layoutPriority(1)
@@ -179,12 +175,8 @@ struct InstancesSettings: View {
private func presenceStatus(for inst: InstanceInfo) -> (label: String, color: Color) {
let nowMs = Date().timeIntervalSince1970 * 1000
let ageSeconds = max(0, Int((nowMs - inst.ts) / 1000))
if ageSeconds <= 120 {
return ("Active", .green)
}
if ageSeconds <= 300 {
return ("Idle", .yellow)
}
if ageSeconds <= 120 { return ("Active", .green) }
if ageSeconds <= 300 { return ("Idle", .yellow) }
return ("Stale", .gray)
}
@@ -239,19 +231,13 @@ struct InstancesSettings: View {
}
private func shouldShowUpdateRow(_ inst: InstanceInfo) -> Bool {
if inst.lastInputSeconds != nil {
return true
}
if self.updateSummaryText(inst, isGateway: false) != nil {
return true
}
if inst.lastInputSeconds != nil { return true }
if self.updateSummaryText(inst, isGateway: false) != nil { return true }
return false
}
private func safeSystemSymbol(_ preferred: String, fallback: String) -> String {
if self.isSystemSymbolAvailable(preferred) {
return preferred
}
if self.isSystemSymbolAvailable(preferred) { return preferred }
return fallback
}
@@ -97,9 +97,7 @@ final class InstancesStore {
}
func refresh() async {
if self.isLoading {
return
}
if self.isLoading { return }
self.statusMessage = nil
self.isLoading = true
defer { self.isLoading = false }
@@ -171,9 +169,7 @@ final class InstancesStore {
private func snippet(_ data: Data?, limit: Int = 256) -> String {
guard let data else { return "<none>" }
if data.isEmpty {
return "<empty>"
}
if data.isEmpty { return "<empty>" }
let prefix = data.prefix(limit)
if let asString = String(data: prefix, encoding: .utf8) {
return asString.replacingOccurrences(of: "\n", with: " ")
@@ -186,14 +182,10 @@ final class InstancesStore {
let data = try await ControlChannel.shared.health(timeout: 8)
guard let snap = decodeHealthSnapshot(from: data) else { return }
let linkId = snap.channelOrder?.first(where: {
if let summary = snap.channels[$0] {
return summary.linked != nil
}
if let summary = snap.channels[$0] { return summary.linked != nil }
return false
}) ?? snap.channels.keys.first(where: {
if let summary = snap.channels[$0] {
return summary.linked != nil
}
if let summary = snap.channels[$0] { return summary.linked != nil }
return false
})
let linked = linkId.flatMap { snap.channels[$0]?.linked } ?? false
@@ -271,19 +263,13 @@ final class InstancesStore {
for inst in instances {
guard let reason = inst.reason?.trimmingCharacters(in: .whitespacesAndNewlines) else { continue }
guard reason == "node-connected" else { continue }
if let mode = inst.mode?.lowercased(), mode == "local" {
continue
}
if let mode = inst.mode?.lowercased(), mode == "local" { continue }
let previous = self.lastPresenceById[inst.id]
if previous?.reason == "node-connected", previous?.ts == inst.ts {
continue
}
if previous?.reason == "node-connected", previous?.ts == inst.ts { continue }
let lastNotified = self.lastLoginNotifiedAtMs[inst.id] ?? 0
if inst.ts <= lastNotified {
continue
}
if inst.ts <= lastNotified { continue }
self.lastLoginNotifiedAtMs[inst.id] = inst.ts
let name = inst.host?.trimmingCharacters(in: .whitespacesAndNewlines)

Some files were not shown because too many files have changed in this diff Show More