export * as PluginPromise from "./promise" import { define } from "@opencode-ai/plugin/v2/effect" import type { Plugin, PluginContext, Registration } from "@opencode-ai/plugin/v2/promise" import { Effect, Scope } from "effect" // The Effect host hands back this registration shape; mirror it structurally so // we do not have to alias the Effect package's `Registration` against the Promise one. type HostRegistration = { readonly dispose: Effect.Effect } /** * Adapts a Promise plugin into an Effect plugin so the existing Effect-only * loader (`PluginV2` / `PluginBoot`) can run it unchanged. * * Hook registrations created during the async `setup` attach to the plugin's * scope, so unloading the plugin disposes them. The captured fiber context * preserves boot-time batching, so Promise-plugin transforms still coalesce * into one reload per domain. */ export function fromPromise(plugin: Plugin) { return define({ id: plugin.id, effect: (host) => Effect.gen(function* () { const scope = yield* Scope.Scope const context = yield* Effect.context() // Run a hook registration on the plugin scope and resolve once it is registered. const register = (effect: Effect.Effect): Promise => Effect.runPromiseWith(context)(Scope.provide(scope)(effect)).then((registration) => ({ dispose: () => Effect.runPromiseWith(context)(registration.dispose), })) const run = (effect: Effect.Effect) => Effect.runPromiseWith(context)(effect) const transform = (domain: { transform: ( callback: (draft: Draft) => Effect.Effect | void, ) => Effect.Effect }) => (callback: (draft: Draft) => Promise | void) => register(domain.transform((draft) => Effect.promise(() => Promise.resolve(callback(draft))))) const context2: PluginContext = { options: host.options, agent: { transform: transform(host.agent), reload: () => run(host.agent.reload()), }, aisdk: { sdk: (callback) => register(host.aisdk.sdk((event) => Effect.promise(() => Promise.resolve(callback(event))))), language: (callback) => register(host.aisdk.language((event) => Effect.promise(() => Promise.resolve(callback(event))))), }, catalog: { transform: transform(host.catalog), reload: () => run(host.catalog.reload()), }, command: { transform: transform(host.command), reload: () => run(host.command.reload()), }, integration: { transform: transform(host.integration), reload: () => run(host.integration.reload()), }, plugin: { transform: transform(host.plugin), reload: () => run(host.plugin.reload()), }, reference: { transform: transform(host.reference), reload: () => run(host.reference.reload()), }, skill: { transform: transform(host.skill), reload: () => run(host.skill.reload()), }, } yield* Effect.promise(() => Promise.resolve(plugin.setup(context2))) }), }) }