summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorDaniel Polito <[email protected]>2026-03-05 03:16:53 -0300
committerGitHub <[email protected]>2026-03-05 06:16:53 +0000
commitf363904febd2134e8c73681e1b02cfb283e075a2 (patch)
tree6662fafa4792199fc75258bb3095c0b8e0699b03 /packages
parent85ff05670a53079066fcbc0abc0271ea355585c1 (diff)
downloadopencode-f363904febd2134e8c73681e1b02cfb283e075a2.tar.gz
opencode-f363904febd2134e8c73681e1b02cfb283e075a2.zip
feat(opencode): Adding options to auth login to skip questions (#14470)
Co-authored-by: Shoubhit Dash <[email protected]>
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/cli/cmd/auth.ts126
1 files changed, 81 insertions, 45 deletions
diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts
index 4afe7a822..a7300e029 100644
--- a/packages/opencode/src/cli/cmd/auth.ts
+++ b/packages/opencode/src/cli/cmd/auth.ts
@@ -20,10 +20,19 @@ type PluginAuth = NonNullable<Hooks["auth"]>
* Handle plugin-based authentication flow.
* 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
- if (plugin.auth.methods.length > 1) {
- const method = await prompts.select({
+ if (methodName) {
+ 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",
options: [
...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()
- index = parseInt(method)
+ if (prompts.isCancel(selected)) throw new UI.CancelledError()
+ index = parseInt(selected)
}
const method = plugin.auth.methods[index]
@@ -252,10 +261,21 @@ export const AuthLoginCommand = cmd({
command: "login [url]",
describe: "log in to a provider",
builder: (yargs) =>
- yargs.positional("url", {
- describe: "opencode auth provider",
- type: "string",
- }),
+ yargs
+ .positional("url", {
+ 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) {
await Instance.provide({
directory: process.cwd(),
@@ -322,60 +342,76 @@ export const AuthLoginCommand = cmd({
enabled,
providerNames: Object.fromEntries(Object.entries(config.provider ?? {}).map(([id, p]) => [id, p.name])),
})
- let provider = await prompts.autocomplete({
- message: "Select provider",
- maxItems: 8,
- options: [
- ...pipe(
- providers,
- values(),
- 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],
- })),
+ const options = [
+ ...pipe(
+ providers,
+ values(),
+ sortBy(
+ (x) => priority[x.id] ?? 99,
+ (x) => x.name ?? x.id,
),
- ...pluginProviders.map((x) => ({
+ map((x) => ({
label: x.name,
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",
- label: "Other",
- },
- ],
- })
-
- if (prompts.isCancel(provider)) throw new UI.CancelledError()
+ ),
+ ...pluginProviders.map((x) => ({
+ label: x.name,
+ value: x.id,
+ hint: "plugin",
+ })),
+ ]
+
+ 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))
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 (provider === "other") {
- provider = await prompts.text({
+ const custom = await prompts.text({
message: "Enter provider id",
validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"),
})
- if (prompts.isCancel(provider)) throw new UI.CancelledError()
- provider = provider.replace(/^@ai-sdk\//, "")
- if (prompts.isCancel(provider)) throw new UI.CancelledError()
+ if (prompts.isCancel(custom)) throw new UI.CancelledError()
+ provider = custom.replace(/^@ai-sdk\//, "")
// Check if a plugin provides auth for this custom provider
const customPlugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
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
}