/** * External CLI auth selection scoping. * Narrows CLI discovery to the provider/profile selected by model auth routing * so runtime auth setup avoids broad CLI probing. */ import { findNormalizedProviderValue, normalizeProviderId, } from "@openclaw/model-catalog-core/provider-id"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { resolveCliRuntimeExecutionProvider } from "../model-runtime-aliases.js"; import { resolveProviderIdForAuth } from "../provider-auth-aliases.js"; import { CLAUDE_CLI_PROFILE_ID } from "./constants.js"; import type { AuthProfileStore } from "./types.js"; const CLAUDE_CLI_PROVIDER_ID = "claude-cli"; /** Resolve external CLI overlay scope from the user's auth/model selection. */ export function resolveExternalCliAuthOverlayScopeFromSelection(params: { provider: string; cfg?: OpenClawConfig; agentId?: string; modelId?: string; workspaceDir?: string; store?: AuthProfileStore; userPinnedAuthProfileId?: string; }): { providerIds?: readonly string[]; ignoreAutoPreferredProfile: boolean; } { const authScope = resolveExternalCliAuthScopeFromAuthSelection({ provider: params.provider, cfg: params.cfg, workspaceDir: params.workspaceDir, store: params.store, userPinnedAuthProfileId: params.userPinnedAuthProfileId, }); const selectedRuntimeProvider = resolveCliRuntimeExecutionProvider({ provider: params.provider, cfg: params.cfg, agentId: params.agentId, modelId: params.modelId, authProfileId: params.userPinnedAuthProfileId, }) || (params.provider === CLAUDE_CLI_PROVIDER_ID ? CLAUDE_CLI_PROVIDER_ID : undefined); const selectedProvider = authScope.selectedProviderId ?? (selectedRuntimeProvider === CLAUDE_CLI_PROVIDER_ID ? CLAUDE_CLI_PROVIDER_ID : undefined); const providerIds = [ ...new Set([ ...authScope.providerIds, ...(selectedRuntimeProvider === CLAUDE_CLI_PROVIDER_ID ? [CLAUDE_CLI_PROVIDER_ID] : []), ]), ]; return { ...(providerIds.length > 0 ? { providerIds } : {}), ignoreAutoPreferredProfile: // Claude CLI should not auto-prefer a profile when runtime selection has // already chosen Claude CLI and the user did not pin a profile. !params.userPinnedAuthProfileId && selectedProvider === CLAUDE_CLI_PROVIDER_ID, }; } function resolveExternalCliAuthScopeFromAuthSelection(params: { provider: string; cfg?: OpenClawConfig; workspaceDir?: string; store?: AuthProfileStore; userPinnedAuthProfileId?: string; }): { providerIds: string[]; selectedProviderId?: string; } { const providerIds: string[] = []; const orderedProfileIds = resolveConfiguredAuthProfileOrder(params); const allProfileIds = [ ...new Set([ ...Object.keys(params.cfg?.auth?.profiles ?? {}), ...Object.keys(params.store?.profiles ?? {}), ]), ]; const discoveredProfileIds = orderedProfileIds.length > 0 ? orderedProfileIds : allProfileIds; const profileIds = params.userPinnedAuthProfileId ? [ params.userPinnedAuthProfileId, ...discoveredProfileIds.filter((profileId) => profileId !== params.userPinnedAuthProfileId), ] : discoveredProfileIds; let sawCompatibleOrderedProfile = false; let selectedProviderId: string | undefined; let compatibleProfileCount = 0; for (const profileId of profileIds) { const resolved = resolveExternalCliProviderIdForCompatibleAuthProfile({ ...params, profileId, }); if (!resolved.compatible) { continue; } compatibleProfileCount += 1; if (!sawCompatibleOrderedProfile) { selectedProviderId = resolved.externalCliProviderId; sawCompatibleOrderedProfile = true; } if (resolved.externalCliProviderId) { providerIds.push(resolved.externalCliProviderId); } } if (params.userPinnedAuthProfileId || orderedProfileIds.length > 0) { return { providerIds: [...new Set(providerIds)], ...(selectedProviderId ? { selectedProviderId } : {}), }; } const uniqueProviderIds = [...new Set(providerIds)]; return { providerIds: uniqueProviderIds, ...(compatibleProfileCount === 1 && uniqueProviderIds[0] ? // Without explicit order, select only when compatibility is unambiguous. { selectedProviderId: uniqueProviderIds[0] } : {}), }; } function resolveConfiguredAuthProfileOrder(params: { provider: string; cfg?: OpenClawConfig; workspaceDir?: string; store?: AuthProfileStore; }): string[] { const providerAuthKey = resolveProviderIdForAuth(params.provider, { config: params.cfg, workspaceDir: params.workspaceDir, }); const orderedProfileIds = resolveAuthProfileOrderEntries({ order: params.store?.order, provider: params.provider, providerAuthKey, }) ?? resolveAuthProfileOrderEntries({ order: params.cfg?.auth?.order, provider: params.provider, providerAuthKey, }) ?? []; return [ ...new Set( orderedProfileIds .map((profileId) => profileId?.trim()) .filter((profileId): profileId is string => Boolean(profileId)), ), ]; } function resolveAuthProfileOrderEntries(params: { order?: Record; provider: string; providerAuthKey: string; }): string[] | undefined { return ( findNormalizedProviderValue(params.order, params.providerAuthKey) ?? (normalizeProviderId(params.providerAuthKey) === normalizeProviderId(params.provider) ? undefined : findNormalizedProviderValue(params.order, params.provider)) ); } function resolveExternalCliProviderIdForCompatibleAuthProfile(params: { provider: string; cfg?: OpenClawConfig; workspaceDir?: string; store?: AuthProfileStore; profileId: string; }): { compatible: boolean; externalCliProviderId?: string; } { const profile = params.cfg?.auth?.profiles?.[params.profileId]; const credential = params.store?.profiles?.[params.profileId]; const profileProvider = profile?.provider ?? credential?.provider ?? (params.profileId === CLAUDE_CLI_PROFILE_ID ? CLAUDE_CLI_PROVIDER_ID : undefined); if (!profileProvider) { return { compatible: false }; } const authAliasParams = { config: params.cfg, workspaceDir: params.workspaceDir, }; const providerAuthKey = resolveProviderIdForAuth(params.provider, authAliasParams); const profileAuthKey = resolveProviderIdForAuth(profileProvider, { ...authAliasParams, storedCredential: true, }); if (!providerAuthKey || profileAuthKey !== providerAuthKey) { return { compatible: false }; } return { compatible: true, ...(normalizeProviderId(profileProvider) === CLAUDE_CLI_PROVIDER_ID ? { externalCliProviderId: CLAUDE_CLI_PROVIDER_ID } : {}), }; }