Refactor into plugin loader and do not enforce (#20112)

This commit is contained in:
Sebastian
2026-03-30 20:36:21 +02:00
committed by GitHub
parent 9f3c2bd861
commit fa95a61c4e
17 changed files with 1056 additions and 351 deletions

View File

@@ -1822,6 +1822,22 @@ describe("resolvePluginSpec", () => {
expect(await Config.resolvePluginSpec("@scope/pkg", file)).toBe("@scope/pkg")
})
test("resolves windows-style relative plugin directory specs", async () => {
if (process.platform !== "win32") return
await using tmp = await tmpdir({
init: async (dir) => {
const plugin = path.join(dir, "plugin")
await fs.mkdir(plugin, { recursive: true })
await Filesystem.write(path.join(plugin, "index.ts"), "export default {}")
},
})
const file = path.join(tmp.path, "opencode.json")
const hit = await Config.resolvePluginSpec(".\\plugin", file)
expect(Config.pluginSpecifier(hit)).toBe(pathToFileURL(path.join(tmp.path, "plugin", "index.ts")).href)
})
test("resolves relative file plugin paths to file urls", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
@@ -1834,7 +1850,7 @@ describe("resolvePluginSpec", () => {
expect(Config.pluginSpecifier(hit)).toBe(pathToFileURL(path.join(tmp.path, "plugin.ts")).href)
})
test("resolves plugin directory paths to package main files", async () => {
test("resolves plugin directory paths to directory urls", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const plugin = path.join(dir, "plugin")
@@ -1848,6 +1864,20 @@ describe("resolvePluginSpec", () => {
},
})
const file = path.join(tmp.path, "opencode.json")
const hit = await Config.resolvePluginSpec("./plugin", file)
expect(Config.pluginSpecifier(hit)).toBe(pathToFileURL(path.join(tmp.path, "plugin")).href)
})
test("resolves plugin directories without package.json to index.ts", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const plugin = path.join(dir, "plugin")
await fs.mkdir(plugin, { recursive: true })
await Filesystem.write(path.join(plugin, "index.ts"), "export default {}")
},
})
const file = path.join(tmp.path, "opencode.json")
const hit = await Config.resolvePluginSpec("./plugin", file)
expect(Config.pluginSpecifier(hit)).toBe(pathToFileURL(path.join(tmp.path, "plugin", "index.ts")).href)

View File

@@ -476,12 +476,13 @@ test("loads managed tui config and gives it highest precedence", async () => {
const config = await TuiConfig.get()
expect(config.theme).toBe("managed-theme")
expect(config.plugin).toEqual(["shared-plugin@2.0.0"])
expect(config.plugin_meta).toEqual({
"shared-plugin@2.0.0": {
expect(config.plugin_records).toEqual([
{
item: "shared-plugin@2.0.0",
scope: "global",
source: path.join(managedConfigDir, "tui.json"),
},
})
])
},
})
})
@@ -539,12 +540,13 @@ test("supports tuple plugin specs with options in tui.json", async () => {
fn: async () => {
const config = await TuiConfig.get()
expect(config.plugin).toEqual([["acme-plugin@1.2.3", { enabled: true, label: "demo" }]])
expect(config.plugin_meta).toEqual({
"acme-plugin@1.2.3": {
expect(config.plugin_records).toEqual([
{
item: ["acme-plugin@1.2.3", { enabled: true, label: "demo" }],
scope: "local",
source: path.join(tmp.path, "tui.json"),
},
})
])
},
})
})
@@ -578,16 +580,18 @@ test("deduplicates tuple plugin specs by name with higher precedence winning", a
["acme-plugin@2.0.0", { source: "project" }],
["second-plugin@3.0.0", { source: "project" }],
])
expect(config.plugin_meta).toEqual({
"acme-plugin@2.0.0": {
expect(config.plugin_records).toEqual([
{
item: ["acme-plugin@2.0.0", { source: "project" }],
scope: "local",
source: path.join(tmp.path, "tui.json"),
},
"second-plugin@3.0.0": {
{
item: ["second-plugin@3.0.0", { source: "project" }],
scope: "local",
source: path.join(tmp.path, "tui.json"),
},
})
])
},
})
})
@@ -615,16 +619,18 @@ test("tracks global and local plugin metadata in merged tui config", async () =>
fn: async () => {
const config = await TuiConfig.get()
expect(config.plugin).toEqual(["global-plugin@1.0.0", "local-plugin@2.0.0"])
expect(config.plugin_meta).toEqual({
"global-plugin@1.0.0": {
expect(config.plugin_records).toEqual([
{
item: "global-plugin@1.0.0",
scope: "global",
source: path.join(Global.Path.config, "tui.json"),
},
"local-plugin@2.0.0": {
{
item: "local-plugin@2.0.0",
scope: "local",
source: path.join(tmp.path, "tui.json"),
},
})
])
},
})
})