Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 deletions packages/app/src/components/dialog-connect-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
import { Spinner } from "@opencode-ai/ui/spinner"
import { TextField } from "@opencode-ai/ui/text-field"
import { showToast } from "@/utils/toast"
import { createEffect, createMemo, createResource, Match, onCleanup, onMount, Switch } from "solid-js"
import { createEffect, createMemo, createResource, Match, onCleanup, onMount, Show, Switch } from "solid-js"
import { createStore, produce } from "solid-js/store"
import { Link } from "@/components/link"
import { useServerSDK } from "@/context/server-sdk"
Expand Down Expand Up @@ -523,13 +523,8 @@ export function DialogConnectProvider(props: { provider: string }) {
}

function OAuthAutoView() {
const code = createMemo(() => {
const instructions = store.authorization?.instructions
if (instructions?.includes(":")) {
return instructions.split(":").pop()?.trim()
}
return instructions
})
const instructions = createMemo(() => store.authorization?.instructions.trim())
const code = createMemo(() => store.authorization?.code?.trim())

onMount(() => {
void (async () => {
Expand Down Expand Up @@ -558,15 +553,24 @@ export function DialogConnectProvider(props: { provider: string }) {
<div class="text-14-regular text-text-base">
{language.t("provider.connect.oauth.auto.visit.prefix")}
<Link href={store.authorization!.url}>{language.t("provider.connect.oauth.auto.visit.link")}</Link>
{language.t("provider.connect.oauth.auto.visit.suffix", { provider: provider().name })}
{code()
? language.t("provider.connect.oauth.auto.visit.suffix", { provider: provider().name })
: language.t("provider.connect.oauth.auto.browser", { provider: provider().name })}
</div>
<TextField
label={language.t("provider.connect.oauth.auto.confirmationCode")}
class="font-mono"
value={code()}
readOnly
copyable
/>
<Show when={!code() && instructions()}>
{(value) => <div class="text-14-regular text-text-base whitespace-pre-wrap">{value()}</div>}
</Show>
<Show when={code()}>
{(value) => (
<TextField
label={language.t("provider.connect.oauth.auto.confirmationCode")}
class="font-mono"
value={value()}
readOnly
copyable
/>
)}
</Show>
<div class="text-14-regular text-text-base flex items-center gap-4">
<Spinner />
<span>{language.t("provider.connect.status.waiting")}</span>
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "هذا الرابط",
"provider.connect.oauth.auto.visit.suffix":
" وأدخل الرمز أدناه لتوصيل حسابك واستخدام نماذج {{provider}} في OpenCode.",
"provider.connect.oauth.auto.browser": " لإكمال التفويض في متصفحك. ستغلق هذه النافذة تلقائيًا.",
"provider.connect.oauth.auto.confirmationCode": "رمز التأكيد",
"provider.connect.toast.connected.title": "تم توصيل {{provider}}",
"provider.connect.toast.connected.description": "نماذج {{provider}} متاحة الآن للاستخدام.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "este link",
"provider.connect.oauth.auto.visit.suffix":
" e digite o código abaixo para conectar sua conta e usar modelos do {{provider}} no OpenCode.",
"provider.connect.oauth.auto.browser":
" para concluir a autorização no seu navegador. Esta janela será fechada automaticamente.",
"provider.connect.oauth.auto.confirmationCode": "Código de confirmação",
"provider.connect.toast.connected.title": "{{provider}} conectado",
"provider.connect.toast.connected.description": "Modelos do {{provider}} agora estão disponíveis para uso.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/bs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "ovaj link",
"provider.connect.oauth.auto.visit.suffix":
" i unesi kod ispod da povežeš račun i koristiš {{provider}} modele u OpenCode-u.",
"provider.connect.oauth.auto.browser":
" da završiš autorizaciju u svom pretraživaču. Ovaj prozor će se automatski zatvoriti.",
"provider.connect.oauth.auto.confirmationCode": "Kod za potvrdu",
"provider.connect.toast.connected.title": "{{provider}} povezan",
"provider.connect.toast.connected.description": "{{provider}} modeli su sada dostupni za korištenje.",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "dette link",
"provider.connect.oauth.auto.visit.suffix":
" og indtast koden nedenfor for at forbinde din konto og bruge {{provider}} modeller i OpenCode.",
"provider.connect.oauth.auto.browser": " for at fuldføre godkendelsen i din browser. Dette vindue lukkes automatisk.",
"provider.connect.oauth.auto.confirmationCode": "Bekræftelseskode",
"provider.connect.toast.connected.title": "{{provider}} forbundet",
"provider.connect.toast.connected.description": "{{provider}} modeller er nu tilgængelige.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "diesen Link",
"provider.connect.oauth.auto.visit.suffix":
" und geben Sie den untenstehenden Code ein, um Ihr Konto zu verbinden und {{provider}} Modelle in OpenCode zu nutzen.",
"provider.connect.oauth.auto.browser":
", um die Autorisierung in Ihrem Browser abzuschließen. Dieses Fenster wird automatisch geschlossen.",
"provider.connect.oauth.auto.confirmationCode": "Bestätigungscode",
"provider.connect.toast.connected.title": "{{provider}} verbunden",
"provider.connect.toast.connected.description": "{{provider}} Modelle sind jetzt verfügbar.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "this link",
"provider.connect.oauth.auto.visit.suffix":
" and enter the code below to connect your account and use {{provider}} models in OpenCode.",
"provider.connect.oauth.auto.browser":
" to complete authorization in your browser. This window will close automatically.",
"provider.connect.oauth.auto.confirmationCode": "Confirmation code",
"provider.connect.toast.connected.title": "{{provider}} connected",
"provider.connect.toast.connected.description": "{{provider}} models are now available to use.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "este enlace",
"provider.connect.oauth.auto.visit.suffix":
" e introduce el código a continuación para conectar tu cuenta y usar modelos de {{provider}} en OpenCode.",
"provider.connect.oauth.auto.browser":
" para completar la autorización en tu navegador. Esta ventana se cerrará automáticamente.",
"provider.connect.oauth.auto.confirmationCode": "Código de confirmación",
"provider.connect.toast.connected.title": "{{provider}} conectado",
"provider.connect.toast.connected.description": "Los modelos de {{provider}} ahora están disponibles para usar.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "ce lien",
"provider.connect.oauth.auto.visit.suffix":
" et entrez le code ci-dessous pour connecter votre compte et utiliser les modèles {{provider}} dans OpenCode.",
"provider.connect.oauth.auto.browser":
" pour terminer l'autorisation dans votre navigateur. Cette fenêtre se fermera automatiquement.",
"provider.connect.oauth.auto.confirmationCode": "Code de confirmation",
"provider.connect.toast.connected.title": "{{provider}} connecté",
"provider.connect.toast.connected.description": "Les modèles {{provider}} sont maintenant disponibles.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "このリンク",
"provider.connect.oauth.auto.visit.suffix":
" にアクセスし、以下のコードを入力してアカウントを接続し、OpenCodeで{{provider}}モデルを使用してください。",
"provider.connect.oauth.auto.browser":
" にアクセスしてブラウザでの認証を完了してください。このウィンドウは自動的に閉じます。",
"provider.connect.oauth.auto.confirmationCode": "確認コード",
"provider.connect.toast.connected.title": "{{provider}}が接続されました",
"provider.connect.toast.connected.description": "{{provider}}モデルが使用可能になりました。",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "이 링크",
"provider.connect.oauth.auto.visit.suffix":
"를 방문하고 아래 코드를 입력하여 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.",
"provider.connect.oauth.auto.browser": "를 방문하여 브라우저에서 인증을 완료하세요. 이 창은 자동으로 닫힙니다.",
"provider.connect.oauth.auto.confirmationCode": "확인 코드",
"provider.connect.toast.connected.title": "{{provider}} 연결됨",
"provider.connect.toast.connected.description": "이제 {{provider}} 모델을 사용할 수 있습니다.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/no.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "denne lenken",
"provider.connect.oauth.auto.visit.suffix":
" og skriv inn koden nedenfor for å koble til kontoen din og bruke {{provider}}-modeller i OpenCode.",
"provider.connect.oauth.auto.browser":
" for å fullføre autorisasjonen i nettleseren din. Dette vinduet vil lukkes automatisk.",
"provider.connect.oauth.auto.confirmationCode": "Bekreftelseskode",
"provider.connect.toast.connected.title": "{{provider}} tilkoblet",
"provider.connect.toast.connected.description": "{{provider}}-modeller er nå tilgjengelige.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "ten link",
"provider.connect.oauth.auto.visit.suffix":
" i wprowadź poniższy kod, aby połączyć konto i używać modeli {{provider}} w OpenCode.",
"provider.connect.oauth.auto.browser":
" aby dokończyć autoryzację w przeglądarce. To okno zamknie się automatycznie.",
"provider.connect.oauth.auto.confirmationCode": "Kod potwierdzający",
"provider.connect.toast.connected.title": "Połączono {{provider}}",
"provider.connect.toast.connected.description": "Modele {{provider}} są teraz dostępne do użycia.",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "эту ссылку",
"provider.connect.oauth.auto.visit.suffix":
" и введите код ниже для подключения аккаунта и использования моделей {{provider}} в OpenCode.",
"provider.connect.oauth.auto.browser": " для завершения авторизации в браузере. Это окно закроется автоматически.",
"provider.connect.oauth.auto.confirmationCode": "Код подтверждения",
"provider.connect.toast.connected.title": "{{provider}} подключён",
"provider.connect.toast.connected.description": "Модели {{provider}} теперь доступны.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/th.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "ลิงก์นี้",
"provider.connect.oauth.auto.visit.suffix":
" และป้อนรหัสด้านล่างเพื่อเชื่อมต่อบัญชีและใช้โมเดล {{provider}} ใน OpenCode",
"provider.connect.oauth.auto.browser":
" เพื่อดำเนินการอนุมัติให้เสร็จสมบูรณ์ในเบราว์เซอร์ของคุณ หน้าต่างนี้จะปิดลงโดยอัตโนมัติ",
"provider.connect.oauth.auto.confirmationCode": "รหัสยืนยัน",
"provider.connect.toast.connected.title": "{{provider}} ที่เชื่อมต่อแล้ว",
"provider.connect.toast.connected.description": "โมเดล {{provider}} พร้อมใช้งานแล้ว",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "Bu bağlantıya",
"provider.connect.oauth.auto.visit.suffix":
" tıklayarak aşağıdaki kodu girin ve hesabınızı bağlayarak OpenCode'da {{provider}} modellerini kullanın.",
"provider.connect.oauth.auto.browser":
" tıklayarak tarayıcınızda yetkilendirmeyi tamamlayın. Bu pencere otomatik olarak kapanacaktır.",
"provider.connect.oauth.auto.confirmationCode": "Onay kodu",
"provider.connect.toast.connected.title": "{{provider}} bağlandı",
"provider.connect.toast.connected.description": "{{provider}} modelleri artık kullanımda.",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/uk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "це посилання",
"provider.connect.oauth.auto.visit.suffix":
" і введіть код нижче, щоб підключити обліковий запис і використовувати моделі {{provider}} у OpenCode.",
"provider.connect.oauth.auto.browser":
" щоб завершити авторизацію у вашому браузері. Це вікно закриється автоматично.",
"provider.connect.oauth.auto.confirmationCode": "Код підтвердження",
"provider.connect.toast.connected.title": "{{provider}} підключено",
"provider.connect.toast.connected.description": "Моделі {{provider}} тепер доступні для використання.",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export const dict = {
"provider.connect.oauth.auto.visit.prefix": "访问 ",
"provider.connect.oauth.auto.visit.link": "此链接",
"provider.connect.oauth.auto.visit.suffix": " 并输入以下代码,以连接你的帐户并在 OpenCode 中使用 {{provider}} 模型。",
"provider.connect.oauth.auto.browser": " 以在浏览器中完成授权。此窗口将自动关闭。",
"provider.connect.oauth.auto.confirmationCode": "确认码",
"provider.connect.toast.connected.title": "{{provider}} 已连接",
"provider.connect.toast.connected.description": "现在可以使用 {{provider}} 模型了。",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/zht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export const dict = {
"provider.connect.oauth.auto.visit.link": "此連結",
"provider.connect.oauth.auto.visit.suffix":
" 並輸入以下程式碼,以連線你的帳戶並在 OpenCode 中使用 {{provider}} 模型。",
"provider.connect.oauth.auto.browser": " 以在瀏覽器中完成授權。此視窗將自動關閉。",
"provider.connect.oauth.auto.confirmationCode": "確認碼",
"provider.connect.toast.connected.title": "{{provider}} 已連線",
"provider.connect.toast.connected.description": "現在可以使用 {{provider}} 模型了。",
Expand Down
3 changes: 3 additions & 0 deletions packages/opencode/src/cli/cmd/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ const handlePluginAuth = Effect.fn("Cli.providers.pluginAuth")(function* (
if (authorize.instructions) {
yield* Prompt.log.info(authorize.instructions)
}
if (authorize.code) {
yield* Prompt.log.info("Code: " + authorize.code)
}
const spinner = Prompt.spinner()
yield* spinner.start("Waiting for authorization...")
const result = yield* cliTry("Failed to authorize: ", () => authorize.callback())
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/plugin/github-copilot/copilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> {

return {
url: deviceData.verification_uri,
instructions: `Enter code: ${deviceData.user_code}`,
instructions: "Enter the confirmation code in your browser.",
code: deviceData.user_code,
method: "auto" as const,
async callback() {
while (true) {
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/plugin/openai/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,8 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug

return {
url: `${ISSUER}/codex/device`,
instructions: `Enter code: ${deviceData.user_code}`,
instructions: "Enter the confirmation code in your browser.",
code: deviceData.user_code,
method: "auto" as const,
async callback() {
while (true) {
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/plugin/xai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,8 @@ export async function XaiAuthPlugin(input: PluginInput, options: XaiAuthPluginOp
const browserUrl = device.verification_uri_complete ?? device.verification_uri
return {
url: browserUrl,
instructions: `Open ${device.verification_uri} on any device and enter code: ${device.user_code}`,
instructions: `Open ${device.verification_uri} on any device and enter the confirmation code.`,
code: device.user_code,
method: "auto" as const,
callback: async () => {
try {
Expand Down
2 changes: 2 additions & 0 deletions packages/opencode/src/provider/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class Authorization extends Schema.Class<Authorization>("ProviderAuthAuth
url: Schema.String,
method: Schema.Literals(["auto", "code"]),
instructions: Schema.String,
code: Schema.optional(Schema.String),
}) {}

export const AuthorizeInput = Schema.Struct({
Expand Down Expand Up @@ -182,6 +183,7 @@ export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> =
url: result.url,
method: result.method,
instructions: result.instructions,
...(result.code ? { code: result.code } : {}),
}
})

Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/test/plugin/xai.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,8 @@ describe("plugin.xai", () => {
expect(result.method).toBe("auto")
expect(result.url).toBe("https://x.ai/device?user_code=ABCD-1234")
expect(result.instructions).toContain("https://x.ai/device")
expect(result.instructions).toContain("ABCD-1234")
expect(result.instructions).not.toContain("ABCD-1234")
expect(result.code).toBe("ABCD-1234")
expect(await (result as any).callback()).toMatchObject({ type: "success", refresh: "RT", access: "AT" })
})

Expand Down
3 changes: 3 additions & 0 deletions packages/opencode/test/server/httpapi-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const projectOptions = { config: { formatter: false, lsp: false } }
const providerID = "test-oauth-parity"
const oauthURL = "https://example.com/oauth"
const oauthInstructions = "Finish OAuth"
const oauthCode = "TEST-CODE"

function providerListHasFetch(list: unknown) {
if (!Array.isArray(list)) return false
Expand Down Expand Up @@ -124,6 +125,7 @@ function writeProviderAuthPlugin(dir: string) {
` url: "${oauthURL}",`,
' method: "code",',
` instructions: "${oauthInstructions}",`,
` code: "${oauthCode}",`,
" callback: async () => ({ type: 'success', key: 'token' }),",
" }),",
" },",
Expand Down Expand Up @@ -303,6 +305,7 @@ describe("provider HttpApi", () => {
url: oauthURL,
method: "code",
instructions: oauthInstructions,
code: oauthCode,
})
}),
{ ...projectOptions, init: writeProviderAuthPlugin },
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export type AuthHook = {
)[]
}

export type AuthOAuthResult = { url: string; instructions: string } & (
export type AuthOAuthResult = { url: string; instructions: string; code?: string } & (
| {
method: "auto"
callback(): Promise<
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2539,6 +2539,7 @@ export type ProviderAuthAuthorization = {
url: string
method: "auto" | "code"
instructions: string
code?: string
}

export type ProviderAuthError1 = {
Expand Down
Loading
Loading