Skip to content

fix(plugin): skip non-function exports in getLegacyPlugins - #1944

Open
Cipher208 wants to merge 5 commits into
XiaomiMiMo:devfrom
Cipher208:fix/plugin-bugfix-clean
Open

fix(plugin): skip non-function exports in getLegacyPlugins#1944
Cipher208 wants to merge 5 commits into
XiaomiMiMo:devfrom
Cipher208:fix/plugin-bugfix-clean

Conversation

@Cipher208

@Cipher208 Cipher208 commented Jul 27, 2026

Copy link
Copy Markdown

Fixes #1891

Problem

External plugins (plugin: [...]) don't execute their module code in MiMoCode. The plugin module IS loaded (ES import() succeeds), but hooks are never registered.

Root Cause

getLegacyPlugins() throws TypeError("Plugin export is not a function") when it encounters ANY export that is not a function and doesn't have a server property (e.g. constants, config objects, type re-exports).

This causes the entire plugin to be silently skipped — the error is caught in applyPlugin's Effect.catch handler, which silently swallows the error and returns Effect.void. The plugin is never loaded, hooks are never registered.

Fix

Two changes in packages/opencode/src/plugin/index.ts:

  1. Bug fix (line 163): Change throw to continue so non-plugin exports are silently skipped, matching the behavior of getServerPlugin() which already returns undefined for non-plugin values.

  2. Logging fix (line 378): Add log.error() in the Effect.catch handler so unhandled errors in the plugin loading pipeline are visible in logs, instead of being silently swallowed.

Testing

  • Typecheck passes (bun typecheck)
  • 27/27 plugin tests pass (bun test test/plugin/)
  • 3/3 file hooks tests pass

Impact

  • Fixes external plugin loading for all MiMoCode users
  • Enables agentsys, skillforge, and other plugin-based tools to work
  • Better error visibility for plugin loading failures
  • No breaking changes

External plugins fail to load because getLegacyPlugins throws
TypeError when encountering any export that is not a function
and doesn't have a 'server' property (e.g. constants, config
objects, type re-exports).

This causes the entire plugin to be silently skipped — the error
is caught in applyPlugin's Effect.catch and logged, but hooks
are never registered.

Fix: change 'throw' to 'continue' so non-plugin exports are
silently skipped, matching the behavior of getServerPlugin
which already returns undefined for non-plugin values.

This fixes the issue where external plugins (plugin: [...]) don't
execute their module code in MiMoCode 0.38.9.
Murat added 4 commits July 27, 2026 16:49
…wallow

The Effect.catch handler at line 392 was silently swallowing errors
with Effect.void and no logging. This made it impossible to debug
plugin loading failures that occurred in the Effect pipeline itself
(after the tryPromise catch handler).

Fix: add log.error() call with error details before returning Effect.void.
This ensures all plugin loading failures are visible in logs, not just
those caught by the tryPromise handler.
Skylos flagged 5 dead-code items in MCP index.ts. After thorough
verification across the entire codebase:

- Failed (NamedError): truly dead code — not imported or used anywhere
  outside index.ts. Removed.
- NamedError import: only used by Failed. Removed.
- defaultLayer: NOT dead code — used in session/prompt.ts, effect/app-runtime.ts,
  command/index.ts (skylos false positive)
- Resource: NOT dead code — used in server/routes/instance/experimental.ts
- ToolsChanged: NOT dead code — used at line 498 in same file

4 of 5 skylos findings were false positives.
Verifies that plugins with non-function exports (constants, types)
load correctly after the getLegacyPlugins fix (throw → continue).

Before fix: getLegacyPlugins threw TypeError on non-function exports,
silently skipping the entire plugin.
After fix: non-function exports are skipped, plugin function loads.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant