Skip to content

Add OpenCode v2 support via ./server adapter entrypoint - #44

Open
roboalchemist wants to merge 1 commit into
Mte90:masterfrom
roboalchemist:feat/opencode-v2-adapter
Open

roboalchemist wants to merge 1 commit into
Mte90:masterfrom
roboalchemist:feat/opencode-v2-adapter

Conversation

@roboalchemist

Copy link
Copy Markdown

Fixes #33 (OpenCode 2.x fails to load — V1 entrypoint, no V2 setup(ctx)).

What

OpenCode 2.x loads plugins through the v2 plugin API ({ id, setup(context) }) and prefers a package's ./server export, while this plugin ships only the v1 Plugin(ctx, options) entrypoint — so 2.x hosts reject it.

This PR adds a v2 entrypoint (src/server.ts) that adapts the existing v1 engine to the v2 API:

  • builds a v1-shaped client bridge on top of the v2 plugin context
  • invokes the unchanged v1 plugin (src/index.ts) with it
  • re-registers the returned v1 hooks (event, config, tool, chat.message, tool.execute.before/after, command.execute.before) into the v2 domain API
  • translates v2 bus events into the v1 event shape (handleEvent's {type, properties: {sessionID, ...}})

The recovery engine is untouched — v1 and v2 hosts run the same logic, so the two stay automatically in sync with future v1 changes. OpenCode 1.x keeps loading main; 2.x loads ./server. The config in the README works unchanged on both.

Why an adapter (vs. #37)

#37 ports v1's behavior into a parallel src/v2 tree with its own test suite — a large surface that must be kept in step with v1 over time. This adapter is the alternative: one engine, thin bridge (~250 lines, one new file + package.json/README wiring), no duplicated recovery logic to maintain. Happy to close this in favor of #37 if the full port is preferred — but this is a much smaller diff to review and can ship immediately.

package.json changes

  • exports: . → ./dist/index.js (unchanged for 1.x), new ./server → ./src/server.ts (OpenCode 2 loads TS entrypoints directly, same pattern as other v2 plugins)
  • files: ship src/server.ts
  • deps: add zod (used by the adapter for tool-schema conversion)
  • build: builds both entries

Testing

  • tsc --noEmit passes (no changes to src/index.ts; v1 behavior byte-identical)
  • Verified under OpenCode 2.0.25: plugin loads via the v2 loader with no failed to load plugin errors; setup() runs the engine construction, tool registration (task_complete via context.tool.transform), and prompt/tool/command hook registration without errors
  • v1 path untouched: 1.x hosts resolve . → dist/index.js exactly as before

OpenCode 2.x loads plugins through the v2 plugin API ({id, setup(context)})
and prefers the ./server export of an npm package (issue Mte90#33).

This adds a v2 entrypoint (src/server.ts) that adapts the existing v1
recovery engine to the v2 API:

- builds a v1-shaped client bridge on top of the v2 plugin context
- invokes the unchanged v1 plugin (src/index.ts) with it
- re-registers the returned v1 hooks (event, config, tool, chat.message,
  tool.execute.before/after, command.execute.before) into the v2 domain API
- translates v2 bus events into the v1 event shape

The recovery engine is untouched, so v1 and v2 hosts automatically run the
same logic and stay in sync with future v1 changes. OpenCode 1.x keeps
loading main (dist/index.js); 2.x loads ./server. Also adds zod (used by
the adapter) to dependencies and builds both entries in the build script.
@Mte90

Mte90 commented Oct 8, 2026

Copy link
Copy Markdown
Owner

what do you think @famewolf?

@famewolf

famewolf commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

@Mte90 My answer: #37 is the one to land; #44 is a clever stopgap that silently removes features instead of failing loudly.

What worries me about #44 as the long-term answer:

  • The bridge stubs the surfaces the plugin actually runs on. In src/server.ts, session.list returns [] (sessions that existed before plugin load are invisible — no discovery), session.todo returns [] (the done-with-open-todos nudge can never fire), session.summarize returns undefined (subagent compaction route is dead), config.get/provider.get return empty objects, and app.log goes to console.error (v2 has no server-log endpoint). Nothing throws — the features are just absent on v2.
  • The event translation is lossy. Anything unrecognized falls through to message.updated. The v1 engine was written against v1's event ordering; the v2 behaviors that actually bite — idle arriving before history flush, session.revert.*, interrupt re-arm, subagent detection via parentID — can't be reproduced by renaming events in a switch table.
  • Its verification is tsc --noEmit plus a manual "loads without errors." auto-resume's entire bug history is healthy-load-but-wrong-behavior: recovery loops, double injections, orphaned watchdogs. Nothing in Add OpenCode v2 support via ./server adapter entrypoint #44 tests for any of those under v2.

What #44 gets right: it's ~250 lines in one new file, reviewable in minutes, v1 stays byte-identical, and one engine means future v1 fixes reach v2 for free. That's a legitimate reason to take it as an interim #33 fix — the two PRs only overlap in package.json and the README.

But #37 is where this should land: it's the build that has been running v2 on my machine daily (the PR head is the deployed source of truth), 822 tests pass / 0 fail, and you already OK'd its scope on 10-02 ("we can proceed"). Its real cost is the review size, and the dual-maintenance concern is fair — which is why docs/v2/backport-to-v1.md exists rather than the divergence being hidden.

For context on pace: I'm submitting commits to the branch daily — shoring up areas the current v2 implementation was found to be lacking as they surface, and some of those fixes turned out to be needed by v1 as well.

Your call, but that's my recommendation: #37 as the destination. If you want #33 closed this week, taking #44 as an interim — with the stubbed surfaces noted in the README — is a reasonable path while #37 stays under review.

@Mte90

Mte90 commented Oct 9, 2026

Copy link
Copy Markdown
Owner

I think too that #37 is the one, just wanted for your opinion as you did all the work for opencode v2 (I am still using the v1).

So I think that we can close this and waiting for #37 when it is finished to merge it and do a new release.

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.

OpenCode 2.x: fails to load — V1 entrypoint, no V2 setup(ctx)

3 participants