Kaynağa Gözat

Merge branch 'dev' into brendan/effect-env

Brendan Allan 1 hafta önce
ebeveyn
işleme
c2f6135daf

+ 3 - 3
packages/opencode/src/agent/agent.ts

@@ -73,6 +73,7 @@ export namespace Agent {
     Effect.gen(function* () {
       const config = yield* Config.Service
       const auth = yield* Auth.Service
+      const plugin = yield* Plugin.Service
       const skill = yield* Skill.Service
       const provider = yield* Provider.Service
 
@@ -335,9 +336,7 @@ export namespace Agent {
           const language = yield* provider.getLanguage(resolved)
 
           const system = [PROMPT_GENERATE]
-          yield* Effect.promise(() =>
-            Plugin.trigger("experimental.chat.system.transform", { model: resolved }, { system }),
-          )
+          yield* plugin.trigger("experimental.chat.system.transform", { model: resolved }, { system })
           const existing = yield* InstanceState.useEffect(state, (s) => s.list())
 
           // TODO: clean this up so provider specific logic doesnt bleed over
@@ -398,6 +397,7 @@ export namespace Agent {
   )
 
   export const defaultLayer = layer.pipe(
+    Layer.provide(Plugin.defaultLayer),
     Layer.provide(Provider.defaultLayer),
     Layer.provide(Auth.defaultLayer),
     Layer.provide(Config.defaultLayer),

+ 9 - 3
packages/opencode/src/cli/cmd/providers.ts

@@ -340,6 +340,12 @@ export const ProvidersLoginCommand = cmd({
           }
           return filtered
         })
+        const hooks = await AppRuntime.runPromise(
+          Effect.gen(function* () {
+            const plugin = yield* Plugin.Service
+            return yield* plugin.list()
+          }),
+        )
 
         const priority: Record<string, number> = {
           opencode: 0,
@@ -351,7 +357,7 @@ export const ProvidersLoginCommand = cmd({
           vercel: 6,
         }
         const pluginProviders = resolvePluginProviders({
-          hooks: await Plugin.list(),
+          hooks,
           existingProviders: providers,
           disabled,
           enabled,
@@ -408,7 +414,7 @@ export const ProvidersLoginCommand = cmd({
           provider = selected as string
         }
 
-        const plugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
+        const plugin = hooks.findLast((x) => x.auth?.provider === provider)
         if (plugin && plugin.auth) {
           const handled = await handlePluginAuth({ auth: plugin.auth }, provider, args.method)
           if (handled) return
@@ -422,7 +428,7 @@ export const ProvidersLoginCommand = cmd({
           if (prompts.isCancel(custom)) throw new UI.CancelledError()
           provider = custom.replace(/^@ai-sdk\//, "")
 
-          const customPlugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
+          const customPlugin = hooks.findLast((x) => x.auth?.provider === provider)
           if (customPlugin && customPlugin.auth) {
             const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider, args.method)
             if (handled) return

+ 0 - 18
packages/opencode/src/plugin/index.ts

@@ -20,7 +20,6 @@ import { CloudflareAIGatewayAuthPlugin, CloudflareWorkersAuthPlugin } from "./cl
 import { Effect, Layer, Context, Stream } from "effect"
 import { EffectLogger } from "@/effect/logger"
 import { InstanceState } from "@/effect/instance-state"
-import { makeRuntime } from "@/effect/run-service"
 import { errorMessage } from "@/util/error"
 import { PluginLoader } from "./loader"
 import { parsePluginSpecifier, readPluginId, readV1Plugin, resolvePluginId } from "./shared"
@@ -290,21 +289,4 @@ export namespace Plugin {
   )
 
   export const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(Config.defaultLayer))
-  const { runPromise } = makeRuntime(Service, defaultLayer)
-
-  export async function trigger<
-    Name extends TriggerName,
-    Input = Parameters<Required<Hooks>[Name]>[0],
-    Output = Parameters<Required<Hooks>[Name]>[1],
-  >(name: Name, input: Input, output: Output): Promise<Output> {
-    return runPromise((svc) => svc.trigger(name, input, output))
-  }
-
-  export async function list(): Promise<Hooks[]> {
-    return runPromise((svc) => svc.list())
-  }
-
-  export async function init() {
-    return runPromise((svc) => svc.init())
-  }
 }

+ 6 - 3
packages/opencode/test/plugin/loader-shared.test.ts

@@ -1,4 +1,5 @@
 import { afterAll, afterEach, describe, expect, spyOn, test } from "bun:test"
+import { Effect } from "effect"
 import fs from "fs/promises"
 import path from "path"
 import { pathToFileURL } from "url"
@@ -29,9 +30,11 @@ afterEach(async () => {
 async function load(dir: string) {
   return Instance.provide({
     directory: dir,
-    fn: async () => {
-      await Plugin.list()
-    },
+    fn: async () =>
+      Effect.gen(function* () {
+        const plugin = yield* Plugin.Service
+        yield* plugin.list()
+      }).pipe(Effect.provide(Plugin.defaultLayer), Effect.runPromise),
   })
 }
 

+ 33 - 28
packages/opencode/test/plugin/trigger.test.ts

@@ -1,4 +1,5 @@
 import { afterAll, afterEach, describe, expect, test } from "bun:test"
+import { Effect } from "effect"
 import path from "path"
 import { pathToFileURL } from "url"
 import { tmpdir } from "../fixture/fixture"
@@ -56,20 +57,22 @@ describe("plugin.trigger", () => {
 
     const out = await Instance.provide({
       directory: tmp.path,
-      fn: async () => {
-        const out = { system: [] as string[] }
-        await Plugin.trigger(
-          "experimental.chat.system.transform",
-          {
-            model: {
-              providerID: "anthropic",
-              modelID: "claude-sonnet-4-6",
-            } as any,
-          },
-          out,
-        )
-        return out
-      },
+      fn: async () =>
+        Effect.gen(function* () {
+          const plugin = yield* Plugin.Service
+          const out = { system: [] as string[] }
+          yield* plugin.trigger(
+            "experimental.chat.system.transform",
+            {
+              model: {
+                providerID: "anthropic",
+                modelID: "claude-sonnet-4-6",
+              } as any,
+            },
+            out,
+          )
+          return out
+        }).pipe(Effect.provide(Plugin.defaultLayer), Effect.runPromise),
     })
 
     expect(out.system).toEqual(["sync"])
@@ -90,20 +93,22 @@ describe("plugin.trigger", () => {
 
     const out = await Instance.provide({
       directory: tmp.path,
-      fn: async () => {
-        const out = { system: [] as string[] }
-        await Plugin.trigger(
-          "experimental.chat.system.transform",
-          {
-            model: {
-              providerID: "anthropic",
-              modelID: "claude-sonnet-4-6",
-            } as any,
-          },
-          out,
-        )
-        return out
-      },
+      fn: async () =>
+        Effect.gen(function* () {
+          const plugin = yield* Plugin.Service
+          const out = { system: [] as string[] }
+          yield* plugin.trigger(
+            "experimental.chat.system.transform",
+            {
+              model: {
+                providerID: "anthropic",
+                modelID: "claude-sonnet-4-6",
+              } as any,
+            },
+            out,
+          )
+          return out
+        }).pipe(Effect.provide(Plugin.defaultLayer), Effect.runPromise),
     })
 
     expect(out.system).toEqual(["async"])

+ 12 - 9
packages/opencode/test/plugin/workspace-adaptor.test.ts

@@ -1,4 +1,5 @@
 import { afterAll, afterEach, describe, expect, test } from "bun:test"
+import { Effect } from "effect"
 import path from "path"
 import { pathToFileURL } from "url"
 import { tmpdir } from "../fixture/fixture"
@@ -72,15 +73,17 @@ describe("plugin.workspace", () => {
 
     const info = await Instance.provide({
       directory: tmp.path,
-      fn: async () => {
-        await Plugin.init()
-        return Workspace.create({
-          type: tmp.extra.type,
-          branch: null,
-          extra: { key: "value" },
-          projectID: Instance.project.id,
-        })
-      },
+      fn: async () =>
+        Effect.gen(function* () {
+          const plugin = yield* Plugin.Service
+          yield* plugin.init()
+          return Workspace.create({
+            type: tmp.extra.type,
+            branch: null,
+            extra: { key: "value" },
+            projectID: Instance.project.id,
+          })
+        }).pipe(Effect.provide(Plugin.defaultLayer), Effect.runPromise),
     })
 
     expect(info.type).toBe(tmp.extra.type)

+ 9 - 4
packages/opencode/test/provider/provider.test.ts

@@ -2436,10 +2436,15 @@ test("plugin config providers persist after instance dispose", async () => {
 
   const first = await Instance.provide({
     directory: tmp.path,
-    fn: async () => {
-      await Plugin.init()
-      return list()
-    },
+    fn: async () =>
+      AppRuntime.runPromise(
+        Effect.gen(function* () {
+          const plugin = yield* Plugin.Service
+          const provider = yield* Provider.Service
+          yield* plugin.init()
+          return yield* provider.list()
+        }),
+      ),
   })
   expect(first[ProviderID.make("demo")]).toBeDefined()
   expect(first[ProviderID.make("demo")].models[ModelID.make("chat")]).toBeDefined()