Browse Source

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

Co-authored-by: Shoubhit Dash <[email protected]>
Daniel Polito 1 tháng trước cách đây
mục cha
commit
f363904feb
1 tập tin đã thay đổi với 81 bổ sung45 xóa
  1. 81 45
      packages/opencode/src/cli/cmd/auth.ts

+ 81 - 45
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
           }