Skip to content

fix(plugin): add V1 default export descriptor to stop legacy loader probing every helper - #89

Open
Futuri-Risk wants to merge 1 commit into
KochC:mainfrom
Futuri-Risk:fix/v1-default-export
Open

fix(plugin): add V1 default export descriptor to stop legacy loader probing every helper#89
Futuri-Risk wants to merge 1 commit into
KochC:mainfrom
Futuri-Risk:fix/v1-default-export

Conversation

@Futuri-Risk

Copy link
Copy Markdown

Fixes #86.

What

Adds a V1 plugin descriptor as the default export of index.js (and the rebuilt dist/llm-proxy.js):

export default { id: "opencode-llm-proxy", server: OpenAIProxyPlugin }

All 28 named exports stay untouched, so direct imports and the test suite are unaffected.

Why

Without a default export, opencode's loader takes the legacy path (getLegacyPlugins), which invokes every function-typed export as if it were the plugin factory. The pure helpers (buildPrompt, mapFinishReason, …) throw on the plugin-init argument, so every worker logs failed to load plugin (messages.filter / finish.includes / messages.map is not a function — whichever helper it reaches). The proxy still serves today only because OpenAIProxyPlugin happens to run first in Object.values order and Bun.serve fires as a side effect before any helper throws — i.e. it works by iteration-order luck.

With the descriptor present, readV1Plugin (packages/opencode/src/plugin/shared.ts) detects it and invokes only server.

Verification

Shipped-artifact path (not a wrapper): npm pack from this branch → installed the tarball into opencode's package cache → registered bare-name ("plugin": ["opencode-llm-proxy"]) in a scratch project → booted opencode serve (1.18.18, current latest) and forced instance creation:

  • failed to load plugin lines: 0 (previously 1 per worker on every boot)
  • proxy came up on its configured port; GET /v1/modelsHTTP 200 with the model list

Unit suite: 232/232 pass (230 baseline + 2 new), eslint clean. New tests assert the descriptor shape and invoke descriptor.server({ client }) under the existing mocked-Bun fixture (hoisted to a shared withMockedBun helper) to prove the proxy actually boots through it.

Older-opencode behavior (no regression)

  • readV1Plugin exists in every opencode release I checked back to v1.15.0, so the V1 path covers everything reasonably current.
  • On loaders that predate it, the legacy path is still safe: getServerPlugin explicitly recognizes { server } objects (index.ts L88–93) — the descriptor is treated as a plugin whose server is OpenAIProxyPlugin, and the plugin's existing state.started guard makes the second invocation a no-op returning {}. Helper-probe log noise on those old builds is unchanged from today.

Extras

  • .gitattributes with dist/** text eol=lf — the committed bundle is regenerated by prepack, so keeping it LF-only avoids whole-file churn on rebuilds.
  • README gains a short Compatibility note (clean load on current opencode; harmless per-worker log line on very old builds) to pre-empt "still broken on 1.14" follow-ups.

…robing every helper

opencode's plugin loader prefers a { id, server } default export
(readV1Plugin) and invokes only `server`. Without one, the legacy
fallback invokes every function-typed export as if it were the plugin;
the pure helpers throw on the plugin-init argument and every worker
logs "failed to load plugin" (messages.filter / finish.includes /
messages.map is not a function) even though the proxy still serves.

Fixes KochC#86
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.

Spurious 'failed to load plugin' error on opencode 1.18.x (cosmetic — proxy still works); one-line V1 default export silences it

1 participant