summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Silverlock <[email protected]>2026-02-20 07:39:15 -0500
committerGitHub <[email protected]>2026-02-20 07:39:15 -0500
commit93615bef28fe0e17f673ba0f90c171309f7d5f91 (patch)
tree6ddd925cece9471e45a8fe07aa8b4b3948396e45
parenta04e4e81fbd1ec0e2a7d20ec6f40dd0dfa277b81 (diff)
downloadopencode-93615bef28fe0e17f673ba0f90c171309f7d5f91.tar.gz
opencode-93615bef28fe0e17f673ba0f90c171309f7d5f91.zip
fix(cli): missing plugin deps cause TUI to black screen (#14432)
-rw-r--r--packages/opencode/src/config/config.ts4
-rw-r--r--packages/opencode/src/plugin/index.ts47
2 files changed, 29 insertions, 22 deletions
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 311884719..aad0fd76c 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -292,7 +292,9 @@ export namespace Config {
...(proxied() ? ["--no-cache"] : []),
],
{ cwd: dir },
- ).catch(() => {})
+ ).catch((err) => {
+ log.warn("failed to install dependencies", { dir, error: err })
+ })
}
async function isWritable(dir: string) {
diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts
index 24dc695d6..e65d21bfd 100644
--- a/packages/opencode/src/plugin/index.ts
+++ b/packages/opencode/src/plugin/index.ts
@@ -41,8 +41,10 @@ export namespace Plugin {
for (const plugin of INTERNAL_PLUGINS) {
log.info("loading internal plugin", { name: plugin.name })
- const init = await plugin(input)
- hooks.push(init)
+ const init = await plugin(input).catch((err) => {
+ log.error("failed to load internal plugin", { name: plugin.name, error: err })
+ })
+ if (init) hooks.push(init)
}
let plugins = config.plugin ?? []
@@ -59,37 +61,40 @@ export namespace Plugin {
const lastAtIndex = plugin.lastIndexOf("@")
const pkg = lastAtIndex > 0 ? plugin.substring(0, lastAtIndex) : plugin
const version = lastAtIndex > 0 ? plugin.substring(lastAtIndex + 1) : "latest"
- const builtin = BUILTIN.some((x) => x.startsWith(pkg + "@"))
plugin = await BunProc.install(pkg, version).catch((err) => {
- if (!builtin) throw err
-
- const message = err instanceof Error ? err.message : String(err)
- log.error("failed to install builtin plugin", {
- pkg,
- version,
- error: message,
- })
+ const cause = err instanceof Error ? err.cause : err
+ const detail = cause instanceof Error ? cause.message : String(cause ?? err)
+ log.error("failed to install plugin", { pkg, version, error: detail })
Bus.publish(Session.Event.Error, {
error: new NamedError.Unknown({
- message: `Failed to install built-in plugin ${pkg}@${version}: ${message}`,
+ message: `Failed to install plugin ${pkg}@${version}: ${detail}`,
}).toObject(),
})
-
return ""
})
if (!plugin) continue
}
- const mod = await import(plugin)
// Prevent duplicate initialization when plugins export the same function
// as both a named export and default export (e.g., `export const X` and `export default X`).
// Object.entries(mod) would return both entries pointing to the same function reference.
- const seen = new Set<PluginInstance>()
- for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
- if (seen.has(fn)) continue
- seen.add(fn)
- const init = await fn(input)
- hooks.push(init)
- }
+ await import(plugin)
+ .then(async (mod) => {
+ const seen = new Set<PluginInstance>()
+ for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
+ if (seen.has(fn)) continue
+ seen.add(fn)
+ hooks.push(await fn(input))
+ }
+ })
+ .catch((err) => {
+ const message = err instanceof Error ? err.message : String(err)
+ log.error("failed to load plugin", { path: plugin, error: message })
+ Bus.publish(Session.Event.Error, {
+ error: new NamedError.Unknown({
+ message: `Failed to load plugin ${plugin}: ${message}`,
+ }).toObject(),
+ })
+ })
}
return {