style: fix swiftlint warnings

This commit is contained in:
Peter Steinberger
2026-01-02 00:17:49 +01:00
parent 38d8a669b4
commit 8a2168ecf6
12 changed files with 182 additions and 112 deletions

View File

@@ -184,7 +184,11 @@ enum CommandResolver {
static func hasAnyClawdisInvoker(searchPaths: [String]? = nil) -> Bool { static func hasAnyClawdisInvoker(searchPaths: [String]? = nil) -> Bool {
if self.clawdisExecutable(searchPaths: searchPaths) != nil { return true } if self.clawdisExecutable(searchPaths: searchPaths) != nil { return true }
if self.findExecutable(named: "pnpm", 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 { return true } if self.findExecutable(named: "node", searchPaths: searchPaths) != nil,
self.nodeCliPath() != nil
{
return true
}
return false return false
} }
@@ -244,7 +248,11 @@ enum CommandResolver {
defaults: UserDefaults = .standard, defaults: UserDefaults = .standard,
searchPaths: [String]? = nil) -> [String] searchPaths: [String]? = nil) -> [String]
{ {
self.clawdisNodeCommand(subcommand: subcommand, extraArgs: extraArgs, defaults: defaults, searchPaths: searchPaths) self.clawdisNodeCommand(
subcommand: subcommand,
extraArgs: extraArgs,
defaults: defaults,
searchPaths: searchPaths)
} }
// MARK: - SSH helpers // MARK: - SSH helpers

View File

@@ -332,7 +332,9 @@ struct ConfigSettings: View {
Text("Using ELEVENLABS_API_KEY from the environment.") Text("Using ELEVENLABS_API_KEY from the environment.")
.font(.footnote) .font(.footnote)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} else if self.gatewayApiKeyFound && self.talkApiKey.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { } else if self.gatewayApiKeyFound
&& self.talkApiKey.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
{
Text("Using API key from the gateway profile.") Text("Using API key from the gateway profile.")
.font(.footnote) .font(.footnote)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)

View File

@@ -114,6 +114,7 @@ struct ClawdisOSLogHandler: LogHandler {
set { self.metadata[key] = newValue } set { self.metadata[key] = newValue }
} }
// swiftlint:disable:next function_parameter_count
func log( func log(
level: Logger.Level, level: Logger.Level,
message: Logger.Message, message: Logger.Message,
@@ -188,6 +189,7 @@ struct ClawdisFileLogHandler: LogHandler {
set { self.metadata[key] = newValue } set { self.metadata[key] = newValue }
} }
// swiftlint:disable:next function_parameter_count
func log( func log(
level: Logger.Level, level: Logger.Level,
message: Logger.Message, message: Logger.Message,

View File

@@ -207,17 +207,25 @@ final class MenuSessionsInjector: NSObject, NSMenuDelegate {
} }
if let error = self.nodesStore.lastError?.nonEmpty { if let error = self.nodesStore.lastError?.nonEmpty {
menu.insertItem(self.makeMessageItem(text: "Error: \(error)", symbolName: "exclamationmark.triangle", menu.insertItem(
width: width), at: cursor) self.makeMessageItem(
text: "Error: \(error)",
symbolName: "exclamationmark.triangle",
width: width),
at: cursor)
cursor += 1 cursor += 1
} else if let status = self.nodesStore.statusMessage?.nonEmpty { } else if let status = self.nodesStore.statusMessage?.nonEmpty {
menu.insertItem(self.makeMessageItem(text: status, symbolName: "info.circle", width: width), at: cursor) menu.insertItem(
self.makeMessageItem(text: status, symbolName: "info.circle", width: width),
at: cursor)
cursor += 1 cursor += 1
} }
if entries.isEmpty { if entries.isEmpty {
let title = self.nodesStore.isLoading ? "Loading devices..." : "No devices yet" let title = self.nodesStore.isLoading ? "Loading devices..." : "No devices yet"
menu.insertItem(self.makeMessageItem(text: title, symbolName: "circle.dashed", width: width), at: cursor) menu.insertItem(
self.makeMessageItem(text: title, symbolName: "circle.dashed", width: width),
at: cursor)
cursor += 1 cursor += 1
} else { } else {
for entry in entries.prefix(8) { for entry in entries.prefix(8) {

View File

@@ -17,29 +17,35 @@ actor MacNodeBridgePairingClient {
let connection = NWConnection(to: endpoint, using: .tcp) let connection = NWConnection(to: endpoint, using: .tcp)
let queue = DispatchQueue(label: "com.steipete.clawdis.macos.bridge-client") let queue = DispatchQueue(label: "com.steipete.clawdis.macos.bridge-client")
defer { connection.cancel() } defer { connection.cancel() }
try await AsyncTimeout.withTimeout(seconds: 8, onTimeout: { try await AsyncTimeout.withTimeout(
NSError(domain: "Bridge", code: 0, userInfo: [ seconds: 8,
NSLocalizedDescriptionKey: "connect timed out", onTimeout: {
]) NSError(domain: "Bridge", code: 0, userInfo: [
}) { NSLocalizedDescriptionKey: "connect timed out",
try await self.startAndWaitForReady(connection, queue: queue) ])
} },
operation: {
try await self.startAndWaitForReady(connection, queue: queue)
})
onStatus?("Authenticating…") onStatus?("Authenticating…")
try await self.send(hello, over: connection) try await self.send(hello, over: connection)
let first = try await AsyncTimeout.withTimeout(seconds: 10, onTimeout: { let first = try await AsyncTimeout.withTimeout(
NSError(domain: "Bridge", code: 0, userInfo: [ seconds: 10,
NSLocalizedDescriptionKey: "hello timed out", onTimeout: {
]) NSError(domain: "Bridge", code: 0, userInfo: [
}) { () -> ReceivedFrame in NSLocalizedDescriptionKey: "hello timed out",
guard let frame = try await self.receiveFrame(over: connection) else {
throw NSError(domain: "Bridge", code: 0, userInfo: [
NSLocalizedDescriptionKey: "Bridge closed connection during hello",
]) ])
} },
return frame operation: { () -> ReceivedFrame in
} guard let frame = try await self.receiveFrame(over: connection) else {
throw NSError(domain: "Bridge", code: 0, userInfo: [
NSLocalizedDescriptionKey: "Bridge closed connection during hello",
])
}
return frame
})
switch first.base.type { switch first.base.type {
case "hello-ok": case "hello-ok":
@@ -68,28 +74,31 @@ actor MacNodeBridgePairingClient {
over: connection) over: connection)
onStatus?("Waiting for approval…") onStatus?("Waiting for approval…")
let ok = try await AsyncTimeout.withTimeout(seconds: 60, onTimeout: { let ok = try await AsyncTimeout.withTimeout(
NSError(domain: "Bridge", code: 0, userInfo: [ seconds: 60,
NSLocalizedDescriptionKey: "pairing approval timed out", onTimeout: {
]) NSError(domain: "Bridge", code: 0, userInfo: [
}) { NSLocalizedDescriptionKey: "pairing approval timed out",
while let next = try await self.receiveFrame(over: connection) { ])
switch next.base.type { },
case "pair-ok": operation: {
return try self.decoder.decode(BridgePairOk.self, from: next.data) while let next = try await self.receiveFrame(over: connection) {
case "error": switch next.base.type {
let e = try self.decoder.decode(BridgeErrorFrame.self, from: next.data) case "pair-ok":
throw NSError(domain: "Bridge", code: 2, userInfo: [ return try self.decoder.decode(BridgePairOk.self, from: next.data)
NSLocalizedDescriptionKey: "\(e.code): \(e.message)", case "error":
]) let e = try self.decoder.decode(BridgeErrorFrame.self, from: next.data)
default: throw NSError(domain: "Bridge", code: 2, userInfo: [
continue NSLocalizedDescriptionKey: "\(e.code): \(e.message)",
])
default:
continue
}
} }
} throw NSError(domain: "Bridge", code: 3, userInfo: [
throw NSError(domain: "Bridge", code: 3, userInfo: [ NSLocalizedDescriptionKey: "Pairing failed: bridge closed connection",
NSLocalizedDescriptionKey: "Pairing failed: bridge closed connection", ])
]) })
}
return ok.token return ok.token

View File

@@ -48,17 +48,23 @@ actor MacNodeBridgeSession {
try await Self.waitForReady(stateStream, timeoutSeconds: 6) try await Self.waitForReady(stateStream, timeoutSeconds: 6)
try await AsyncTimeout.withTimeout(seconds: 6, onTimeout: { try await AsyncTimeout.withTimeout(
TimeoutError(message: "operation timed out") seconds: 6,
}) { onTimeout: {
try await self.send(hello) TimeoutError(message: "operation timed out")
} },
operation: {
try await self.send(hello)
})
guard let line = try await AsyncTimeout.withTimeout(seconds: 6, onTimeout: { guard let line = try await AsyncTimeout.withTimeout(
TimeoutError(message: "operation timed out") seconds: 6,
}, operation: { onTimeout: {
try await self.receiveLine() TimeoutError(message: "operation timed out")
}), },
operation: {
try await self.receiveLine()
}),
let data = line.data(using: .utf8), let data = line.data(using: .utf8),
let base = try? self.decoder.decode(BridgeBaseFrame.self, from: data) let base = try? self.decoder.decode(BridgeBaseFrame.self, from: data)
else { else {
@@ -294,27 +300,30 @@ actor MacNodeBridgeSession {
_ stream: AsyncStream<NWConnection.State>, _ stream: AsyncStream<NWConnection.State>,
timeoutSeconds: Double) async throws timeoutSeconds: Double) async throws
{ {
try await AsyncTimeout.withTimeout(seconds: timeoutSeconds, onTimeout: { try await AsyncTimeout.withTimeout(
TimeoutError(message: "operation timed out") seconds: timeoutSeconds,
}) { onTimeout: {
for await state in stream { TimeoutError(message: "operation timed out")
switch state { },
case .ready: operation: {
return for await state in stream {
case let .failed(err): switch state {
throw err case .ready:
case .cancelled: return
throw NSError(domain: "Bridge", code: 20, userInfo: [ case let .failed(err):
NSLocalizedDescriptionKey: "Connection cancelled", throw err
]) case .cancelled:
default: throw NSError(domain: "Bridge", code: 20, userInfo: [
continue NSLocalizedDescriptionKey: "Connection cancelled",
])
default:
continue
}
} }
} throw NSError(domain: "Bridge", code: 21, userInfo: [
throw NSError(domain: "Bridge", code: 21, userInfo: [ NSLocalizedDescriptionKey: "Connection closed",
NSLocalizedDescriptionKey: "Connection closed", ])
]) })
}
} }

View File

@@ -228,29 +228,32 @@ final class MacNodeModeCoordinator {
_ stream: AsyncStream<NWConnection.State>, _ stream: AsyncStream<NWConnection.State>,
timeoutSeconds: Double) async throws timeoutSeconds: Double) async throws
{ {
try await AsyncTimeout.withTimeout(seconds: timeoutSeconds, onTimeout: { try await AsyncTimeout.withTimeout(
NSError(domain: "Bridge", code: 22, userInfo: [ seconds: timeoutSeconds,
NSLocalizedDescriptionKey: "operation timed out", onTimeout: {
]) NSError(domain: "Bridge", code: 22, userInfo: [
}) { NSLocalizedDescriptionKey: "operation timed out",
for await state in stream { ])
switch state { },
case .ready: operation: {
return for await state in stream {
case let .failed(err): switch state {
throw err case .ready:
case .cancelled: return
throw NSError(domain: "Bridge", code: 20, userInfo: [ case let .failed(err):
NSLocalizedDescriptionKey: "Connection cancelled", throw err
]) case .cancelled:
default: throw NSError(domain: "Bridge", code: 20, userInfo: [
continue NSLocalizedDescriptionKey: "Connection cancelled",
])
default:
continue
}
} }
} throw NSError(domain: "Bridge", code: 21, userInfo: [
throw NSError(domain: "Bridge", code: 21, userInfo: [ NSLocalizedDescriptionKey: "Connection closed",
NSLocalizedDescriptionKey: "Connection closed", ])
]) })
}
} }
private func resolveBridgeEndpoint(timeoutSeconds: Double) async -> NWEndpoint? { private func resolveBridgeEndpoint(timeoutSeconds: Double) async -> NWEndpoint? {

View File

@@ -46,7 +46,8 @@ struct NotificationManager {
if Self.hasTimeSensitiveEntitlement { if Self.hasTimeSensitiveEntitlement {
content.interruptionLevel = .timeSensitive content.interruptionLevel = .timeSensitive
} else { } else {
self.logger.debug("time-sensitive notification requested without entitlement; falling back to active") self.logger.debug(
"time-sensitive notification requested without entitlement; falling back to active")
content.interruptionLevel = .active content.interruptionLevel = .active
} }
} }

View File

@@ -746,7 +746,9 @@ extension OnboardingView {
Text("Couldnt load skills from the Gateway.") Text("Couldnt load skills from the Gateway.")
.font(.footnote.weight(.semibold)) .font(.footnote.weight(.semibold))
.foregroundStyle(.orange) .foregroundStyle(.orange)
Text("Make sure the Gateway is running and connected, then hit Refresh (or open Settings → Skills).") Text(
"Make sure the Gateway is running and connected, " +
"then hit Refresh (or open Settings → Skills).")
.font(.footnote) .font(.footnote)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)

View File

@@ -76,7 +76,10 @@ final class PeekabooBridgeHostCoordinator {
} }
var infoCF: CFDictionary? var infoCF: CFDictionary?
guard SecCodeCopySigningInformation(staticCode, SecCSFlags(rawValue: kSecCSSigningInformation), &infoCF) == errSecSuccess, guard SecCodeCopySigningInformation(
staticCode,
SecCSFlags(rawValue: kSecCSSigningInformation),
&infoCF) == errSecSuccess,
let info = infoCF as? [String: Any] let info = infoCF as? [String: Any]
else { else {
return nil return nil

View File

@@ -24,7 +24,11 @@ final class TalkModeController {
self.phase = phase self.phase = phase
TalkOverlayController.shared.updatePhase(phase) TalkOverlayController.shared.updatePhase(phase)
let effectivePhase = self.isPaused ? "paused" : phase.rawValue let effectivePhase = self.isPaused ? "paused" : phase.rawValue
Task { await GatewayConnection.shared.talkMode(enabled: AppStateStore.shared.talkEnabled, phase: effectivePhase) } Task {
await GatewayConnection.shared.talkMode(
enabled: AppStateStore.shared.talkEnabled,
phase: effectivePhase)
}
} }
func updateLevel(_ level: Double) { func updateLevel(_ level: Double) {
@@ -37,7 +41,11 @@ final class TalkModeController {
self.isPaused = paused self.isPaused = paused
TalkOverlayController.shared.updatePaused(paused) TalkOverlayController.shared.updatePaused(paused)
let effectivePhase = paused ? "paused" : self.phase.rawValue let effectivePhase = paused ? "paused" : self.phase.rawValue
Task { await GatewayConnection.shared.talkMode(enabled: AppStateStore.shared.talkEnabled, phase: effectivePhase) } Task {
await GatewayConnection.shared.talkMode(
enabled: AppStateStore.shared.talkEnabled,
phase: effectivePhase)
}
Task { await TalkModeRuntime.shared.setPaused(paused) } Task { await TalkModeRuntime.shared.setPaused(paused) }
} }

View File

@@ -337,7 +337,9 @@ actor TalkModeRuntime {
let runId = UUID().uuidString let runId = UUID().uuidString
let startedAt = Date().timeIntervalSince1970 let startedAt = Date().timeIntervalSince1970
self.logger.info( self.logger.info(
"talk send start runId=\(runId, privacy: .public) session=\(sessionKey, privacy: .public) chars=\(prompt.count, privacy: .public)") "talk send start runId=\(runId, privacy: .public) " +
"session=\(sessionKey, privacy: .public) " +
"chars=\(prompt.count, privacy: .public)")
do { do {
let response = try await GatewayConnection.shared.chatSend( let response = try await GatewayConnection.shared.chatSend(
@@ -348,7 +350,8 @@ actor TalkModeRuntime {
attachments: []) attachments: [])
guard self.isCurrent(gen) else { return } guard self.isCurrent(gen) else { return }
self.logger.info( self.logger.info(
"talk chat.send ok runId=\(response.runId, privacy: .public) session=\(sessionKey, privacy: .public)") "talk chat.send ok runId=\(response.runId, privacy: .public) " +
"session=\(sessionKey, privacy: .public)")
guard let assistantText = await self.waitForAssistantText( guard let assistantText = await self.waitForAssistantText(
sessionKey: sessionKey, sessionKey: sessionKey,
@@ -433,6 +436,7 @@ actor TalkModeRuntime {
} }
} }
// swiftlint:disable:next cyclomatic_complexity function_body_length
private func playAssistant(text: String) async { private func playAssistant(text: String) async {
let gen = self.lifecycleGeneration let gen = self.lifecycleGeneration
let parse = TalkDirectiveParser.parse(text) let parse = TalkDirectiveParser.parse(text)
@@ -443,7 +447,9 @@ actor TalkModeRuntime {
if !parse.unknownKeys.isEmpty { if !parse.unknownKeys.isEmpty {
self.logger self.logger
.warning("talk directive ignored keys: \(parse.unknownKeys.joined(separator: ","), privacy: .public)") .warning(
"talk directive ignored keys: " +
"\(parse.unknownKeys.joined(separator: ","), privacy: .public)")
} }
let requestedVoice = directive?.voiceId?.trimmingCharacters(in: .whitespacesAndNewlines) let requestedVoice = directive?.voiceId?.trimmingCharacters(in: .whitespacesAndNewlines)
@@ -490,7 +496,9 @@ actor TalkModeRuntime {
self.ttsLogger.warning("talk missing voiceId; falling back to system voice") self.ttsLogger.warning("talk missing voiceId; falling back to system voice")
} else if let voiceId { } else if let voiceId {
self.ttsLogger self.ttsLogger
.info("talk TTS request voiceId=\(voiceId, privacy: .public) chars=\(cleaned.count, privacy: .public)") .info(
"talk TTS request voiceId=\(voiceId, privacy: .public) " +
"chars=\(cleaned.count, privacy: .public)")
} }
self.lastSpokenText = cleaned self.lastSpokenText = cleaned
@@ -503,7 +511,8 @@ actor TalkModeRuntime {
if outputFormat == nil, !desiredOutputFormat.isEmpty { if outputFormat == nil, !desiredOutputFormat.isEmpty {
self.logger self.logger
.warning( .warning(
"talk output_format unsupported for local playback: \(desiredOutputFormat, privacy: .public)") "talk output_format unsupported for local playback: " +
"\(desiredOutputFormat, privacy: .public)")
} }
let modelId = directive?.modelId ?? self.currentModelId ?? self.defaultModelId let modelId = directive?.modelId ?? self.currentModelId ?? self.defaultModelId
@@ -558,7 +567,8 @@ actor TalkModeRuntime {
} }
self.ttsLogger self.ttsLogger
.info( .info(
"talk audio result finished=\(result.finished, privacy: .public) interruptedAt=\(String(describing: result.interruptedAt), privacy: .public)") "talk audio result finished=\(result.finished, privacy: .public) " +
"interruptedAt=\(String(describing: result.interruptedAt), privacy: .public)")
if !result.finished, result.interruptedAt == nil { if !result.finished, result.interruptedAt == nil {
throw NSError(domain: "StreamingAudioPlayer", code: 1, userInfo: [ throw NSError(domain: "StreamingAudioPlayer", code: 1, userInfo: [
NSLocalizedDescriptionKey: "audio playback failed", NSLocalizedDescriptionKey: "audio playback failed",
@@ -583,7 +593,9 @@ actor TalkModeRuntime {
} }
} catch { } catch {
self.ttsLogger self.ttsLogger
.error("talk TTS failed: \(error.localizedDescription, privacy: .public); falling back to system voice") .error(
"talk TTS failed: \(error.localizedDescription, privacy: .public); " +
"falling back to system voice")
do { do {
if self.interruptOnSpeech { if self.interruptOnSpeech {
await self.startRecognition() await self.startRecognition()
@@ -717,7 +729,10 @@ actor TalkModeRuntime {
let modelLabel = (cfg.modelId?.isEmpty == false) ? cfg.modelId! : "none" let modelLabel = (cfg.modelId?.isEmpty == false) ? cfg.modelId! : "none"
self.logger self.logger
.info( .info(
"talk config voiceId=\(voiceLabel, privacy: .public) modelId=\(modelLabel, privacy: .public) apiKey=\(hasApiKey, privacy: .public) interrupt=\(cfg.interruptOnSpeech, privacy: .public)") "talk config voiceId=\(voiceLabel, privacy: .public) " +
"modelId=\(modelLabel, privacy: .public) " +
"apiKey=\(hasApiKey, privacy: .public) " +
"interrupt=\(cfg.interruptOnSpeech, privacy: .public)")
} }
private struct TalkRuntimeConfig { private struct TalkRuntimeConfig {