fix(opencode-plugin): use @relaycast/sdk instead of dead bespoke RPC API
Merged
WI
4mo ago+913+913+012345678901234567890123456789-237-237-012345678901234567890123456789
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(oldwwwhost is dead; no data continuity). Still configurable via the existingRelayState.apiBaseUrl, now routed into the SDK asbaseUrl. - Removed the bespoke
fetch/normalizeBaseUrlplumbing. - Tests now mock the SDK (
RelayCast/AgentClient) instead of the dead HTTP URLs, with equivalent coverage (19 tests).
Endpoint → SDK mapping
| Bespoke endpoint | SDK call |
|---|---|
/register | new RelayCast({ apiKey: workspace, baseUrl }).registerOrRotate({ name }) → then relay.as(token) for the agent client |
/dm/send | AgentClient.dm(to, text) |
/inbox/check | AgentClient.inbox() flattened by inboxToMessages() |
/agent/list | RelayCast.agents.list() |
/message/post | AgentClient.post(channel, text) |
/agent/add | RelayCast.agents.registerOrGet({ name, metadata: { cli, task } }) |
/agent/remove | RelayCast.agents.delete(name) |
Things that didn't map cleanly
- Inbox shape.
/v1/inboxreturns{ unread_channels, mentions, unread_dms, recent_reactions }— nomessages[].inboxToMessages()flattens channelmentions[]andunread_dms[](using each conversation'slastMessage) into the flatRelayMessage[]the inbox tool and idle hook expect.unread_channelsandrecent_reactionsare not message-like and are ignored. /agent/add(worker registration). The SDK'sagents.spawnrequires aclienum (claude|codex|gemini|aider|goose) that excludesopencode, 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 withagents.registerOrGet({ name, metadata: { cli: 'opencode', task } }). The localspawn(...)behavior, bootstrap prompt, and env vars are unchanged.relay_agentsreturn type. Previously passed through whatever the bespoke API returned; now returns the SDK'sAgent[]objects. Shape ({ agents: [...] }) is preserved.
Build / test
npm run build(tsc): passesnpm 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