summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/opencode/src/agent/agent.ts6
-rw-r--r--packages/opencode/src/cli/cmd/providers.ts12
-rw-r--r--packages/opencode/src/plugin/index.ts18
-rw-r--r--packages/opencode/test/plugin/loader-shared.test.ts9
-rw-r--r--packages/opencode/test/plugin/trigger.test.ts61
-rw-r--r--packages/opencode/test/plugin/workspace-adaptor.test.ts21
-rw-r--r--packages/opencode/test/provider/provider.test.ts13
7 files changed, 72 insertions, 68 deletions
diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts
index cebcaa048..562c90cc0 100644
--- a/packages/opencode/src/agent/agent.ts
+++ b/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),
diff --git a/packages/opencode/src/cli/cmd/providers.ts b/packages/opencode/src/cli/cmd/providers.ts
index 8d6159c9a..5d5cd1ff8 100644
--- a/packages/opencode/src/cli/cmd/providers.ts
+++ b/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
diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts
index 60942915a..0dc53d997 100644
--- a/packages/opencode/src/plugin/index.ts
+++ b/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())
- }
}
diff --git a/packages/opencode/test/plugin/loader-shared.test.ts b/packages/opencode/test/plugin/loader-shared.test.ts
index 32b6c601d..5f1e2b168 100644
--- a/packages/opencode/test/plugin/loader-shared.test.ts
+++ b/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),
})
}
diff --git a/packages/opencode/test/plugin/trigger.test.ts b/packages/opencode/test/plugin/trigger.test.ts
index d89d930c6..972ba61b1 100644
--- a/packages/opencode/test/plugin/trigger.test.ts
+++ b/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"])
diff --git a/packages/opencode/test/plugin/workspace-adaptor.test.ts b/packages/opencode/test/plugin/workspace-adaptor.test.ts
index cc098b124..a5f56df5e 100644
--- a/packages/opencode/test/plugin/workspace-adaptor.test.ts
+++ b/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)
diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts
index 73e77be5f..ac990bc0f 100644
--- a/packages/opencode/test/provider/provider.test.ts
+++ b/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()