From 483c3576cb41cc98c3e76464b01d8d1c3f0f17d2 Mon Sep 17 00:00:00 2001 From: Bryan Font Date: Wed, 28 Jan 2026 14:09:09 -0500 Subject: [PATCH 1/2] fix(cli): align auth plugin selection --- packages/opencode/src/cli/cmd/auth.ts | 24 ++++++++---- .../test/cli/auth-plugin-selection.test.ts | 37 +++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 packages/opencode/test/cli/auth-plugin-selection.test.ts diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts index bbaecfd8c711..45180b5373ea 100644 --- a/packages/opencode/src/cli/cmd/auth.ts +++ b/packages/opencode/src/cli/cmd/auth.ts @@ -3,7 +3,7 @@ import { cmd } from "./cmd" import * as prompts from "@clack/prompts" import { UI } from "../ui" import { ModelsDev } from "../../provider/models" -import { map, pipe, sortBy, values } from "remeda" +import { filter, fromEntries, map, pipe, sortBy, values } from "remeda" import path from "path" import os from "os" import { Config } from "../../config/config" @@ -14,6 +14,16 @@ import type { Hooks } from "@opencode-ai/plugin" type PluginAuth = NonNullable +export function authPlugin(plugins: Hooks[], provider: string): PluginAuth | undefined { + const auths = pipe( + plugins, + filter((x) => x.auth?.provider !== undefined), + map((x) => [x.auth!.provider, x.auth!] as const), + fromEntries(), + ) + return auths[provider] +} + /** * Handle plugin-based authentication flow. * Returns true if auth was handled, false if it should fall through to default handling. @@ -307,9 +317,9 @@ export const AuthLoginCommand = cmd({ if (prompts.isCancel(provider)) throw new UI.CancelledError() - const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider)) - if (plugin && plugin.auth) { - const handled = await handlePluginAuth({ auth: plugin.auth }, provider) + const auth = await Plugin.list().then((x) => authPlugin(x, provider)) + if (auth) { + const handled = await handlePluginAuth({ auth }, provider) if (handled) return } @@ -323,9 +333,9 @@ export const AuthLoginCommand = cmd({ if (prompts.isCancel(provider)) throw new UI.CancelledError() // Check if a plugin provides auth for this custom provider - const customPlugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider)) - if (customPlugin && customPlugin.auth) { - const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider) + const custom = await Plugin.list().then((x) => authPlugin(x, provider)) + if (custom) { + const handled = await handlePluginAuth({ auth: custom }, provider) if (handled) return } diff --git a/packages/opencode/test/cli/auth-plugin-selection.test.ts b/packages/opencode/test/cli/auth-plugin-selection.test.ts new file mode 100644 index 000000000000..e19f96a6b506 --- /dev/null +++ b/packages/opencode/test/cli/auth-plugin-selection.test.ts @@ -0,0 +1,37 @@ +import { test, expect } from "bun:test" +import type { Hooks } from "@opencode-ai/plugin" + +const plugins = [ + { + auth: { + provider: "openai", + methods: [{ type: "api", label: "First" }], + }, + }, + { + auth: { + provider: "openai", + methods: [{ type: "api", label: "Second" }], + }, + }, +] satisfies Hooks[] + +test("authPlugin picks last auth provider", async () => { + const mod = await import("../../src/cli/cmd/auth") + const pick = (mod as Record).authPlugin as + | ((items: Hooks[], provider: string) => Hooks["auth"] | undefined) + | undefined + + const result = pick?.(plugins, "openai") + expect(result).toBe(plugins[1].auth) +}) + +test("authPlugin returns undefined when missing", async () => { + const mod = await import("../../src/cli/cmd/auth") + const pick = (mod as Record).authPlugin as + | ((items: Hooks[], provider: string) => Hooks["auth"] | undefined) + | undefined + + const result = pick?.(plugins, "anthropic") + expect(result).toBeUndefined() +}) From 8d69fe1fc03f3953d8fe94f6577ad6299fdfbbb5 Mon Sep 17 00:00:00 2001 From: Bryan Font Date: Wed, 28 Jan 2026 21:08:29 -0500 Subject: [PATCH 2/2] fix(cli): guard auth provider type --- packages/opencode/src/cli/cmd/auth.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts index 45180b5373ea..64a945781ee6 100644 --- a/packages/opencode/src/cli/cmd/auth.ts +++ b/packages/opencode/src/cli/cmd/auth.ts @@ -14,7 +14,8 @@ import type { Hooks } from "@opencode-ai/plugin" type PluginAuth = NonNullable -export function authPlugin(plugins: Hooks[], provider: string): PluginAuth | undefined { +export function authPlugin(plugins: Hooks[], provider: string | symbol): PluginAuth | undefined { + if (typeof provider !== "string") return const auths = pipe( plugins, filter((x) => x.auth?.provider !== undefined),