import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-mnp54Vah.js";
import { c as redactSensitiveText } from "./redact-B-zel-ih.js";
import { o as asDateTimestampMs } from "./number-coercion-CJQ8TR--.js";
import { i as formatErrorMessage } from "./errors-Ca_eBjrO.js";
import "./number-coercion-Z7n6tXLk.js";
import { p as normalizeSecretInputString, s as coerceSecretRef } from "./types.secrets-BHLVnd7g.js";
import { i as normalizeProviderId } from "./provider-id-Dq06Bcx6.js";
import { i as resolveSecretRefString } from "./resolve-kVXc_5sH.js";
import { i as getRuntimeConfig } from "./io-CHZy8A_F.js";
import { r as resolveProviderIdForAuth } from "./provider-auth-aliases-DFlrLmps.js";
import { o as withFileLock } from "./file-lock-BOaqUSu6.js";
import "./file-lock-DQM8YrNh.js";
import "./config-CP7xGHZu.js";
import { f as resolveOAuthRefreshLockPath, i as hasRuntimeAuthProfileStoreSnapshot, l as resolveAuthStorePath, n as getRuntimeAuthProfileStoreSnapshot, o as setRuntimeAuthProfileStoreSnapshot } from "./runtime-snapshots-BrlbKjFt.js";
import { C as readExternalCliFallbackCredential, D as hasUsableOAuthCredential, E as hasMatchingOAuthIdentity, H as OAUTH_REFRESH_CALL_TIMEOUT_MS, I as resolveTokenExpiryState, M as shouldReplaceStoredOAuthCredential, O as isSafeToAdoptBootstrapOAuthIdentity, S as readExternalCliBootstrapCredential, T as areOAuthCredentialsEquivalent, U as OAUTH_REFRESH_LOCK_OPTIONS, W as log, f as resolvePersistedAuthProfileOwnerAgentDir, i as ensureAuthProfileStoreWithoutExternalProfiles, j as shouldBootstrapFromExternalCliCredential, k as isSafeToAdoptMainStoreOAuthIdentity, l as loadAuthProfileStoreForSecretsRuntime, m as updateAuthProfileStoreWithLock, u as loadAuthProfileStoreWithoutExternalProfiles } from "./store-BJHxj4tW.js";
import { i as formatProviderAuthProfileApiKeyWithPlugin, n as buildProviderAuthDoctorHintWithPlugin, o as refreshProviderOAuthCredentialWithPlugin } from "./provider-runtime.runtime.js";
import { r as getOAuthProviders, t as getOAuthApiKey } from "./oauth-DuxSZjfh.js";
import { t as normalizeOptionalSecretInput } from "./normalize-secret-input-JuG5HlWn.js";
import { a as refreshChutesTokens } from "./chutes-oauth-XPlYj6Mv.js";
import { t as OAuthRefreshFailureError } from "./oauth-refresh-failure-DNxwJzrt.js";
import { t as assertNoOAuthSecretRefPolicyViolations } from "./policy-CoLboh9g.js";
import { t as clearLastGoodProfileWithLock } from "./profiles-DJprfDgq.js";
import { n as suggestOAuthProfileIdForLegacyDefault } from "./repair-Cjru85Y0.js";
//#region src/agents/auth-profiles/doctor.ts
/**
* Provider-specific auth doctor hints.
* Adds local migration guidance for known legacy profiles before falling back
* to provider plugin doctor copy.
*/
const QWEN_PORTAL_OAUTH_MIGRATION_HINT = "Legacy Qwen Portal OAuth profiles are not refreshable. Re-authenticate with a current portal token: openclaw onboard --auth-choice qwen-oauth.";
function hasLegacyQwenPortalOAuthProfile(store, profileId) {
	return (profileId ? [store.profiles[profileId]] : Object.values(store.profiles)).some((profile) => profile?.type === "oauth" && normalizeProviderId(profile.provider) === "qwen-portal");
}
/** Formats provider-specific auth doctor guidance for a profile/store. */
async function formatAuthDoctorHint(params) {
	const normalizedProvider = normalizeProviderId(params.provider);
	if (normalizedProvider === "qwen-portal" && hasLegacyQwenPortalOAuthProfile(params.store, params.profileId)) return QWEN_PORTAL_OAUTH_MIGRATION_HINT;
	const pluginHint = await buildProviderAuthDoctorHintWithPlugin({
		provider: normalizedProvider,
		context: {
			config: params.cfg,
			store: params.store,
			provider: normalizedProvider,
			profileId: params.profileId
		}
	});
	if (typeof pluginHint === "string" && pluginHint.trim()) return pluginHint;
	return "";
}
//#endregion
//#region src/agents/auth-profiles/oauth-identity.ts
/**
* OAuth identity comparison and mirroring decisions.
* Guards cross-agent credential copy/adoption so refreshed credentials cannot
* overwrite a different account's local auth state.
*/
/** Normalize account-id style identity tokens for exact comparison. */
function normalizeAuthIdentityToken(value) {
	const trimmed = value?.trim();
	return trimmed ? trimmed : void 0;
}
/** Normalize email identity tokens for case-insensitive comparison. */
function normalizeAuthEmailToken(value) {
	return normalizeAuthIdentityToken(value)?.toLowerCase();
}
/**
* One-sided copy gate for both directions:
* - mirror: sub-agent refresh -> main-agent store
* - adopt: main-agent store -> sub-agent store
*/
function isSafeToCopyOAuthIdentity(existing, incoming) {
	const aAcct = normalizeAuthIdentityToken(existing.accountId);
	const bAcct = normalizeAuthIdentityToken(incoming.accountId);
	const aEmail = normalizeAuthEmailToken(existing.email);
	const bEmail = normalizeAuthEmailToken(incoming.email);
	if (aAcct !== void 0 && bAcct !== void 0) return aAcct === bAcct;
	if (aEmail !== void 0 && bEmail !== void 0) return aEmail === bEmail;
	if (aAcct !== void 0 || aEmail !== void 0) return false;
	return true;
}
/** Decide whether a refreshed OAuth credential should mirror into another store. */
function shouldMirrorRefreshedOAuthCredential(params) {
	const { existing, refreshed } = params;
	if (!existing) return {
		shouldMirror: true,
		reason: "no-existing-credential"
	};
	if (existing.type !== "oauth") return {
		shouldMirror: false,
		reason: "non-oauth-existing-credential"
	};
	if (existing.provider !== refreshed.provider) return {
		shouldMirror: false,
		reason: "provider-mismatch"
	};
	if (!isSafeToCopyOAuthIdentity(existing, refreshed)) return {
		shouldMirror: false,
		reason: "identity-mismatch-or-regression"
	};
	const refreshedExpires = asDateTimestampMs(refreshed.expires);
	if (refreshedExpires === void 0) return {
		shouldMirror: false,
		reason: "incoming-not-fresher"
	};
	const existingExpires = asDateTimestampMs(existing.expires);
	if (existingExpires !== void 0 && existingExpires >= refreshedExpires) return {
		shouldMirror: false,
		reason: "incoming-not-fresher"
	};
	return {
		shouldMirror: true,
		reason: "incoming-fresher"
	};
}
//#endregion
//#region src/agents/auth-profiles/oauth-refresh-lock-errors.ts
/**
* OAuth refresh lock error helpers.
* Distinguishes global refresh-lock contention from auth-store lock timeouts
* and builds the user-facing contention error.
*/
/** Returns true when an error came from the global OAuth refresh lock. */
function isGlobalRefreshLockTimeoutError(error, lockPath) {
	const candidate = typeof error === "object" && error !== null ? error : void 0;
	return candidate?.code === "file_lock_timeout" && candidate.lockPath === `${lockPath}.lock`;
}
/** Builds the user-facing OAuth refresh contention error. */
function buildRefreshContentionError(params) {
	return Object.assign(new Error(`OAuth refresh failed (refresh_contention): another process is already refreshing ${params.provider} for ${params.profileId}. Please wait for the in-flight refresh to finish and retry.`, { cause: params.cause }), {
		code: "refresh_contention",
		cause: params.cause
	});
}
//#endregion
//#region src/agents/auth-profiles/oauth-manager.ts
/** Refresh failure that preserves a redacted refreshed store and credential. */
var OAuthManagerRefreshError = class extends OAuthRefreshFailureError {
	#refreshedStore;
	#credential;
	constructor(params) {
		const structuredCause = typeof params.cause === "object" && params.cause !== null ? params.cause : void 0;
		const delegatedCause = structuredCause?.code === "refresh_contention" && structuredCause.cause ? structuredCause.cause : params.cause;
		const storedCredential = params.refreshedStore.profiles[params.profileId];
		const secrets = collectOAuthCredentialSecrets(params.credential, ...params.attemptedCredentials ?? [], storedCredential?.type === "oauth" ? storedCredential : void 0);
		const causeMessage = formatRedactedOAuthRefreshError(params.cause, secrets);
		super({
			provider: params.credential.provider,
			message: `OAuth token refresh failed for ${params.credential.provider}: ${causeMessage}`,
			cause: createRedactedOAuthRefreshCause(delegatedCause, secrets)
		});
		this.name = "OAuthManagerRefreshError";
		this.#credential = params.credential;
		this.profileId = params.profileId;
		this.#refreshedStore = params.refreshedStore;
		if (structuredCause) {
			this.code = typeof structuredCause.code === "string" ? structuredCause.code : void 0;
			if (typeof structuredCause.lockPath === "string") this.lockPath = structuredCause.lockPath;
			else if (typeof structuredCause.cause === "object" && structuredCause.cause !== null && "lockPath" in structuredCause.cause && typeof structuredCause.cause.lockPath === "string") this.lockPath = structuredCause.cause.lockPath;
		}
	}
	getRefreshedStore() {
		return this.#refreshedStore;
	}
	getCredential() {
		return this.#credential;
	}
	toJSON() {
		return {
			name: this.name,
			message: this.message,
			profileId: this.profileId,
			provider: this.provider
		};
	}
};
function hasOAuthCredentialChanged(previous, current) {
	return previous.access !== current.access || previous.refresh !== current.refresh || previous.expires !== current.expires;
}
function canReuseOAuthCredentialAfterRefreshFailure(params) {
	return !params.forceRefresh || hasOAuthCredentialChanged(params.attempted, params.candidate);
}
function collectOAuthCredentialSecrets(...credentials) {
	const secrets = /* @__PURE__ */ new Set();
	for (const credential of credentials) for (const secret of [
		credential?.access,
		credential?.refresh,
		credential?.idToken
	]) if (secret) secrets.add(secret);
	return Array.from(secrets).toSorted((a, b) => b.length - a.length);
}
function redactOAuthCredentialSecrets(message, secrets) {
	let redacted = message;
	for (const secret of secrets) redacted = redacted.split(secret).join("[redacted]");
	return redacted;
}
function formatRawErrorMessage(error) {
	if (error instanceof Error) {
		let formatted = error.message || error.name || "Error";
		let cause = error.cause;
		const seen = new Set([error]);
		while (cause && !seen.has(cause)) {
			seen.add(cause);
			if (cause instanceof Error) {
				if (cause.message) formatted += ` | ${cause.message}`;
				cause = cause.cause;
			} else if (typeof cause === "string") {
				formatted += ` | ${cause}`;
				break;
			} else break;
		}
		return formatted;
	}
	if (typeof error === "string" || typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") return String(error);
	try {
		return JSON.stringify(error) ?? String(error);
	} catch {
		return Object.prototype.toString.call(error);
	}
}
function formatRedactedOAuthRefreshError(error, secrets) {
	return redactSensitiveText(redactOAuthCredentialSecrets(formatRawErrorMessage(error), secrets));
}
function createRedactedOAuthRefreshCause(cause, secrets) {
	const redacted = formatRedactedOAuthRefreshError(cause, secrets);
	const sanitized = new Error(redacted);
	if (cause instanceof Error && cause.name) sanitized.name = cause.name;
	return sanitized;
}
function loadStoredOAuthRefreshStore(agentDir) {
	return loadAuthProfileStoreWithoutExternalProfiles(agentDir, { allowKeychainPrompt: true });
}
async function loadFreshStoredOAuthCredential(params) {
	const reloaded = loadStoredOAuthRefreshStore(params.agentDir).profiles[params.profileId];
	if (reloaded?.type !== "oauth" || reloaded.provider !== params.provider || !hasUsableOAuthCredential(reloaded)) return null;
	if (params.requireChange && params.previous && !hasOAuthCredentialChanged(params.previous, reloaded)) return null;
	return reloaded;
}
/** Select local OAuth unless a safe external bootstrap credential should win. */
function resolveEffectiveOAuthCredential(params) {
	const imported = params.readBootstrapCredential({
		profileId: params.profileId,
		credential: params.credential
	});
	if (!imported) return params.credential;
	if (hasUsableOAuthCredential(params.credential)) {
		log.debug("resolved oauth credential from canonical local store", {
			profileId: params.profileId,
			provider: params.credential.provider,
			localExpires: params.credential.expires,
			externalExpires: imported.expires
		});
		return params.credential;
	}
	if (!isSafeToAdoptBootstrapOAuthIdentity(params.credential, imported)) {
		log.warn("refused external oauth bootstrap credential: identity mismatch or missing binding", {
			profileId: params.profileId,
			provider: params.credential.provider
		});
		return params.credential;
	}
	if (shouldBootstrapFromExternalCliCredential({
		existing: params.credential,
		imported
	})) {
		log.debug("resolved oauth credential from external cli bootstrap", {
			profileId: params.profileId,
			provider: imported.provider,
			localExpires: params.credential.expires,
			externalExpires: imported.expires
		});
		return imported;
	}
	return params.credential;
}
/** Create an OAuth manager bound to provider-specific build/refresh adapters. */
function createOAuthManager(adapter) {
	function adoptNewerMainOAuthCredential(params) {
		if (!params.agentDir) return null;
		try {
			const mainCred = ensureAuthProfileStoreWithoutExternalProfiles(void 0, { allowKeychainPrompt: false }).profiles[params.profileId];
			if (mainCred?.type !== "oauth") return null;
			const mainExpires = asDateTimestampMs(mainCred.expires);
			const localExpires = asDateTimestampMs(params.credential.expires);
			if (mainCred.provider === params.credential.provider && hasUsableOAuthCredential(mainCred) && mainExpires !== void 0 && (localExpires === void 0 || mainExpires > localExpires) && isSafeToAdoptMainStoreOAuthIdentity(params.credential, mainCred)) {
				params.store.profiles[params.profileId] = { ...mainCred };
				log.info("adopted newer OAuth credentials from main agent", {
					profileId: params.profileId,
					agentDir: params.agentDir,
					expires: new Date(mainCred.expires).toISOString()
				});
				return mainCred;
			}
		} catch (err) {
			log.debug("adoptNewerMainOAuthCredential failed", {
				profileId: params.profileId,
				error: formatErrorMessage(err)
			});
		}
		return null;
	}
	const refreshQueues = /* @__PURE__ */ new Map();
	function refreshQueueKey(provider, profileId) {
		return `${provider}\u0000${profileId}`;
	}
	async function withRefreshCallTimeout(label, timeoutMs, fn) {
		let timeoutHandle;
		try {
			return await new Promise((resolve, reject) => {
				timeoutHandle = setTimeout(() => {
					reject(/* @__PURE__ */ new Error(`OAuth refresh call "${label}" exceeded hard timeout (${timeoutMs}ms)`));
				}, timeoutMs);
				fn().then(resolve, reject);
			});
		} finally {
			if (timeoutHandle) clearTimeout(timeoutHandle);
		}
	}
	async function mirrorRefreshedCredentialIntoMainStore(params) {
		try {
			await updateAuthProfileStoreWithLock({
				agentDir: void 0,
				updater: (store) => {
					const existing = store.profiles[params.profileId];
					const decision = shouldMirrorRefreshedOAuthCredential({
						existing,
						refreshed: params.refreshed
					});
					if (!decision.shouldMirror) {
						if (decision.reason === "identity-mismatch-or-regression") log.warn("refused to mirror OAuth credential: identity mismatch or regression", { profileId: params.profileId });
						return false;
					}
					store.profiles[params.profileId] = { ...params.refreshed };
					log.debug("mirrored refreshed OAuth credential to main agent store", {
						profileId: params.profileId,
						expires: Number.isFinite(params.refreshed.expires) ? new Date(params.refreshed.expires).toISOString() : void 0
					});
					return true;
				}
			});
		} catch (err) {
			log.debug("mirrorRefreshedCredentialIntoMainStore failed", {
				profileId: params.profileId,
				error: formatErrorMessage(err)
			});
		}
	}
	async function saveOAuthCredentialWithStoreLock(params) {
		let saved = false;
		return await updateAuthProfileStoreWithLock({
			agentDir: params.agentDir,
			updater: (store) => {
				const existing = store.profiles[params.profileId];
				const expectedCredentials = Array.isArray(params.expected) ? params.expected : [params.expected];
				if (existing?.type !== "oauth" || !expectedCredentials.some((expected) => areOAuthCredentialsEquivalent(existing, expected))) {
					log.debug("skipped OAuth credential write because stored profile changed", { profileId: params.profileId });
					return false;
				}
				if (!isSafeToAdoptBootstrapOAuthIdentity(existing, params.credential) || !shouldReplaceStoredOAuthCredential(existing, params.credential)) {
					log.debug("skipped OAuth credential write because stored profile changed", { profileId: params.profileId });
					return false;
				}
				store.profiles[params.profileId] = { ...params.credential };
				saved = true;
				return true;
			}
		}) !== null && saved;
	}
	async function doRefreshOAuthTokenWithLock(params) {
		const ownerAgentDir = resolvePersistedAuthProfileOwnerAgentDir(params);
		const authPath = resolveAuthStorePath(ownerAgentDir);
		const globalRefreshLockPath = resolveOAuthRefreshLockPath(params.provider, params.profileId);
		try {
			return await withFileLock(globalRefreshLockPath, OAUTH_REFRESH_LOCK_OPTIONS, async () => {
				const store = loadStoredOAuthRefreshStore(ownerAgentDir);
				const cred = store.profiles[params.profileId];
				if (!cred || cred.type !== "oauth") return null;
				let credentialToRefresh = cred;
				if (!params.forceRefresh && hasUsableOAuthCredential(cred)) return {
					apiKey: await adapter.buildApiKey(cred.provider, cred, {
						cfg: params.cfg,
						agentDir: params.agentDir
					}),
					credential: cred
				};
				if (params.agentDir) try {
					const mainCred = loadStoredOAuthRefreshStore(void 0).profiles[params.profileId];
					if (mainCred?.type === "oauth" && mainCred.provider === cred.provider && hasUsableOAuthCredential(mainCred) && !params.forceRefresh && isSafeToAdoptMainStoreOAuthIdentity(cred, mainCred)) {
						store.profiles[params.profileId] = { ...mainCred };
						log.info("adopted fresh OAuth credential from main store (under refresh lock)", {
							profileId: params.profileId,
							agentDir: params.agentDir,
							expires: new Date(mainCred.expires).toISOString()
						});
						return {
							apiKey: await adapter.buildApiKey(mainCred.provider, mainCred, {
								cfg: params.cfg,
								agentDir: params.agentDir
							}),
							credential: mainCred
						};
					} else if (mainCred?.type === "oauth" && mainCred.provider === cred.provider && hasUsableOAuthCredential(mainCred) && !isSafeToAdoptMainStoreOAuthIdentity(cred, mainCred)) log.warn("refused to adopt fresh main-store OAuth credential: identity mismatch", {
						profileId: params.profileId,
						agentDir: params.agentDir
					});
				} catch (err) {
					log.debug("inside-lock main-store adoption failed; proceeding to refresh", {
						profileId: params.profileId,
						error: formatErrorMessage(err)
					});
				}
				const externallyManaged = adapter.readBootstrapCredential({
					profileId: params.profileId,
					credential: cred
				});
				if (externallyManaged) if (externallyManaged.provider !== cred.provider) log.warn("refused external oauth bootstrap credential: provider mismatch", {
					profileId: params.profileId,
					provider: cred.provider
				});
				else if (!isSafeToAdoptBootstrapOAuthIdentity(cred, externallyManaged)) log.warn("refused external oauth bootstrap credential: identity mismatch or missing binding", {
					profileId: params.profileId,
					provider: cred.provider
				});
				else {
					if (shouldReplaceStoredOAuthCredential(cred, externallyManaged) && !areOAuthCredentialsEquivalent(cred, externallyManaged)) {
						store.profiles[params.profileId] = { ...externallyManaged };
						await saveOAuthCredentialWithStoreLock({
							agentDir: ownerAgentDir,
							profileId: params.profileId,
							expected: cred,
							credential: externallyManaged
						});
					}
					credentialToRefresh = externallyManaged;
					if (!params.forceRefresh && hasUsableOAuthCredential(externallyManaged)) return {
						apiKey: await adapter.buildApiKey(externallyManaged.provider, externallyManaged, {
							cfg: params.cfg,
							agentDir: params.agentDir
						}),
						credential: externallyManaged
					};
				}
				if (normalizeSecretInputString(credentialToRefresh.refresh) === void 0) return null;
				const refreshedCredentials = await withRefreshCallTimeout(`refreshOAuthCredential(${cred.provider})`, OAUTH_REFRESH_CALL_TIMEOUT_MS, async () => {
					params.attemptedCredentials?.push(credentialToRefresh);
					const refreshed = await adapter.refreshCredential(credentialToRefresh);
					return refreshed ? {
						...credentialToRefresh,
						...refreshed,
						type: "oauth"
					} : null;
				});
				if (!refreshedCredentials) return null;
				store.profiles[params.profileId] = refreshedCredentials;
				if (!await saveOAuthCredentialWithStoreLock({
					agentDir: ownerAgentDir,
					profileId: params.profileId,
					expected: credentialToRefresh === cred || areOAuthCredentialsEquivalent(credentialToRefresh, cred) ? credentialToRefresh : [credentialToRefresh, cred],
					credential: refreshedCredentials
				})) throw new Error("Failed to persist refreshed OAuth credential");
				if (ownerAgentDir) {
					if (resolveAuthStorePath(void 0) !== authPath) await mirrorRefreshedCredentialIntoMainStore({
						profileId: params.profileId,
						refreshed: refreshedCredentials
					});
				}
				return {
					apiKey: await adapter.buildApiKey(cred.provider, refreshedCredentials, {
						cfg: params.cfg,
						agentDir: params.agentDir
					}),
					credential: refreshedCredentials
				};
			});
		} catch (error) {
			if (isGlobalRefreshLockTimeoutError(error, globalRefreshLockPath)) throw buildRefreshContentionError({
				provider: params.provider,
				profileId: params.profileId,
				cause: error
			});
			throw error;
		}
	}
	async function refreshOAuthTokenWithLock(params) {
		const key = refreshQueueKey(params.provider, params.profileId);
		const prev = refreshQueues.get(key) ?? Promise.resolve();
		let release;
		const gate = new Promise((resolve) => {
			release = resolve;
		});
		refreshQueues.set(key, gate);
		try {
			await prev;
			return await doRefreshOAuthTokenWithLock(params);
		} finally {
			release();
			if (refreshQueues.get(key) === gate) refreshQueues.delete(key);
		}
	}
	async function resolveOAuthAccess(params) {
		const adoptedCredential = adoptNewerMainOAuthCredential({
			store: params.store,
			profileId: params.profileId,
			agentDir: params.agentDir,
			credential: params.credential
		}) ?? params.credential;
		const effectiveCredential = resolveEffectiveOAuthCredential({
			profileId: params.profileId,
			credential: adoptedCredential,
			readBootstrapCredential: adapter.readBootstrapCredential
		});
		const attemptedCredentials = [];
		if (!params.forceRefresh && hasUsableOAuthCredential(effectiveCredential)) return {
			apiKey: await adapter.buildApiKey(effectiveCredential.provider, effectiveCredential, {
				cfg: params.cfg,
				agentDir: params.agentDir
			}),
			credential: effectiveCredential
		};
		try {
			return await refreshOAuthTokenWithLock({
				profileId: params.profileId,
				provider: params.credential.provider,
				agentDir: params.agentDir,
				cfg: params.cfg,
				forceRefresh: params.forceRefresh,
				attemptedCredentials
			});
		} catch (error) {
			const refreshedStore = loadStoredOAuthRefreshStore(params.agentDir);
			const refreshed = refreshedStore.profiles[params.profileId];
			if (refreshed?.type === "oauth" && hasUsableOAuthCredential(refreshed) && canReuseOAuthCredentialAfterRefreshFailure({
				forceRefresh: params.forceRefresh,
				attempted: effectiveCredential,
				candidate: refreshed
			})) return {
				apiKey: await adapter.buildApiKey(refreshed.provider, refreshed, {
					cfg: params.cfg,
					agentDir: params.agentDir
				}),
				credential: refreshed
			};
			if (adapter.isRefreshTokenReusedError(error) && refreshed?.type === "oauth" && refreshed.provider === params.credential.provider && hasOAuthCredentialChanged(params.credential, refreshed)) {
				const recovered = await loadFreshStoredOAuthCredential({
					profileId: params.profileId,
					agentDir: params.agentDir,
					provider: params.credential.provider,
					previous: effectiveCredential,
					requireChange: true
				});
				if (recovered) return {
					apiKey: await adapter.buildApiKey(recovered.provider, recovered, {
						cfg: params.cfg,
						agentDir: params.agentDir
					}),
					credential: recovered
				};
				try {
					const retried = await refreshOAuthTokenWithLock({
						profileId: params.profileId,
						provider: params.credential.provider,
						agentDir: params.agentDir,
						cfg: params.cfg,
						forceRefresh: params.forceRefresh,
						attemptedCredentials
					});
					if (retried) return retried;
				} catch {}
			}
			if (params.agentDir) try {
				const mainCred = ensureAuthProfileStoreWithoutExternalProfiles(void 0, { allowKeychainPrompt: false }).profiles[params.profileId];
				if (mainCred?.type === "oauth" && mainCred.provider === params.credential.provider && hasUsableOAuthCredential(mainCred) && canReuseOAuthCredentialAfterRefreshFailure({
					forceRefresh: params.forceRefresh,
					attempted: effectiveCredential,
					candidate: mainCred
				}) && isSafeToAdoptMainStoreOAuthIdentity(params.credential, mainCred)) {
					refreshedStore.profiles[params.profileId] = { ...mainCred };
					log.info("inherited fresh OAuth credentials from main agent", {
						profileId: params.profileId,
						agentDir: params.agentDir,
						expires: new Date(mainCred.expires).toISOString()
					});
					return {
						apiKey: await adapter.buildApiKey(mainCred.provider, mainCred, {
							cfg: params.cfg,
							agentDir: params.agentDir
						}),
						credential: mainCred
					};
				}
			} catch {}
			const fallback = adapter.readFallbackCredential?.({
				profileId: params.profileId,
				credential: effectiveCredential
			});
			if (fallback && fallback.provider === params.credential.provider && hasUsableOAuthCredential(fallback) && hasMatchingOAuthIdentity(params.credential, fallback) && canReuseOAuthCredentialAfterRefreshFailure({
				forceRefresh: params.forceRefresh,
				attempted: effectiveCredential,
				candidate: fallback
			})) {
				log.info("using external OAuth credential after refresh failure", {
					profileId: params.profileId,
					provider: fallback.provider,
					expires: new Date(fallback.expires).toISOString()
				});
				return {
					apiKey: await adapter.buildApiKey(fallback.provider, fallback, {
						cfg: params.cfg,
						agentDir: params.agentDir
					}),
					credential: fallback
				};
			}
			throw new OAuthManagerRefreshError({
				credential: params.credential,
				attemptedCredentials: [effectiveCredential, ...attemptedCredentials],
				profileId: params.profileId,
				refreshedStore,
				cause: error
			});
		}
	}
	function resetRefreshQueuesForTest() {
		refreshQueues.clear();
	}
	return {
		resolveOAuthAccess,
		resetRefreshQueuesForTest
	};
}
//#endregion
//#region src/agents/auth-profiles/oauth.ts
/**
* Auth profile API-key/OAuth runtime resolver.
* Converts selected auth profiles into provider API keys, refreshes OAuth
* credentials, resolves SecretRefs, and maintains runtime store snapshots.
*/
function listOAuthProviderIds() {
	if (typeof getOAuthProviders !== "function") return [];
	const providers = getOAuthProviders();
	if (!Array.isArray(providers)) return [];
	return providers.map((provider) => provider && typeof provider === "object" && "id" in provider && typeof provider.id === "string" ? provider.id : void 0).filter((providerId) => typeof providerId === "string");
}
const OAUTH_PROVIDER_IDS = new Set(listOAuthProviderIds());
const isOAuthProvider = (provider) => OAUTH_PROVIDER_IDS.has(provider);
const resolveOAuthProvider = (provider) => isOAuthProvider(provider) ? provider : null;
/** Bearer-token auth modes that are interchangeable (oauth tokens and raw tokens). */
const BEARER_AUTH_MODES = new Set(["oauth", "token"]);
const isCompatibleModeType = (mode, type) => {
	if (!mode || !type) return false;
	if (mode === type) return true;
	return BEARER_AUTH_MODES.has(mode) && BEARER_AUTH_MODES.has(type);
};
function isProfileConfigCompatible(params) {
	const profileConfig = params.cfg?.auth?.profiles?.[params.profileId];
	if (profileConfig && profileConfig.provider !== params.provider) return false;
	if (profileConfig && !isCompatibleModeType(profileConfig.mode, params.mode)) return false;
	return true;
}
async function buildOAuthApiKey(provider, credentials, context) {
	const formatted = await formatProviderAuthProfileApiKeyWithPlugin({
		provider,
		config: context.cfg,
		context: credentials
	});
	return typeof formatted === "string" && formatted.length > 0 ? formatted : credentials.access;
}
function buildApiKeyProfileResult(params) {
	const result = {
		apiKey: params.apiKey,
		provider: params.provider,
		email: params.email
	};
	Object.defineProperties(result, {
		profileId: {
			value: params.profileId,
			enumerable: false
		},
		profileType: {
			value: params.profileType,
			enumerable: false
		},
		credential: {
			value: params.credential,
			enumerable: false
		}
	});
	return result;
}
function extractErrorMessage(error) {
	return formatErrorMessage(error);
}
/** Detect provider errors caused by single-use OAuth refresh token races. */
function isRefreshTokenReusedError(error) {
	const message = normalizeLowercaseStringOrEmpty(extractErrorMessage(error));
	return message.includes("refresh_token_reused") || message.includes("refresh token has already been used") || message.includes("already been used to generate a new access token");
}
async function refreshOAuthCredential(credential) {
	const pluginRefreshed = await refreshProviderOAuthCredentialWithPlugin({
		provider: credential.provider,
		context: credential
	});
	if (pluginRefreshed) return pluginRefreshed;
	if (credential.provider === "chutes") return await refreshChutesTokens({ credential });
	const oauthProvider = resolveOAuthProvider(credential.provider);
	if (!oauthProvider || typeof getOAuthApiKey !== "function") return null;
	return (await getOAuthApiKey(oauthProvider, { [credential.provider]: credential }))?.newCredentials ?? null;
}
/** Refresh one OAuth credential and merge provider-returned token fields. */
async function refreshOAuthCredentialForRuntime(params) {
	const refreshed = await refreshOAuthCredential(params.credential);
	return refreshed ? {
		...params.credential,
		...refreshed,
		type: "oauth"
	} : null;
}
const oauthManager = createOAuthManager({
	buildApiKey: buildOAuthApiKey,
	refreshCredential: refreshOAuthCredential,
	readBootstrapCredential: ({ profileId, credential }) => readExternalCliBootstrapCredential({
		profileId,
		credential
	}),
	readFallbackCredential: ({ profileId, credential }) => credential.provider === "openai" ? readExternalCliFallbackCredential({
		profileId,
		credential,
		allowKeychainPrompt: false
	}) : null,
	isRefreshTokenReusedError
});
async function tryResolveOAuthProfile(params) {
	const { cfg, store, profileId } = params;
	const cred = store.profiles[profileId];
	if (!cred || cred.type !== "oauth") return null;
	if (!isProfileConfigCompatible({
		cfg,
		profileId,
		provider: cred.provider,
		mode: cred.type
	})) return null;
	const resolved = await oauthManager.resolveOAuthAccess({
		store,
		profileId,
		credential: cred,
		agentDir: params.agentDir,
		cfg,
		forceRefresh: params.forceRefresh
	});
	if (!resolved) return null;
	return buildApiKeyProfileResult({
		apiKey: resolved.apiKey,
		provider: resolved.credential.provider,
		email: resolved.credential.email ?? cred.email,
		profileId,
		profileType: cred.type,
		credential: resolved.credential
	});
}
async function resolveProfileSecretString(params) {
	let resolvedValue = params.value?.trim();
	if (resolvedValue) {
		const inlineRef = coerceSecretRef(resolvedValue, params.refDefaults);
		if (inlineRef) try {
			resolvedValue = await resolveSecretRefString(inlineRef, {
				config: params.configForRefResolution,
				env: process.env,
				cache: params.cache
			});
		} catch (err) {
			log.debug(params.inlineFailureMessage, {
				profileId: params.profileId,
				provider: params.provider,
				error: formatErrorMessage(err)
			});
		}
	}
	const explicitRef = coerceSecretRef(params.valueRef, params.refDefaults);
	if (!resolvedValue && explicitRef) try {
		resolvedValue = await resolveSecretRefString(explicitRef, {
			config: params.configForRefResolution,
			env: process.env,
			cache: params.cache
		});
	} catch (err) {
		log.debug(params.refFailureMessage, {
			profileId: params.profileId,
			provider: params.provider,
			error: formatErrorMessage(err)
		});
	}
	return normalizeOptionalSecretInput(resolvedValue);
}
/** Resolve a selected auth profile into the provider API key string. */
async function resolveApiKeyForProfile(params) {
	const { cfg, store, profileId } = params;
	const cred = store.profiles[profileId];
	if (!cred) return null;
	if (!isProfileConfigCompatible({
		cfg,
		profileId,
		provider: cred.provider,
		mode: cred.type,
		allowOAuthTokenCompatibility: true
	})) return null;
	const refResolveCache = {};
	const configForRefResolution = cfg ?? getRuntimeConfig();
	const refDefaults = configForRefResolution.secrets?.defaults;
	assertNoOAuthSecretRefPolicyViolations({
		store,
		cfg: configForRefResolution,
		profileIds: [profileId],
		context: `auth profile ${profileId}`
	});
	if (cred.type === "api_key") {
		const key = await resolveProfileSecretString({
			profileId,
			provider: cred.provider,
			value: cred.key,
			valueRef: cred.keyRef,
			refDefaults,
			configForRefResolution,
			cache: refResolveCache,
			inlineFailureMessage: "failed to resolve inline auth profile api_key ref",
			refFailureMessage: "failed to resolve auth profile api_key ref"
		});
		if (!key) return null;
		return buildApiKeyProfileResult({
			apiKey: key,
			provider: cred.provider,
			email: cred.email,
			profileId,
			profileType: cred.type
		});
	}
	if (cred.type === "token") {
		const expiryState = resolveTokenExpiryState(cred.expires);
		if (expiryState === "expired" || expiryState === "invalid_expires") return null;
		const token = await resolveProfileSecretString({
			profileId,
			provider: cred.provider,
			value: cred.token,
			valueRef: cred.tokenRef,
			refDefaults,
			configForRefResolution,
			cache: refResolveCache,
			inlineFailureMessage: "failed to resolve inline auth profile token ref",
			refFailureMessage: "failed to resolve auth profile token ref"
		});
		if (!token) return null;
		return buildApiKeyProfileResult({
			apiKey: token,
			provider: cred.provider,
			email: cred.email,
			profileId,
			profileType: cred.type
		});
	}
	try {
		const resolved = await oauthManager.resolveOAuthAccess({
			store,
			agentDir: params.agentDir,
			profileId,
			credential: cred,
			cfg,
			forceRefresh: params.forceRefresh
		});
		if (!resolved) return null;
		return buildApiKeyProfileResult({
			apiKey: resolved.apiKey,
			provider: resolved.credential.provider,
			email: resolved.credential.email ?? cred.email,
			profileId,
			profileType: cred.type,
			credential: resolved.credential
		});
	} catch (error) {
		let refreshedStore = error instanceof OAuthManagerRefreshError ? error.getRefreshedStore() : loadAuthProfileStoreForSecretsRuntime(params.agentDir);
		const surfacedCause = error instanceof OAuthManagerRefreshError && error.cause ? error.cause : error;
		const surfacedMessageError = error instanceof OAuthManagerRefreshError && error.code === "refresh_contention" ? error : surfacedCause;
		if (isRefreshTokenReusedError(surfacedCause)) {
			const ownerAgentDir = resolvePersistedAuthProfileOwnerAgentDir({
				agentDir: params.agentDir,
				profileId
			});
			await clearLastGoodProfileWithLock({
				provider: cred.provider,
				profileId,
				agentDir: ownerAgentDir
			});
			if (params.agentDir !== ownerAgentDir && hasRuntimeAuthProfileStoreSnapshot(params.agentDir)) {
				const snapshot = getRuntimeAuthProfileStoreSnapshot(params.agentDir);
				const providerKey = resolveProviderIdForAuth(cred.provider);
				if (snapshot?.lastGood?.[providerKey] === profileId) {
					delete snapshot.lastGood[providerKey];
					if (Object.keys(snapshot.lastGood).length === 0) snapshot.lastGood = void 0;
					setRuntimeAuthProfileStoreSnapshot(snapshot, params.agentDir);
				}
			}
			refreshedStore = loadAuthProfileStoreForSecretsRuntime(params.agentDir);
		}
		const fallbackProfileId = suggestOAuthProfileIdForLegacyDefault({
			cfg,
			store: refreshedStore,
			provider: cred.provider,
			legacyProfileId: profileId
		});
		if (fallbackProfileId && fallbackProfileId !== profileId) try {
			const fallbackResolved = await tryResolveOAuthProfile({
				cfg,
				store: refreshedStore,
				profileId: fallbackProfileId,
				agentDir: params.agentDir,
				forceRefresh: params.forceRefresh
			});
			if (fallbackResolved) return fallbackResolved;
		} catch {}
		const message = extractErrorMessage(surfacedMessageError);
		const hint = await formatAuthDoctorHint({
			cfg,
			store: refreshedStore,
			provider: cred.provider,
			profileId
		});
		throw new OAuthRefreshFailureError({
			provider: cred.provider,
			message: `OAuth token refresh failed for ${cred.provider}: ${message}. Please try again or re-authenticate.` + (hint ? `\n\n${hint}` : ""),
			cause: error
		});
	}
}
//#endregion
export { formatAuthDoctorHint as i, resolveApiKeyForProfile as n, resolveEffectiveOAuthCredential as r, refreshOAuthCredentialForRuntime as t };
