UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,234 lines • 52.1 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs";
import { o as asDateTimestampMs } from "./number-coercion-CuVhdCBs.mjs";
import { u as toErrorObject } from "./error-coercion-CvJK4lmH.mjs";
import { c as trackAsyncWork } from "./async-work-scope-BYeX3gh6.mjs";
import { _ as secretRefKey } from "./ref-contract-D0kWy5jy.mjs";
import { f as normalizeSecretInputString, h as parseSecretRef } from "./types.secrets-DsPRn9Dz.mjs";
import { o as racePromiseWithAbortSignal } from "./src-D1BHGNTj.mjs";
import "./abort-signal-QqAmLWTl.mjs";
import { t as formatErrorMessage } from "./errors-O33D01XW.mjs";
import { t as KeyedAsyncQueue } from "./keyed-async-queue-CTreGrmR.mjs";
import { r as normalizeProviderId } from "./provider-id-D1VImdKk.mjs";
import "./file-lock-CkzOvhYo.mjs";
import "./file-lock-Cl3feKST.mjs";
import { i as resolveProviderIdForAuth } from "./provider-auth-aliases-DGVQj_99.mjs";
import { r as getRuntimeConfig } from "./io.runtime-BsUXSsD4.mjs";
import "./config-DLycWFvB.mjs";
import "./profile-ids-B9fFWPvP.mjs";
import { i as getOAuthProviders, r as getOAuthApiKey, t as OAuthProviderConfiguredUnavailableError } from "./provider-runtime.errors-DEkO3luo.mjs";
import { c as resolveProviderOAuthRefreshCapabilityWithPlugin, n as buildProviderAuthDoctorHintWithPlugin, r as formatProviderAuthProfileApiKeyWithPlugin, s as resolveProviderOAuthCredentialWithPlugin } from "./provider-runtime.runtime.js";
import { a as resolveOAuthRefreshLockPath, c as resolveSharedAuthStorePath } from "./path-resolve-CIRhdX6A.mjs";
import { g as resolveAuthProfileDatabasePath } from "./sqlite-CW8wNN4G.mjs";
import { n as resolveAuthProfileSecretOwnerId } from "./runtime-auth-profile-owner-lkATIqd6.mjs";
import { c as findActiveDegradedSecretOwner, n as SecretSurfaceUnavailableError } from "./runtime-degraded-state-oevwKU3u.mjs";
import { v as isUserModelAuthProfileId } from "./profile-usage-stats-BLwxBqRR.mjs";
import { t as normalizeOptionalSecretInput } from "./normalize-secret-input-DBJvdk-L.mjs";
import { C as authProfilesLog, x as OAUTH_REFRESH_CALL_TIMEOUT_MS } from "./persisted-BVyWmvfF.mjs";
import { a as resolveTokenExpiryState, c as createOAuthRefreshFence, d as isSameOAuthRefreshGeneration, f as readOAuthRefreshGenerationDigest, l as isOAuthRefreshFence, n as evaluateStoredCredentialEligibility, p as readPendingOAuthRefreshClaimId, r as hasUsableOAuthCredential, s as createFailedOAuthRefreshFence, u as isPendingOAuthRefreshFence } from "./credential-state-WXO5HScp.mjs";
import { a as isSafeToAdoptBootstrapOAuthIdentity, b as observeCanonicalAuthProfileCredentials, c as shouldBootstrapFromExternalCliCredential, g as shouldMirrorRefreshedOAuthCredential, i as isSafeOAuthPostClaimSettlement, n as hasMatchingOAuthIdentity, o as isSafeToAdoptMainStoreOAuthIdentity, r as isSafeOAuthOwnerRefreshResult } from "./oauth-shared-CFtD6sCU.mjs";
import { E as readExternalCliBootstrapCredential, i as findPersistedAuthProfileCredential, u as resolvePersistedAuthProfileOwnerAgentDir, w as isPersistedExternalCliAuthProfile } from "./store-Bn_NKkGr.mjs";
import { d as OAuthRefreshPeerFenceError, f as failOAuthRefreshPeerClaims, h as settleOAuthRefreshPeerClaims, m as rollbackOAuthRefreshPeerClaims, p as fenceOAuthRefreshPeers, t as clearLastGoodProfileWithLock, v as withOAuthProfileLock } from "./profiles-zTWlOxGK.mjs";
import { d as markOAuthRefreshFailureSettled, n as OAuthRefreshFailureError, r as appendOAuthRefreshCleanupErrors, t as OAuthManagerRefreshError, u as isSettledOAuthRefreshFailure } from "./oauth-refresh-failure-B2gKOXl5.mjs";
import { B as isExactOAuthCredential, H as observeOAuthRefreshFenceSettlement, O as updateRuntimeAuthProfileStoreSnapshot, R as beginOAuthRefreshObservation, U as observeOAuthRefreshSettlement, d as getRuntimeAuthProfileStoreSnapshotCore, g as hasRuntimeAuthProfileStoreSnapshot } from "./runtime-snapshots-kS-hnXTd.mjs";
import { c as isSetupCredentialAccessible, s as getSetupCredentialRuntimeProfile } from "./order-BJ9-s7yV.mjs";
import { c as loadAuthProfileStoreForSecretsRuntime, i as ensureAuthProfileStoreWithoutExternalProfiles, l as loadAuthProfileStoreWithoutExternalProfiles, p as updateAuthProfileStoreWithLock } from "./store-runtime-DZk7O5wt.mjs";
import { t as assertNoOAuthSecretRefPolicyViolations } from "./policy-BLyaiMEH.mjs";
import { n as suggestOAuthProfileIdForLegacyDefault } from "./repair-D-SnIpjs.mjs";
import { isDeepStrictEqual } from "node:util";
//#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 Qwen API key: openclaw onboard --auth-choice qwen-api-key.";
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/effective-oauth.ts
/**
* Effective OAuth credential resolver.
* Allows external CLI bootstrap credentials to fill unusable local profile state.
*/
/** Select local OAuth unless a safe external bootstrap credential should win. */
function resolveEffectiveOAuthCredentialCore(params) {
	if (isUserModelAuthProfileId(params.profileId)) return params.credential;
	const imported = params.readBootstrapCredential({
		store: params.store,
		profileId: params.profileId,
		credential: params.credential
	});
	if (!imported) return params.credential;
	if (hasUsableOAuthCredential(params.credential)) {
		authProfilesLog.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)) {
		authProfilesLog.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
	})) {
		authProfilesLog.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;
}
/** Resolves the effective OAuth credential, optionally reading external CLI bootstrap state. */
function resolveEffectiveOAuthCredential(params) {
	return resolveEffectiveOAuthCredentialCore({
		store: params.store,
		profileId: params.profileId,
		credential: params.credential,
		readBootstrapCredential: ({ store, profileId, credential }) => readExternalCliBootstrapCredential({
			store,
			profileId,
			credential,
			allowKeychainPrompt: params.allowKeychainPrompt ?? false
		})
	});
}
//#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
const oauthRefreshRecoveryBuildFailures = /* @__PURE__ */ new WeakSet();
function canReuseOAuthCredentialAfterRefreshFailure(params) {
	return !params.forceRefresh || params.attempted.provider === params.candidate.provider && params.attempted.access !== params.candidate.access && hasMatchingOAuthIdentity(params.attempted, params.candidate);
}
function loadStoredOAuthRefreshStore(agentDir, profileId) {
	return loadAuthProfileStoreWithoutExternalProfiles(agentDir, {
		allowKeychainPrompt: true,
		profileId
	});
}
/** Create an OAuth manager bound to provider-specific build/refresh adapters. */
function createOAuthManager(adapter) {
	async function buildValidatedAccess(credential, context) {
		context.validateCredential?.(credential);
		return {
			apiKey: await adapter.buildApiKey(credential.provider, credential, {
				cfg: context.cfg,
				agentDir: context.agentDir
			}),
			credential
		};
	}
	function adoptNewerMainOAuthCredential(params) {
		if (!params.agentDir || isUserModelAuthProfileId(params.profileId)) 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)) return mainCred;
		} catch (err) {
			authProfilesLog.debug("adoptNewerMainOAuthCredential failed", {
				profileId: params.profileId,
				error: formatErrorMessage(err)
			});
		}
		return null;
	}
	let refreshQueue = new KeyedAsyncQueue();
	class OAuthSettlementCredentialValidationError extends Error {
		constructor(cause, cleanupErrors = []) {
			const error = toErrorObject(cause, "OAuth credential validation failed");
			super(error.message, { cause: appendOAuthRefreshCleanupErrors(error, cleanupErrors) });
			this.name = "OAuthSettlementCredentialValidationError";
		}
	}
	function validateSettlementCredential(validateCredential, credential) {
		try {
			validateCredential?.(credential);
		} catch (error) {
			throw new OAuthSettlementCredentialValidationError(error);
		}
	}
	async function resolveAuthoritativeSharedOAuthCredentialUnderLock(params) {
		let validatedAuthoritative = false;
		const acceptAuthoritative = (credential) => {
			try {
				validateSettlementCredential(params.validateCredential, credential);
				validatedAuthoritative = true;
				return true;
			} catch {
				authProfilesLog.warn("refused shared OAuth credential during settlement: credential validation failed", { profileId: params.profileId });
				return false;
			}
		};
		const updated = await updateAuthProfileStoreWithLock({
			agentDir: void 0,
			profileId: params.profileId,
			sharedStoreWrite: true,
			updater: (store) => {
				const existing = store.profiles[params.profileId];
				const decision = shouldMirrorRefreshedOAuthCredential({
					existing,
					refreshed: params.candidate
				});
				if (!decision.shouldMirror) {
					if (decision.reason === "identity-mismatch-or-regression") authProfilesLog.warn("refused to mirror OAuth credential: identity mismatch or regression", { profileId: params.profileId });
					if (decision.reason === "incoming-not-fresher" && existing?.type === "oauth") acceptAuthoritative(existing);
					return false;
				}
				if (existing?.type === "oauth" && !acceptAuthoritative(existing)) return false;
				store.profiles[params.profileId] = { ...params.candidate };
				validatedAuthoritative = true;
				authProfilesLog.debug("mirrored refreshed OAuth credential to main agent store", {
					profileId: params.profileId,
					expires: Number.isFinite(params.candidate.expires) ? new Date(params.candidate.expires).toISOString() : void 0
				});
				return true;
			}
		});
		if (updated === null) throw new Error("Failed to read authoritative shared OAuth credential");
		if (!validatedAuthoritative) return;
		const authoritative = updated.profiles[params.profileId];
		return authoritative?.type === "oauth" ? authoritative : void 0;
	}
	async function settlePeerClaimsUnderRefreshLock(params) {
		validateSettlementCredential(params.validateCredential, params.replacement);
		const authoritativeSharedCredential = params.claim.authPath === resolveSharedAuthStorePath() ? params.replacement : await resolveAuthoritativeSharedOAuthCredentialUnderLock({
			profileId: params.claim.profileId,
			candidate: params.replacement,
			validateCredential: params.validateCredential
		});
		settleOAuthRefreshPeerClaims({
			profileId: params.claim.profileId,
			fence: params.claim.fence,
			claims: params.claims,
			authoritativeSharedCredential,
			replacement: params.replacement
		});
	}
	async function settleOAuthRefreshClaim(params) {
		const current = loadStoredOAuthRefreshStore(params.agentDir, params.profileId).profiles[params.profileId];
		if (current?.type === "oauth" && !isExactOAuthCredential(current, params.fence) && isSafeOAuthPostClaimSettlement(params.generation, current)) return {
			credential: current,
			persisted: false
		};
		let credential = null;
		let persisted = false;
		return await updateAuthProfileStoreWithLock({
			agentDir: params.agentDir,
			profileId: params.profileId,
			updater: (store) => {
				const existing = store.profiles[params.profileId];
				if (existing?.type !== "oauth") return false;
				if (isExactOAuthCredential(existing, params.fence)) {
					store.profiles[params.profileId] = { ...params.refreshed };
					credential = params.refreshed;
					persisted = true;
					return true;
				}
				credential = isSafeOAuthPostClaimSettlement(params.generation, existing) ? existing : null;
				return false;
			}
		}) === null || !credential ? null : {
			credential,
			persisted
		};
	}
	async function markOAuthRefreshClaimFailed(params) {
		if (await updateAuthProfileStoreWithLock({
			agentDir: params.agentDir,
			profileId: params.profileId,
			updater: (store) => {
				const existing = store.profiles[params.profileId];
				if (!isExactOAuthCredential(existing, params.settledCredential ?? params.fence)) return false;
				store.profiles[params.profileId] = createFailedOAuthRefreshFence(params.fence);
				return true;
			}
		}) === null) throw new Error("Failed to persist terminal OAuth refresh fence");
	}
	async function rollbackOAuthRefreshOwnerClaim(params) {
		let restored = false;
		if (await updateAuthProfileStoreWithLock({
			agentDir: params.ownerAgentDir,
			profileId: params.profileId,
			updater: (store) => {
				const existing = store.profiles[params.profileId];
				if (!isExactOAuthCredential(existing, params.fence)) return false;
				store.profiles[params.profileId] = { ...params.original };
				restored = true;
				return true;
			}
		}) !== null && restored) return;
		await markOAuthRefreshClaimFailed({
			agentDir: params.ownerAgentDir,
			profileId: params.profileId,
			fence: params.fence
		});
	}
	function mergePeerClaims(existing, discovered) {
		const claims = new Map(existing.map((claim) => [claim.candidate.databasePath, claim]));
		for (const claim of discovered) {
			const current = claims.get(claim.candidate.databasePath);
			claims.set(claim.candidate.databasePath, current?.original ? current : claim);
		}
		return [...claims.values()].toSorted((left, right) => left.candidate.databasePath.localeCompare(right.candidate.databasePath));
	}
	async function claimOAuthRefresh(params) {
		const personalProfile = isUserModelAuthProfileId(params.profileId);
		const ownerAgentDir = personalProfile ? void 0 : resolvePersistedAuthProfileOwnerAgentDir(params);
		const authPath = ownerAgentDir ? resolveAuthProfileDatabasePath(ownerAgentDir) : resolveSharedAuthStorePath();
		const globalRefreshLockPath = resolveOAuthRefreshLockPath(params.provider, params.profileId);
		const peerConfig = params.cfg ?? {};
		const fenceTerminalPeers = (credential) => fenceOAuthRefreshPeers({
			cfg: peerConfig,
			ownerDatabasePath: authPath,
			profileId: params.profileId,
			generation: credential,
			fence: credential
		});
		let observation;
		let observationTransferred = false;
		try {
			const claim = await withOAuthProfileLock({
				provider: params.provider,
				profileId: params.profileId
			}, async () => {
				params.signal?.throwIfAborted();
				const cred = loadStoredOAuthRefreshStore(ownerAgentDir, params.profileId).profiles[params.profileId];
				if (!cred || cred.type !== "oauth" || cred.provider !== params.provider) return { kind: "unavailable" };
				const storedFence = isOAuthRefreshFence(cred);
				if (!storedFence) params.validateCredential?.(cred);
				let credentialToRefresh = cred;
				if (!storedFence && !personalProfile && isPersistedExternalCliAuthProfile({
					profileId: params.profileId,
					credential: cred
				})) {
					authProfilesLog.warn("refused native OAuth refresh for an externally owned credential", {
						profileId: params.profileId,
						provider: cred.provider
					});
					return { kind: "unavailable" };
				}
				if (params.forceRefresh && hasUsableOAuthCredential(cred) && canReuseOAuthCredentialAfterRefreshFailure({
					forceRefresh: true,
					attempted: params.attemptedCredential,
					candidate: cred
				})) return {
					kind: "use",
					credential: cred
				};
				if (!storedFence && !params.forceRefresh && hasUsableOAuthCredential(cred)) return {
					kind: "use",
					credential: cred
				};
				if (!storedFence && params.agentDir && !personalProfile) try {
					const mainCred = loadStoredOAuthRefreshStore(void 0).profiles[params.profileId];
					if (ownerAgentDir && mainCred?.type === "oauth" && isSameOAuthRefreshGeneration({
						profileId: params.profileId,
						left: cred,
						right: mainCred
					})) return { kind: "unavailable" };
					if (mainCred?.type === "oauth" && mainCred.provider === cred.provider && hasUsableOAuthCredential(mainCred) && !params.forceRefresh && isSafeToAdoptMainStoreOAuthIdentity(cred, mainCred)) {
						params.validateCredential?.(mainCred);
						authProfilesLog.info("adopted fresh OAuth credential from main store (under refresh lock)", {
							profileId: params.profileId,
							agentDir: params.agentDir,
							expires: new Date(mainCred.expires).toISOString()
						});
						return {
							kind: "use",
							credential: mainCred
						};
					} else if (mainCred?.type === "oauth" && mainCred.provider === cred.provider && hasUsableOAuthCredential(mainCred) && !isSafeToAdoptMainStoreOAuthIdentity(cred, mainCred)) authProfilesLog.warn("refused to adopt fresh main-store OAuth credential: identity mismatch", {
						profileId: params.profileId,
						agentDir: params.agentDir
					});
				} catch (err) {
					authProfilesLog.debug("inside-lock main-store adoption failed; proceeding to refresh", {
						profileId: params.profileId,
						error: formatErrorMessage(err)
					});
				}
				const externallyManaged = !personalProfile && params.bootstrapCredential && params.bootstrapBaseCredential && isExactOAuthCredential(cred, params.bootstrapBaseCredential) ? params.bootstrapCredential : null;
				if (externallyManaged) {
					if (externallyManaged.provider !== cred.provider) authProfilesLog.warn("refused external oauth bootstrap credential: provider mismatch", {
						profileId: params.profileId,
						provider: cred.provider
					});
					else if (storedFence || !isSafeToAdoptBootstrapOAuthIdentity(cred, externallyManaged)) authProfilesLog.warn("refused external oauth bootstrap credential: fenced or identity mismatch", {
						profileId: params.profileId,
						provider: cred.provider
					});
					else {
						credentialToRefresh = externallyManaged;
						params.validateCredential?.(credentialToRefresh);
						if (!params.forceRefresh && hasUsableOAuthCredential(externallyManaged)) return {
							kind: "use",
							credential: externallyManaged
						};
					}
				}
				if (storedFence && credentialToRefresh === cred) {
					if (isPendingOAuthRefreshFence(cred)) return {
						kind: "observe",
						ownerAgentDir,
						generation: cred
					};
					const peerClaims = personalProfile ? [] : await fenceTerminalPeers(cred);
					failOAuthRefreshPeerClaims({
						profileId: params.profileId,
						fence: cred,
						claims: peerClaims
					});
					return { kind: "unavailable" };
				}
				if (normalizeSecretInputString(credentialToRefresh.refresh) === void 0) return { kind: "unavailable" };
				if (!await adapter.canRefreshCredential(credentialToRefresh, {
					cfg: params.cfg,
					agentDir: params.agentDir
				})) return { kind: "unavailable" };
				const fence = createOAuthRefreshFence({
					profileId: params.profileId,
					credential: credentialToRefresh
				});
				const claimId = readPendingOAuthRefreshClaimId(fence);
				if (!claimId) throw new Error("OAuth refresh fence is missing its claim identity");
				observation = beginOAuthRefreshObservation({
					databasePath: authPath,
					profileId: params.profileId,
					provider: params.provider,
					claimId,
					generation: readOAuthRefreshGenerationDigest({
						profileId: params.profileId,
						credential: fence
					})
				});
				let claimed = false;
				if (await updateAuthProfileStoreWithLock({
					agentDir: ownerAgentDir,
					profileId: params.profileId,
					updater: (authoritative) => {
						const existing = authoritative.profiles[params.profileId];
						params.signal?.throwIfAborted();
						if (!isExactOAuthCredential(existing, cred)) return false;
						authoritative.profiles[params.profileId] = fence;
						claimed = true;
						return true;
					}
				}) === null || !claimed) {
					const current = loadStoredOAuthRefreshStore(ownerAgentDir, params.profileId).profiles[params.profileId];
					if (current?.type !== "oauth" || current.provider !== params.provider) return { kind: "unavailable" };
					if (!isOAuthRefreshFence(current)) params.validateCredential?.(current);
					if (isPendingOAuthRefreshFence(current)) return {
						kind: "observe",
						ownerAgentDir,
						generation: current
					};
					if (isOAuthRefreshFence(current)) {
						const peerClaims = personalProfile ? [] : await fenceTerminalPeers(current);
						failOAuthRefreshPeerClaims({
							profileId: params.profileId,
							fence: current,
							claims: peerClaims
						});
						return { kind: "unavailable" };
					}
					return hasUsableOAuthCredential(current) ? {
						kind: "use",
						credential: current
					} : { kind: "unavailable" };
				}
				let peerClaims = [];
				const peerGeneration = credentialToRefresh === cred ? cred : void 0;
				try {
					if (!personalProfile && peerGeneration) peerClaims = await fenceOAuthRefreshPeers({
						cfg: peerConfig,
						ownerDatabasePath: authPath,
						profileId: params.profileId,
						generation: peerGeneration,
						fence,
						rollbackOnFailure: false,
						onFence: observation.includeDatabase
					});
				} catch (error) {
					observation.beginSettlement();
					if (error instanceof OAuthRefreshPeerFenceError) peerClaims = mergePeerClaims(peerClaims, error.claims);
					const cleanupErrors = [];
					try {
						rollbackOAuthRefreshPeerClaims({
							profileId: params.profileId,
							fence,
							claims: peerClaims
						});
					} catch (cleanupError) {
						cleanupErrors.push(cleanupError);
					}
					try {
						await rollbackOAuthRefreshOwnerClaim({
							ownerAgentDir,
							profileId: params.profileId,
							fence,
							original: cred
						});
					} catch (cleanupError) {
						cleanupErrors.push(cleanupError);
					}
					if (cleanupErrors.length > 0) throw new AggregateError([error, ...cleanupErrors], "Failed to claim OAuth refresh ownership and roll back partial claims.", { cause: error });
					throw error;
				}
				return {
					kind: "claimed",
					profileId: params.profileId,
					credential: credentialToRefresh,
					fence,
					ownerAgentDir,
					authPath,
					peerClaims,
					...peerGeneration ? { peerGeneration } : {},
					observation
				};
			});
			observationTransferred = claim.kind === "claimed";
			return claim;
		} catch (error) {
			if (isGlobalRefreshLockTimeoutError(error, globalRefreshLockPath)) throw buildRefreshContentionError({
				provider: params.provider,
				profileId: params.profileId,
				cause: error
			});
			throw error;
		} finally {
			if (!observationTransferred) observation?.finish();
		}
	}
	async function refreshOAuthTokenWithLock(params) {
		params.signal?.throwIfAborted();
		const claim = await claimOAuthRefresh(params);
		if (claim.kind === "unavailable") return null;
		if (claim.kind === "observe") return await observeOAuthRefreshFenceSettlement({
			label: `refreshOAuthCredential(${params.provider})`,
			timeoutMs: OAUTH_REFRESH_CALL_TIMEOUT_MS,
			signal: params.signal,
			read: () => loadStoredOAuthRefreshStore(claim.ownerAgentDir, params.profileId).profiles[params.profileId],
			isPending: (credential) => credential?.type === "oauth" && credential.provider === claim.generation.provider && isPendingOAuthRefreshFence(credential),
			resolve: async (credential) => {
				if (credential?.type !== "oauth" || !isSafeOAuthPostClaimSettlement(claim.generation, credential)) return null;
				return await buildValidatedAccess(credential, params);
			}
		});
		if (claim.kind === "use") return await buildValidatedAccess(claim.credential, params);
		params.attemptedCredentials?.push(claim.credential);
		const peerConfig = params.cfg ?? {};
		let activePeerClaims = claim.peerClaims;
		const rediscoverPeerClaims = async (generation) => {
			try {
				activePeerClaims = mergePeerClaims(activePeerClaims, await fenceOAuthRefreshPeers({
					cfg: peerConfig,
					ownerDatabasePath: claim.authPath,
					profileId: params.profileId,
					generation,
					fence: claim.fence,
					rollbackOnFailure: false,
					onFence: claim.observation.includeDatabase
				}));
			} catch (error) {
				if (error instanceof OAuthRefreshPeerFenceError) activePeerClaims = mergePeerClaims(activePeerClaims, error.claims);
				throw error;
			}
		};
		const failClaim = async () => {
			let result = {
				supersedingOwner: null,
				validationError: null,
				cleanupErrors: []
			};
			try {
				await withOAuthProfileLock({
					provider: params.provider,
					profileId: params.profileId
				}, async () => {
					const cleanupErrors = [];
					let supersedingOwner = null;
					let validationError = null;
					try {
						const owner = loadStoredOAuthRefreshStore(claim.ownerAgentDir, params.profileId).profiles[params.profileId];
						supersedingOwner = owner?.type === "oauth" && !isExactOAuthCredential(owner, claim.fence) && isSafeOAuthPostClaimSettlement(claim.credential, owner) && canReuseOAuthCredentialAfterRefreshFailure({
							forceRefresh: params.forceRefresh,
							attempted: claim.credential,
							candidate: owner
						}) ? owner : null;
					} catch (error) {
						cleanupErrors.push(error);
					}
					if (claim.peerGeneration) try {
						await rediscoverPeerClaims(claim.peerGeneration);
					} catch (error) {
						cleanupErrors.push(error);
					}
					if (supersedingOwner && cleanupErrors.length === 0) try {
						await settlePeerClaimsUnderRefreshLock({
							claim,
							claims: activePeerClaims,
							replacement: supersedingOwner,
							validateCredential: params.validateCredential
						});
						result = {
							supersedingOwner,
							validationError,
							cleanupErrors
						};
						return;
					} catch (error) {
						if (error instanceof OAuthSettlementCredentialValidationError) validationError = error;
						else cleanupErrors.push(error);
					}
					try {
						failOAuthRefreshPeerClaims({
							profileId: params.profileId,
							fence: claim.fence,
							claims: activePeerClaims
						});
					} catch (error) {
						cleanupErrors.push(error);
					}
					try {
						await markOAuthRefreshClaimFailed({
							agentDir: claim.ownerAgentDir,
							profileId: params.profileId,
							fence: claim.fence
						});
					} catch (error) {
						cleanupErrors.push(error);
					}
					result = {
						supersedingOwner: null,
						validationError,
						cleanupErrors
					};
				});
				return result;
			} catch (error) {
				return {
					supersedingOwner: null,
					validationError: result.validationError,
					cleanupErrors: [...result.cleanupErrors, error]
				};
			}
		};
		const settleFailure = async (failure) => {
			claim.observation.beginSettlement();
			const initiatingError = failure ? toErrorObject(failure.error, "OAuth refresh failed") : void 0;
			const { supersedingOwner, validationError, cleanupErrors } = await failClaim();
			if (validationError) throw new OAuthSettlementCredentialValidationError(validationError, cleanupErrors);
			if (supersedingOwner) try {
				return await buildValidatedAccess(supersedingOwner, params);
			} catch (error) {
				const combinedFailure = initiatingError !== void 0 ? appendOAuthRefreshCleanupErrors(initiatingError, [...cleanupErrors, error]) : appendOAuthRefreshCleanupErrors(error, cleanupErrors);
				oauthRefreshRecoveryBuildFailures.add(combinedFailure);
				throw combinedFailure;
			}
			if (initiatingError !== void 0) {
				const error = appendOAuthRefreshCleanupErrors(initiatingError, cleanupErrors);
				if (failure?.externalRefresh && cleanupErrors.length === 0) {
					const settled = new OAuthRefreshFailureError({
						provider: params.provider,
						profileId: params.profileId,
						message: error.message,
						cause: error
					});
					markOAuthRefreshFailureSettled(settled, error);
					throw settled;
				}
				throw error;
			}
			if (cleanupErrors.length === 0) return null;
			throw appendOAuthRefreshCleanupErrors(cleanupErrors[0], cleanupErrors.slice(1));
		};
		const settlement = trackAsyncWork(async () => {
			let refreshed;
			try {
				refreshed = await adapter.refreshCredential(claim.credential, {
					cfg: params.cfg,
					agentDir: params.agentDir
				});
			} catch (error) {
				return await settleFailure({
					error,
					externalRefresh: true
				});
			}
			claim.observation.beginSettlement();
			if (!refreshed) return await settleFailure();
			try {
				const rotated = {
					...claim.credential,
					...refreshed,
					type: "oauth"
				};
				if (!hasUsableOAuthCredential(rotated, { refreshMarginMs: 0 })) throw new Error("OAuth refresh returned an unusable credential");
				if (!isSafeOAuthOwnerRefreshResult(claim.credential, rotated)) throw new Error("OAuth refresh returned credentials for a different OAuth account");
				params.validateCredential?.(rotated);
				const settled = await withOAuthProfileLock({
					provider: params.provider,
					profileId: params.profileId
				}, async () => {
					if (claim.peerGeneration) await rediscoverPeerClaims(claim.peerGeneration);
					const claimSettlement = await settleOAuthRefreshClaim({
						agentDir: claim.ownerAgentDir,
						profileId: params.profileId,
						generation: claim.credential,
						fence: claim.fence,
						refreshed: rotated
					});
					if (!claimSettlement) return null;
					try {
						await settlePeerClaimsUnderRefreshLock({
							claim,
							claims: activePeerClaims,
							replacement: claimSettlement.credential,
							validateCredential: params.validateCredential
						});
					} catch (peerSettlementError) {
						if (peerSettlementError instanceof OAuthSettlementCredentialValidationError) {
							const cleanupErrors = [];
							try {
								failOAuthRefreshPeerClaims({
									profileId: params.profileId,
									fence: claim.fence,
									claims: activePeerClaims
								});
							} catch (error) {
								cleanupErrors.push(error);
							}
							if (claimSettlement.persisted) try {
								await markOAuthRefreshClaimFailed({
									agentDir: claim.ownerAgentDir,
									profileId: params.profileId,
									fence: claim.fence,
									settledCredential: claimSettlement.credential
								});
							} catch (error) {
								cleanupErrors.push(error);
							}
							throw new OAuthSettlementCredentialValidationError(peerSettlementError, cleanupErrors);
						}
						try {
							failOAuthRefreshPeerClaims({
								profileId: params.profileId,
								fence: claim.fence,
								claims: activePeerClaims
							});
						} catch (error) {
							authProfilesLog.warn("failed to terminally fence an OAuth refresh peer", {
								profileId: params.profileId,
								error: formatErrorMessage(error)
							});
						}
						authProfilesLog.warn("OAuth refresh peer settlement degraded", {
							profileId: params.profileId,
							error: formatErrorMessage(peerSettlementError)
						});
					}
					return claimSettlement;
				});
				if (!settled) throw new Error("Failed to persist refreshed OAuth credential");
				observeCanonicalAuthProfileCredentials(claim.authPath, { [params.profileId]: settled.credential });
				return await buildValidatedAccess(settled.credential, params);
			} catch (error) {
				if (error instanceof OAuthSettlementCredentialValidationError) throw error;
				return await settleFailure({ error });
			}
		});
		settlement.then(claim.observation.finish, claim.observation.finish);
		return await observeOAuthRefreshSettlement(`refreshOAuthCredential(${claim.credential.provider})`, OAUTH_REFRESH_CALL_TIMEOUT_MS, settlement, params.signal);
	}
	async function resolveOAuthAccess(params) {
		params.signal?.throwIfAborted();
		const personalProfile = isUserModelAuthProfileId(params.profileId);
		let credential = params.credential;
		if (personalProfile) {
			const owned = loadStoredOAuthRefreshStore(params.agentDir, params.profileId).profiles[params.profileId];
			if (owned?.type !== "oauth") return null;
			credential = owned;
		}
		const newerMainCredential = adoptNewerMainOAuthCredential({
			profileId: params.profileId,
			agentDir: params.agentDir,
			credential
		});
		if (newerMainCredential) {
			params.validateCredential?.(newerMainCredential);
			params.store.profiles[params.profileId] = { ...newerMainCredential };
			authProfilesLog.info("adopted newer OAuth credentials from main agent", {
				profileId: params.profileId,
				agentDir: params.agentDir,
				expires: new Date(newerMainCredential.expires).toISOString()
			});
		}
		const adoptedCredential = newerMainCredential ?? credential;
		const bootstrapCredential = personalProfile ? null : adapter.readBootstrapCredential({
			store: params.store,
			profileId: params.profileId,
			credential: adoptedCredential
		});
		const effectiveCredential = resolveEffectiveOAuthCredentialCore({
			store: params.store,
			profileId: params.profileId,
			credential: adoptedCredential,
			readBootstrapCredential: () => bootstrapCredential
		});
		const attemptedCredentials = [];
		if (!params.forceRefresh && !isOAuthRefreshFence(adoptedCredential) && hasUsableOAuthCredential(effectiveCredential)) return await buildValidatedAccess(effectiveCredential, params);
		try {
			const queued = trackAsyncWork(() => refreshQueue.enqueue(`${credential.provider}\u0000${params.profileId}`, () => refreshOAuthTokenWithLock({
				profileId: params.profileId,
				provider: credential.provider,
				agentDir: params.agentDir,
				cfg: params.cfg,
				signal: params.signal,
				forceRefresh: params.forceRefresh,
				attemptedCredential: effectiveCredential,
				attemptedCredentials,
				bootstrapCredential,
				bootstrapBaseCredential: adoptedCredential,
				validateCredential: params.validateCredential
			})));
			const resolved = await racePromiseWithAbortSignal(queued, params.signal);
			params.signal?.throwIfAborted();
			return resolved;
		} catch (error) {
			params.signal?.throwIfAborted();
			let refreshError = error;
			let recoveryBuildFailed = refreshError instanceof OAuthSettlementCredentialValidationError || refreshError instanceof Error && oauthRefreshRecoveryBuildFailures.has(refreshError);
			let refreshedStore = params.store;
			let recoveryStoreLoaded = false;
			const buildRecoveryAccess = async (candidate) => {
				try {
					return await buildValidatedAccess(candidate, params);
				} catch (cleanupError) {
					refreshError = appendOAuthRefreshCleanupErrors(refreshError, [cleanupError]);
					recoveryBuildFailed = true;
					return null;
				}
			};
			try {
				refreshedStore = loadStoredOAuthRefreshStore(params.agentDir, params.profileId);
				recoveryStoreLoaded = true;
			} catch (cleanupError) {
				refreshError = appendOAuthRefreshCleanupErrors(refreshError, [cleanupError]);
			}
			const claimedGeneration = attemptedCredentials.at(-1) ?? effectiveCredential;
			const refreshed = refreshedStore.profiles[params.profileId];
			if (recoveryStoreLoaded && !recoveryBuildFailed) {
				if (refreshed?.type === "oauth" && isSafeOAuthPostClaimSettlement(claimedGeneration, refreshed) && canReuseOAuthCredentialAfterRefreshFailure({
					forceRefresh: params.forceRefresh,
					attempted: claimedGeneration,
					candidate: refreshed
				})) {
					const recovered = await buildRecoveryAccess(refreshed);
					if (recovered) return recovered;
				}
			}
			if (recoveryStoreLoaded && params.agentDir && !personalProfile && !recoveryBuildFailed) try {
				const mainCred = ensureAuthProfileStoreWithoutExternalProfiles(void 0, { allowKeychainPrompt: false }).profiles[params.profileId];
				if (mainCred?.type === "oauth" && isSafeOAuthPostClaimSettlement(claimedGeneration, mainCred) && canReuseOAuthCredentialAfterRefreshFailure({
					forceRefresh: params.forceRefresh,
					attempted: claimedGeneration,
					candidate: mainCred
				})) {
					params.validateCredential?.(mainCred);
					refreshedStore.profiles[params.profileId] = { ...mainCred };
					authProfilesLog.info("inherited fresh OAuth credentials from main agent", {
						profileId: params.profileId,
						agentDir: params.agentDir,
						expires: new Date(mainCred.expires).toISOString()
					});
					const recovered = await buildRecoveryAccess(mainCred);
					if (recovered) return recovered;
				}
			} catch (cleanupError) {
				refreshError = appendOAuthRefreshCleanupErrors(refreshError, [cleanupError]);
			}
			throw new OAuthManagerRefreshError({
				credential,
				attemptedCredentials: [effectiveCredential, ...attemptedCredentials],
				profileId: params.profileId,
				refreshedStore,
				cause: refreshError
			});
		}
	}
	function resetRefreshQueuesForTest() {
		refreshQueue = new KeyedAsyncQueue();
	}
	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.
