diff --git a/extensions/clickclack/src/channel.ts b/extensions/clickclack/src/channel.ts index 0cd4e150442..0ce0f86f34e 100644 --- a/extensions/clickclack/src/channel.ts +++ b/extensions/clickclack/src/channel.ts @@ -139,7 +139,9 @@ export const clickClackPlugin: ChannelPlugin = create }, resolveSessionConversation: ({ rawId }) => { const parsed = parseClickClackTarget(rawId); - if (parsed.kind === "dm") return null; + if (parsed.kind === "dm") { + return null; + } return { id: parsed.id, threadId: parsed.kind === "thread" ? parsed.id : undefined, diff --git a/extensions/clickclack/src/gateway.ts b/extensions/clickclack/src/gateway.ts index 9b5124409a7..54c5bb28dbb 100644 --- a/extensions/clickclack/src/gateway.ts +++ b/extensions/clickclack/src/gateway.ts @@ -1,4 +1,5 @@ import type { ChannelGatewayContext } from "openclaw/plugin-sdk/channel-contract"; +import type { RawData } from "ws"; import { resolveClickClackAccount } from "./accounts.js"; import { createClickClackClient } from "./http-client.js"; import { handleClickClackInbound } from "./inbound.js"; @@ -20,7 +21,9 @@ async function resolveEventMessage(params: { event: ClickClackEvent; }): Promise { const messageId = payloadString(params.event, "message_id"); - if (!messageId) return null; + if (!messageId) { + return null; + } const directConversationId = payloadString(params.event, "direct_conversation_id"); if (directConversationId && typeof params.event.seq === "number") { const messages = await params.client.directMessages( @@ -32,7 +35,9 @@ async function resolveEventMessage(params: { } if (params.event.type === "thread.reply_created") { const rootId = payloadString(params.event, "root_message_id"); - if (!rootId) return null; + if (!rootId) { + return null; + } const thread = await params.client.thread(rootId); return thread.replies.find((message) => message.id === messageId) ?? null; } @@ -47,6 +52,19 @@ async function resolveEventMessage(params: { return null; } +function decodeSocketMessage(data: RawData): string { + if (typeof data === "string") { + return data; + } + if (Buffer.isBuffer(data)) { + return data.toString("utf8"); + } + if (data instanceof ArrayBuffer) { + return Buffer.from(data).toString("utf8"); + } + return Buffer.concat(data).toString("utf8"); +} + async function processEvent(params: { account: ResolvedClickClackAccount; config: CoreConfig; @@ -128,7 +146,7 @@ export async function startClickClackGatewayAccount( ctx.abortSignal.addEventListener("abort", abort, { once: true }); socket.on("message", (data) => { void (async () => { - const event = JSON.parse(String(data)) as ClickClackEvent; + const event = JSON.parse(decodeSocketMessage(data)) as ClickClackEvent; afterCursor = event.cursor || afterCursor; await processEvent({ account, diff --git a/extensions/clickclack/src/http-client.ts b/extensions/clickclack/src/http-client.ts index 6359e58195e..3c5587314fb 100644 --- a/extensions/clickclack/src/http-client.ts +++ b/extensions/clickclack/src/http-client.ts @@ -113,7 +113,9 @@ export function createClickClackClient(options: ClientOptions) { }, events: async (workspaceId: string, afterCursor?: string): Promise => { const query = new URLSearchParams({ workspace_id: workspaceId }); - if (afterCursor) query.set("after_cursor", afterCursor); + if (afterCursor) { + query.set("after_cursor", afterCursor); + } const data = await request<{ events: ClickClackEvent[] }>( `/api/realtime/events?${query.toString()}`, ); @@ -123,7 +125,9 @@ export function createClickClackClient(options: ClientOptions) { const url = new URL(`${baseUrl}/api/realtime/ws`); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; url.searchParams.set("workspace_id", workspaceId); - if (afterCursor) url.searchParams.set("after_cursor", afterCursor); + if (afterCursor) { + url.searchParams.set("after_cursor", afterCursor); + } return new WebSocket(url, { headers: { Authorization: `Bearer ${options.token}`, diff --git a/extensions/clickclack/src/inbound.ts b/extensions/clickclack/src/inbound.ts index 6218e8d7960..ab2ff28038a 100644 --- a/extensions/clickclack/src/inbound.ts +++ b/extensions/clickclack/src/inbound.ts @@ -176,7 +176,9 @@ export async function handleClickClackInbound(params: { payload && typeof payload === "object" && "text" in payload ? ((payload as { text?: string }).text ?? "") : ""; - if (!text.trim()) return; + if (!text.trim()) { + return; + } await sendClickClackText({ cfg: params.config, accountId: params.account.accountId,