fix(opencode-plugin): use @relaycast/sdk instead of dead bespoke RPC API

Merged
WI
4mo ago
+913-237

Problem

The OpenCode Relay plugin (plugins/opencode-relay-plugin) talked to a bespoke RPC API at https://www.relaycast.dev/api/v1 (/register, /dm/send, /inbox/check, /agent/list, /message/post, /agent/add, /agent/remove). That host is dead (returns HTTP 522), so the plugin is fully broken.

Change

Transport swap only — same tool names, arguments, return shapes, and idle inbox-polling behavior. The plugin now uses the published @relaycast/sdk (^4.1.6) pointed at the current engine.

  • Default base URL → https://cast.agentrelay.com (old www host is dead; no data continuity). Still configurable via the existing RelayState.apiBaseUrl, now routed into the SDK as baseUrl.
  • Removed the bespoke fetch / normalizeBaseUrl plumbing.
  • Tests now mock the SDK (RelayCast / AgentClient) instead of the dead HTTP URLs, with equivalent coverage (19 tests).

Endpoint → SDK mapping

Bespoke endpointSDK call
/registernew RelayCast({ apiKey: workspace, baseUrl }).registerOrRotate({ name }) → then relay.as(token) for the agent client
/dm/sendAgentClient.dm(to, text)
/inbox/checkAgentClient.inbox() flattened by inboxToMessages()
/agent/listRelayCast.agents.list()
/message/postAgentClient.post(channel, text)
/agent/addRelayCast.agents.registerOrGet({ name, metadata: { cli, task } })
/agent/removeRelayCast.agents.delete(name)

Things that didn't map cleanly

  • Inbox shape. /v1/inbox returns { unread_channels, mentions, unread_dms, recent_reactions } — no messages[]. inboxToMessages() flattens channel mentions[] and unread_dms[] (using each conversation's lastMessage) into the flat RelayMessage[] the inbox tool and idle hook expect. unread_channels and recent_reactions are not message-like and are ignored.
  • /agent/add (worker registration). The SDK's agents.spawn requires a cli enum (claude|codex|gemini|aider|goose) that excludes opencode, and it is meant to spawn a remote process. The plugin instead spawns a local OpenCode process, so the relay-side step is just registering the worker identity — implemented with agents.registerOrGet({ name, metadata: { cli: 'opencode', task } }). The local spawn(...) behavior, bootstrap prompt, and env vars are unchanged.
  • relay_agents return type. Previously passed through whatever the bespoke API returned; now returns the SDK's Agent[] objects. Shape ({ agents: [...] }) is preserved.

Build / test

  • npm run build (tsc): passes
  • npm test (vitest): 19/19 passing
  • Validated against @relaycast/sdk@4.1.6.

A standalone vitest.config.ts was added to the plugin so its tests run in isolation (the plugin is not part of the monorepo npm workspaces; without it vitest climbs to the root config which can't resolve in a fresh plugin install).

🤖 Generated with Claude Code