feat(core): manage configurable plugin generations
This commit is contained in:
parent
f9d1d3b259
commit
a9b7bd9e2f
83 changed files with 1116 additions and 819 deletions
|
|
@ -1,16 +1,14 @@
|
|||
export * as PluginInternal from "./internal"
|
||||
|
||||
import { makeLocationNode } from "../effect/app-node"
|
||||
import { httpClient } from "../effect/app-node-platform"
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import { Context, Effect, Layer, Scope } from "effect"
|
||||
import type { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { Context, Effect, Scope } from "effect"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
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"
|
||||
|
|
@ -25,8 +23,6 @@ import { Location } from "../location"
|
|||
import { LocationMutation } from "../location-mutation"
|
||||
import { ModelsDev } from "../models-dev"
|
||||
import { Npm } from "../npm"
|
||||
import { PluginV2 } from "../plugin"
|
||||
import { PluginRuntime } from "../plugin/runtime"
|
||||
import { PermissionV2 } from "../permission"
|
||||
import { QuestionV2 } from "../question"
|
||||
import { Reference } from "../reference"
|
||||
|
|
@ -35,177 +31,137 @@ import { SessionInstructions } from "../session/instructions"
|
|||
import { SessionTodo } from "../session/todo"
|
||||
import { Shell } from "../shell"
|
||||
import { SkillV2 } from "../skill"
|
||||
import { State } from "../state"
|
||||
import { ToolRegistry } from "../tool/registry"
|
||||
import { Tools } from "../tool/tools"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import { AgentPlugin } from "./agent"
|
||||
import { CommandPlugin } from "./command"
|
||||
import { ModelsDevPlugin } from "./models-dev"
|
||||
import { ProviderPlugins } from "./provider"
|
||||
import { SdkPlugins } from "./sdk"
|
||||
import { SkillPlugin } from "./skill"
|
||||
import { VariantPlugin } from "./variant"
|
||||
import { ApplyPatchTool } from "../tool/apply-patch"
|
||||
import { EditTool } from "../tool/edit"
|
||||
import { GlobTool } from "../tool/glob"
|
||||
import { GrepTool } from "../tool/grep"
|
||||
import { QuestionTool } from "../tool/question"
|
||||
import { ReadTool } from "../tool/read"
|
||||
import { ReadToolFileSystem } from "../tool/read-filesystem"
|
||||
import { ReadTool } from "../tool/read"
|
||||
import { ShellTool } from "../tool/shell"
|
||||
import { SkillTool } from "../tool/skill"
|
||||
import { SubagentTool } from "../tool/subagent"
|
||||
import { TodoWriteTool } from "../tool/todowrite"
|
||||
import { Tools } from "../tool/tools"
|
||||
import { WebFetchTool } from "../tool/webfetch"
|
||||
import { WebSearchTool } from "../tool/websearch"
|
||||
import { WriteTool } from "../tool/write"
|
||||
import { AgentPlugin } from "./agent"
|
||||
import { CommandPlugin } from "./command"
|
||||
import { ModelsDevPlugin } from "./models-dev"
|
||||
import { ProviderPlugins } from "./provider"
|
||||
import { PluginRuntime } from "./runtime"
|
||||
import { SkillPlugin } from "./skill"
|
||||
import { VariantPlugin } from "./variant"
|
||||
|
||||
export type Requirements =
|
||||
| AgentV2.Service
|
||||
| Catalog.Service
|
||||
| CommandV2.Service
|
||||
| Config.Service
|
||||
| EventV2.Service
|
||||
| FileMutation.Service
|
||||
| FileSystem.Service
|
||||
| FSUtil.Service
|
||||
| Global.Service
|
||||
| HttpClient.HttpClient
|
||||
| Image.Service
|
||||
| Integration.Service
|
||||
| Location.Service
|
||||
| LocationMutation.Service
|
||||
| ModelsDev.Service
|
||||
| Npm.Service
|
||||
| PermissionV2.Service
|
||||
| PluginRuntime.Service
|
||||
| QuestionV2.Service
|
||||
| ReadToolFileSystem.Service
|
||||
| Reference.Service
|
||||
| Ripgrep.Service
|
||||
| SessionInstructions.Service
|
||||
| SessionTodo.Service
|
||||
| Shell.Service
|
||||
| SkillV2.Service
|
||||
| Tools.Service
|
||||
| WebSearchTool.ConfigService
|
||||
|
||||
export interface Plugin<R = never> {
|
||||
readonly id: string
|
||||
readonly effect: (context: PluginContext) => Effect.Effect<void, never, R | Scope.Scope>
|
||||
}
|
||||
|
||||
export function define<R>(plugin: Plugin<R>) {
|
||||
return plugin
|
||||
}
|
||||
|
||||
const layer = Layer.effectDiscard(
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const sdkPlugins = yield* SdkPlugins.Service
|
||||
const services = Context.mergeAll(
|
||||
Context.make(Catalog.Service, yield* Catalog.Service),
|
||||
Context.make(CommandV2.Service, yield* CommandV2.Service),
|
||||
Context.make(Integration.Service, yield* Integration.Service),
|
||||
Context.make(AgentV2.Service, yield* AgentV2.Service),
|
||||
Context.make(Config.Service, yield* Config.Service),
|
||||
Context.make(Location.Service, yield* Location.Service),
|
||||
Context.make(ModelsDev.Service, yield* ModelsDev.Service),
|
||||
Context.make(Npm.Service, yield* Npm.Service),
|
||||
Context.make(EventV2.Service, yield* EventV2.Service),
|
||||
Context.make(FSUtil.Service, yield* FSUtil.Service),
|
||||
Context.make(FileSystem.Service, yield* FileSystem.Service),
|
||||
Context.make(Global.Service, yield* Global.Service),
|
||||
Context.make(HttpClient.HttpClient, yield* HttpClient.HttpClient),
|
||||
Context.make(LocationMutation.Service, yield* LocationMutation.Service),
|
||||
Context.make(FileMutation.Service, yield* FileMutation.Service),
|
||||
Context.make(Image.Service, yield* Image.Service),
|
||||
Context.make(PermissionV2.Service, yield* PermissionV2.Service),
|
||||
Context.make(QuestionV2.Service, yield* QuestionV2.Service),
|
||||
Context.make(ReadToolFileSystem.Service, yield* ReadToolFileSystem.Service),
|
||||
Context.make(SessionInstructions.Service, yield* SessionInstructions.Service),
|
||||
Context.make(SessionTodo.Service, yield* SessionTodo.Service),
|
||||
Context.make(SkillV2.Service, yield* SkillV2.Service),
|
||||
Context.make(Reference.Service, yield* Reference.Service),
|
||||
Context.make(Ripgrep.Service, yield* Ripgrep.Service),
|
||||
Context.make(Shell.Service, yield* Shell.Service),
|
||||
Context.make(Tools.Service, yield* Tools.Service),
|
||||
Context.make(PluginRuntime.Service, yield* PluginRuntime.Service),
|
||||
Context.make(WebSearchTool.ConfigService, yield* WebSearchTool.ConfigService),
|
||||
)
|
||||
const add = (input: Plugin<Requirements | Scope.Scope>) =>
|
||||
plugin.add(PluginV2.ID.make(input.id), (context: PluginContext) =>
|
||||
input.effect(context).pipe(Effect.provide(services)),
|
||||
)
|
||||
|
||||
yield* State.batch(
|
||||
Effect.gen(function* () {
|
||||
yield* add(ConfigReferencePlugin.Plugin)
|
||||
yield* add(AgentPlugin.Plugin)
|
||||
yield* add(CommandPlugin.Plugin)
|
||||
yield* add(SkillPlugin.Plugin)
|
||||
yield* add(ModelsDevPlugin)
|
||||
yield* add(ConfigExternalPlugin.Plugin)
|
||||
yield* add(ApplyPatchTool.Plugin)
|
||||
yield* add(EditTool.Plugin)
|
||||
yield* add(GlobTool.Plugin)
|
||||
yield* add(GrepTool.Plugin)
|
||||
yield* add(QuestionTool.Plugin)
|
||||
yield* add(ReadTool.Plugin)
|
||||
yield* add(ShellTool.Plugin)
|
||||
yield* add(SkillTool.Plugin)
|
||||
yield* add(SubagentTool.Plugin)
|
||||
yield* add(TodoWriteTool.Plugin)
|
||||
yield* add(WebFetchTool.Plugin)
|
||||
yield* add(WebSearchTool.Plugin)
|
||||
yield* add(WriteTool.Plugin)
|
||||
yield* add(ConfigAgentPlugin.Plugin)
|
||||
yield* add(ConfigCommandPlugin.Plugin)
|
||||
yield* add(ConfigSkillPlugin.Plugin)
|
||||
for (const item of ProviderPlugins) yield* add(item)
|
||||
yield* add(ConfigProviderPlugin.Plugin)
|
||||
yield* add(VariantPlugin.Plugin)
|
||||
// Embedder-contributed plugins are added last so they layer over config.
|
||||
for (const plugin of sdkPlugins.all()) yield* add(plugin)
|
||||
}),
|
||||
).pipe(Effect.withSpan("PluginInternal.boot"), Effect.forkScoped({ startImmediately: true }))
|
||||
}),
|
||||
)
|
||||
|
||||
export const node = makeLocationNode({
|
||||
name: "plugin-internal",
|
||||
layer,
|
||||
deps: [
|
||||
Catalog.node,
|
||||
CommandV2.node,
|
||||
PluginV2.node,
|
||||
Integration.node,
|
||||
AgentV2.node,
|
||||
Config.node,
|
||||
Location.node,
|
||||
LocationMutation.node,
|
||||
FileMutation.node,
|
||||
Image.node,
|
||||
ModelsDev.node,
|
||||
Npm.node,
|
||||
EventV2.node,
|
||||
FSUtil.node,
|
||||
FileSystem.node,
|
||||
Global.node,
|
||||
httpClient,
|
||||
PermissionV2.node,
|
||||
QuestionV2.node,
|
||||
ReadToolFileSystem.node,
|
||||
SessionInstructions.node,
|
||||
SessionTodo.node,
|
||||
SkillV2.node,
|
||||
Reference.node,
|
||||
Ripgrep.node,
|
||||
Shell.node,
|
||||
ToolRegistry.toolsNode,
|
||||
PluginRuntime.node,
|
||||
SdkPlugins.node,
|
||||
WebSearchTool.configNode,
|
||||
],
|
||||
const services = Effect.fn("PluginInternal.services")(function* () {
|
||||
const agent = yield* AgentV2.Service
|
||||
const catalog = yield* Catalog.Service
|
||||
const command = yield* CommandV2.Service
|
||||
const config = yield* Config.Service
|
||||
const events = yield* EventV2.Service
|
||||
const mutation = yield* FileMutation.Service
|
||||
const filesystem = yield* FileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const global = yield* Global.Service
|
||||
const http = yield* HttpClient.HttpClient
|
||||
const image = yield* Image.Service
|
||||
const integration = yield* Integration.Service
|
||||
const location = yield* Location.Service
|
||||
const locationMutation = yield* LocationMutation.Service
|
||||
const models = yield* ModelsDev.Service
|
||||
const npm = yield* Npm.Service
|
||||
const permission = yield* PermissionV2.Service
|
||||
const runtime = yield* PluginRuntime.Service
|
||||
const question = yield* QuestionV2.Service
|
||||
const read = yield* ReadToolFileSystem.Service
|
||||
const reference = yield* Reference.Service
|
||||
const ripgrep = yield* Ripgrep.Service
|
||||
const instructions = yield* SessionInstructions.Service
|
||||
const todo = yield* SessionTodo.Service
|
||||
const shell = yield* Shell.Service
|
||||
const skill = yield* SkillV2.Service
|
||||
const tools = yield* Tools.Service
|
||||
const websearch = yield* WebSearchTool.ConfigService
|
||||
return Context.mergeAll(
|
||||
Context.make(AgentV2.Service, agent),
|
||||
Context.make(Catalog.Service, catalog),
|
||||
Context.make(CommandV2.Service, command),
|
||||
Context.make(Config.Service, config),
|
||||
Context.make(EventV2.Service, events),
|
||||
Context.make(FileMutation.Service, mutation),
|
||||
Context.make(FileSystem.Service, filesystem),
|
||||
Context.make(FSUtil.Service, fs),
|
||||
Context.make(Global.Service, global),
|
||||
Context.make(HttpClient.HttpClient, http),
|
||||
Context.make(Image.Service, image),
|
||||
Context.make(Integration.Service, integration),
|
||||
Context.make(Location.Service, location),
|
||||
Context.make(LocationMutation.Service, locationMutation),
|
||||
Context.make(ModelsDev.Service, models),
|
||||
Context.make(Npm.Service, npm),
|
||||
Context.make(PermissionV2.Service, permission),
|
||||
Context.make(PluginRuntime.Service, runtime),
|
||||
Context.make(QuestionV2.Service, question),
|
||||
Context.make(ReadToolFileSystem.Service, read),
|
||||
Context.make(Reference.Service, reference),
|
||||
Context.make(Ripgrep.Service, ripgrep),
|
||||
Context.make(SessionInstructions.Service, instructions),
|
||||
Context.make(SessionTodo.Service, todo),
|
||||
Context.make(Shell.Service, shell),
|
||||
Context.make(SkillV2.Service, skill),
|
||||
Context.make(Tools.Service, tools),
|
||||
Context.make(WebSearchTool.ConfigService, websearch),
|
||||
)
|
||||
})
|
||||
|
||||
type ContextServices<A> = A extends Context.Context<infer R> ? R : never
|
||||
|
||||
export type Requirements = ContextServices<Effect.Success<ReturnType<typeof services>>>
|
||||
|
||||
export type InternalPlugin = Plugin<Requirements | Scope.Scope>
|
||||
|
||||
const pre = [
|
||||
AgentPlugin.Plugin,
|
||||
CommandPlugin.Plugin,
|
||||
SkillPlugin.Plugin,
|
||||
ModelsDevPlugin,
|
||||
...ProviderPlugins,
|
||||
ApplyPatchTool.Plugin,
|
||||
EditTool.Plugin,
|
||||
GlobTool.Plugin,
|
||||
GrepTool.Plugin,
|
||||
QuestionTool.Plugin,
|
||||
ReadTool.Plugin,
|
||||
ShellTool.Plugin,
|
||||
SkillTool.Plugin,
|
||||
SubagentTool.Plugin,
|
||||
TodoWriteTool.Plugin,
|
||||
WebFetchTool.Plugin,
|
||||
WebSearchTool.Plugin,
|
||||
WriteTool.Plugin,
|
||||
] as const satisfies readonly InternalPlugin[]
|
||||
|
||||
const post = [
|
||||
ConfigReferencePlugin.Plugin,
|
||||
ConfigAgentPlugin.Plugin,
|
||||
ConfigCommandPlugin.Plugin,
|
||||
ConfigSkillPlugin.Plugin,
|
||||
ConfigProviderPlugin.Plugin,
|
||||
VariantPlugin.Plugin,
|
||||
] as const satisfies readonly InternalPlugin[]
|
||||
|
||||
export const list = Effect.fn("PluginInternal.list")(function* () {
|
||||
const context = yield* services()
|
||||
const resolve = (plugins: readonly InternalPlugin[]) =>
|
||||
plugins.map(
|
||||
(plugin): Plugin => ({
|
||||
id: plugin.id,
|
||||
effect: (host) => plugin.effect(host).pipe(Effect.provide(context)),
|
||||
}),
|
||||
)
|
||||
return {
|
||||
pre: resolve(pre),
|
||||
post: resolve(post),
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue