diff --git a/packages/opencode/test/plugin/trigger.test.ts b/packages/opencode/test/plugin/trigger.test.ts index 972ba61b14..5e16af42be 100644 --- a/packages/opencode/test/plugin/trigger.test.ts +++ b/packages/opencode/test/plugin/trigger.test.ts @@ -1,18 +1,18 @@ -import { afterAll, afterEach, describe, expect, test } from "bun:test" -import { Effect } from "effect" +import { afterAll, describe, expect } from "bun:test" +import { Effect, Layer } from "effect" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import path from "path" import { pathToFileURL } from "url" -import { tmpdir } from "../fixture/fixture" +import { ModelID, ProviderID } from "../../src/provider/schema" +import { provideTmpdirInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1" const { Plugin } = await import("../../src/plugin/index") -const { Instance } = await import("../../src/project/instance") - -afterEach(async () => { - await Instance.disposeAll() -}) +const it = testEffect(Layer.mergeAll(Plugin.defaultLayer, CrossSpawnSpawner.defaultLayer)) +const systemHook = "experimental.chat.system.transform" afterAll(() => { if (disableDefault === undefined) { @@ -22,95 +22,81 @@ afterAll(() => { process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault }) -async function project(source: string) { - return tmpdir({ - init: async (dir) => { +function withProject(source: string, self: Effect.Effect) { + return provideTmpdirInstance((dir) => + Effect.gen(function* () { const file = path.join(dir, "plugin.ts") - await Bun.write(file, source) - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify( - { - $schema: "https://opencode.ai/config.json", - plugin: [pathToFileURL(file).href], - }, - null, - 2, - ), + yield* Effect.all( + [ + Effect.promise(() => Bun.write(file, source)), + Effect.promise(() => + Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify( + { + $schema: "https://opencode.ai/config.json", + plugin: [pathToFileURL(file).href], + }, + null, + 2, + ), + ), + ), + ], + { discard: true, concurrency: 2 }, ) - }, - }) + return yield* self + }), + ) } +const triggerSystemTransform = Effect.fn("PluginTriggerTest.triggerSystemTransform")(function* () { + const plugin = yield* Plugin.Service + const out = { system: [] as string[] } + yield* plugin.trigger( + systemHook, + { + model: { + providerID: ProviderID.anthropic, + modelID: ModelID.make("claude-sonnet-4-6"), + }, + }, + out, + ) + return out.system +}) + describe("plugin.trigger", () => { - test("runs synchronous hooks without crashing", async () => { - await using tmp = await project( + it.live("runs synchronous hooks without crashing", () => + withProject( [ "export default async () => ({", - ' "experimental.chat.system.transform": (_input, output) => {', + ` ${JSON.stringify(systemHook)}: (_input, output) => {`, ' output.system.unshift("sync")', " },", "})", "", ].join("\n"), - ) + Effect.gen(function* () { + expect(yield* triggerSystemTransform()).toEqual(["sync"]) + }), + ), + ) - const out = await Instance.provide({ - directory: tmp.path, - 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"]) - }) - - test("awaits asynchronous hooks", async () => { - await using tmp = await project( + it.live("awaits asynchronous hooks", () => + withProject( [ "export default async () => ({", - ' "experimental.chat.system.transform": async (_input, output) => {', + ` ${JSON.stringify(systemHook)}: async (_input, output) => {`, " await Bun.sleep(1)", ' output.system.unshift("async")', " },", "})", "", ].join("\n"), - ) - - const out = await Instance.provide({ - directory: tmp.path, - 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"]) - }) + Effect.gen(function* () { + expect(yield* triggerSystemTransform()).toEqual(["async"]) + }), + ), + ) })