*/
const OAUTH_PROVIDER_IDS = new Set(getOAuthProviders().map((provider) => provider.id));
/** Bearer-token auth modes that are interchangeable (oauth tokens and raw tokens). */
const BEARER_AUTH_MODES = /* @__PURE__ */ 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;
}
/** Detect provider errors caused by single-use OAuth refresh token races. */
function isRefreshTokenReusedError(error) {
	const message = normalizeLowercaseStringOrEmpty(formatErrorMessage(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, context = {}) {
	const pluginResult = await resolveProviderOAuthCredentialWithPlugin({
		provider: credential.provider,
		config: context.cfg,
		credential,
		refresh: true
	});
	if (pluginResult.status === "available") return pluginResult.credential;
	if (pluginResult.status === "configured-unavailable") throw new OAuthProviderConfiguredUnavailableError(credential.provider);
	if (!OAUTH_PROVIDER_IDS.has(credential.provider)) return null;
	return (await getOAuthApiKey(credential.provider, { [credential.provider]: credential }))?.newCredentials ?? null;
}
async function canRefreshOAuthCredential(credential, context = {}) {
	const pluginCapability = await resolveProviderOAuthRefreshCapabilityWithPlugin({
		provider: credential.provider,
		config: context.cfg
	});
	if (pluginCapability.status === "available") return true;
	if (pluginCapability.status === "configured-unavailable") throw new OAuthProviderConfiguredUnavailableError(credential.provider);
	return OAUTH_PROVIDER_IDS.has(credential.provider);
}
/** Refresh one OAuth credential and merge provider-returned token fields. */
async function refreshOAuthCredentialForRuntime(params) {
	const refreshed = await refreshOAuthCredential(params.credential, { cfg: params.cfg });
	return refreshed ? {
		...params.credential,
		...refreshed,
		type: "oauth"
	} : null;
}
const oauthManager = createOAuthManager({
	buildApiKey: buildOAuthApiKey,
	refreshCredential: refreshOAuthCredential,
	canRefreshCredential: canRefreshOAuthCredential,
	readBootstrapCredential: readExternalCliBootstrapCredential
});
if (process.env.VITEST || false) globalThis[Symbol.for("openclaw.oauthTestApi")] = {
	isRefreshTokenReusedError,
	resetOAuthRefreshQueuesForTest: oauthManager.resetRefreshQueuesForTest
};
async function resolveOAuthProfileAccess(params, credential) {
	const resolved = await oauthManager.resolveOAuthAccess({
		store: params.store,
		profileId: params.profileId,
		credential,
		agentDir: params.agentDir,
		cfg: params.cfg,
		forceRefresh: params.forceRefresh,
		validateCredential: params.validateOAuthCredential,
		signal: params.signal
	});
	return resolved ? buildApiKeyProfileResult({
		apiKey: resolved.apiKey,
		provider: resolved.credential.provider,
		email: resolved.credential.email ?? credential.email,
		profileId: params.profileId,
		profileType: credential.type,
		credential: resolved.credential
	}) : null;
}
async function tryResolveOAuthProfile(params) {
	const { cfg, store, profileId } = params;
	if (profileId === "anthropic:claude-cli") return null;
	const cred = store.profiles[profileId];
	if (!cred || cred.type !== "oauth" || !isSetupCredentialAccessible({
		profileId,
		credential: cred,
		agentDir: params.agentDir
	})) return null;
	if (!isProfileConfigCompatible({
		cfg,
		profileId,
		provider: cred.provider,
		mode: cred.type
	})) return null;
	const resolved = await resolveOAuthProfileAccess(params, cred);
	params.signal?.throwIfAborted();
	return resolved;
}
function authProfileSecretRefKey(profile, defaults) {
	const ref = profile.type === "api_key" ? parseSecretRef(profile.keyRef, defaults) ?? parseSecretRef(profile.key, defaults) : profile.type === "token" ? parseSecretRef(profile.tokenRef, defaults) ?? parseSecretRef(profile.token, defaults) : null;
	return ref ? secretRefKey(ref) : void 0;
}
function resolveRuntimeAuthProfile(params) {
	const setupProfile = getSetupCredentialRuntimeProfile(params);
	const runtimeProfile = setupProfile === void 0 ? getRuntimeAuthProfileStoreSnapshotCore(params.agentDir)?.profiles[params.profileId] : setupProfile;
	const inputRefKey = authProfileSecretRefKey(params.profile, params.defaults);
	const runtimeRefKey = runtimeProfile ? authProfileSecretRefKey(runtimeProfile, params.defaults) : void 0;
	const published = Boolean(runtimeProfile && (isDeepStrictEqual(runtimeProfile, params.profile) || inputRefKey && runtimeRefKey === inputRefKey && runtimeProfile.type === params.profile.type && runtimeProfile.provider === params.profile.provider));
	let profile = params.profile;
	if (published && runtimeProfile?.type === "api_key" && params.profile.type === "api_key") {
		const value = runtimeProfile.key;
		profile = {
			...params.profile,
			key: value
		};
	} else if (published && runtimeProfile?.type === "token" && params.profile.type === "token") {
		const value = runtimeProfile.token;
		profile = {
			...params.profile,
			token: value
		};
	}
	return {
		profile,
		published
	};
}
function assertRuntimeAuthProfileSecretOwnerAvailable(params) {
	const degraded = findActiveDegradedSecretOwner("account", resolveAuthProfileSecretOwnerId(params));
	if (degraded && params.published) throw new SecretSurfaceUnavailableError(degraded);
}
function throwUnmaterializedAuthProfileSecretRef(params) {
	throw new SecretSurfaceUnavailableError({
		ownerKind: "account",
		ownerId: resolveAuthProfileSecretOwnerId(params),
		state: "unavailable",
		paths: [`auth-profiles.${params.profileId}.${params.pathSuffix}`],
		refKeys: [secretRefKey(params.ref)],
		reason: "secret reference was not materialized by the active runtime"
	});
}
/** Resolve a selected auth profile into the provider API key string. */
async function resolveApiKeyForProfile(params) {
	params.signal?.throwIfAborted();
	const { cfg, store, profileId } = params;
	const storedProfile = isUserModelAuthProfileId(profileId) ? findPersistedAuthProfileCredential({
		agentDir: params.agentDir,
		profileId
	}) : store.profiles[profileId];
	if (!storedProfile || !isSetupCredentialAccessible({
		profileId,
		credential: storedProfile,
		agentDir: params.agentDir
	})) return null;
	if (profileId === "anthropic:claude-cli") return null;
	const configForRefResolution = cfg ?? getRuntimeConfig();
	const refDefaults = configForRefResolution.secrets?.defaults;
	const runtimeProfile = resolveRuntimeAuthProfile({
		agentDir: params.agentDir,
		profileId,
		profile: storedProfile,
		defaults: refDefaults
	});
	const cred = runtimeProfile.profile;
	if (!isProfileConfigCompatible({
		cfg,
		profileId,
		provider: cred.provider,
		mode: cred.type
	})) return null;
	assertNoOAuthSecretRefPolicyViolations({
		store,
		cfg: configForRefResolution,
		profileIds: [profileId],
		context: `auth profile ${profileId}`
	});
	if (cred.type === "api_key" || cred.type === "token") {
		if (cred.type === "api_key") {
			if (!evaluateStoredCredentialEligibility({ credential: cred }).eligible) return null;
		} else {
			const expiryState = resolveTokenExpiryState(cred.expires);
			if (expiryState === "expired" || expiryState === "invalid_expires") return null;
		}
		assertRuntimeAuthProfileSecretOwnerAvailable({
			agentDir: params.agentDir,
			profileId,
			published: runtimeProfile.published
		});
		const inlineValue = cred.type === "api_key" ? cred.key : cred.token;
		const ref = parseSecretRef(cred.type === "api_key" ? cred.keyRef : cred.tokenRef, refDefaults) ?? parseSecretRef(inlineValue, refDefaults);
		const apiKey = normalizeOptionalSecretInput(inlineValue);
		if (ref && (!runtimeProfile.published || !apiKey)) throwUnmaterializedAuthProfileSecretRef({
			agentDir: params.agentDir,
			profileId,
			pathSuffix: cred.type === "api_key" ? "key" : "token",
			ref
		});
		if (!apiKey) return null;
		return buildApiKeyProfileResult({
			apiKey,
			provider: cred.provider,
			email: cred.email,
			profileId,
			profileType: cred.type
		});
	}
	try {
		const resolved = await resolveOAuthProfileAccess(params, cred);
		params.signal?.throwIfAborted();
		return resolved;
	} catch (error) {
		params.signal?.throwIfAborted();
		let settlementComplete = isSettledOAuthRefreshFailure(error);
		let refreshedStore = error instanceof OAuthManagerRefreshError ? error.getRefreshedStore() : loadAuthProfileStoreForSecretsRuntime(params.agentDir, { profileId });
		const surfacedCause = error instanceof OAuthManagerRefreshError && error.cause ? error.cause : error;
		if (isRefreshTokenReusedError(surfacedCause)) {
			const ownerAgentDir = resolvePersistedAuthProfileOwnerAgentDir({
				agentDir: params.agentDir,
				profileId
			});
			let clearedLastGood = false;
			try {
				await clearLastGoodProfileWithLock({
					provider: cred.provider,
					profileId,
					agentDir: ownerAgentDir
				});
				clearedLastGood = true;
			} catch (cleanupError) {
				settlementComplete = false;
				authProfilesLog.warn("failed to clear stale OAuth last-good state after refresh failure", { error: formatErrorMessage(cleanupError) });
			}
			if (params.agentDir !== ownerAgentDir && hasRuntimeAuthProfileStoreSnapshot(params.agentDir)) {
				const snapshot = getRuntimeAuthProfileStoreSnapshotCore(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;
					updateRuntimeAuthProfileStoreSnapshot(snapshot, params.agentDir);
				}
			}
			if (clearedLastGood) refreshedStore = loadAuthProfileStoreForSecretsRuntime(params.agentDir, { profileId });
		}
		const fallbackProfileId = params.allowProfileFallback === false ? null : 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,
				validateOAuthCredential: params.validateOAuthCredential,
				signal: params.signal
			});
			params.signal?.throwIfAborted();
			if (fallbackResolved) return fallbackResolved;
		} catch {
			params.signal?.throwIfAborted();
		}
		const message = formatErrorMessage(surfacedCause);
		const hint = await formatAuthDoctorHint({
			cfg,
			store: refreshedStore,
			provider: cred.provider,
			profileId
		});
		const failure = new OAuthRefreshFailureError({
			provider: cred.provider,
			profileId,
			message: `OAuth token refresh failed for ${cred.provider}: ${message}. Please try again or re-authenticate.` + (hint ? `\n\n${hint}` : ""),
			cause: error
		});
		if (settlementComplete) markOAuthRefreshFailureSettled(failure);
		throw failure;
	}
}
//#endregion
export { formatAuthDoctorHint as i, resolveApiKeyForProfile as n, resolveEffectiveOAuthCredential as r, refreshOAuthCredentialForRuntime as t };