diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index d769c30a4..8c60ba150 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -160,7 +160,7 @@ function getLegacyPlugins(mod: Record) { if (seen.has(entry)) continue seen.add(entry) const plugin = getServerPlugin(entry) - if (!plugin) throw new TypeError("Plugin export is not a function") + if (!plugin) continue result.push(plugin) } @@ -374,13 +374,11 @@ export const layer = Layer.effect( return message }, }).pipe( - Effect.catch(() => { - // TODO: make proper events for this - // bus.publish(Session.Event.Error, { - // error: new NamedError.Unknown({ - // message: `Failed to load plugin ${load.spec}: ${message}`, - // }).toObject(), - // }) + Effect.catch((err) => { + log.error("unhandled error in plugin loading pipeline", { + path: load.spec, + error: errorMessage(err), + }) return Effect.void }), ) diff --git a/packages/opencode/test/plugin/loader-shared.test.ts b/packages/opencode/test/plugin/loader-shared.test.ts index cd9d45fae..bdc0ce9f0 100644 --- a/packages/opencode/test/plugin/loader-shared.test.ts +++ b/packages/opencode/test/plugin/loader-shared.test.ts @@ -68,6 +68,38 @@ describe("plugin.loader.shared", () => { expect(await fs.readFile(tmp.extra.mark, "utf8")).toBe("called") }) + test("loads a file:// plugin with non-function exports", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + const file = path.join(dir, "plugin.ts") + const mark = path.join(dir, "called.txt") + await Bun.write( + file, + [ + "export const config = { foo: 'bar' }", + "export type Config = { foo: string }", + "export const VERSION = '1.0.0'", + "export default async () => {", + ` await Bun.write(${JSON.stringify(mark)}, "called")`, + " return {}", + "}", + "", + ].join("\n"), + ) + + await Bun.write( + path.join(dir, "mimocode.json"), + JSON.stringify({ plugin: [pathToFileURL(file).href] }, null, 2), + ) + + return { mark } + }, + }) + + await load(tmp.path) + expect(await fs.readFile(tmp.extra.mark, "utf8")).toBe("called") + }) + test("deduplicates same function exported as default and named", async () => { await using tmp = await tmpdir({ init: async (dir) => {