fix(opencode): port plugin to the OpenCode v2 plugin API#2004
Open
saiqulhaq wants to merge 1 commit into
Open
Conversation
OpenCode v2 replaced the v1 plugin API entirely; per OpenCode's migration
guide, "V1 plugins will not work in V2." The existing plugin used the v1 API
(SuperpowersPlugin named export, config + experimental.chat.messages.transform
hooks, {info,parts} message shape), so it no longer functioned under v2.
Rewrite .opencode/plugins/superpowers.js against the v2 API:
- Default `{ id, setup }` export (Plugin.define is an identity wrapper, so the
plugin stays zero-dependency with no runtime import).
- ctx.skill.transform() + ctx.skill.reload() register the bundled skills dir as
a directory skill source (replaces the v1 config.skills.paths mutation).
- ctx.session.hook("context", ...) injects the bootstrap into the first user
message using the v2 { role, content: [{type,text}] } shape (replaces
experimental.chat.messages.transform). Module-level bootstrap caching (obra#1202)
and the double-injection guard are preserved.
- Tool mapping updated to v2 tool names: file mutation is now write/edit
(v2 removed apply_patch).
Verified live against opencode2 (next-15718): skills register and are listed,
the context hook fires and injects, and the canonical acceptance test
("Let's make a react todo list") auto-triggers the brainstorming skill.
Also update the OpenCode tests and docs for v2:
- tests/opencode/test-bootstrap-caching.mjs drives the v2 setup(ctx)/context
hook shape instead of the v1 transform export.
- tests/opencode/{test-tools,test-priority}.sh drop the invalid v2
--print-logs flag.
- docs/README.opencode.md, .opencode/INSTALL.md, docs/porting-to-a-new-harness.md
use the canonical v2 `plugins` config key, describe the new hook mechanism,
and reference v2 tool names and log locations.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
|
It looks like this would immediately break all opencode v1 users. is that right? If so, it's probably a no-go. Is there a way to add opencode 2 support that won't break v1? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Who is submitting this PR? (required)
claude-opus-4-8[1m]superpowers(Claude Code plugin) — the code was tested against the plugin being changed; plus unrelated MCP servers (ClickUp, Slack, Gmail, Obsidian) that played no roleWhat problem are you trying to solve?
The bundled OpenCode plugin (
.opencode/plugins/superpowers.js) targets the OpenCode v1 plugin API and does not function under OpenCode v2. OpenCode's own migration guide states plainly: "V1 plugins will not work in V2." (https://v2.opencode.ai/migrate-v1)Concretely, under v2 the current plugin is loaded but never does anything, because v2 replaced the entire plugin contract:
SuperpowersPlugin({ client, directory })factory; v2 expects a default{ id, setup }export. v2 never calls the v1 factory, sosetupnever runs.config.skills.pathsinside aconfighook; that hook does not exist in v2.experimental.chat.messages.transformover{ info, parts }messages; v2 removed that hook and changed the message shape to{ role, content: [{ type, text }] }.Result on OpenCode v2: no skills registered, no bootstrap injected, so no superpowers skills auto-trigger. Verified on a real
opencode2(next-15718) install: with the old plugin theusing-superpowersbootstrap is absent and skills never fire.What does this PR change?
Rewrites
.opencode/plugins/superpowers.jsagainst the OpenCode v2 plugin API ({ id, setup }default export,ctx.skill.transformfor skill registration,ctx.session.hook("context", …)for bootstrap injection), and updates the OpenCode tests and docs to match. Behavior is otherwise identical to the v1 plugin (same bootstrap content, same module-level caching from #1202, same double-injection guard).Is this change appropriate for the core library?
Yes. This is not a new harness or a new skill — it repairs an existing, first-party integration that ships in core (
.opencode/,tests/opencode/,docs/README.opencode.md). OpenCode support is already part of core; this keeps it working as OpenCode moves to v2. It adds no third-party dependency (the plugin remains zero-dependency;Plugin.defineis an identity wrapper, so no runtime import is required) and does not touch any skill content.What alternatives did you consider?
@opencode-ai/plugin/v2and usePlugin.define. Rejected:defineis an identity function, and adding a runtime import risks module-resolution failures across the git-package/npm/local install layouts superpowers ships through. A plain default export is equivalent and dependency-free. Types can still be consulted for development.ctx.skill.transform. Rejected: the transform API is the v2-sanctioned way and keeps the symlink-free, no-manual-config property the v1 plugin had."request"(as the v2 docs table shows) vs"context". The shipped@opencode-ai/plugintypes and the runningopencode2build both use"context"; verified live that"context"fires and mutates messages. Used"context".Does this PR contain multiple unrelated changes?
No. Every change is the single concern of making the OpenCode plugin work on v2: the plugin rewrite, its tests, and its docs. The one-line edits to
docs/porting-to-a-new-harness.mdupdate that guide's OpenCode references (mechanism, log-check command) to stay consistent with the rewritten plugin.Existing PRs
opencode,opencode2,opencode v2,Plugin.define,session.hook,v2 plugin. The closest prior OpenCode work is fix(opencode): Usesynthetic: truefor invisible content injection #122 (merged, v1-erasynthetic:trueinjection) and refactor: use import.meta.dirname and fs/promises in opencode plugin #1247 (an unrelatedimport.meta.dirnamerefactor of the v1 plugin) — neither addresses the v2 API.Environment tested
opencode2)v0.0.0-next-15718build · hy3-freeNew harness support
Not a new harness — this is a v1→v2 API migration for the existing OpenCode integration. Including the acceptance evidence anyway, since the change affects whether the bootstrap loads.
Ran the canonical acceptance test on a real
opencode2(next-15718) install with this plugin loaded, in a clean empty directory:The agent auto-triggered the
brainstormingskill before writing any code (from--format jsonoutput):Also verified directly (via a sidecar probe plugin) that:
ctx.skill.list()returns the bundled superpowers skills (brainstorming,systematic-debugging,test-driven-development,using-superpowers, …) — soctx.skill.transform+reloadregistered theskills/directory.ctx.session.hook("context", …)callback fires, first-user-message parts have the{ type, text }shape, and the injected bootstrap reaches the model.tests/opencode/run-tests.sh(non-integration: plugin-loading + bootstrap-caching) passes with the rewritten v2-driven caching test.