Avoid bootstrapping server plugins from TUI plugin runtime (#26938)

This commit is contained in:
Kit Langton
2026-05-11 17:32:16 -04:00
committed by GitHub
parent bdd5a80886
commit a5c35bf182
2 changed files with 60 additions and 39 deletions
@@ -17,7 +17,6 @@ import { TuiConfig } from "@/cli/cmd/tui/config/tui"
import * as Log from "@opencode-ai/core/util/log" import * as Log from "@opencode-ai/core/util/log"
import { errorData, errorMessage } from "@/util/error" import { errorData, errorMessage } from "@/util/error"
import { isRecord } from "@/util/record" import { isRecord } from "@/util/record"
import { WithInstance } from "@/project/with-instance"
import { import {
readPackageThemes, readPackageThemes,
readPluginId, readPluginId,
@@ -838,10 +837,7 @@ async function addPluginBySpec(state: RuntimeState | undefined, raw: string) {
state.pending.delete(spec) state.pending.delete(spec)
return true return true
} }
const ready = await WithInstance.provide({ const ready = await resolveExternalPlugins([cfg], () => TuiConfig.waitForDependencies()).catch((error) => {
directory: state.directory,
fn: () => resolveExternalPlugins([cfg], () => TuiConfig.waitForDependencies()),
}).catch((error) => {
fail("failed to add tui plugin", { path: next, error }) fail("failed to add tui plugin", { path: next, error })
return [] as PluginLoad[] return [] as PluginLoad[]
}) })
@@ -1034,9 +1030,6 @@ async function load(input: { api: Api; config: TuiConfig.Resolved }) {
} }
runtime = next runtime = next
try { try {
await WithInstance.provide({
directory: cwd,
fn: async () => {
const records = Flag.OPENCODE_PURE ? [] : (config.plugin_origins ?? []) const records = Flag.OPENCODE_PURE ? [] : (config.plugin_origins ?? [])
if (Flag.OPENCODE_PURE && config.plugin_origins?.length) { if (Flag.OPENCODE_PURE && config.plugin_origins?.length) {
log.info("skipping external tui plugins in pure mode", { count: config.plugin_origins.length }) log.info("skipping external tui plugins in pure mode", { count: config.plugin_origins.length })
@@ -1068,8 +1061,6 @@ async function load(input: { api: Api; config: TuiConfig.Resolved }) {
// and hook chains rely on stable plugin ordering. // and hook chains rely on stable plugin ordering.
await activatePluginEntry(next, plugin, false) await activatePluginEntry(next, plugin, false)
} }
},
})
} catch (error) { } catch (error) {
fail("failed to load tui plugins", { directory: cwd, error }) fail("failed to load tui plugins", { directory: cwd, error })
} }
@@ -5,7 +5,7 @@ import { pathToFileURL } from "url"
import { createTestKeymap } from "@opentui/keymap/testing" import { createTestKeymap } from "@opentui/keymap/testing"
import { tmpdir } from "../../fixture/fixture" import { tmpdir } from "../../fixture/fixture"
import { createTuiPluginApi } from "../../fixture/tui-plugin" import { createTuiPluginApi } from "../../fixture/tui-plugin"
import { createTuiResolvedConfig } from "../../fixture/tui-runtime" import { createTuiResolvedConfig, mockTuiRuntime } from "../../fixture/tui-runtime"
import { Global } from "@opencode-ai/core/global" import { Global } from "@opencode-ai/core/global"
import { TuiConfig } from "../../../src/cli/cmd/tui/config/tui" import { TuiConfig } from "../../../src/cli/cmd/tui/config/tui"
import { Filesystem } from "@/util/filesystem" import { Filesystem } from "@/util/filesystem"
@@ -647,6 +647,36 @@ export default {
} }
}) })
test("does not bootstrap server plugins while initializing tui plugins", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const marker = path.join(dir, "server-plugin-called.txt")
const plugin = path.join(dir, "server-plugin.ts")
await Bun.write(
plugin,
[
"export default async () => {",
` await Bun.write(${JSON.stringify(marker)}, "called")`,
" return {}",
"}",
"",
].join("\n"),
)
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ plugin: [pathToFileURL(plugin).href] }))
return { marker }
},
})
const mock = mockTuiRuntime(tmp.path, [])
try {
await TuiPluginRuntime.init({ api: createTuiPluginApi(), config: mock.config })
await expect(fs.stat(tmp.extra.marker)).rejects.toThrow()
} finally {
await TuiPluginRuntime.dispose()
mock.restore()
}
})
describe("tui.plugin.loader", () => { describe("tui.plugin.loader", () => {
let data: Data let data: Data