|
|
@@ -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 {
|