From a48955075263bf5050ce8c08d5f69987ab587314 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 7 Dec 2025 05:00:52 +0100 Subject: [PATCH] feat(cli): add agent send command and wire through XPC --- apps/macos/Sources/Clawdis/XPCService.swift | 16 ++++++++++++++ apps/macos/Sources/ClawdisCLI/main.swift | 23 +++++++++++++++++++++ apps/macos/Sources/ClawdisIPC/IPC.swift | 15 ++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/apps/macos/Sources/Clawdis/XPCService.swift b/apps/macos/Sources/Clawdis/XPCService.swift index 3002c525a..b6a377a81 100644 --- a/apps/macos/Sources/Clawdis/XPCService.swift +++ b/apps/macos/Sources/Clawdis/XPCService.swift @@ -67,6 +67,22 @@ final class ClawdisXPCService: NSObject, ClawdisXPCProtocol { guard authorized else { return Response(ok: false, message: "screen recording permission missing") } } return await ShellRunner.run(command: command, cwd: cwd, env: env, timeout: timeoutSec) + + case let .agent(message, thinking, session): + let trimmed = message.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmed.isEmpty else { return Response(ok: false, message: "message empty") } + + let sent = await MainActor.run { + WebChatManager.shared.sendMessage( + trimmed, + thinking: thinking ?? "default", + sessionKey: session ?? "main") + } + + if sent { + return Response(ok: true, message: "sent") + } + return Response(ok: false, message: "failed to enqueue message") } } } diff --git a/apps/macos/Sources/ClawdisCLI/main.swift b/apps/macos/Sources/ClawdisCLI/main.swift index bb4c91149..b78e4f21c 100644 --- a/apps/macos/Sources/ClawdisCLI/main.swift +++ b/apps/macos/Sources/ClawdisCLI/main.swift @@ -133,6 +133,28 @@ struct ClawdisCLI { case "status": return .status + case "agent": + var message: String? + var thinking: String? + var session: String? + + while !args.isEmpty { + let arg = args.removeFirst() + switch arg { + case "--message": message = args.popFirst() + case "--thinking": thinking = args.popFirst() + case "--session": session = args.popFirst() + default: + // Support bare message as last argument + if message == nil { + message = arg + } + } + } + + guard let message else { throw CLIError.help } + return .agent(message: message, thinking: thinking, session: session) + default: throw CLIError.help } @@ -152,6 +174,7 @@ struct ClawdisCLI { clawdis-mac screenshot [--display-id ] [--window-id ] clawdis-mac run [--cwd ] [--env KEY=VAL] [--timeout ] [--needs-screen-recording] clawdis-mac status + clawdis-mac agent --message [--thinking ] [--session ] clawdis-mac --help Returns JSON to stdout: diff --git a/apps/macos/Sources/ClawdisIPC/IPC.swift b/apps/macos/Sources/ClawdisIPC/IPC.swift index 9c97b881a..d7a61d424 100644 --- a/apps/macos/Sources/ClawdisIPC/IPC.swift +++ b/apps/macos/Sources/ClawdisIPC/IPC.swift @@ -25,6 +25,7 @@ public enum Request: Sendable { timeoutSec: Double?, needsScreenRecording: Bool) case status + case agent(message: String, thinking: String?, session: String?) } // MARK: - Responses @@ -51,6 +52,7 @@ extension Request: Codable { case caps, interactive case displayID, windowID, format case command, cwd, env, timeoutSec, needsScreenRecording + case message, thinking, session } private enum Kind: String, Codable { @@ -59,6 +61,7 @@ extension Request: Codable { case screenshot case runShell case status + case agent } public func encode(to encoder: Encoder) throws { @@ -91,6 +94,12 @@ extension Request: Codable { case .status: try container.encode(Kind.status, forKey: .type) + + case let .agent(message, thinking, session): + try container.encode(Kind.agent, forKey: .type) + try container.encode(message, forKey: .message) + try container.encodeIfPresent(thinking, forKey: .thinking) + try container.encodeIfPresent(session, forKey: .session) } } @@ -125,6 +134,12 @@ extension Request: Codable { case .status: self = .status + + case .agent: + let message = try container.decode(String.self, forKey: .message) + let thinking = try container.decodeIfPresent(String.self, forKey: .thinking) + let session = try container.decodeIfPresent(String.self, forKey: .session) + self = .agent(message: message, thinking: thinking, session: session) } } }