// RPC implementation (Effect flavor) — template // // Docs: https://opencode.ai/v2/docs/build/plugins/effect/rpc/ // // Needs templates/rpc-effect.ts copied next to this file as src/rpc.ts, so the // doc's "./rpc.js" specifier resolves. Rename it rpc.ts on save; the contract // shape is identical, only the schema dialect differs. // // Registration goes inside the plugin `effect`, NOT `setup`. // // The docs use "@opencode/plugin" and "@opencode/plugin/effect". Install the // package at your OpenCode version and restart the service first — see the // PREREQUISITE block in promise-plugin.ts. import { Plugin } from "@opencode/plugin/effect" import { Effect, Stream } from "effect" import { Acme } from "./rpc.js" export default Plugin.define({ id: "acme-effect-plugin", effect: (ctx) => Effect.gen(function* () { const registration = yield* ctx.rpc.register(Acme, { // Input arrives already decoded — destructure it, do not cast. search: ({ query }, context) => findText(query).pipe( Effect.flatMap((text) => text ? Effect.succeed({ text }) : Effect.fail(context.error("not_found", "Result not found", { query })), ), ), }) // The same plugin can call its own RPC. const acme = ctx.rpc(Acme) const result = yield* acme.search({ query: "hello" }) yield* registration.events.emit("updated", { itemID: "item-1", text: result.text }) // Subscriptions are a Stream; forkScoped handles interruption. // "Subscriptions are live only and close when Stream consumption stops." yield* acme.events.subscribe("updated").pipe( Stream.runForEach((event) => Effect.logInfo(event.data.text)), Effect.forkScoped, ) // context.signal is NOT documented on the Effect page. Use interruption. }).pipe(Effect.orDie), }) // Calling over HTTP uses the Effect client and needs an HTTP client layer: // // import { OpenCode } from "@opencode/client/effect" // import { Effect } from "effect" // import { FetchHttpClient } from "effect/unstable/http" // import { Acme } from "opencode-acme-plugin/rpc" // // const program = Effect.gen(function* () { // const client = yield* OpenCode.make({ baseUrl: "http://localhost:4096" }) // const acme = client.rpc(Acme) // return yield* acme.search({ query: "hello" }) // }) // // const result = await Effect.runPromise( // program.pipe(Effect.provide(FetchHttpClient.layer)), // ) // // Another Effect plugin calls it with ctx.rpc(Acme). events.on and the // prefixed event type are documented only on the Promise page — check before // relying on either here. declare function findText(query: string): Effect.Effect