From ece4b4738c48c22300c08160d9c29d8d01852ccc Mon Sep 17 00:00:00 2001 From: Akshar Patel Date: Tue, 13 Jan 2026 22:34:18 -0500 Subject: [PATCH] feat: show connected providers in /connect dialog --- .../cli/cmd/tui/component/dialog-provider.tsx | 115 +++++++++--------- 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx index cb33c6301bde..74195c8f934e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx @@ -26,67 +26,72 @@ export function createDialogProviderOptions() { const sync = useSync() const dialog = useDialog() const sdk = useSDK() + const connected = createMemo(() => new Set(sync.data.provider_next.connected)) const options = createMemo(() => { return pipe( sync.data.provider_next.all, sortBy((x) => PROVIDER_PRIORITY[x.id] ?? 99), - map((provider) => ({ - title: provider.name, - value: provider.id, - description: { - opencode: "(Recommended)", - anthropic: "(Claude Max or API key)", - openai: "(ChatGPT Plus/Pro or API key)", - }[provider.id], - category: provider.id in PROVIDER_PRIORITY ? "Popular" : "Other", - async onSelect() { - const methods = sync.data.provider_auth[provider.id] ?? [ - { - type: "api", - label: "API key", - }, - ] - let index: number | null = 0 - if (methods.length > 1) { - index = await new Promise((resolve) => { - dialog.replace( - () => ( - ({ - title: x.label, - value: index, - }))} - onSelect={(option) => resolve(option.value)} - /> - ), - () => resolve(null), - ) - }) - } - if (index == null) return - const method = methods[index] - if (method.type === "oauth") { - const result = await sdk.client.provider.oauth.authorize({ - providerID: provider.id, - method: index, - }) - if (result.data?.method === "code") { - dialog.replace(() => ( - - )) + map((provider) => { + const isConnected = connected().has(provider.id) + return { + title: provider.name, + value: provider.id, + description: { + opencode: "(Recommended)", + anthropic: "(Claude Max or API key)", + openai: "(ChatGPT Plus/Pro or API key)", + }[provider.id], + category: provider.id in PROVIDER_PRIORITY ? "Popular" : "Other", + footer: isConnected ? "Connected" : undefined, + async onSelect() { + const methods = sync.data.provider_auth[provider.id] ?? [ + { + type: "api", + label: "API key", + }, + ] + let index: number | null = 0 + if (methods.length > 1) { + index = await new Promise((resolve) => { + dialog.replace( + () => ( + ({ + title: x.label, + value: index, + }))} + onSelect={(option) => resolve(option.value)} + /> + ), + () => resolve(null), + ) + }) } - if (result.data?.method === "auto") { - dialog.replace(() => ( - - )) + if (index == null) return + const method = methods[index] + if (method.type === "oauth") { + const result = await sdk.client.provider.oauth.authorize({ + providerID: provider.id, + method: index, + }) + if (result.data?.method === "code") { + dialog.replace(() => ( + + )) + } + if (result.data?.method === "auto") { + dialog.replace(() => ( + + )) + } } - } - if (method.type === "api") { - return dialog.replace(() => ) - } - }, - })), + if (method.type === "api") { + return dialog.replace(() => ) + } + }, + } + }), ) }) return options