[PR #7639] feat(plugin)!: migrate plugin system to SDK v2 #12463

Closed
opened 2026-02-16 18:17:22 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/7639

State: closed
Merged: No


Summary

  • Migrates plugin system to use SDK v2 types and client exclusively
  • Removes v1 SDK compatibility layer - this is now a full breaking change
  • Key context: Many hooks already had type drift between v1 contract and v2 runtime, so this breaking change is less severe than it appears

Why This Breaking Change Is Acceptable

Hook Types Were Already Broken

Analysis revealed significant type drift between what the plugin package defined and what the OpenCode core actually passed at runtime:

Hook Plugin Expected Core Passed Impact
permission.ask Permission with title Permission.Info with message Field name mismatch - input.title returns undefined
chat.params Provider Promise<Provider.Info> Promise wrapper not in type
chat.message UserMessage MessageV2.Info Different type structure

The core was already using @ts-expect-error workarounds to suppress these mismatches. Plugins accessing input.title in permission.ask were already getting undefined at runtime.

This Change Fixes the Type Mismatch

Instead of maintaining broken v1 types, we:

  1. Update the plugin contract to match the actual v2 runtime behavior
  2. Provide clean, consistent types that match what OpenCode core actually passes
  3. Remove the UnifiedClient complexity (no more .v2 accessor needed)

Changes

Plugin Package (packages/plugin)

  • Updated all imports from @opencode-ai/sdk@opencode-ai/sdk/v2
  • Changed hook types to use v2 SDK types (PermissionRequest instead of Permission, etc.)
  • Simplified PluginInput.client to be v2 OpencodeClient only
  • Added ToolContext.metadata() and ToolResult types

Plugin Loader (packages/opencode)

  • Removed v1 SDK client creation
  • Removed unified client proxy (.v2 accessor)
  • Now creates and passes v2 SDK client only

Breaking Changes

What Before After
SDK client input.client (v1) + input.client.v2 (v2) input.client (v2 only)
Permission type Permission with title PermissionRequest with permission
Permission reply status: ask/deny/allow reply: once/always/reject
SDK calls Nested { path, body, query } Flattened parameters

Migration for Plugin Authors

  1. Change imports: @opencode-ai/plugin (no /v2)
  2. Update permission hook:
    // Before
    (input: Permission, output: { status: "ask" | "deny" | "allow" }) => { ... }
    
    // After
    (input: PermissionRequest, output: { reply: "once" | "always" | "reject" }) => { ... }
    
  3. Update SDK calls to use flattened parameters

Why Not Maintain v1 Compatibility?

  • The SDK client had massive breaking changes (every method call changed from nested to flat)
  • Hook types already had significant drift (not just style changes, but actual field mismatches)
  • Maintaining both v1 and v2 code paths added complexity
  • Clean break forces plugin authors to update, resulting in better type safety

Closes #7641

**Original Pull Request:** https://github.com/anomalyco/opencode/pull/7639 **State:** closed **Merged:** No --- ## Summary - Migrates plugin system to use SDK v2 types and client exclusively - Removes v1 SDK compatibility layer - this is now a **full breaking change** - **Key context**: Many hooks already had type drift between v1 contract and v2 runtime, so this breaking change is less severe than it appears ## Why This Breaking Change Is Acceptable ### Hook Types Were Already Broken Analysis revealed significant type drift between what the plugin package defined and what the OpenCode core actually passed at runtime: | Hook | Plugin Expected | Core Passed | Impact | |------|----------------|-------------|--------| | `permission.ask` | `Permission` with `title` | `Permission.Info` with `message` | Field name mismatch - `input.title` returns `undefined` | | `chat.params` | `Provider` | `Promise<Provider.Info>` | Promise wrapper not in type | | `chat.message` | `UserMessage` | `MessageV2.Info` | Different type structure | The core was already using `@ts-expect-error` workarounds to suppress these mismatches. Plugins accessing `input.title` in `permission.ask` were already getting `undefined` at runtime. ### This Change Fixes the Type Mismatch Instead of maintaining broken v1 types, we: 1. Update the plugin contract to match the actual v2 runtime behavior 2. Provide clean, consistent types that match what OpenCode core actually passes 3. Remove the `UnifiedClient` complexity (no more `.v2` accessor needed) ## Changes ### Plugin Package (`packages/plugin`) - Updated all imports from `@opencode-ai/sdk` → `@opencode-ai/sdk/v2` - Changed hook types to use v2 SDK types (`PermissionRequest` instead of `Permission`, etc.) - Simplified `PluginInput.client` to be v2 `OpencodeClient` only - Added `ToolContext.metadata()` and `ToolResult` types ### Plugin Loader (`packages/opencode`) - Removed v1 SDK client creation - Removed unified client proxy (`.v2` accessor) - Now creates and passes v2 SDK client only ## Breaking Changes | What | Before | After | |------|--------|-------| | SDK client | `input.client` (v1) + `input.client.v2` (v2) | `input.client` (v2 only) | | Permission type | `Permission` with `title` | `PermissionRequest` with `permission` | | Permission reply | `status: ask/deny/allow` | `reply: once/always/reject` | | SDK calls | Nested `{ path, body, query }` | Flattened parameters | ## Migration for Plugin Authors 1. **Change imports**: `@opencode-ai/plugin` (no `/v2`) 2. **Update permission hook**: ```typescript // Before (input: Permission, output: { status: "ask" | "deny" | "allow" }) => { ... } // After (input: PermissionRequest, output: { reply: "once" | "always" | "reject" }) => { ... } ``` 3. **Update SDK calls** to use flattened parameters ## Why Not Maintain v1 Compatibility? - The SDK client had **massive breaking changes** (every method call changed from nested to flat) - Hook types already had **significant drift** (not just style changes, but actual field mismatches) - Maintaining both v1 and v2 code paths added complexity - Clean break forces plugin authors to update, resulting in better type safety Closes #7641
yindo added the pull-request label 2026-02-16 18:17:22 -05:00
yindo closed this issue 2026-02-16 18:17:22 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#12463