style: fix swiftlint warnings
This commit is contained in:
@@ -184,7 +184,11 @@ enum CommandResolver {
|
||||
static func hasAnyClawdisInvoker(searchPaths: [String]? = nil) -> Bool {
|
||||
if self.clawdisExecutable(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
|
||||
}
|
||||
|
||||
@@ -244,7 +248,11 @@ enum CommandResolver {
|
||||
defaults: UserDefaults = .standard,
|
||||
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
|
||||
|
||||
@@ -332,7 +332,9 @@ struct ConfigSettings: View {
|
||||
Text("Using ELEVENLABS_API_KEY from the environment.")
|
||||
.font(.footnote)
|
||||
.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.")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
@@ -114,6 +114,7 @@ struct ClawdisOSLogHandler: LogHandler {
|
||||
set { self.metadata[key] = newValue }
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func log(
|
||||
level: Logger.Level,
|
||||
message: Logger.Message,
|
||||
@@ -188,6 +189,7 @@ struct ClawdisFileLogHandler: LogHandler {
|
||||
set { self.metadata[key] = newValue }
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func log(
|
||||
level: Logger.Level,
|
||||
message: Logger.Message,
|
||||
|
||||
@@ -207,17 +207,25 @@ final class MenuSessionsInjector: NSObject, NSMenuDelegate {
|
||||
}
|
||||
|
||||
if let error = self.nodesStore.lastError?.nonEmpty {
|
||||
menu.insertItem(self.makeMessageItem(text: "Error: \(error)", symbolName: "exclamationmark.triangle",
|
||||
width: width), at: cursor)
|
||||
menu.insertItem(
|
||||
self.makeMessageItem(
|
||||
text: "Error: \(error)",
|
||||
symbolName: "exclamationmark.triangle",
|
||||
width: width),
|
||||
at: cursor)
|
||||
cursor += 1
|
||||
} 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
|
||||
}
|
||||
|
||||
if entries.isEmpty {
|
||||
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
|
||||
} else {
|
||||
for entry in entries.prefix(8) {
|
||||
|
||||
@@ -17,29 +17,35 @@ actor MacNodeBridgePairingClient {
|
||||
let connection = NWConnection(to: endpoint, using: .tcp)
|
||||
let queue = DispatchQueue(label: "com.steipete.clawdis.macos.bridge-client")
|
||||
defer { connection.cancel() }
|
||||
try await AsyncTimeout.withTimeout(seconds: 8, onTimeout: {
|
||||
NSError(domain: "Bridge", code: 0, userInfo: [
|
||||
NSLocalizedDescriptionKey: "connect timed out",
|
||||
])
|
||||
}) {
|
||||
try await self.startAndWaitForReady(connection, queue: queue)
|
||||
}
|
||||
try await AsyncTimeout.withTimeout(
|
||||
seconds: 8,
|
||||
onTimeout: {
|
||||
NSError(domain: "Bridge", code: 0, userInfo: [
|
||||
NSLocalizedDescriptionKey: "connect timed out",
|
||||
])
|
||||
},
|
||||
operation: {
|
||||
try await self.startAndWaitForReady(connection, queue: queue)
|
||||
})
|
||||
|
||||
onStatus?("Authenticating…")
|
||||
try await self.send(hello, over: connection)
|
||||
|
||||
let first = try await AsyncTimeout.withTimeout(seconds: 10, onTimeout: {
|
||||
NSError(domain: "Bridge", code: 0, userInfo: [
|
||||
NSLocalizedDescriptionKey: "hello timed out",
|
||||
])
|
||||
}) { () -> 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",
|
||||
let first = try await AsyncTimeout.withTimeout(
|
||||
seconds: 10,
|
||||
onTimeout: {
|
||||
NSError(domain: "Bridge", code: 0, userInfo: [
|
||||
NSLocalizedDescriptionKey: "hello timed out",
|
||||
])
|
||||
}
|
||||
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 {
|
||||
case "hello-ok":
|
||||
@@ -68,28 +74,31 @@ actor MacNodeBridgePairingClient {
|
||||
over: connection)
|
||||
|
||||
onStatus?("Waiting for approval…")
|
||||
let ok = try await AsyncTimeout.withTimeout(seconds: 60, 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":
|
||||
return try self.decoder.decode(BridgePairOk.self, from: next.data)
|
||||
case "error":
|
||||
let e = try self.decoder.decode(BridgeErrorFrame.self, from: next.data)
|
||||
throw NSError(domain: "Bridge", code: 2, userInfo: [
|
||||
NSLocalizedDescriptionKey: "\(e.code): \(e.message)",
|
||||
])
|
||||
default:
|
||||
continue
|
||||
let ok = try await AsyncTimeout.withTimeout(
|
||||
seconds: 60,
|
||||
onTimeout: {
|
||||
NSError(domain: "Bridge", code: 0, userInfo: [
|
||||
NSLocalizedDescriptionKey: "pairing approval timed out",
|
||||
])
|
||||
},
|
||||
operation: {
|
||||
while let next = try await self.receiveFrame(over: connection) {
|
||||
switch next.base.type {
|
||||
case "pair-ok":
|
||||
return try self.decoder.decode(BridgePairOk.self, from: next.data)
|
||||
case "error":
|
||||
let e = try self.decoder.decode(BridgeErrorFrame.self, from: next.data)
|
||||
throw NSError(domain: "Bridge", code: 2, userInfo: [
|
||||
NSLocalizedDescriptionKey: "\(e.code): \(e.message)",
|
||||
])
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
throw NSError(domain: "Bridge", code: 3, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Pairing failed: bridge closed connection",
|
||||
])
|
||||
}
|
||||
throw NSError(domain: "Bridge", code: 3, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Pairing failed: bridge closed connection",
|
||||
])
|
||||
})
|
||||
|
||||
return ok.token
|
||||
|
||||
|
||||
@@ -48,17 +48,23 @@ actor MacNodeBridgeSession {
|
||||
|
||||
try await Self.waitForReady(stateStream, timeoutSeconds: 6)
|
||||
|
||||
try await AsyncTimeout.withTimeout(seconds: 6, onTimeout: {
|
||||
TimeoutError(message: "operation timed out")
|
||||
}) {
|
||||
try await self.send(hello)
|
||||
}
|
||||
try await AsyncTimeout.withTimeout(
|
||||
seconds: 6,
|
||||
onTimeout: {
|
||||
TimeoutError(message: "operation timed out")
|
||||
},
|
||||
operation: {
|
||||
try await self.send(hello)
|
||||
})
|
||||
|
||||
guard let line = try await AsyncTimeout.withTimeout(seconds: 6, onTimeout: {
|
||||
TimeoutError(message: "operation timed out")
|
||||
}, operation: {
|
||||
try await self.receiveLine()
|
||||
}),
|
||||
guard let line = try await AsyncTimeout.withTimeout(
|
||||
seconds: 6,
|
||||
onTimeout: {
|
||||
TimeoutError(message: "operation timed out")
|
||||
},
|
||||
operation: {
|
||||
try await self.receiveLine()
|
||||
}),
|
||||
let data = line.data(using: .utf8),
|
||||
let base = try? self.decoder.decode(BridgeBaseFrame.self, from: data)
|
||||
else {
|
||||
@@ -294,28 +300,31 @@ actor MacNodeBridgeSession {
|
||||
_ stream: AsyncStream<NWConnection.State>,
|
||||
timeoutSeconds: Double) async throws
|
||||
{
|
||||
try await AsyncTimeout.withTimeout(seconds: timeoutSeconds, onTimeout: {
|
||||
TimeoutError(message: "operation timed out")
|
||||
}) {
|
||||
for await state in stream {
|
||||
switch state {
|
||||
case .ready:
|
||||
return
|
||||
case let .failed(err):
|
||||
throw err
|
||||
case .cancelled:
|
||||
throw NSError(domain: "Bridge", code: 20, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection cancelled",
|
||||
])
|
||||
default:
|
||||
continue
|
||||
try await AsyncTimeout.withTimeout(
|
||||
seconds: timeoutSeconds,
|
||||
onTimeout: {
|
||||
TimeoutError(message: "operation timed out")
|
||||
},
|
||||
operation: {
|
||||
for await state in stream {
|
||||
switch state {
|
||||
case .ready:
|
||||
return
|
||||
case let .failed(err):
|
||||
throw err
|
||||
case .cancelled:
|
||||
throw NSError(domain: "Bridge", code: 20, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection cancelled",
|
||||
])
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
throw NSError(domain: "Bridge", code: 21, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection closed",
|
||||
])
|
||||
}
|
||||
throw NSError(domain: "Bridge", code: 21, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection closed",
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -228,29 +228,32 @@ final class MacNodeModeCoordinator {
|
||||
_ stream: AsyncStream<NWConnection.State>,
|
||||
timeoutSeconds: Double) async throws
|
||||
{
|
||||
try await AsyncTimeout.withTimeout(seconds: timeoutSeconds, onTimeout: {
|
||||
NSError(domain: "Bridge", code: 22, userInfo: [
|
||||
NSLocalizedDescriptionKey: "operation timed out",
|
||||
])
|
||||
}) {
|
||||
for await state in stream {
|
||||
switch state {
|
||||
case .ready:
|
||||
return
|
||||
case let .failed(err):
|
||||
throw err
|
||||
case .cancelled:
|
||||
throw NSError(domain: "Bridge", code: 20, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection cancelled",
|
||||
])
|
||||
default:
|
||||
continue
|
||||
try await AsyncTimeout.withTimeout(
|
||||
seconds: timeoutSeconds,
|
||||
onTimeout: {
|
||||
NSError(domain: "Bridge", code: 22, userInfo: [
|
||||
NSLocalizedDescriptionKey: "operation timed out",
|
||||
])
|
||||
},
|
||||
operation: {
|
||||
for await state in stream {
|
||||
switch state {
|
||||
case .ready:
|
||||
return
|
||||
case let .failed(err):
|
||||
throw err
|
||||
case .cancelled:
|
||||
throw NSError(domain: "Bridge", code: 20, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection cancelled",
|
||||
])
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
throw NSError(domain: "Bridge", code: 21, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection closed",
|
||||
])
|
||||
}
|
||||
throw NSError(domain: "Bridge", code: 21, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Connection closed",
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
private func resolveBridgeEndpoint(timeoutSeconds: Double) async -> NWEndpoint? {
|
||||
|
||||
@@ -46,7 +46,8 @@ struct NotificationManager {
|
||||
if Self.hasTimeSensitiveEntitlement {
|
||||
content.interruptionLevel = .timeSensitive
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,7 +746,9 @@ extension OnboardingView {
|
||||
Text("Couldn’t load skills from the Gateway.")
|
||||
.font(.footnote.weight(.semibold))
|
||||
.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)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
@@ -76,7 +76,10 @@ final class PeekabooBridgeHostCoordinator {
|
||||
}
|
||||
|
||||
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]
|
||||
else {
|
||||
return nil
|
||||
|
||||
@@ -24,7 +24,11 @@ final class TalkModeController {
|
||||
self.phase = phase
|
||||
TalkOverlayController.shared.updatePhase(phase)
|
||||
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) {
|
||||
@@ -37,7 +41,11 @@ final class TalkModeController {
|
||||
self.isPaused = paused
|
||||
TalkOverlayController.shared.updatePaused(paused)
|
||||
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) }
|
||||
}
|
||||
|
||||
|
||||
@@ -337,7 +337,9 @@ actor TalkModeRuntime {
|
||||
let runId = UUID().uuidString
|
||||
let startedAt = Date().timeIntervalSince1970
|
||||
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 {
|
||||
let response = try await GatewayConnection.shared.chatSend(
|
||||
@@ -348,7 +350,8 @@ actor TalkModeRuntime {
|
||||
attachments: [])
|
||||
guard self.isCurrent(gen) else { return }
|
||||
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(
|
||||
sessionKey: sessionKey,
|
||||
@@ -433,6 +436,7 @@ actor TalkModeRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity function_body_length
|
||||
private func playAssistant(text: String) async {
|
||||
let gen = self.lifecycleGeneration
|
||||
let parse = TalkDirectiveParser.parse(text)
|
||||
@@ -443,7 +447,9 @@ actor TalkModeRuntime {
|
||||
|
||||
if !parse.unknownKeys.isEmpty {
|
||||
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)
|
||||
@@ -490,7 +496,9 @@ actor TalkModeRuntime {
|
||||
self.ttsLogger.warning("talk missing voiceId; falling back to system voice")
|
||||
} else if let voiceId {
|
||||
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
|
||||
|
||||
@@ -503,7 +511,8 @@ actor TalkModeRuntime {
|
||||
if outputFormat == nil, !desiredOutputFormat.isEmpty {
|
||||
self.logger
|
||||
.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
|
||||
@@ -558,7 +567,8 @@ actor TalkModeRuntime {
|
||||
}
|
||||
self.ttsLogger
|
||||
.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 {
|
||||
throw NSError(domain: "StreamingAudioPlayer", code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: "audio playback failed",
|
||||
@@ -583,7 +593,9 @@ actor TalkModeRuntime {
|
||||
}
|
||||
} catch {
|
||||
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 {
|
||||
if self.interruptOnSpeech {
|
||||
await self.startRecognition()
|
||||
@@ -717,7 +729,10 @@ actor TalkModeRuntime {
|
||||
let modelLabel = (cfg.modelId?.isEmpty == false) ? cfg.modelId! : "none"
|
||||
self.logger
|
||||
.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 {
|
||||
|
||||
Reference in New Issue
Block a user