Port plugin to the OpenCode V2 TUI plugin API - #25
LucasInstra wants to merge 8 commits into
Conversation
736d8c4 to
7d3242a
Compare
- Add a CI workflow (push to main + pull requests) running typecheck, unit tests, build, and the packaged output check. - Update verify-packaged-tui.mjs for the V2 entrypoint: assert the exported definition has an id and a setup function instead of the V1 tui function. - Handle npm 11's npm pack --json object output and Windows' npm.cmd. - Move @opencode/plugin to dependencies so the published package resolves the host module (per the V2 migration guide).
A parent npm run exports the user configuration into the child environment, and npm 12 rejects allow-scripts on the isolated --prefix install this script performs (EALLOWSCRIPTS). Strip the problematic keys from the child environment; the install already passes --ignore-scripts.
The OpenTUI packages declare node >= 26.4 engines, so npm installs on the CI Node 24 emit EBADENGINE warnings. bun install is the same path publish.yml already uses, satisfies the engine, and was verified locally with the committed package-lock.json.
opencode plugin add accepts Git package specs, but dist/ is not committed: without prepare the installed package had no entrypoint. prepare mirrors the publish-time build.
The prepare script runs inside the host package preparation step, where invoking npm recursively may not resolve. Run the build script with node instead.
|
Split as requested: this PR now contains only the V2 port (feature parity with V1). The branch was rebuilt so the port commits come first — it is content-identical to the previous head, no code was dropped. The new features moved to #26, which is stacked on this branch; please review/merge this one first. Once it is merged I will rebase #26 so that PR shows only the feature commits. |
OpenCode 2.0.8 replaced background.surface with background.raised, and reading the old field inside the app slot crashed the plugin. Read every theme token defensively with fallbacks for both shapes, and cover the 2.0.8 shape and a partial theme with tests. Also refresh the lockfile to @OpenCode 2.0.8 (same declared ranges).
|
Compatibility fix pushed: OpenCode 2.0.8 renamed the resolved theme background ( The theme adapter now reads every token defensively with fallbacks for both shapes, and tests cover the 2.0.8 shape plus a partial theme. Verified by calling the built adapter with both theme shapes (2.0.8 -> |
Port plugin to the OpenCode V2 TUI plugin API
Migrates the plugin from the V1 TUI plugin API (
@opencode-ai/plugin/tui) to the V2 CLI plugin API (@opencode/plugin/tui+@opencode/client). Fixes #24.As requested, this PR now contains only the V2 port (feature parity with V1). The new features built on top of it live in #26 — please review this one first.
Tested against
opencode2.0.3 and verified up to 2.0.8.V1 → V2 mapping
export default { id, tui(api, options, meta) }→Plugin.define({ id, setup(ctx) }); cleanup is returned fromsetup.appslot (ctx.ui.slot). Keymap layers are registered inside the slot component becausectx.keymap.layer()requires a component owner. The V1 legacyapi.commandfallback was dropped.api.route.current→ctx.ui.router.current().ctx.ui.dialogandctx.ui.toast.show;ctx.themeis mapped to the token names the components already use (src/opencode.ts). The adapter reads every token defensively and supports both the <= 2.0.7background.surfaceand the 2.0.8background.raisedshapes, so a theme change degrades gracefully instead of crashing the slot.state.session.messages+state.part→client.session.context({ sessionID })(V2 embeds content parts in the message and has no separate part store).client.model.list()+client.provider.list(); the fallback default model comes fromclient.model.default().session.createwithlocation,modeland V2 permission rules; the mini system prompt is attached withsession.instructions.entry.put;session.promptdelivers the question;session.interrupt/session.removeon close.session.next.text.delta/message.part.updated→ V2 eventssession.text.delta,session.reasoning.delta,session.tool.*,session.execution.*,session.idleviactx.data.on().*, then allow the configured tools (listis not a V2 permission action; thereadtool lists directories).opencode plugin update opencode-mini-session. Unlike V1 it does not delete its own package cache, because V2 ships a first-class plugin update command.@opencode-ai/plugin/@opencode-ai/sdk→@opencode/plugin/@opencode/client^2.0.5(@opencode/pluginis a runtime dependency, as the migration guide recommends, so the packaged entrypoint resolves it). OpenTUI^0.4.3→^0.5.11(@opentui/solidpinssolid-js@1.9.12, sobabel-preset-solidis pinned to1.9.12as well);engines.opencode→>=2.2.0.0for the breaking V2 port — happy to drop that if you prefer to handle releases yourself.Behavior notes (no exact V2 equivalent)
tui.appendPrompthas no V2 client API, so the transcript is queued into the main session withsession.prompt({ delivery: "queue" }).SessionCreateInputhas noparentID, so mini sessions are regular sessions. They are tagged withmetadata.opencodeMiniSessionand deleted on close.Tooling
.github/workflows/ci.ymlruns typecheck, unit tests, build, and the packaged output check. The package check now verifies the V2 entrypoint (id+setup), handles npm 11'snpm pack --jsonoutput, and works on Windows.preparescript buildsdist/, soopencode plugin add github:...works without a manual build step.Tests
84 tests across 7 files (
agent,context,model,session,update,counter,routing), ported from the V1 suite and adapted to the V2 API.Verification
opencode2.0.3 (stage=setup completed, noplugin failedbanner).alt+b; context counter, transcript, input, and footer render.tsc --noEmit,vitest run,npm run build, andnpm run test:packagepass.How to try it
After the 2.x release on npm:
opencode plugin add opencode-mini-session.Without waiting for a release, from this branch: clone, build, and load the checkout through the global plugin directory:
On Windows use
mklink /Jfor the two links. Restart OpenCode after rebuilding.opencode plugin add github:...works where Git packages are enabled. npm 12 disables them by default (allow-git=none), so enable it first (npm config set allow-git all) if the install is refused.