feat(opencode): Adding options to auth login to skip questions (#14470)

Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
This commit is contained in:
Daniel Polito
2026-03-05 03:16:53 -03:00
committed by GitHub
parent 85ff05670a
commit f363904feb

View File

@@ -20,10 +20,19 @@ type PluginAuth = NonNullable<Hooks["auth"]>
* Handle plugin-based authentication flow. * Handle plugin-based authentication flow.
* Returns true if auth was handled, false if it should fall through to default handling. * Returns true if auth was handled, false if it should fall through to default handling.
*/ */
async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string): Promise<boolean> { async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string, methodName?: string): Promise<boolean> {
let index = 0 let index = 0
if (plugin.auth.methods.length > 1) { if (methodName) {
const method = await prompts.select({ const match = plugin.auth.methods.findIndex((x) => x.label.toLowerCase() === methodName.toLowerCase())
if (match === -1) {
prompts.log.error(
`Unknown method "${methodName}" for ${provider}. Available: ${plugin.auth.methods.map((x) => x.label).join(", ")}`,
)
process.exit(1)
}
index = match
} else if (plugin.auth.methods.length > 1) {
const selected = await prompts.select({
message: "Login method", message: "Login method",
options: [ options: [
...plugin.auth.methods.map((x, index) => ({ ...plugin.auth.methods.map((x, index) => ({
@@ -32,8 +41,8 @@ async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string):
})), })),
], ],
}) })
if (prompts.isCancel(method)) throw new UI.CancelledError() if (prompts.isCancel(selected)) throw new UI.CancelledError()
index = parseInt(method) index = parseInt(selected)
} }
const method = plugin.auth.methods[index] const method = plugin.auth.methods[index]
@@ -252,10 +261,21 @@ export const AuthLoginCommand = cmd({
command: "login [url]", command: "login [url]",
describe: "log in to a provider", describe: "log in to a provider",
builder: (yargs) => builder: (yargs) =>
yargs.positional("url", { yargs
describe: "opencode auth provider", .positional("url", {
type: "string", describe: "opencode auth provider",
}), type: "string",
})
.option("provider", {
alias: ["p"],
describe: "provider id or name to log in to (skips provider selection)",
type: "string",
})
.option("method", {
alias: ["m"],
describe: "login method label (skips method selection)",
type: "string",
}),
async handler(args) { async handler(args) {
await Instance.provide({ await Instance.provide({
directory: process.cwd(), directory: process.cwd(),
@@ -322,60 +342,76 @@ export const AuthLoginCommand = cmd({
enabled, enabled,
providerNames: Object.fromEntries(Object.entries(config.provider ?? {}).map(([id, p]) => [id, p.name])), providerNames: Object.fromEntries(Object.entries(config.provider ?? {}).map(([id, p]) => [id, p.name])),
}) })
let provider = await prompts.autocomplete({ const options = [
message: "Select provider", ...pipe(
maxItems: 8, providers,
options: [ values(),
...pipe( sortBy(
providers, (x) => priority[x.id] ?? 99,
values(), (x) => x.name ?? x.id,
sortBy(
(x) => priority[x.id] ?? 99,
(x) => x.name ?? x.id,
),
map((x) => ({
label: x.name,
value: x.id,
hint: {
opencode: "recommended",
anthropic: "Claude Max or API key",
openai: "ChatGPT Plus/Pro or API key",
}[x.id],
})),
), ),
...pluginProviders.map((x) => ({ map((x) => ({
label: x.name, label: x.name,
value: x.id, value: x.id,
hint: "plugin", hint: {
opencode: "recommended",
anthropic: "Claude Max or API key",
openai: "ChatGPT Plus/Pro or API key",
}[x.id],
})), })),
{ ),
value: "other", ...pluginProviders.map((x) => ({
label: "Other", label: x.name,
}, value: x.id,
], hint: "plugin",
}) })),
]
if (prompts.isCancel(provider)) throw new UI.CancelledError() let provider: string
if (args.provider) {
const input = args.provider
const byID = options.find((x) => x.value === input)
const byName = options.find((x) => x.label.toLowerCase() === input.toLowerCase())
const match = byID ?? byName
if (!match) {
prompts.log.error(`Unknown provider "${input}"`)
process.exit(1)
}
provider = match.value
} else {
const selected = await prompts.autocomplete({
message: "Select provider",
maxItems: 8,
options: [
...options,
{
value: "other",
label: "Other",
},
],
})
if (prompts.isCancel(selected)) throw new UI.CancelledError()
provider = selected as string
}
const plugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider)) const plugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
if (plugin && plugin.auth) { if (plugin && plugin.auth) {
const handled = await handlePluginAuth({ auth: plugin.auth }, provider) const handled = await handlePluginAuth({ auth: plugin.auth }, provider, args.method)
if (handled) return if (handled) return
} }
if (provider === "other") { if (provider === "other") {
provider = await prompts.text({ const custom = await prompts.text({
message: "Enter provider id", message: "Enter provider id",
validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"), validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"),
}) })
if (prompts.isCancel(provider)) throw new UI.CancelledError() if (prompts.isCancel(custom)) throw new UI.CancelledError()
provider = provider.replace(/^@ai-sdk\//, "") provider = custom.replace(/^@ai-sdk\//, "")
if (prompts.isCancel(provider)) throw new UI.CancelledError()
// Check if a plugin provides auth for this custom provider // Check if a plugin provides auth for this custom provider
const customPlugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider)) const customPlugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
if (customPlugin && customPlugin.auth) { if (customPlugin && customPlugin.auth) {
const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider) const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider, args.method)
if (handled) return if (handled) return
} }