From f66c8292316184e536fc1b725469f026a0357594 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Sat, 4 Jul 2026 01:54:30 -0400 Subject: [PATCH] Revert "fix(core): bust external plugin import cache" This reverts commit afe3ebbc35731131893b98893e8fadfbcf4562dd. --- packages/core/src/config/plugin/external.ts | 19 +----- packages/core/test/config/plugin.test.ts | 73 --------------------- 2 files changed, 2 insertions(+), 90 deletions(-) diff --git a/packages/core/src/config/plugin/external.ts b/packages/core/src/config/plugin/external.ts index 29a63396a9..c67f67d481 100644 --- a/packages/core/src/config/plugin/external.ts +++ b/packages/core/src/config/plugin/external.ts @@ -3,7 +3,6 @@ export * as ConfigExternalPlugin from "./external" import type { Plugin as EffectPlugin } from "@opencode-ai/plugin/v2/effect" import type { Plugin as PromisePlugin } from "@opencode-ai/plugin/v2/promise" import { Effect, Schema, Stream } from "effect" -import { createRequire } from "node:module" import path from "path" import { fileURLToPath, pathToFileURL } from "url" import { Config } from "../../config" @@ -36,9 +35,6 @@ const PluginPackage = Schema.Struct({ module: Schema.optional(Schema.String), }) -let importGeneration = 0 -const moduleCache = createRequire(import.meta.url).cache - export const Plugin = define({ id: "config-plugin", effect: Effect.fn(function* (ctx) { @@ -110,7 +106,7 @@ export const Plugin = define({ : (yield* npm.add(ref.package)).entrypoint if (!entrypoint) return yield* Effect.log({ msg: "loading plugin", id: ref.package, entrypoint }) - const mod = yield* Effect.promise(() => import(cacheBust(entrypoint))) + const mod = yield* Effect.promise(() => import(entrypoint)) const value = (yield* Schema.decodeUnknownEffect(PluginModule)(mod)).default const plugin = "effect" in value ? value : PluginPromise.fromPromise(value) return { @@ -118,11 +114,7 @@ export const Plugin = define({ effect: (host: Parameters[0]) => plugin.effect({ ...host, options: ref.options ?? {} }), } - }).pipe( - Effect.catchCause((cause) => - Effect.logError("failed to load plugin", { package: ref.package, cause }).pipe(Effect.as(undefined)), - ), - ), + }).pipe(Effect.catchCause(() => Effect.succeed(undefined))), ).pipe(Effect.map((plugins) => plugins.filter((plugin) => plugin !== undefined))) }) const reconcile = Effect.fn("ConfigExternalPlugin.reconcile")(function* () { @@ -145,13 +137,6 @@ export const Plugin = define({ }), }) -function cacheBust(entrypoint: string) { - const url = path.isAbsolute(entrypoint) ? pathToFileURL(entrypoint) : new URL(entrypoint) - if (url.protocol === "file:") delete moduleCache[fileURLToPath(url)] - url.searchParams.set("opencode-reload", String(++importGeneration)) - return url.href -} - const resolvePackageEntrypoint = Effect.fnUntraced(function* (fs: FSUtil.Interface, directory: string) { const pkg = yield* fs.readJson(path.join(directory, "package.json")).pipe( Effect.flatMap(Schema.decodeUnknownEffect(PluginPackage)), diff --git a/packages/core/test/config/plugin.test.ts b/packages/core/test/config/plugin.test.ts index 8a28077c3e..b72a62df8a 100644 --- a/packages/core/test/config/plugin.test.ts +++ b/packages/core/test/config/plugin.test.ts @@ -1,19 +1,15 @@ -import fs from "fs/promises" import path from "path" import { describe, expect } from "bun:test" -import { Config as ConfigSchema } from "@opencode-ai/schema/config" import { Effect, Schema } from "effect" import { AgentV2 } from "@opencode-ai/core/agent" import { Config } from "@opencode-ai/core/config" import { ConfigExternalPlugin } from "@opencode-ai/core/config/plugin/external" -import { EventV2 } from "@opencode-ai/core/event" import { FSUtil } from "@opencode-ai/core/fs-util" import { Location } from "@opencode-ai/core/location" import { Npm } from "@opencode-ai/core/npm" import { PluginV2 } from "@opencode-ai/core/plugin" import { PluginHost } from "@opencode-ai/core/plugin/host" import { AbsolutePath } from "@opencode-ai/core/schema" -import { tmpdir } from "../fixture/tmpdir" import { testEffect } from "../lib/effect" import { PluginTestLayer } from "../plugin/fixture" @@ -244,49 +240,6 @@ describe("ConfigExternalPlugin", () => { }) }), ) - - it.live("reloads changed plugin source from the same entrypoint", () => - Effect.acquireRelease( - Effect.promise(() => tmpdir()), - (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), - ).pipe( - Effect.flatMap((tmp) => - Effect.gen(function* () { - const plugins = yield* PluginV2.Service - const agents = yield* AgentV2.Service - const events = yield* EventV2.Service - const fsUtil = yield* FSUtil.Service - const location = yield* Location.Service - const npm = yield* Npm.Service - const host = yield* PluginHost.make(plugins) - const plugin = path.join(tmp.path, "plugin.ts") - const config = Config.Service.of({ - entries: () => - Effect.succeed([ - new Config.Document({ - type: "document", - info: decode({ plugins: [plugin] }), - }), - ]), - }) - - yield* Effect.promise(() => fs.writeFile(plugin, pluginSource("First source"))) - yield* ConfigExternalPlugin.Plugin.effect(host).pipe( - Effect.provideService(PluginV2.Service, plugins), - Effect.provideService(FSUtil.Service, fsUtil), - Effect.provideService(Location.Service, location), - Effect.provideService(Npm.Service, npm), - Effect.provideService(Config.Service, config), - ) - expect((yield* waitForAgent(agents, "hot-reload"))?.description).toBe("First source") - - yield* Effect.promise(() => fs.writeFile(plugin, pluginSource("Second source"))) - yield* events.publish(ConfigSchema.Event.Updated, {}) - expect(yield* waitForAgentDescription(agents, "hot-reload", "Second source")).toBe(true) - }), - ), - ), - ) }) const waitForAgent = Effect.fnUntraced(function* (agents: AgentV2.Interface, id: string) { @@ -297,29 +250,3 @@ const waitForAgent = Effect.fnUntraced(function* (agents: AgentV2.Interface, id: } return yield* Effect.die(`Timed out waiting for agent ${id}`) }) - -const waitForAgentDescription = Effect.fnUntraced(function* ( - agents: AgentV2.Interface, - id: string, - description: string, -) { - for (let attempt = 0; attempt < 100; attempt++) { - if ((yield* agents.get(AgentV2.ID.make(id)))?.description === description) return true - yield* Effect.sleep("10 millis") - } - return false -}) - -function pluginSource(description: string) { - return `export default { - id: "source-hot-reload", - setup: async (ctx) => { - await ctx.agent.transform((agents) => { - agents.update("hot-reload", (agent) => { - agent.description = ${JSON.stringify(description)} - agent.mode = "subagent" - }) - }) - }, -}` -}