diff --git a/sdk/typescript/src/cli/daemon/runtime.ts b/sdk/typescript/src/cli/daemon/runtime.ts index d9f94074..3c2cc410 100644 Binary files a/sdk/typescript/src/cli/daemon/runtime.ts and b/sdk/typescript/src/cli/daemon/runtime.ts differ diff --git a/sdk/typescript/tests/daemon.test.ts b/sdk/typescript/tests/daemon.test.ts index 76ecb9ee..347945f5 100644 --- a/sdk/typescript/tests/daemon.test.ts +++ b/sdk/typescript/tests/daemon.test.ts @@ -28,6 +28,7 @@ import { } from "../src/cli/daemon/runtime.js"; import { opencodeEventsFromLine } from "../src/cli/harness-events.js"; import type { TaskFrame } from "../src/cli/daemon/protocol.js"; +import { TinyPlaceError } from "../src/index.js"; // ── protocol ───────────────────────────────────────────────────────────────── @@ -339,6 +340,34 @@ describe("DaemonRuntime task protocol", () => { expect(statusCount).toBe(1); }); + it("logs the relay's rejection reason when a send fails", async () => { + const logs: Array = []; + const runtime = new DaemonRuntime({ + ...baseDeps, + send: async () => { + throw new TinyPlaceError( + 400, + { error: "body must be encrypted ciphertext" }, + "HTTP 400: /messages", + ); + }, + runTask: async () => ({ provider: "claude", reply: "out", events: 0 }), + log: (line) => logs.push(line), + statusThrottleMs: 0, + }); + runtime.handleMessage( + "peerC", + { text: "" }, + { proto: TINYPLACE_PROTO, kind: "task", taskId: "t9", text: "go", ts: "now" }, + ); + await vi.waitFor(() => + expect(logs.some((l) => l.startsWith("send to peerC failed"))).toBe(true), + ); + expect(logs.find((l) => l.startsWith("send to peerC failed"))).toBe( + "send to peerC failed: HTTP 400: /messages — body must be encrypted ciphertext", + ); + }); + it("errors when the requested provider is unavailable", async () => { const { sent, send } = collector(); const runtime = new DaemonRuntime({