plugin.test.ts 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Exit, Fiber } from "effect"
  3. import { define } from "@opencode-ai/plugin/v2/effect"
  4. import { AgentV2 } from "@opencode-ai/core/agent"
  5. import { PluginV2 } from "@opencode-ai/core/plugin"
  6. import { testEffect } from "./lib/effect"
  7. import { PluginTestLayer } from "./plugin/fixture"
  8. const it = testEffect(PluginTestLayer)
  9. describe("PluginV2", () => {
  10. it.effect("waits for a plugin and returns immediately once active", () =>
  11. Effect.gen(function* () {
  12. const plugins = yield* PluginV2.Service
  13. const id = PluginV2.ID.make("waited")
  14. const waiting = yield* plugins.wait(id).pipe(Effect.forkChild)
  15. yield* plugins.add(id, () => Effect.void)
  16. yield* Fiber.join(waiting)
  17. yield* plugins.wait(id)
  18. }),
  19. )
  20. it.effect("propagates plugin activation defects to waiters", () =>
  21. Effect.gen(function* () {
  22. const plugins = yield* PluginV2.Service
  23. const id = PluginV2.ID.make("failed")
  24. const waiting = yield* plugins.wait(id).pipe(Effect.exit, Effect.forkChild)
  25. const added = yield* plugins.add(id, () => Effect.die("boom")).pipe(Effect.exit)
  26. const pending = yield* Fiber.join(waiting)
  27. const later = yield* plugins.wait(id).pipe(Effect.exit)
  28. expect(Exit.isFailure(added)).toBe(true)
  29. expect(Exit.isFailure(pending)).toBe(true)
  30. expect(Exit.isFailure(later)).toBe(true)
  31. }),
  32. )
  33. it.effect("adds, replaces, and removes plugins", () =>
  34. Effect.gen(function* () {
  35. const plugins = yield* PluginV2.Service
  36. const agents = yield* AgentV2.Service
  37. let description = "first"
  38. const managed = () =>
  39. define({
  40. id: "managed",
  41. effect: (ctx) =>
  42. ctx.agent
  43. .transform((agents) =>
  44. agents.update("configured", (agent) => {
  45. agent.description = description
  46. }),
  47. )
  48. .pipe(Effect.asVoid),
  49. })
  50. yield* plugins.add(PluginV2.ID.make("managed"), managed().effect)
  51. expect((yield* agents.get(AgentV2.ID.make("configured")))?.description).toBe("first")
  52. description = "second"
  53. yield* plugins.add(PluginV2.ID.make("managed"), managed().effect)
  54. expect((yield* agents.get(AgentV2.ID.make("configured")))?.description).toBe("second")
  55. yield* plugins.remove(PluginV2.ID.make("managed"))
  56. expect(yield* agents.get(AgentV2.ID.make("configured"))).toBeUndefined()
  57. }),
  58. )
  59. })