debug: add voice forward test button
This commit is contained in:
@@ -12,6 +12,9 @@ struct DebugSettings: View {
|
||||
@State private var relayRootInput: String = RelayProcessManager.shared.projectRootPath()
|
||||
@State private var sessionStorePath: String = SessionLoader.defaultStorePath
|
||||
@State private var sessionStoreSaveError: String?
|
||||
@State private var debugSendInFlight = false
|
||||
@State private var debugSendStatus: String?
|
||||
@State private var debugSendError: String?
|
||||
|
||||
var body: some View {
|
||||
ScrollView(.vertical) {
|
||||
@@ -129,6 +132,31 @@ struct DebugSettings: View {
|
||||
Task { _ = await NotificationManager().send(title: "Clawdis", body: "Test notification", sound: nil) }
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Button {
|
||||
Task { await self.sendVoiceDebug() }
|
||||
} label: {
|
||||
Label(
|
||||
self.debugSendInFlight ? "Sending debug voice…" : "Send debug voice via forwarder",
|
||||
systemImage: self.debugSendInFlight ? "bolt.horizontal.circle" : "waveform")
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.disabled(self.debugSendInFlight)
|
||||
|
||||
if let debugSendStatus {
|
||||
Text(debugSendStatus)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
} else if let debugSendError {
|
||||
Text(debugSendError)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.red)
|
||||
} else {
|
||||
Text("Sends the same command path as Voice Wake (ssh target + clawdis-mac agent → rpc → node cli → p-agent → WhatsApp).")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Button("Restart app") { self.relaunch() }
|
||||
Button("Reveal app in Finder") { self.revealApp() }
|
||||
@@ -211,6 +239,30 @@ struct DebugSettings: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func sendVoiceDebug() async {
|
||||
await MainActor.run {
|
||||
self.debugSendInFlight = true
|
||||
self.debugSendError = nil
|
||||
self.debugSendStatus = nil
|
||||
}
|
||||
|
||||
let message = "This is a debug test from the Mac app. Reply with \"Debug test works (and a funny pun)\" if you received that."
|
||||
let config = await MainActor.run { AppStateStore.shared.voiceWakeForwardConfig }
|
||||
let result = await VoiceWakeForwarder.forward(transcript: message, config: config)
|
||||
|
||||
await MainActor.run {
|
||||
self.debugSendInFlight = false
|
||||
switch result {
|
||||
case .success:
|
||||
self.debugSendStatus = "Sent via \(config.target). Await WhatsApp reply."
|
||||
self.debugSendError = nil
|
||||
case let .failure(error):
|
||||
self.debugSendStatus = nil
|
||||
self.debugSendError = error.localizedDescription
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func relaunch() {
|
||||
let url = Bundle.main.bundleURL
|
||||
let task = Process()
|
||||
|
||||
@@ -86,6 +86,7 @@ enum VoiceWakeForwarder {
|
||||
case launchFailed(String)
|
||||
case nonZeroExit(Int32, String)
|
||||
case cliMissingOrFailed(Int32, String)
|
||||
case disabled
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
@@ -101,16 +102,18 @@ enum VoiceWakeForwarder {
|
||||
return clipped.isEmpty
|
||||
? "clawdis-mac failed on remote (code \(code))"
|
||||
: "clawdis-mac failed on remote (code \(code)): \(clipped)"
|
||||
case .disabled: return "Voice wake forwarding disabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func forward(transcript: String, config: VoiceWakeForwardConfig) async {
|
||||
guard config.enabled else { return }
|
||||
@discardableResult
|
||||
static func forward(transcript: String, config: VoiceWakeForwardConfig) async -> Result<Void, VoiceWakeForwardError> {
|
||||
guard config.enabled else { return .failure(.disabled) }
|
||||
let destination = config.target.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard let parsed = self.parse(target: destination) else {
|
||||
self.logger.error("voice wake forward skipped: host missing")
|
||||
return
|
||||
return .failure(.invalidTarget)
|
||||
}
|
||||
|
||||
let userHost = parsed.user.map { "\($0)@\(parsed.host)" } ?? parsed.host
|
||||
@@ -144,7 +147,7 @@ enum VoiceWakeForwarder {
|
||||
try process.run()
|
||||
} catch {
|
||||
self.logger.error("voice wake forward failed to start ssh: \(error.localizedDescription, privacy: .public)")
|
||||
return
|
||||
return .failure(.launchFailed(error.localizedDescription))
|
||||
}
|
||||
|
||||
if let data = transcript.data(using: .utf8) {
|
||||
@@ -155,12 +158,17 @@ enum VoiceWakeForwarder {
|
||||
let out = await self.wait(process, timeout: config.timeout)
|
||||
if process.terminationStatus == 0 {
|
||||
self.logger.info("voice wake forward ok host=\(userHost, privacy: .public)")
|
||||
} else {
|
||||
// surface the failure instead of being silent
|
||||
let clipped = out.prefix(240)
|
||||
self.logger.error(
|
||||
"voice wake forward failed exit=\(process.terminationStatus) host=\(userHost, privacy: .public) out=\(clipped, privacy: .public)")
|
||||
return .success(())
|
||||
}
|
||||
|
||||
// surface the failure instead of being silent
|
||||
let clipped = out.prefix(240)
|
||||
self.logger.error(
|
||||
"voice wake forward failed exit=\(process.terminationStatus) host=\(userHost, privacy: .public) out=\(clipped, privacy: .public)")
|
||||
if process.terminationStatus == 127 {
|
||||
return .failure(.cliMissingOrFailed(process.terminationStatus, out))
|
||||
}
|
||||
return .failure(.nonZeroExit(process.terminationStatus, out))
|
||||
}
|
||||
|
||||
static func checkConnection(config: VoiceWakeForwardConfig) async -> Result<Void, VoiceWakeForwardError> {
|
||||
|
||||
Reference in New Issue
Block a user