diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index d0f025b0614..5c9d73107ce 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -385,8 +385,8 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { log.info("refreshing codex access token") const tokens = await refreshAccessToken(currentAuth.refresh) await input.client.auth.set({ - path: { id: "codex" }, - body: { + providerID: "codex", + auth: { type: "oauth", refresh: tokens.refresh_token, access: tokens.access_token, @@ -400,7 +400,9 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { const headers = new Headers() if (init?.headers) { if (init.headers instanceof Headers) { - init.headers.forEach((value, key) => headers.set(key, value)) + init.headers.forEach((value, key) => { + headers.set(key, value) + }) } else if (Array.isArray(init.headers)) { for (const [key, value] of init.headers) { if (value !== undefined) headers.set(key, String(value)) diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index 4912b8f74ba..42fa1936f51 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -1,8 +1,9 @@ -import type { Hooks, PluginInput, Plugin as PluginInstance } from "@opencode-ai/plugin" +import type { PluginInput, Hooks } from "@opencode-ai/plugin" +import type { Plugin as PluginFn } from "@opencode-ai/plugin" import { Config } from "../config/config" import { Bus } from "../bus" import { Log } from "../util/log" -import { createOpencodeClient } from "@opencode-ai/sdk" +import { createOpencodeClient } from "@opencode-ai/sdk/v2" import { Server } from "../server/server" import { BunProc } from "../bun" import { Instance } from "../project/instance" @@ -15,7 +16,7 @@ export namespace Plugin { const BUILTIN = ["opencode-copilot-auth@0.0.11", "opencode-anthropic-auth@0.0.8"] // Built-in plugins that are directly imported (not installed from npm) - const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin] + const INTERNAL_PLUGINS = [CodexAuthPlugin] const state = Instance.state(async () => { const client = createOpencodeClient({ @@ -23,8 +24,10 @@ export namespace Plugin { // @ts-ignore - fetch type incompatibility fetch: async (...args) => Server.App().fetch(...args), }) + const config = await Config.get() const hooks: Hooks[] = [] + const input: PluginInput = { client, project: Instance.project, @@ -54,23 +57,26 @@ export namespace Plugin { if (!plugin.startsWith("file://")) { const lastAtIndex = plugin.lastIndexOf("@") const pkg = lastAtIndex > 0 ? plugin.substring(0, lastAtIndex) : plugin - const version = lastAtIndex > 0 ? plugin.substring(lastAtIndex + 1) : "latest" + const pkgVersion = lastAtIndex > 0 ? plugin.substring(lastAtIndex + 1) : "latest" const builtin = BUILTIN.some((x) => x.startsWith(pkg + "@")) - plugin = await BunProc.install(pkg, version).catch((err) => { + plugin = await BunProc.install(pkg, pkgVersion).catch((err) => { if (builtin) return "" throw err }) if (!plugin) continue } const mod = await import(plugin) + // Prevent duplicate initialization when plugins export the same function // as both a named export and default export (e.g., `export const X` and `export default X`). // Object.entries(mod) would return both entries pointing to the same function reference. - const seen = new Set() - for (const [_name, fn] of Object.entries(mod)) { - if (seen.has(fn)) continue - seen.add(fn) - const init = await fn(input) + const seen = new Set() + for (const [_name, fn] of Object.entries(mod)) { + if (typeof fn !== "function") continue + const pluginFn = fn as PluginFn + if (seen.has(pluginFn)) continue + seen.add(pluginFn) + const init = await pluginFn(input) hooks.push(init) } } @@ -106,7 +112,6 @@ export namespace Plugin { const hooks = await state().then((x) => x.hooks) const config = await Config.get() for (const hook of hooks) { - // @ts-expect-error this is because we haven't moved plugin to sdk v2 await hook.config?.(config) } Bus.subscribeAll(async (input) => { diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index bf9b6e8c2d8..6fc37c76c64 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -1,16 +1,16 @@ import type { Event, - createOpencodeClient, Project, Model, Provider, - Permission, + PermissionRequest, UserMessage, Message, Part, Auth, Config, -} from "@opencode-ai/sdk" + OpencodeClient, +} from "@opencode-ai/sdk/v2" import type { BunShell } from "./shell" import { type ToolDefinition } from "./tool" @@ -24,7 +24,7 @@ export type ProviderContext = { } export type PluginInput = { - client: ReturnType + client: OpencodeClient project: Project directory: string worktree: string @@ -170,7 +170,7 @@ export interface Hooks { input: { sessionID: string; agent: string; model: Model; provider: ProviderContext; message: UserMessage }, output: { temperature: number; topP: number; topK: number; options: Record }, ) => Promise - "permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise + "permission.ask"?: (input: PermissionRequest, output: { status: "ask" | "deny" | "allow" | "reject" }) => Promise "tool.execute.before"?: ( input: { tool: string; sessionID: string; callID: string }, output: { args: any },