Revert "feat(tui): load external plugin exports"
This reverts commit fdd6498909.
This commit is contained in:
parent
fdd6498909
commit
46148bbc6c
7 changed files with 55 additions and 129 deletions
|
|
@ -9,7 +9,6 @@ import { ServerConnection } from "../../services/server-connection"
|
|||
import { Updater } from "../../services/updater"
|
||||
import { UpdatePreflight } from "../../services/update-preflight"
|
||||
import { Npm } from "@opencode-ai/core/npm"
|
||||
import { createPluginHost } from "../../plugin-host"
|
||||
|
||||
export default Runtime.handler(Commands, (input) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -60,9 +59,10 @@ export default Runtime.handler(Commands, (input) =>
|
|||
get: () => runPromise(config.get()),
|
||||
update: (update) => runPromise(config.update(update)),
|
||||
},
|
||||
pluginHost: createPluginHost((spec) =>
|
||||
runPromise(npm.add(spec, { subpaths: ["tui"] }).pipe(Effect.map((result) => result.entrypoint))),
|
||||
),
|
||||
packages: {
|
||||
resolve: (spec) =>
|
||||
runPromise(npm.add(spec, { subpaths: ["tui"] }).pipe(Effect.map((result) => result.entrypoint))),
|
||||
},
|
||||
terminalHandoff: () => preflight.finish(),
|
||||
log: (level, message, tags) => {
|
||||
const effect =
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
import type { Plugin } from "@opencode-ai/plugin/v2/tui"
|
||||
import type { PluginHost } from "@opencode-ai/tui/plugin/context"
|
||||
import path from "path"
|
||||
import { stat } from "fs/promises"
|
||||
import { fileURLToPath, pathToFileURL } from "url"
|
||||
|
||||
export function createPluginHost(resolvePackage: (spec: string) => Promise<string | undefined>): PluginHost {
|
||||
return {
|
||||
async load(spec, directory) {
|
||||
const local = spec.startsWith("file://")
|
||||
? new URL(spec)
|
||||
: spec.startsWith("./") || spec.startsWith("../") || path.isAbsolute(spec)
|
||||
? pathToFileURL(path.resolve(directory, spec))
|
||||
: undefined
|
||||
const entrypoint = local ? await resolveLocal(local) : await resolvePackage(spec)
|
||||
if (!entrypoint) return
|
||||
const mod: { readonly default?: unknown } = await import(entrypoint)
|
||||
if (!isPlugin(mod.default)) throw new Error(`Invalid V2 TUI plugin module: ${spec}`)
|
||||
return mod.default
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveLocal(url: URL) {
|
||||
const info = await stat(url)
|
||||
if (info.isFile()) return url.href
|
||||
if (!info.isDirectory()) return
|
||||
const manifest = Bun.file(path.join(fileURLToPath(url), "package.json"))
|
||||
if (await manifest.exists()) {
|
||||
const value: unknown = await manifest.json()
|
||||
if (typeof value === "object" && value !== null && "exports" in value) {
|
||||
const exports = value.exports
|
||||
const target =
|
||||
typeof exports === "object" && exports !== null && "./tui" in exports ? exports["./tui"] : undefined
|
||||
if (typeof target === "string") return pathToFileURL(path.resolve(fileURLToPath(url), target)).href
|
||||
}
|
||||
}
|
||||
return resolve(pathToFileURL(path.join(fileURLToPath(url), "tui")).href)
|
||||
}
|
||||
|
||||
function resolve(specifier: string) {
|
||||
try {
|
||||
return import.meta.resolve(specifier)
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function isPlugin(value: unknown): value is Plugin.Definition {
|
||||
return (
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
"id" in value &&
|
||||
typeof value.id === "string" &&
|
||||
value.id.length > 0 &&
|
||||
"setup" in value &&
|
||||
typeof value.setup === "function"
|
||||
)
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
import { afterEach, describe, expect, test } from "bun:test"
|
||||
import path from "path"
|
||||
import { createPluginHost } from "../src/plugin-host"
|
||||
|
||||
const directories: string[] = []
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(directories.splice(0).map((directory) => Bun.$`rm -rf ${directory}`.quiet()))
|
||||
})
|
||||
|
||||
describe("plugin host", () => {
|
||||
test("loads the tui export from a local package", async () => {
|
||||
const directory = await temp()
|
||||
await Bun.write(
|
||||
path.join(directory, "package.json"),
|
||||
JSON.stringify({ type: "module", exports: { "./tui": "./src/tui.js" } }),
|
||||
)
|
||||
await Bun.write(
|
||||
path.join(directory, "src/tui.js"),
|
||||
"export default { id: 'example.tui', setup() { return () => {} } }",
|
||||
)
|
||||
|
||||
const plugin = await createPluginHost(async () => undefined).load(directory, directory)
|
||||
|
||||
expect(plugin?.id).toBe("example.tui")
|
||||
})
|
||||
|
||||
test("loads a package resolver tui entrypoint", async () => {
|
||||
const directory = await temp()
|
||||
const entrypoint = path.join(directory, "tui.js")
|
||||
await Bun.write(entrypoint, "export default { id: 'npm.tui', setup() {} }")
|
||||
|
||||
const plugin = await createPluginHost(async (spec) => {
|
||||
expect(spec).toBe("example-plugin")
|
||||
return entrypoint
|
||||
}).load("example-plugin", directory)
|
||||
|
||||
expect(plugin?.id).toBe("npm.tui")
|
||||
})
|
||||
|
||||
test("reports invalid tui exports without terminating the host", async () => {
|
||||
const directory = await temp()
|
||||
const entrypoint = path.join(directory, "tui.js")
|
||||
await Bun.write(entrypoint, "export default { id: 'invalid' }")
|
||||
const host = createPluginHost(async () => entrypoint)
|
||||
|
||||
expect(host.load("invalid-plugin", directory)).rejects.toThrow("Invalid V2 TUI plugin module: invalid-plugin")
|
||||
expect(await host.load("unsupported-plugin", directory).catch(() => undefined)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
async function temp() {
|
||||
const directory = await Bun.$`mktemp -d`.text()
|
||||
directories.push(directory.trim())
|
||||
return directory.trim()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue