import type { ProviderAuthInteraction } from "@earendil-works/pi-ai"; import type { OAuthLoginCallbacks } from "@earendil-works/pi-ai/oauth"; import { resolveApiKey } from "./auth.js"; import { ENV_API_KEY } from "./env.js"; import { resolveClineAuthCredentials, refreshWorkosToken, credentialsFromWorkos, WORKOS_REFRESH_MARGIN_MS, isWorkosToken, } from "./workos.js"; export function interactionToOAuthCallbacks( interaction: ProviderAuthInteraction, ): OAuthLoginCallbacks { return { onAuth: (info) => { interaction.notify({ type: "auth_url", url: info.url, instructions: info.instructions }); }, onDeviceCode: (info) => { interaction.notify({ type: "device_code", userCode: info.userCode, verificationUri: info.verificationUri, intervalSeconds: info.intervalSeconds, expiresInSeconds: info.expiresInSeconds, }); }, onPrompt: async (prompt) => interaction.prompt({ type: "secret", message: prompt.message, placeholder: prompt.placeholder, signal: interaction.signal, }), onSelect: async (prompt) => { const selected = await interaction.prompt({ type: "select", message: prompt.message, options: prompt.options.map((option) => ({ id: option.id, label: option.label, })), signal: interaction.signal, }); return selected; }, onProgress: (message) => { interaction.notify({ type: "progress", message }); }, }; } export async function resolveAmbientAccessToken( signal?: AbortSignal, ): Promise<{ token: string; source: string } | undefined> { signal?.throwIfAborted(); const envKey = process.env[ENV_API_KEY]?.trim(); if (envKey) return { token: envKey, source: "CLINE_API_KEY" }; const staticKey = resolveApiKey(); if (staticKey) return { token: staticKey, source: "Cline config" }; const clineAuth = resolveClineAuthCredentials(); if (!clineAuth) return undefined; if (clineAuth.expiresAt <= Date.now() + WORKOS_REFRESH_MARGIN_MS) { const refreshed = await refreshWorkosToken( credentialsFromWorkos( clineAuth.accessToken, clineAuth.refreshToken, clineAuth.expiresAt, ), ); return { token: refreshed.access, source: "Cline CLI OAuth" }; } return { token: clineAuth.accessToken, source: "Cline CLI OAuth" }; } export function oauthCredentialToApiKey(credential: { access?: string; refresh?: string; type?: string; key?: string; }): string | undefined { if (typeof credential.key === "string" && credential.key.trim()) { return credential.key.trim(); } if (typeof credential.access === "string" && credential.access.trim()) { const access = credential.access.trim(); if (isWorkosToken(access) || access.length >= 20) return access; } return undefined; }