refactor(plugin): consolidate internal registration

This commit is contained in:
Dax Raad 2026-06-22 19:49:00 -04:00
parent 23fd5907be
commit cd97de7391
4 changed files with 99 additions and 119 deletions

View File

@ -7,7 +7,7 @@ import { Catalog } from "./catalog"
import { Integration } from "./integration"
import { CommandV2 } from "./command"
import { AgentV2 } from "./agent"
import { PluginBoot } from "./plugin/boot"
import { PluginInternal } from "./plugin/internal"
import { Project } from "./project"
import { ProjectCopy } from "./project/copy"
import { ProjectDirectories } from "./project/directories"
@ -65,7 +65,7 @@ export class LocationServiceMap extends LayerMap.Service<LocationServiceMap>()("
Integration.locationLayer,
CommandV2.locationLayer,
AgentV2.locationLayer,
PluginBoot.locationLayer,
PluginInternal.locationLayer,
ProjectCopy.locationLayer,
FileSystem.locationLayer,
Watcher.locationLayer,

View File

@ -1,101 +0,0 @@
export * as PluginBoot from "./boot"
import { Effect, Layer } from "effect"
import { Integration } from "../integration"
import { AgentV2 } from "../agent"
import { AISDK } from "../aisdk"
import { Catalog } from "../catalog"
import { CommandV2 } from "../command"
import { Config } from "../config"
import { ConfigAgentPlugin } from "../config/plugin/agent"
import { ConfigCommandPlugin } from "../config/plugin/command"
import { ConfigSkillPlugin } from "../config/plugin/skill"
import { ConfigReferencePlugin } from "../config/plugin/reference"
import { ConfigExternalPlugin } from "../config/plugin/external"
import { EventV2 } from "../event"
import { FSUtil } from "../fs-util"
import { FileSystem } from "../filesystem"
import { Global } from "../global"
import { Location } from "../location"
import { ModelsDev } from "../models-dev"
import { Npm } from "../npm"
import { PluginV2 } from "../plugin"
import { AgentPlugin } from "./agent"
import { CommandPlugin } from "./command"
import { SkillPlugin } from "./skill"
import { ConfigProviderPlugin } from "../config/plugin/provider"
import { ModelsDevPlugin } from "./models-dev"
import { ProviderPlugins } from "./provider"
import { SkillV2 } from "../skill"
import { Reference } from "../reference"
import { State } from "../state"
import { PluginHost } from "./host"
import { PluginInternal } from "./internal"
export const locationLayer = Layer.effectDiscard(
Effect.gen(function* () {
const catalog = yield* Catalog.Service
const commands = yield* CommandV2.Service
const plugin = yield* PluginV2.Service
const integration = yield* Integration.Service
const agents = yield* AgentV2.Service
const config = yield* Config.Service
const location = yield* Location.Service
const modelsDev = yield* ModelsDev.Service
const npm = yield* Npm.Service
const events = yield* EventV2.Service
const fs = yield* FSUtil.Service
const filesystem = yield* FileSystem.Service
const global = yield* Global.Service
const skill = yield* SkillV2.Service
const reference = yield* Reference.Service
const host = yield* PluginHost.make(plugin)
const add = <R>(input: PluginInternal.Plugin<R>) =>
input
.effect({ ...host, options: {} })
.pipe(
Effect.provideService(Catalog.Service, catalog),
Effect.provideService(CommandV2.Service, commands),
Effect.provideService(Integration.Service, integration),
Effect.provideService(AgentV2.Service, agents),
Effect.provideService(Config.Service, config),
Effect.provideService(Location.Service, location),
Effect.provideService(ModelsDev.Service, modelsDev),
Effect.provideService(Npm.Service, npm),
Effect.provideService(EventV2.Service, events),
Effect.provideService(FSUtil.Service, fs),
Effect.provideService(FileSystem.Service, filesystem),
Effect.provideService(Global.Service, global),
Effect.provideService(SkillV2.Service, skill),
Effect.provideService(Reference.Service, reference),
)
yield* State.batch(
Effect.gen(function* () {
yield* add(AgentPlugin.Plugin)
yield* add(CommandPlugin.Plugin)
yield* add(SkillPlugin.Plugin)
yield* add(ModelsDevPlugin)
yield* add(ConfigProviderPlugin.Plugin)
yield* add(ConfigAgentPlugin.Plugin)
yield* add(ConfigCommandPlugin.Plugin)
yield* add(ConfigSkillPlugin.Plugin)
yield* add(ConfigReferencePlugin.Plugin)
for (const item of ProviderPlugins) yield* add(item)
yield* add(ConfigExternalPlugin.Plugin)
}),
).pipe(Effect.withSpan("PluginBoot.boot"))
}),
).pipe(
Layer.provideMerge(PluginV2.locationLayer),
Layer.provideMerge(AISDK.locationLayer),
Layer.provideMerge(Integration.locationLayer),
Layer.provideMerge(Catalog.locationLayer),
Layer.provideMerge(CommandV2.locationLayer),
Layer.provideMerge(Config.locationLayer),
Layer.provideMerge(AgentV2.locationLayer),
Layer.provideMerge(SkillV2.locationLayer),
Layer.provideMerge(Reference.locationLayer),
Layer.provideMerge(FileSystem.locationLayer),
)

View File

@ -1,21 +1,35 @@
export * as PluginInternal from "./internal"
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
import type { Effect, Scope } from "effect"
import type { AgentV2 } from "../agent"
import type { Catalog } from "../catalog"
import type { CommandV2 } from "../command"
import type { Config } from "../config"
import type { EventV2 } from "../event"
import type { FileSystem } from "../filesystem"
import type { FSUtil } from "../fs-util"
import type { Global } from "../global"
import type { Integration } from "../integration"
import type { Location } from "../location"
import type { ModelsDev } from "../models-dev"
import type { Npm } from "../npm"
import type { Reference } from "../reference"
import type { SkillV2 } from "../skill"
import { Effect, Layer, Scope } from "effect"
import { AgentV2 } from "../agent"
import { Catalog } from "../catalog"
import { CommandV2 } from "../command"
import { Config } from "../config"
import { ConfigAgentPlugin } from "../config/plugin/agent"
import { ConfigCommandPlugin } from "../config/plugin/command"
import { ConfigExternalPlugin } from "../config/plugin/external"
import { ConfigProviderPlugin } from "../config/plugin/provider"
import { ConfigReferencePlugin } from "../config/plugin/reference"
import { ConfigSkillPlugin } from "../config/plugin/skill"
import { EventV2 } from "../event"
import { FileSystem } from "../filesystem"
import { FSUtil } from "../fs-util"
import { Global } from "../global"
import { Integration } from "../integration"
import { Location } from "../location"
import { ModelsDev } from "../models-dev"
import { Npm } from "../npm"
import { PluginV2 } from "../plugin"
import { Reference } from "../reference"
import { SkillV2 } from "../skill"
import { State } from "../state"
import { AgentPlugin } from "./agent"
import { CommandPlugin } from "./command"
import { PluginHost } from "./host"
import { ModelsDevPlugin } from "./models-dev"
import { ProviderPlugins } from "./provider"
import { SkillPlugin } from "./skill"
export type Requirements =
| AgentV2.Service
@ -41,3 +55,70 @@ export interface Plugin<R = never> {
export function define<R>(plugin: Plugin<R>) {
return plugin
}
export const locationLayer = Layer.effectDiscard(
Effect.gen(function* () {
const catalog = yield* Catalog.Service
const commands = yield* CommandV2.Service
const plugin = yield* PluginV2.Service
const integration = yield* Integration.Service
const agents = yield* AgentV2.Service
const config = yield* Config.Service
const location = yield* Location.Service
const modelsDev = yield* ModelsDev.Service
const npm = yield* Npm.Service
const events = yield* EventV2.Service
const fs = yield* FSUtil.Service
const filesystem = yield* FileSystem.Service
const global = yield* Global.Service
const skill = yield* SkillV2.Service
const reference = yield* Reference.Service
const host = yield* PluginHost.make(plugin)
const wrap = <R>(input: Plugin<R>) => ({
id: input.id,
effect: (context: PluginContext) =>
input
.effect(context)
.pipe(
Effect.provideService(Catalog.Service, catalog),
Effect.provideService(CommandV2.Service, commands),
Effect.provideService(Integration.Service, integration),
Effect.provideService(AgentV2.Service, agents),
Effect.provideService(Config.Service, config),
Effect.provideService(Location.Service, location),
Effect.provideService(ModelsDev.Service, modelsDev),
Effect.provideService(Npm.Service, npm),
Effect.provideService(EventV2.Service, events),
Effect.provideService(FSUtil.Service, fs),
Effect.provideService(FileSystem.Service, filesystem),
Effect.provideService(Global.Service, global),
Effect.provideService(SkillV2.Service, skill),
Effect.provideService(Reference.Service, reference),
),
})
yield* State.batch(
Effect.gen(function* () {
yield* plugin.transform((plugins) => {
plugins.add(wrap(AgentPlugin.Plugin))
plugins.add(wrap(CommandPlugin.Plugin))
plugins.add(wrap(SkillPlugin.Plugin))
plugins.add(wrap(ModelsDevPlugin))
plugins.add(wrap(ConfigProviderPlugin.Plugin))
plugins.add(wrap(ConfigAgentPlugin.Plugin))
plugins.add(wrap(ConfigCommandPlugin.Plugin))
plugins.add(wrap(ConfigSkillPlugin.Plugin))
plugins.add(wrap(ConfigReferencePlugin.Plugin))
for (const item of ProviderPlugins) plugins.add(wrap(item))
})
yield* wrap(ConfigExternalPlugin.Plugin).effect(host)
}),
).pipe(Effect.withSpan("PluginInternal.boot"), Effect.forkScoped({ startImmediately: true }))
}),
).pipe(
Layer.provideMerge(PluginV2.locationLayer),
Layer.provideMerge(Config.locationLayer),
Layer.provideMerge(FileSystem.locationLayer),
)

View File

@ -10,7 +10,7 @@ type HostRegistration = { readonly dispose: Effect.Effect<void> }
/**
* Adapts a Promise plugin into an Effect plugin so the existing Effect-only
* loader (`PluginV2` / `PluginBoot`) can run it unchanged.
* loader (`PluginV2` / `PluginInternal`) 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