diff --git a/packages/core/src/plugin/internal.ts b/packages/core/src/plugin/internal.ts index 25a8d4a9ca..f522e85a66 100644 --- a/packages/core/src/plugin/internal.ts +++ b/packages/core/src/plugin/internal.ts @@ -3,7 +3,7 @@ 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 { Effect, Layer, Scope } from "effect" +import { Context, Effect, Layer, Scope } from "effect" import { AgentV2 } from "../agent" import { Catalog } from "../catalog" import { CommandV2 } from "../command" @@ -27,6 +27,7 @@ import { PluginV2 } from "../plugin" import { PluginRuntime } from "../plugin/runtime" import { PermissionV2 } from "../permission" import { Reference } from "../reference" +import { Ripgrep } from "../ripgrep" import { Shell } from "../shell" import { SkillV2 } from "../skill" import { State } from "../state" @@ -40,6 +41,7 @@ import { ProviderPlugins } from "./provider" import { SdkPlugins } from "./sdk" import { SkillPlugin } from "./skill" import { VariantPlugin } from "./variant" +import { GlobTool } from "../tool/glob" import { ShellTool } from "../tool/shell" import { SubagentTool } from "../tool/subagent" @@ -61,6 +63,7 @@ export type Requirements = | PermissionV2.Service | PluginRuntime.Service | Reference.Service + | Ripgrep.Service | Shell.Service | SkillV2.Service | Tools.Service @@ -76,59 +79,35 @@ export function define(plugin: Plugin) { const layer = Layer.effectDiscard( Effect.gen(function* () { - const catalog = yield* Catalog.Service - const commands = yield* CommandV2.Service const plugin = yield* PluginV2.Service const sdkPlugins = yield* SdkPlugins.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 http = yield* HttpClient.HttpClient - const mutation = yield* LocationMutation.Service - const permission = yield* PermissionV2.Service - const skill = yield* SkillV2.Service - const reference = yield* Reference.Service - const shell = yield* Shell.Service - const tools = yield* Tools.Service - const runtime = yield* PluginRuntime.Service - const add = (input: Plugin) => { - const loaded = { - 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(HttpClient.HttpClient, http), - Effect.provideService(LocationMutation.Service, mutation), - Effect.provideService(PermissionV2.Service, permission), - Effect.provideService(SkillV2.Service, skill), - Effect.provideService(Reference.Service, reference), - Effect.provideService(Shell.Service, shell), - Effect.provideService(Tools.Service, tools), - Effect.provideService(PluginRuntime.Service, runtime), - ), - } - return plugin.add(PluginV2.ID.make(loaded.id), loaded.effect) - } + 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(PermissionV2.Service, yield* PermissionV2.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), + ) + const add = (input: Plugin) => + plugin.add(PluginV2.ID.make(input.id), (context: PluginContext) => + input.effect(context).pipe(Effect.provide(services)), + ) yield* State.batch( Effect.gen(function* () { @@ -138,6 +117,7 @@ const layer = Layer.effectDiscard( yield* add(SkillPlugin.Plugin) yield* add(ModelsDevPlugin) yield* add(ConfigExternalPlugin.Plugin) + yield* add(GlobTool.Plugin) yield* add(ShellTool.Plugin) yield* add(SubagentTool.Plugin) yield* add(ConfigAgentPlugin.Plugin) @@ -175,6 +155,7 @@ export const node = makeLocationNode({ PermissionV2.node, SkillV2.node, Reference.node, + Ripgrep.node, Shell.node, ToolRegistry.toolsNode, PluginRuntime.node, diff --git a/packages/core/src/tool/builtins.ts b/packages/core/src/tool/builtins.ts index 65473d1620..c72d07d0e7 100644 --- a/packages/core/src/tool/builtins.ts +++ b/packages/core/src/tool/builtins.ts @@ -4,7 +4,6 @@ import { makeLocationNode } from "../effect/app-node" import { Context, Layer } from "effect" import { ApplyPatchTool } from "./apply-patch" import { EditTool } from "./edit" -import { GlobTool } from "./glob" import { GrepTool } from "./grep" import { QuestionTool } from "./question" import { ReadTool } from "./read" @@ -38,7 +37,6 @@ export const node = makeLocationNode({ deps: [ ApplyPatchTool.node, EditTool.node, - GlobTool.node, GrepTool.node, QuestionTool.node, ReadTool.node, diff --git a/packages/core/src/tool/glob.ts b/packages/core/src/tool/glob.ts index f8bd1869e1..d4412ae302 100644 --- a/packages/core/src/tool/glob.ts +++ b/packages/core/src/tool/glob.ts @@ -1,17 +1,15 @@ export * as GlobTool from "./glob" import { ToolFailure } from "@opencode-ai/llm" -import { Effect, Layer, Schema } from "effect" +import type { PluginContext } from "@opencode-ai/plugin/v2/effect" +import { Effect, Schema } from "effect" import path from "path" -import { makeLocationNode } from "../effect/app-node" import { FileSystem } from "../filesystem" import { Location } from "../location" import { Ripgrep } from "../ripgrep" import { RelativePath } from "../schema" import { PermissionV2 } from "../permission" -import { ToolRegistry } from "./registry" import { Tool } from "./tool" -import { Tools } from "./tools" export const name = "glob" @@ -35,14 +33,14 @@ export const toModelOutput = (output: ModelOutput) => { } /** Glob leaf that defaults its filesystem root to the active Location. */ -const layer = Layer.effectDiscard( - Effect.gen(function* () { - const tools = yield* Tools.Service +export const Plugin = { + id: "core-glob-tool", + effect: Effect.fn("GlobTool.Plugin")(function* (ctx: PluginContext) { const ripgrep = yield* Ripgrep.Service const location = yield* Location.Service const permission = yield* PermissionV2.Service - yield* tools + yield* ctx.tool .register({ [name]: Tool.make({ description: @@ -96,10 +94,4 @@ const layer = Layer.effectDiscard( }) .pipe(Effect.orDie) }), -) - -export const node = makeLocationNode({ - name: "tool/glob", - layer, - deps: [ToolRegistry.node, Ripgrep.node, Location.node, PermissionV2.node], -}) +} diff --git a/packages/core/test/location-layer.test.ts b/packages/core/test/location-layer.test.ts index f1fa19864e..2b5bd55c52 100644 --- a/packages/core/test/location-layer.test.ts +++ b/packages/core/test/location-layer.test.ts @@ -24,9 +24,7 @@ import { EventV2 } from "../src/event" import { Reference } from "../src/reference" import { ToolRegistry } from "../src/tool/registry" -const it = testEffect( - AppNodeBuilder.build(LayerNode.group([Database.node, EventV2.node, LocationServiceMap.node])), -) +const it = testEffect(AppNodeBuilder.build(LayerNode.group([Database.node, EventV2.node, LocationServiceMap.node]))) describe("LocationServiceMap", () => { it.live("reuses cached services for constructed and decoded location refs", () => @@ -75,6 +73,7 @@ describe("LocationServiceMap", () => { const catalog = yield* Catalog.Service yield* catalog.transform((editor) => editor.provider.update(ProviderV2.ID.make("test"), () => {})) const registry = yield* ToolRegistry.Service + yield* waitForTool(registry, "glob") yield* waitForTool(registry, "shell") yield* waitForTool(registry, "subagent") return {