UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,777 lines • 93.5 kB
import { m as readNonBlankString } from "./string-coerce-1VuiLaaR.mjs";
import { c as isRecord, l as isStringRecord } from "./record-coerce-TIsquoVR.mjs";
import { t as isBlockedObjectKey } from "./prototype-keys-CuYw53fZ.mjs";
import { a as coerceSecretRef } from "./types.secrets-DD-Q2SS_.mjs";
import { p as shortenHomePath } from "./utils-CitNzLyF.mjs";
import { t as formatCliCommand } from "./command-format-DwEdrDKL.mjs";
import { a as executeSqliteQueryTakeFirstSync, i as executeSqliteQuerySync, o as getNodeSqliteKysely } from "./kysely-sync-DUWzQvCU.mjs";
import { d as readDatabasePathIdentitySync, r as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import { r as openNodeSqliteDatabase } from "./node-sqlite-DyeJqxPf.mjs";
import { u as getOpenClawDatabaseMaintenanceScope } from "./openclaw-state-db-async-lifecycle-DwFy2ZTk.mjs";
import { Fn as object, Jn as string, Nt as array, xn as literal } from "./schemas-BOYIvvln.mjs";
import { n as sha256Hex } from "./node-crypto-BG4u3UnX.mjs";
import { n as listAgentEntries } from "./agent-roster-DH6r_8f4.mjs";
import "./agent-scope-config-BEk6-ThS.mjs";
import { a as readOpenClawAgentDatabaseIdentity } from "./openclaw-agent-db-identity-BlmER9-X.mjs";
import { b as requireOpenClawStateDatabaseIdentity } from "./openclaw-state-db-cache-CmYLFRSt.mjs";
import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-DJZ7EKoI.mjs";
import { u as withExistingOpenClawStateDatabaseReadOnly } from "./openclaw-state-db-readonly-ywwvuxdQ.mjs";
import { a as recordLegacyMigrationReceipt, i as readLegacyMigrationReceiptFromDatabase, o as recordLegacyMigrationRun, r as readLegacyMigrationReceipt, s as recordLegacyMigrationSource } from "./state-migrations.receipts-CEp8vxSz.mjs";
import { t as splitTrailingAuthProfile } from "./model-ref-profile-BNjB2hED.mjs";
import { t as isChannelConfigMetadataKey } from "./config-metadata-aX1D2IMg.mjs";
import { M as collectConfiguredModelRefs } from "./runtime-snapshot-De_QxZI9.mjs";
import { n as OPENAI_PROVIDER_ID } from "./openai-routing-DNTQ-lG2.mjs";
import { t as listMutableCodexRouteAgentEntries } from "./codex-route-agent-entries-Bgrqtcd0.mjs";
import { d as acquireFileLockSyncWithRetry } from "./update-managed-service-handoff-database-B-BTd_aW.mjs";
import { c as resolveSharedAuthStoreOwnership, d as resolveSharedMainAuthAgentDir, u as resolveSharedAuthStorePath } from "./path-resolve-caruxX2d.mjs";
import { a as inspectAuthProfileJsonCell, o as readAuthProfileJsonCellText } from "./sqlite-json-CKBJ4R1M.mjs";
import { F as resolveLegacyOAuthPath, M as listLegacyAuthProfileArchives, S as writePersistedAuthProfileStoreRaw, a as inspectPersistedAuthProfileStoreRaw, b as runAuthProfileWriteTransaction, d as readAuthProfileStateJsonTextReadOnly, f as readPersistedAuthProfileStateRaw, h as readPersistedSharedAuthProfileStoreRaw, i as inspectPersistedAuthProfileStateRaw, m as readPersistedSharedAuthProfileStateRaw, o as inspectPersistedSharedAuthProfileStateRaw, p as readPersistedAuthProfileStoreRaw, s as inspectPersistedSharedAuthProfileStoreRaw, v as resolveAuthProfileDatabasePath, x as writePersistedAuthProfileStateRaw } from "./sqlite-Bk_bX_Ka.mjs";
import { n as normalizeSecretInput } from "./normalize-secret-input-DBJvdk-L.mjs";
import { t as loadJsonFileThroughSymlink } from "./json-file-5C1aYJVp.mjs";
import { n as hasMatchingOAuthIdentity, t as areOAuthCredentialsEquivalent } from "./oauth-shared-BTdq77ay.mjs";
import { m as renameUserProfileAuthLinks } from "./user-model-accounts-_80jPaa1.mjs";
import { a as loadPersistedSharedAuthProfileStore, r as loadPersistedAuthProfileStore, u as coerceAuthProfileState } from "./persisted-Bg_WZMIU.mjs";
import { G as isInheritedMainOAuthCredentialFromStores, i as clearRuntimeAuthProfileStoreSnapshots } from "./runtime-snapshots-DU02_IZD.mjs";
import { _ as normalizeLegacyAuthProfileFields, f as applyLegacyAuthStore, g as hasUsableAuthProfileCredential, h as coerceLegacyFlatCredential, m as coerceLegacyAuthStore, o as clearAuthProfileMigrationDiagnostics, p as coerceLegacyAuthProfileStore, u as readLegacyAuthProfileProviders, v as normalizeLegacyCredentialFields, y as parseLegacyCredentialEntry } from "./legacy-source-diagnostic-fzj_CB_g.mjs";
import { p as saveAuthProfileStoreWithPreparedOwner } from "./store-runtime-DPTEKEq5.mjs";
import { r as resolveLegacyInheritedAuthAgentDir } from "./legacy-inherited-auth-dir-DRLyVuen.mjs";
import { r as stripImportedConfigAuthProfileCredentials, t as ensureConfigAuthProfiles } from "./doctor-auth-profile-config-BJAofJwB.mjs";
import { t as note } from "./note-Bi0VsI6R.mjs";
import { t as createVerifiedSqliteSnapshot } from "./sqlite-snapshot-D8sq8SUj.mjs";
import { n as assertNoRetiredStateFiles } from "./state-migrations.retired-files-Dlsbs5FH.mjs";
import { a as resolveLegacyAuthStatePath, n as listAuthProfileRepairCandidates, o as resolveLegacyFlatAuthPath, r as listReferencedLegacyOAuthSidecarPaths } from "./doctor-auth-legacy-paths-BQcoV-Tb.mjs";
import { n as resolveLegacyRuntimeModelProviderAlias } from "./legacy-runtime-model-providers-BPqY-s89.mjs";
import { n as repairModelRefAuthProfile, r as repairRetiredConfigModelRefs } from "./retired-model-ref-repair-DkvvQ133.mjs";
import { t as inspectAuthDatabaseFiles } from "./stale-auth-order-store-B7nTlm34.mjs";
import fs from "node:fs";
import path from "node:path";
import { isDeepStrictEqual } from "node:util";
import { createHash, randomUUID } from "node:crypto";
//#region src/plugins/auth-profile-config-refs.ts
/** Installed plugins can predate Doctor's rename map; these fields reference host credentials. */
function rewritePluginAuthProfileRefs(config, profileIdMap) {
	let changed = false;
	const rewrite = (value) => {
		if (Array.isArray(value)) {
			value.forEach(rewrite);
			return;
		}
		if (!isRecord(value)) return;
		for (const [key, entry] of Object.entries(value)) if ((key === "authProfileId" || key === "defaultAuthProfileId") && typeof entry === "string") {
			const replacement = profileIdMap.get(entry.trim());
			if (replacement && replacement !== entry) {
				value[key] = replacement;
				changed = true;
			}
		} else rewrite(entry);
	};
	for (const entry of Object.values(config.plugins?.entries ?? {})) rewrite(entry.config);
	for (const [channel, settings] of Object.entries(config.channels ?? {})) if (!isChannelConfigMetadataKey(channel)) rewrite(settings);
	return changed;
}
//#endregion
//#region src/commands/doctor-auth-migration-receipts.ts
const MIGRATION_KIND = "auth-profile-json-to-sqlite-v2";
function createAuthProfileMigrationSourceReceipt(params) {
	const sourcePath = path.resolve(params.sourcePath);
	const sourceSha256 = sha256Hex(params.sourceBytes);
	const sourceKey = `auth-profile-v2:${sha256Hex(`${sourcePath}\0${sourceSha256}`)}`;
	const stamp = (params.now ?? /* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-");
	return {
		sourceKey,
		runId: `${sourceKey}:${randomUUID()}`,
		sourcePath,
		sourceSha256,
		sourceSizeBytes: params.sourceBytes.byteLength,
		sourceRecordCount: params.sourceRecordCount,
		sourceBytes: Buffer.from(params.sourceBytes),
		targetDatabasePath: path.resolve(params.targetDatabasePath),
		targetTable: params.targetTable,
		...params.targetStoreKey ? { targetStoreKey: params.targetStoreKey } : {},
		archivePath: `${sourcePath}.migrated-${stamp}-${randomUUID()}`,
		...params.env ? { env: params.env } : {}
	};
}
function reportJson(receipt) {
	return JSON.stringify({
		format: MIGRATION_KIND,
		archivePath: receipt.archivePath,
		targetDatabasePath: receipt.targetDatabasePath,
		targetTable: receipt.targetTable,
		targetStoreKey: receipt.targetStoreKey ?? "primary",
		expectedProfileSha256: receipt.expectedProfileSha256,
		expectedStateSha256: receipt.expectedStateSha256,
		completionStatus: receipt.completionStatus ?? "completed"
	});
}
function digestAuthProfileMigrationValue(value) {
	return sha256Hex(JSON.stringify(value) ?? "<undefined>");
}
function recordAuthProfileMigrationImported(receipt, now = Date.now()) {
	runOpenClawStateWriteTransaction(({ db }) => {
		const kysely = getNodeSqliteKysely(db);
		const existing = executeSqliteQueryTakeFirstSync(db, kysely.selectFrom("migration_sources").select(["last_run_id", "status"]).where("source_key", "=", receipt.sourceKey));
		if (existing && existing.last_run_id !== receipt.runId && existing.status !== "retryable" && existing.status !== "superseded") throw new Error(`auth profile migration source already owned by ${existing.status} receipt`);
		const report = reportJson(receipt);
		recordLegacyMigrationRun(db, {
			runId: receipt.runId,
			startedAt: now,
			finishedAt: null,
			status: "imported",
			reportJson: report,
			upsert: true
		});
		recordLegacyMigrationSource(db, {
			sourceKey: receipt.sourceKey,
			migrationKind: MIGRATION_KIND,
			sourcePath: receipt.sourcePath,
			targetTable: receipt.targetTable,
			sourceSha256: receipt.sourceSha256,
			sourceSizeBytes: receipt.sourceSizeBytes,
			sourceRecordCount: receipt.sourceRecordCount,
			runId: receipt.runId,
			status: "imported",
			importedAt: now,
			reportJson: report,
			upsert: true
		});
	}, { env: receipt.env });
}
function updateAuthProfileMigrationReceipt(receipt, status, previousStatus, now = Date.now()) {
	runOpenClawStateWriteTransaction(({ db }) => {
		const kysely = getNodeSqliteKysely(db);
		let run = kysely.updateTable("migration_runs").set({
			status,
			finished_at: now
		}).where("id", "=", receipt.runId);
		let source = kysely.updateTable("migration_sources").set({
			status,
			...status === "completed" || status === "archived-unparsed" ? { removed_source: 1 } : {}
		}).where("source_key", "=", receipt.sourceKey).where("last_run_id", "=", receipt.runId);
		if (previousStatus) {
			run = run.where("status", "=", previousStatus);
			source = source.where("status", "=", previousStatus);
		}
		executeSqliteQuerySync(db, run);
		executeSqliteQuerySync(db, source);
	}, { env: receipt.env });
}
function restoreAuthProfileMigrationArchiveNoClobber(receipt) {
	try {
		fs.linkSync(receipt.archivePath, receipt.sourcePath);
	} catch (error) {
		if (error.code === "EEXIST") return "source-exists";
		throw error;
	}
	fs.unlinkSync(receipt.archivePath);
	return "restored";
}
function archiveAuthProfileMigrationSource(receipt) {
	if (fs.existsSync(receipt.sourcePath)) {
		const sourceBytes = fs.readFileSync(receipt.sourcePath);
		if (sha256Hex(sourceBytes) !== receipt.sourceSha256) throw new Error("legacy auth source changed after verification");
		fs.renameSync(receipt.sourcePath, receipt.archivePath);
	}
	const archiveBytes = fs.readFileSync(receipt.archivePath);
	if (sha256Hex(archiveBytes) !== receipt.sourceSha256) throw new Error("legacy auth archive verification failed");
}
function acquireAuthProfileMigrationSourceLocks(sourcePaths) {
	const releases = [];
	const releaseAll = () => {
		for (const release of releases.toReversed()) release();
	};
	try {
		for (const sourcePath of [...new Set(sourcePaths.map((entry) => path.resolve(entry)))].toSorted()) releases.push(acquireFileLockSyncWithRetry(sourcePath));
	} catch (error) {
		releaseAll();
		throw error;
	}
	return releaseAll;
}
function verifyAuthProfileMigrationTarget(receipt) {
	const expectedProfiles = Object.entries(receipt.expectedProfileSha256 ?? {});
	if (expectedProfiles.length === 0 && !receipt.expectedStateSha256) return;
	const db = openNodeSqliteDatabase(receipt.targetDatabasePath, { readOnly: true });
	try {
		const readTarget = (kind) => {
			const json = readAuthProfileJsonCellText(db, kind, receipt.targetStoreKey === "shared" ? "shared-state" : "agent");
			return typeof json === "string" ? JSON.parse(json) : null;
		};
		const store = expectedProfiles.length > 0 ? readTarget("store") : null;
		for (const [profileId, expectedSha256] of expectedProfiles) if (digestAuthProfileMigrationValue(store?.profiles?.[profileId]) !== expectedSha256) throw new Error("auth profile migration target verification failed");
		if (receipt.expectedStateSha256 && digestAuthProfileMigrationValue(readTarget("state")) !== receipt.expectedStateSha256) throw new Error("auth profile migration target verification failed");
	} finally {
		db.close();
	}
}
/** Finalize while the migration owner holds the source-file lock. */
function finalizeAuthProfileMigrationSource(receipt, status = "completed") {
	receipt.completionStatus = status;
	recordAuthProfileMigrationImported(receipt);
	verifyAuthProfileMigrationTarget(receipt);
	archiveAuthProfileMigrationSource(receipt);
	updateAuthProfileMigrationReceipt(receipt, status);
}
function resumePendingAuthProfileMigrationArchives(env, recoverCompleted) {
	const changes = [];
	const rows = withExistingOpenClawStateDatabaseReadOnly(({ db }) => executeSqliteQuerySync(db, getNodeSqliteKysely(db).selectFrom("migration_sources as source").innerJoin("migration_runs as run", "run.id", "source.last_run_id").select([
		"source.source_key",
		"source.source_path",
		"source.source_sha256",
		"source.source_size_bytes",
		"source.source_record_count",
		"source.target_table",
		"source.last_run_id",
		"source.report_json",
		"source.status"
	]).where("source.migration_kind", "=", MIGRATION_KIND).where((eb) => eb.or([eb.and([eb("source.status", "=", "imported"), eb("source.removed_source", "=", 0)]), eb.and([eb("source.status", "=", "completed"), eb("source.removed_source", "=", 1)])]))).rows, { env }) ?? [];
	for (const row of rows) {
		const report = JSON.parse(row.report_json);
		const completed = row.status === "completed";
		if (completed && (!recoverCompleted || Object.hasOwn(report, "expectedProfileSha256") || row.target_table === "auth_profile_state" || typeof report.archivePath !== "string" || !fs.existsSync(report.archivePath))) continue;
		if (typeof row.source_sha256 !== "string" || typeof row.source_size_bytes !== "number" || typeof row.source_record_count !== "number" || typeof report.archivePath !== "string" || typeof report.targetDatabasePath !== "string" || row.target_table !== "auth_profile_store" && row.target_table !== "auth_profile_stores" && row.target_table !== "auth_profile_state") throw new Error("invalid pending auth profile migration receipt");
		const receipt = {
			sourceKey: row.source_key,
			runId: row.last_run_id,
			sourcePath: row.source_path,
			sourceSha256: row.source_sha256,
			sourceSizeBytes: row.source_size_bytes,
			sourceRecordCount: row.source_record_count,
			targetDatabasePath: report.targetDatabasePath,
			targetTable: row.target_table,
			targetStoreKey: report.targetStoreKey === "shared" ? "shared" : "primary",
			archivePath: report.archivePath,
			...isStringRecord(report.expectedProfileSha256) ? { expectedProfileSha256: report.expectedProfileSha256 } : {},
			...typeof report.expectedStateSha256 === "string" ? { expectedStateSha256: report.expectedStateSha256 } : {},
			completionStatus: report.completionStatus === "archived-unparsed" ? "archived-unparsed" : "completed",
			...env ? { env } : {}
		};
		if (!fs.existsSync(receipt.sourcePath) && !fs.existsSync(receipt.archivePath)) throw new Error("pending auth profile migration has neither source nor archive");
		const lockTarget = fs.existsSync(receipt.sourcePath) ? receipt.sourcePath : receipt.archivePath;
		const release = acquireFileLockSyncWithRetry(lockTarget);
		try {
			const sourceExists = fs.existsSync(receipt.sourcePath);
			if (completed) {
				receipt.sourceBytes = fs.readFileSync(receipt.archivePath);
				if (sha256Hex(receipt.sourceBytes) !== receipt.sourceSha256 || sourceExists && sha256Hex(fs.readFileSync(receipt.sourcePath)) !== receipt.sourceSha256 || !recoverCompleted?.(receipt)) continue;
				if (!sourceExists) fs.linkSync(receipt.archivePath, receipt.sourcePath);
				updateAuthProfileMigrationReceipt(receipt, "retryable", "completed");
				changes.push("Reset an inconsistent completed auth migration receipt for retry.");
				continue;
			}
			const bytes = fs.readFileSync(sourceExists ? receipt.sourcePath : receipt.archivePath);
			if (sha256Hex(bytes) !== receipt.sourceSha256) {
				if (!sourceExists) throw new Error("legacy auth archive verification failed");
				updateAuthProfileMigrationReceipt(receipt, "superseded", "imported");
				changes.push("Retired an interrupted auth migration receipt for a changed source.");
				continue;
			}
			try {
				verifyAuthProfileMigrationTarget(receipt);
			} catch {
				let status = "retryable";
				if (!sourceExists) {
					if (restoreAuthProfileMigrationArchiveNoClobber(receipt) === "source-exists") {
						const currentBytes = fs.readFileSync(receipt.sourcePath);
						status = sha256Hex(currentBytes) === receipt.sourceSha256 ? "retryable" : "superseded";
					}
				}
				updateAuthProfileMigrationReceipt(receipt, status, "imported");
				changes.push(status === "retryable" ? "Reset an interrupted auth migration receipt for retry." : "Retired an interrupted auth migration receipt for a changed source.");
				continue;
			}
			archiveAuthProfileMigrationSource(receipt);
			updateAuthProfileMigrationReceipt(receipt, receipt.completionStatus ?? "completed");
		} finally {
			release();
		}
		changes.push(`Finalized interrupted auth profile archive -> ${receipt.archivePath}`);
	}
	return changes;
}
function hasTerminalAuthProfileMigrationReceipt(sourceKey, env) {
	const row = withExistingOpenClawStateDatabaseReadOnly(({ db }) => executeSqliteQueryTakeFirstSync(db, getNodeSqliteKysely(db).selectFrom("migration_sources").select("status").where("source_key", "=", sourceKey)), { env });
	return row?.status === "completed" || row?.status === "archived-unparsed";
}
if (process.env.VITEST || false) globalThis[Symbol.for("openclaw.authProfileMigrationReceiptsTestApi")] = {
	recordAuthProfileMigrationImported,
	restoreAuthProfileMigrationArchiveNoClobber
};
//#endregion
//#region src/commands/doctor/auth-alias-receipt.ts
const SOURCE_KEY = "auth-profile-sqlite-alias-map:v1";
const receiptSchema = object({
	format: literal(SOURCE_KEY),
	mappings: array(object({
		from: string(),
		to: string(),
		credentials: array(object({
			databasePath: string(),
			beforeSha256: string().nullable(),
			afterSha256: string(),
			beforeCanonicalFieldsSha256: string().optional(),
			afterCanonicalFieldsSha256: string().optional()
		})).min(1),
		sources: array(object({
			path: string(),
			sha256: string()
		})).optional()
	}))
});
function profiles(raw) {
	return isRecord(raw) && isRecord(raw.profiles) ? raw.profiles : {};
}
/** Persist the collision decision before independently committed owners can lose its source. */
function recordAuthAliasMigration(params) {
	const previousReceipt = readLegacyMigrationReceipt(SOURCE_KEY, params.env);
	const previousMappings = previousReceipt ? receiptSchema.parse(JSON.parse(previousReceipt.reportJson)).mappings : [];
	if (params.importedProfileIds) {
		for (const { from } of previousMappings) if (params.importedProfileIds.has(from) && !params.profileIdMap.has(from)) throw new Error(`Recorded auth account ${from} could not be verified; its import source was preserved.`);
	}
	const mappings = [];
	for (const [from, to] of params.profileIdMap) {
		if (from === to) continue;
		const credentials = params.stores.flatMap(({ databasePath, store, migratedStore }) => {
			const sourceProfiles = profiles(store);
			const before = sourceProfiles[from];
			const after = profiles(migratedStore)[to];
			const current = before ?? sourceProfiles[to];
			const historical = previousMappings.filter((entry) => entry.from === from && entry.to === to).flatMap((entry) => entry.credentials).find((expected) => expected.databasePath === databasePath && current !== void 0 && (before === void 0 ? [expected.afterSha256, expected.afterCanonicalFieldsSha256] : [expected.beforeSha256, expected.beforeCanonicalFieldsSha256]).includes(digestAuthProfileMigrationValue(current)));
			if (after === void 0 || before === void 0 && !historical && !(params.importedProfileIds?.has(from) && params.sources?.length)) return [];
			if (params.importedProfileIds?.has(from) && before !== void 0 && (!isRecord(before) || !isRecord(after) || digestAuthProfileMigrationValue({
				...before,
				provider: after.provider
			}) !== digestAuthProfileMigrationValue(after))) throw new Error(`Legacy auth input conflicts with the existing account ${from}; its source was preserved.`);
			if (historical) {
				if (before === void 0 && (!isRecord(current) || digestAuthProfileMigrationValue(normalizeLegacyCredentialFields(current)) !== digestAuthProfileMigrationValue(after))) throw new Error(`Recorded auth account ${from} changed during migration; its source was preserved.`);
				return [{
					...historical,
					...before !== void 0 ? { beforeCanonicalFieldsSha256: digestAuthProfileMigrationValue(before) } : {},
					afterCanonicalFieldsSha256: digestAuthProfileMigrationValue(after)
				}];
			}
			return [{
				databasePath,
				beforeSha256: before === void 0 ? null : digestAuthProfileMigrationValue(before),
				afterSha256: digestAuthProfileMigrationValue(after)
			}];
		});
		if (credentials.length > 0) mappings.push({
			from,
			to,
			credentials,
			...params.sources?.length ? { sources: [...params.sources] } : {}
		});
	}
	if (mappings.length === 0 && (!previousReceipt || !params.normalizeCredentialFields)) return previousReceipt?.sourceSha256 ?? void 0;
	return runOpenClawStateWriteTransaction(({ db, path }) => {
		const prior = readLegacyMigrationReceiptFromDatabase(db, SOURCE_KEY);
		const previous = prior ? receiptSchema.parse(JSON.parse(prior.reportJson)).mappings : [];
		const records = new Map(params.normalizeCredentialFields ? [] : previous.map((entry) => [digestAuthProfileMigrationValue(entry), entry]));
		for (const entry of params.normalizeCredentialFields ? previous : []) {
			const normalized = structuredClone(entry);
			for (const expected of normalized.credentials) {
				const store = params.stores.find((candidate) => candidate.databasePath === expected.databasePath);
				if (!store) continue;
				const before = profiles(store.store);
				const after = profiles(store.migratedStore);
				for (const [id, hashKey, canonicalHashKey] of [[
					entry.from,
					"beforeSha256",
					"beforeCanonicalFieldsSha256"
				], [
					entry.to,
					"afterSha256",
					"afterCanonicalFieldsSha256"
				]]) {
					const value = before[id];
					if (isRecord(value) && after[id] !== void 0 && [expected[hashKey], expected[canonicalHashKey]].includes(digestAuthProfileMigrationValue(value)) && digestAuthProfileMigrationValue(normalizeLegacyCredentialFields(value)) === digestAuthProfileMigrationValue(after[id])) expected[canonicalHashKey] = digestAuthProfileMigrationValue(after[id]);
				}
			}
			records.set(digestAuthProfileMigrationValue(normalized), normalized);
		}
		for (const entry of mappings) records.set(digestAuthProfileMigrationValue(entry), entry);
		const report = {
			format: SOURCE_KEY,
			mappings: [...records.values()]
		};
		const reportJson = JSON.stringify(report);
		const sourceSha256 = digestAuthProfileMigrationValue(report);
		if (prior?.sourceSha256 === sourceSha256 && prior.reportJson === reportJson) return sourceSha256;
		recordLegacyMigrationReceipt(db, {
			sourceKey: SOURCE_KEY,
			migrationKind: "auth-profile-sqlite-alias-map",
			sourcePath: path,
			targetTable: "migration_sources",
			sourceSha256,
			sourceSizeBytes: null,
			sourceRecordCount: report.mappings.length,
			runId: `${SOURCE_KEY}:${sourceSha256}`,
			now: Date.now(),
			reportJson,
			upsert: true
		});
		return sourceSha256;
	}, { env: params.env });
}
function runWithAuthAliasMigrationReceipt(expectedSha256, env, operation) {
	if (expectedSha256 === void 0) return operation();
	return runOpenClawStateWriteTransaction((database) => {
		if (readLegacyMigrationReceiptFromDatabase(database.db, SOURCE_KEY)?.sourceSha256 !== expectedSha256) throw new Error("Auth alias migration receipt changed before repair; rerun Doctor.");
		return operation(database);
	}, { env });
}
/** Recover only a recorded account, never a same-suffix credential or a newly reused source ID. */
function recoverAuthAliasMigration(params) {
	const recovered = /* @__PURE__ */ new Map();
	const blocked = /* @__PURE__ */ new Set();
	const receipt = readLegacyMigrationReceipt(SOURCE_KEY, params.env);
	if (!receipt) return {
		recovered,
		blocked
	};
	const report = receiptSchema.parse(JSON.parse(receipt.reportJson));
	const stores = new Map(params.stores.map((entry) => [entry.databasePath, profiles(entry.store)]));
	const matches = /* @__PURE__ */ new Map();
	for (const mapping of report.mappings) {
		const sourcePaths = mapping.sources?.map((source) => source.path) ?? [];
		const archived = sourcePaths.length > 0 && sourcePaths.every((source) => !fs.existsSync(source));
		let matched;
		if (archived) {
			const archive = params.archivedMappings?.get(mapping.from);
			const recordedSources = report.mappings.filter((entry) => entry.from === mapping.from && entry.to === mapping.to).flatMap((entry) => entry.sources ?? []);
			const verifiedStores = new Set(archive?.origins.filter((origin) => recordedSources.some((source) => source.path === origin.sourcePath && source.sha256 === origin.sourceSha256)).map((origin) => origin.databasePath));
			matched = archive?.profileId === mapping.to && verifiedStores.size > 0 && [...stores].every(([databasePath, entries]) => entries[mapping.from] === void 0 && (entries[mapping.to] === void 0 || verifiedStores.has(databasePath)));
		} else matched = mapping.credentials.every((expected) => {
			const entries = stores.get(expected.databasePath);
			if (!entries) return false;
			const before = entries[mapping.from];
			const after = entries[mapping.to];
			return before !== void 0 && after === void 0 && [expected.beforeSha256, expected.beforeCanonicalFieldsSha256].includes(digestAuthProfileMigrationValue(before)) || before === void 0 && after !== void 0 && [expected.afterSha256, expected.afterCanonicalFieldsSha256].includes(digestAuthProfileMigrationValue(after)) || before === void 0 && after === void 0 && expected.beforeSha256 === null && mapping.sources !== void 0 && mapping.sources.length > 0 && mapping.sources.every((source) => {
				try {
					return createHash("sha256").update(fs.readFileSync(source.path)).digest("hex") === source.sha256;
				} catch (error) {
					if (isRecord(error) && error.code === "ENOENT") return false;
					throw error;
				}
			});
		}) && [...stores].every(([databasePath, entries]) => mapping.credentials.some((entry) => entry.databasePath === databasePath) || entries[mapping.from] === void 0 && entries[mapping.to] === void 0);
		if (matched) {
			const targets = matches.get(mapping.from) ?? /* @__PURE__ */ new Set();
			targets.add(mapping.to);
			matches.set(mapping.from, targets);
		}
	}
	for (const from of new Set(report.mappings.map((entry) => entry.from))) {
		const targets = matches.get(from);
		if (targets?.size === 1) for (const to of targets) recovered.set(from, to);
		else blocked.add(from);
	}
	return {
		recovered,
		blocked
	};
}
//#endregion
//#region src/commands/doctor/auth-alias-transforms.ts
const LEGACY_OPENAI_CODEX_PROVIDER_ID = "openai-codex";
function isLegacyOpenAICodexProvider(value) {
	return typeof value === "string" && value.trim().toLowerCase() === LEGACY_OPENAI_CODEX_PROVIDER_ID;
}
function isLegacyOpenAICodexProfileId(profileId) {
	return profileId.trim().toLowerCase().startsWith(`${LEGACY_OPENAI_CODEX_PROVIDER_ID}:`);
}
function canonicalLegacyAuthProvider(provider) {
	const normalized = provider.trim().toLowerCase();
	if (isLegacyOpenAICodexProvider(normalized)) return OPENAI_PROVIDER_ID;
	const legacy = resolveLegacyRuntimeModelProviderAlias(normalized);
	return legacy?.legacyProvider === normalized ? legacy.provider : normalized;
}
function legacyAuthProfileTarget(profileId) {
	if (profileId === "openai:codex-cli") return {
		provider: OPENAI_PROVIDER_ID,
		suffix: "default"
	};
	const separator = profileId.indexOf(":");
	if (separator <= 0) return null;
	const provider = profileId.slice(0, separator).trim().toLowerCase();
	const canonical = canonicalLegacyAuthProvider(provider);
	return canonical === provider ? null : {
		provider: canonical,
		suffix: profileId.slice(separator + 1).trim() || "default"
	};
}
function isLegacyAuthProfileId(profileId) {
	return legacyAuthProfileTarget(profileId) !== null;
}
function collectRawAuthRotationProfileIds(raw) {
	if (!isRecord(raw)) return [];
	const ids = [];
	for (const field of [
		"order",
		"lastGood",
		"usageStats"
	]) {
		const entries = raw[field];
		if (!isRecord(entries)) continue;
		if (field === "usageStats") {
			ids.push(...Object.keys(entries));
			continue;
		}
		for (const value of Object.values(entries)) for (const id of Array.isArray(value) ? value : [value]) if (typeof id === "string") ids.push(id);
	}
	return ids;
}
function isReadableAuthAliasState(raw) {
	if (!isRecord(raw)) return false;
	const readableEntries = (value, accepts) => value === void 0 || isRecord(value) && Object.values(value).every(accepts);
	return readableEntries(raw.order, (ids) => Array.isArray(ids) && ids.every((id) => typeof id === "string")) && readableEntries(raw.lastGood, (id) => typeof id === "string") && readableEntries(raw.usageStats, isRecord);
}
function isReadableAuthAliasStore(raw) {
	if (!isRecord(raw) || !isRecord(raw.profiles) || !isReadableAuthAliasState(raw)) return false;
	return Object.values(raw.profiles).every((value) => parseLegacyCredentialEntry(value) !== null);
}
function allocateLegacyAuthProfileId(legacyProfileId, occupied) {
	const target = legacyAuthProfileTarget(legacyProfileId);
	if (!target) throw new Error(`Not a retired auth profile id: ${legacyProfileId}`);
	const { provider, suffix } = target;
	let candidate = `${provider}:${suffix}`;
	const chatgpt = `${provider}:${isLegacyOpenAICodexProfileId(legacyProfileId) ? "chatgpt" : "cli"}-${suffix}`;
	for (let index = 1; occupied.has(candidate); index += 1) candidate = index === 1 ? chatgpt : `${chatgpt}-${index}`;
	occupied.add(candidate);
	return candidate;
}
function canonicalizeLegacyAuthProfileEntries(profiles, options) {
	const occupied = new Set(Object.keys(profiles).filter((id) => !isLegacyAuthProfileId(id)));
	const reservedMappedIds = new Set(options?.profileIdMap?.values() ?? []);
	const profileIdMap = /* @__PURE__ */ new Map();
	let changed = false;
	for (const [profileId, rawProfile] of Object.entries({ ...profiles })) {
		if (!isRecord(rawProfile)) continue;
		const target = legacyAuthProfileTarget(profileId);
		const legacyId = target !== null;
		const provider = typeof rawProfile.provider === "string" ? canonicalLegacyAuthProvider(rawProfile.provider) : target?.provider;
		const legacyProvider = typeof rawProfile.provider === "string" && provider !== rawProfile.provider.trim().toLowerCase();
		if (!legacyId && !legacyProvider) continue;
		if (target && provider !== target.provider) continue;
		if (options?.preserveUnmappedLegacyIds && !options.profileIdMap?.has(profileId)) continue;
		const mappedProfileId = options?.profileIdMap?.get(profileId);
		const nextProfileId = mappedProfileId && !occupied.has(mappedProfileId) ? mappedProfileId : legacyId ? allocateLegacyAuthProfileId(profileId, /* @__PURE__ */ new Set([...occupied, ...reservedMappedIds])) : profileId;
		occupied.add(nextProfileId);
		const nextProfile = {
			...rawProfile,
			provider
		};
		if (nextProfileId !== profileId) {
			delete profiles[profileId];
			profileIdMap.set(profileId, nextProfileId);
		}
		profiles[nextProfileId] = nextProfile;
		changed = true;
	}
	return {
		profileIdMap,
		changed
	};
}
function canonicalizeLegacyAuthOrder(auth, profileIdMap, options) {
	if (!isRecord(auth.order)) return false;
	const order = auth.order;
	const before = structuredClone(order);
	const occupied = /* @__PURE__ */ new Set([...Object.values(order).flatMap((entries) => Array.isArray(entries) ? entries.filter((entry) => typeof entry === "string" && !isLegacyAuthProfileId(entry)) : []), ...profileIdMap.values()]);
	const unresolved = (entry) => typeof entry !== "string" || Boolean(options?.preserveUnmappedLegacyIds && !profileIdMap.has(entry));
	const rewrite = (entry) => {
		if (typeof entry !== "string") return entry;
		const mapped = profileIdMap.get(entry);
		if (mapped) return mapped;
		if (!isLegacyAuthProfileId(entry) || options?.preserveUnmappedLegacyIds) return entry;
		const allocated = allocateLegacyAuthProfileId(entry, occupied);
		profileIdMap.set(entry, allocated);
		return allocated;
	};
	const aliases = /* @__PURE__ */ new Map();
	for (const provider of Object.keys(order)) {
		const canonical = canonicalLegacyAuthProvider(provider);
		if (canonical !== provider && Array.isArray(order[provider])) {
			const group = aliases.get(canonical) ?? [];
			group.push(provider);
			aliases.set(canonical, group);
		}
	}
	const aliasedProviders = new Set([...aliases.values()].flat());
	for (const [provider, entries] of Object.entries(order)) if (Array.isArray(entries) && !aliasedProviders.has(provider)) order[provider] = entries.map(rewrite);
	for (const [canonical, providers] of aliases) {
		const canonicalEntries = order[canonical];
		if (canonicalEntries !== void 0 && !Array.isArray(canonicalEntries)) continue;
		const moved = [];
		let hasResolvedAlias = false;
		for (const provider of providers) {
			const entries = order[provider];
			if (!Array.isArray(entries)) continue;
			const retained = entries.filter(unresolved);
			const resolved = entries.filter((entry) => !unresolved(entry));
			if (resolved.length > 0 || entries.length === 0) {
				hasResolvedAlias = true;
				moved.push(...resolved.map(rewrite));
			}
			if (retained.length > 0) order[provider] = retained;
			else delete order[provider];
		}
		if (hasResolvedAlias) {
			const combined = Array.isArray(canonicalEntries) && canonicalEntries.length === 0 ? [] : [...moved, ...canonicalEntries ?? []];
			order[canonical] = [...new Set(combined)];
		}
	}
	return !isDeepStrictEqual(before, order);
}
function canonicalizeLegacyAuthLastGood(record, profileIdMap, options) {
	const before = structuredClone(record);
	for (const [provider, value] of Object.entries(before)) {
		const canonical = canonicalLegacyAuthProvider(provider);
		const mapped = typeof value === "string" ? profileIdMap.get(value) : void 0;
		if (canonical !== provider && options?.preserveUnmappedLegacyIds && mapped === void 0) continue;
		if (canonical !== provider) {
			delete record[provider];
			if (Object.hasOwn(before, canonical)) continue;
		}
		record[canonical] = mapped ?? value;
	}
	return !isDeepStrictEqual(before, record);
}
function canonicalizeLegacyAuthStore(raw, stateRaw, profileIdMap) {
	if (!isRecord(raw) || !isRecord(raw.profiles)) {
		if (isRecord(stateRaw)) canonicalizeLegacyAuthRotationState(stateRaw, new Map(profileIdMap));
		return null;
	}
	const rewrite = canonicalizeLegacyAuthProfileEntries(raw.profiles, {
		profileIdMap,
		preserveUnmappedLegacyIds: true
	});
	const effectiveProfileIdMap = new Map([...profileIdMap, ...rewrite.profileIdMap]);
	const rotation = canonicalizeLegacyAuthRotationState(raw, effectiveProfileIdMap);
	if (isRecord(stateRaw)) canonicalizeLegacyAuthRotationState(stateRaw, effectiveProfileIdMap);
	return rewrite.changed || rotation ? rewrite.profileIdMap.size : null;
}
function canonicalizeLegacyAuthRotationState(auth, profileIdMap) {
	const options = { preserveUnmappedLegacyIds: true };
	const orderChanged = canonicalizeLegacyAuthOrder(auth, profileIdMap, options);
	let usageChanged = false;
	if (isRecord(auth.usageStats)) {
		const usage = auth.usageStats;
		for (const [key, value] of Object.entries({ ...usage })) {
			const nextKey = profileIdMap.get(key);
			if (nextKey && nextKey !== key) {
				delete usage[key];
				usage[nextKey] = value;
				usageChanged = true;
			}
		}
	}
	const lastGoodChanged = isRecord(auth.lastGood) ? canonicalizeLegacyAuthLastGood(auth.lastGood, profileIdMap, options) : false;
	return orderChanged || usageChanged || lastGoodChanged;
}
//#endregion
//#region src/commands/doctor-auth-flat-profiles.ts
function resolveMigrationTargetDatabasePath(agentDir, env = process.env) {
	return agentDir ? resolveAuthProfileDatabasePath(agentDir) : resolveSharedAuthStorePath(env);
}
function listAuthProfileMigrationTargets(candidates, env) {
	const targets = /* @__PURE__ */ new Map([[resolveSharedAuthStorePath(env), void 0]]);
	for (const agentDir of [resolveSharedMainAuthAgentDir(env), ...candidates.flatMap((candidate) => candidate.agentDir ? [candidate.agentDir] : [])]) {
		const databasePath = resolveAuthProfileDatabasePath(agentDir);
		if (!targets.has(databasePath)) targets.set(databasePath, agentDir);
	}
	return targets;
}
var AuthProfileMigrationVerificationError = class extends Error {
	constructor(detail) {
		super("auth profile SQLite verification failed");
		this.detail = detail;
		this.name = "AuthProfileMigrationVerificationError";
	}
};
function isSafeLegacyProviderKey(key) {
	return key.trim().length > 0 && !isBlockedObjectKey(key);
}
function extractProviderPrefix(value, separator) {
	const index = value.indexOf(separator);
	return index > 0 ? readNonBlankString(value.slice(0, index)) : void 0;
}
function extractProviderFromModelRef(modelRef) {
	return extractProviderPrefix(splitTrailingAuthProfile(modelRef).model, "/");
}
function collectLegacyConfigAuthProfileProviderHints(cfg) {
	const hints = /* @__PURE__ */ new Map();
	const addHint = (profileId, provider) => {
		const existing = hints.get(profileId);
		hints.set(profileId, existing === void 0 || existing === provider ? provider : null);
	};
	const addModelHints = (models) => {
		if (!isRecord(models)) return;
		for (const [modelRef, rawModel] of Object.entries(models)) {
			const provider = extractProviderFromModelRef(modelRef);
			if (!provider || !isSafeLegacyProviderKey(provider) || !isRecord(rawModel)) continue;
			const agentRuntime = isRecord(rawModel.agentRuntime) ? rawModel.agentRuntime : null;
			const authProfileId = agentRuntime ? readNonBlankString(agentRuntime.authProfileId) : void 0;
			if (authProfileId) addHint(authProfileId, provider);
		}
	};
	for (const { value } of collectConfiguredModelRefs(cfg)) {
		const { profile } = splitTrailingAuthProfile(value);
		const provider = extractProviderFromModelRef(value);
		if (profile && provider && isSafeLegacyProviderKey(provider)) addHint(profile, provider);
	}
	const root = cfg;
	const auth = isRecord(root.auth) ? root.auth : null;
	const order = auth && isRecord(auth.order) ? auth.order : null;
	if (order) for (const [provider, profileIds] of Object.entries(order)) {
		if (!isSafeLegacyProviderKey(provider) || !Array.isArray(profileIds)) continue;
		for (const profileId of profileIds) {
			const normalizedProfileId = readNonBlankString(profileId);
			if (normalizedProfileId) addHint(normalizedProfileId, provider);
		}
	}
	const agents = isRecord(root.agents) ? root.agents : null;
	addModelHints((agents && isRecord(agents.defaults) ? agents.defaults : null)?.models);
	for (const agent of listAgentEntries(cfg)) addModelHints(agent.models);
	return hints;
}
function coerceLegacyFlatAuthProfileStore(raw) {
	if (!isRecord(raw) || "profiles" in raw) return null;
	const store = {
		version: 1,
		profiles: {}
	};
	for (const [key, value] of Object.entries(raw)) {
		const providerId = key.trim();
		if (!isSafeLegacyProviderKey(providerId)) continue;
		const credential = coerceLegacyFlatCredential(providerId, value);
		if (!credential) continue;
		store.profiles[`${providerId}:default`] = credential;
	}
	return Object.keys(store.profiles).length > 0 ? store : null;
}
function listAuthProfileSqliteMigrationCandidates(cfg, env) {
	return listAuthProfileRepairCandidates(cfg, env).map((candidate) => ({
		agentDir: candidate.agentDir,
		authPath: candidate.authPath,
		statePath: resolveLegacyAuthStatePath(path.dirname(candidate.authPath)),
		legacyPath: resolveLegacyFlatAuthPath(path.dirname(candidate.authPath))
	}));
}
function hasAuthProfileState(state) {
	return Boolean(state.order || state.lastGood || state.usageStats);
}
function collectAuthProfileStateProfileIds(state) {
	return [.../* @__PURE__ */ new Set([
		...Object.values(state.order ?? {}).flat(),
		...Object.values(state.lastGood ?? {}),
		...Object.keys(state.usageStats ?? {})
	])];
}
function collectAuthOwnerProfileIds(store, state) {
	const profiles = isRecord(store) && isRecord(store.profiles) ? store.profiles : {};
	return /* @__PURE__ */ new Set([
		...Object.keys(profiles),
		...collectRawAuthRotationProfileIds(store),
		...collectRawAuthRotationProfileIds(state)
	]);
}
const CONFIG_AUTH_VALUE_FIELDS = {
	api_key: [
		"key",
		"apiKey",
		"api_key"
	],
	token: ["token"]
};
function readConfigAuthAlias(raw, fields, read) {
	for (const field of fields) {
		const value = read(raw[field]);
		if (value != null) return value;
	}
}
function inferLegacyConfigAuthProfileMode(raw) {
	const explicit = readNonBlankString(raw.mode) ?? readNonBlankString(raw.type);
	if (explicit === "api_key" || explicit === "token" || explicit === "oauth") return explicit;
	for (const mode of ["api_key", "token"]) {
		const fields = CONFIG_AUTH_VALUE_FIELDS[mode];
		if (readConfigAuthAlias(raw, fields, readNonBlankString) || readConfigAuthAlias(raw, [`${fields[0]}Ref`, ...fields], coerceSecretRef)) return mode;
	}
	if (readNonBlankString(raw.access) && readNonBlankString(raw.refresh) && typeof raw.expires === "number") return "oauth";
}
function coerceLegacyConfigAuthProfileStore(cfg) {
	const cfgRecord = cfg;
	const auth = isRecord(cfgRecord.auth) ? cfgRecord.auth : null;
	const profiles = auth && isRecord(auth.profiles) ? auth.profiles : null;
	if (!profiles) return null;
	const providerHints = collectLegacyConfigAuthProfileProviderHints(cfg);
	const store = {
		version: 1,
		profiles: {}
	};
	for (const [profileId, raw] of Object.entries(profiles)) {
		if (!isRecord(raw)) continue;
		const mode = inferLegacyConfigAuthProfileMode(raw);
		if (!mode) continue;
		const provider = readNonBlankString(raw.provider) ?? extractProviderPrefix(profileId, ":") ?? providerHints.get(profileId);
		if (!provider || !isSafeLegacyProviderKey(provider)) continue;
		const next = {
			...raw,
			provider,
			mode
		};
		if (mode === "api_key" || mode === "token") {
			const fields = CONFIG_AUTH_VALUE_FIELDS[mode];
			const valueField = fields[0];
			const refField = `${valueField}Ref`;
			const ref = readConfigAuthAlias(raw, [refField, ...fields], coerceSecretRef);
			const value = readConfigAuthAlias(raw, fields, readNonBlankString);
			if (ref) {
				next[refField] = ref;
				for (const field of fields) delete next[field];
			} else if (value) {
				next[valueField] = value;
				delete next[refField];
			} else continue;
		} else if (!readNonBlankString(raw.access) || !readNonBlankString(raw.refresh) || typeof raw.expires !== "number") continue;
		store.profiles[profileId] = next;
	}
	const canonicalStore = coerceLegacyAuthProfileStore(store);
	return canonicalStore && Object.keys(canonicalStore.profiles).length > 0 ? canonicalStore : null;
}
function isDefaultAgentCandidate(candidate, cfg, env) {
	return candidate.agentDir === void 0 || path.resolve(candidate.agentDir) === path.resolve(resolveLegacyInheritedAuthAgentDir(cfg, env));
}
function mergeImportedAuthProfiles(params) {
	const profiles = { ...params.store.profiles };
	for (const [profileId, credential] of Object.entries(params.profiles)) {
		const existing = profiles[profileId];
		if (!params.existingProfileIds.has(profileId) || params.replaceExistingWithoutCredential && existing && !hasUsableAuthProfileCredential(existing) && hasUsableAuthProfileCredential(credential)) profiles[profileId] = credential;
	}
	return {
		...params.store,
		profiles
	};
}
function mergeImportedAuthProfileState(params) {
	const next = { ...params.store };
	for (const field of [
		"order",
		"lastGood",
		"usageStats"
	]) {
		const incoming = params.state[field];
		if (!incoming) continue;
		const existing = params.existingState[field] ?? {};
		Object.assign(next, { [field]: {
			...params.store[field],
			...Object.fromEntries(Object.entries(incoming).filter(([key]) => !Object.hasOwn(existing, key)))
		} });
	}
	return next;
}
function formatMissingAuthProfileSqliteVerification(params) {
	const missingProfileIds = [...params.importedProfileIds].filter((profileId) => !params.loaded?.profiles[profileId]);
	const missingStateFields = [];
	for (const field of ["order", "lastGood"]) for (const [provider, expected] of Object.entries(params.expected[field] ?? {})) if (!isDeepStrictEqual(params.loaded?.[field]?.[provider], expected)) missingStateFields.push(`${field}.${provider}`);
	for (const profileId of Object.keys(params.expected.usageStats ?? {})) if (!params.loaded?.usageStats?.[profileId]) missingStateFields.push(`usageStats.${profileId}`);
	const parts = [];
	if (missingProfileIds.length > 0) parts.push(`imported profile(s): ${missingProfileIds.toSorted().join(", ")}`);
	if (missingStateFields.length > 0) parts.push(`auth state field(s): ${missingStateFields.toSorted().join(", ")}`);
	return parts.length > 0 ? parts.join("; ") : null;
}
function collectUnresolvedLegacyOAuthSidecarProfileIds(raw) {
	if (!isRecord(raw) || !isRecord(raw.profiles)) return [];
	const profileIds = [];
	for (const [profileId, profile] of Object.entries(raw.profiles)) {
		if (!isRecord(profile) || profile.type !== "oauth" || !isRecord(profile.oauthRef)) continue;
		if (readNonBlankString(profile.oauthRef.id) && readNonBlankString(profile.oauthRef.provider) && (!readNonBlankString(profile.access) || !readNonBlankString(profile.refresh))) profileIds.push(profileId);
	}
	return profileIds;
}
function hasImportableAuthProfileStore(store) {
	return Boolean(store && (Object.keys(store.profiles).length > 0 || hasAuthProfileState(store)));
}
function prepareAuthProfileSourceReceipt(params) {
	const sourceBytes = fs.readFileSync(params.pathname);
	let sourceRecordCount = 0;
	try {
		const parsed = JSON.parse(sourceBytes.toString("utf8"));
		sourceRecordCount = isRecord(parsed) ? Object.keys(parsed).length : 0;
	} catch {}
	return createAuthProfileMigrationSourceReceipt({
		sourcePath: params.pathname,
		sourceBytes,
		sourceRecordCount,
		targetDatabasePath: params.targetDatabasePath,
		targetTable: params.targetTable,
		...params.targetStoreKey ? { targetStoreKey: params.targetStoreKey } : {},
		now: new Date(params.now()),
		...params.env ? { env: params.env } : {}
	});
}
function assertAuthProfileMigrationSourcesUnchanged(candidate, receipts) {
	const receiptByPath = new Map(receipts.map((receipt) => [receipt.sourcePath, receipt]));
	for (const pathname of [
		candidate.authPath,
		candidate.statePath,
		candidate.legacyPath
	]) {
		const receipt = receiptByPath.get(path.resolve(pathname));
		if (fs.existsSync(pathname) !== Boolean(receipt)) throw new Error("legacy auth source set changed during migration; retry Doctor");
		if (!receipt) continue;
		if (createHash("sha256").update(fs.readFileSync(pathname)).digest("hex") !== receipt.sourceSha256) throw new Error("legacy auth source changed during migration; retry Doctor");
	}
}
function parseAuthProfileMigrationSource(receipt) {
	if (!receipt?.sourceBytes) return null;
	try {
		return JSON.parse(receipt.sourceBytes.toString("utf8"));
	} catch {
		return null;
	}
}
function archivePreviouslyMigratedAuthProfileSource(receipt, result) {
	if (!hasTerminalAuthProfileMigrationReceipt(receipt.sourceKey, receipt.env)) return false;
	archiveAuthProfileMigrationSource(receipt);
	result.changes.push(`Archived a previously migrated legacy auth source without replaying credentials (${shortenHomePath(receipt.archivePath)}).`);
	return true;
}
function loadAuthProfileMigrationTargetStore(agentDir, database, env = process.env) {
	const explicitSharedRead = agentDir === void 0 && database === void 0;
	const inspection = explicitSharedRead ? inspectPersistedSharedAuthProfileStoreRaw(env) : inspectPersistedAuthProfileStoreRaw(agentDir, database);
	const store = explicitSharedRead ? loadPersistedSharedAuthProfileStore(env) : loadPersistedAuthProfileStore(agentDir, database ? { database } : void 0);
	if (store) return store;
	if (inspection.status !== "missing") throw new Error("canonical auth profile store is unreadable; legacy source left in place");
	if ((explicitSharedRead ? inspectPersistedSharedAuthProfileStateRaw(env) : inspectPersistedAuthProfileStateRaw(agentDir, database)).status === "unreadable") throw new Error("canonical auth profile state is unreadable; legacy source left in place");
	return {
		version: 1,
		profiles: {},
		...coerceAuthProfileState(explicitSharedRead ? readPersistedSharedAuthProfileStateRaw(env) : readPersistedAuthProfileStateRaw(agentDir, database))
	};
}
/**
* Imports legacy auth profile JSON and state files into the per-agent SQLite store.
*
* JSON files are verified and atomically renamed to timestamped archives only after import.
* OAuth profiles that still depend on missing sidecar secrets migrate as unavailable ref-only rows.
*/
async function maybeMigrateAuthProfileJsonStoresToSqlite(params) {
	const now = params.now ?? Date.now;
	const env = params.env ?? process.env;
	assertNoRetiredStateFiles("OAuth credential sidecars", listReferencedLegacyOAuthSidecarPaths(env, params.cfg));
	const candidates = listAuthProfileSqliteMigrationCandidates(params.cfg, env);
	const oauthPath = resolveLegacyOAuthPath(env);
	const recoverableSources = /* @__PURE__ */ new Set();
	let recoveryApproved = false;
	const recoverCompleted = (receipt) => {
		const candidate = candidates.find((entry) => [entry.authPath, entry.legacyPath].includes(receipt.sourcePath));
		if (!candidate) return false;
		const raw = parseAuthProfileMigrationSource(receipt);
		normalizeLegacyAuthProfileFields(raw);
		const imported = coerceLegacyAuthProfileStore(raw) ?? coerceLegacyFlatAuthProfileStore(raw);
		if (!imported || !Object.values(imported.profiles).some(hasUsableAuthProfileCredential)) return false;
		const inspection = candidate.agentDir ? inspectPersistedAuthProfileStoreRaw(candidate.agentDir) : inspectPersistedSharedAuthProfileStoreRaw(env);
		const rawTarget = inspection.status === "missing" ? { profiles: {} } : inspection.status === "readable" ? inspection.raw : null;
		if (!isRecord(rawTarget) || !isRecord(rawTarget.profiles)) return false;
		const existing = rawTarget.profiles;
		if (Object.entries(imported.profiles).some(([id, credential]) => Object.hasOwn(existing, id) || (isLegacyOpenAICodexProfileId(id) || isLegacyOpenAICodexProvider(credential.provider)) && Object.entries(existing).some(([key, entry]) => key.startsWith("openai:") || isRecord(entry) && entry.provider === "openai"))) return false;
		recoverableSources.add(receipt.sourcePath);
		return recoveryApproved;
	};
	const warnings = [];
	const migratedProfileIds = /* @__PURE__ */ new Set();
	const blockedProfileIds = /* @__PURE__ */ new Set();
	const resume = () => {
		try {
			return resumePendingAuthProfileMigrationArchives(env, recoverCompleted);
		} catch (err) {
			params.openAICodexAuthProfileIdMap?.forEach((_target, id) => blockedProfileIds.add(id));
			warnings.push(`Could not finalize an interrupted auth profile archive; legacy sources were left for recovery: ${String(err)}`);
			return [];
		}
	};
	const resumedChanges = resume();
	const configStore = coerceLegacyConfigAuthProfileStore(params.cfg);
	const candidateSources = (candidate) => [
		candidate.authPath,
		candidate.statePath,
		candidate.legacyPath
	].filter((pathname) => fs.existsSync(pathname) || recoverableSources.has(pathname) || configStore && isDefaultAgentCandidate(candidate, params.cfg, env) && pathname === candidate.authPath);
	const detected = candidates.filter((candidate) => candidateSources(candidate).length > 0);
	const result = {
		detected: detected.flatMap(candidateSources),
		changes: resumedChanges,
		migratedProfileIds,
		blockedProfileIds,
		warnings
	};
	if (warnings.length > 0) return result;
	if (fs.existsSync(oauthPath)) {
		result.detected.push(oauthPath);
		warnings.push(`Pre-June OAuth credentials at ${shortenHomePath(oauthPath)} were left unchanged. Install OpenClaw 2026.9.5 and run ${formatCliCommand("openclaw doctor --fix")} before upgrading to latest; see https://docs.openclaw.ai/install/updating#upgrading-very-old-versions.`);
	}
	if (detected.length === 0) return result;
	note([...detected.map((candidate) => {
		const hasCredentials = fs.existsSync(candidate.authPath) || fs.existsSync(candidate.legacyPath);
		const providers = readLegacyAuthProfileProviders([{
			kind: "auth-profiles",
			path: candidate.authPath
		}, ...fs.existsSync(candidate.legacyPath) ? [{
			kind: "legacy-auth",
			path: candidate.legacyPath
		}] : []]);
		return `- ${shortenHomePath(candidate.authPath)} / ${shortenHomePath(candidate.statePath)}${hasCredentials ? ` (affected providers: ${providers?.join(", ") ?? "unknown; provider scope unavailable"})` : ""}`;
	}), `- ${formatCliCommand("openclaw doctor --fix")} imports legacy auth profile JSON into SQLite, verifies it, records a receipt, and archives the original bytes.`].join("\n"), "Auth profile SQLite migration");
	if (!await params.prompter.confirmAutoFix({
		message: "Migrate auth profile JSON files into SQLite now?",
		initialValue: true
	})) return result;
	if (recoverableSources.size > 0) {
		recoveryApproved = true;
		const warningCount = warnings.length;
		result.changes.push(...resume());
		if (warnings.length > warningCount) return result;
	}
	const requestedProfileIdMap = params.openAICodexAuthProfileIdMap ?? collectOpenAICodexAuthProfileStoreIdMap({
		cfg: params.cfg,
		env
	});
	const repairedFields = await maybeRepairLegacyAuthProfileStores({
		cfg: params.cfg,
		env,
		profileIdMap: requestedProfileIdMap,
		renameProfileIds: false
	});
	result.changes.push(...repairedFields.changes);
	warnings.push(...repairedFields.warnings);
	const openAIProfileIdMap = repairedFields.profileIdMap;
	for (const [from, to] of requestedProfileIdMap) if (openAIProfileIdMap.get(from) !== to) {
		blockedProfileIds.add(from);
		blockedProfileIds.add(to);
	}
	for (const candidate of detected) {
		const configOwnerCandidate = isDefaultAgentCandidate(candidate, params.cfg, env);
		const candidateProfileIds = /* @__PURE__ */ new Set();
		let completed = false;
		let releaseSources;
		try {
			const candidateSourcePaths = [
				candidate.authPath,
				candidate.statePath,
				candidate.legacyPath
			];
			for (const pathname of candidateSourcePaths) fs.mkdirSync(path.dirname(pathname), { recursive: true });
			releaseSources = acquireAuthProfileMigrationSourceLocks(candidateSourcePaths);
			const targetDatabasePath = resolveMigrationTargetDatabasePath(candidate.agentDir, env);
			const sharedStateTarget = candidate.agentDir === void 0 && resolveSharedAuthStoreOwnership(env).location === "state-db";
			const transactionAgentDir = sharedStateTarget || candidate.agentDir !== void 0 ? candidate.agentDir : resolveSharedMainAuthAgentDir(env);
			let sourceReceipts = candidateSourcePaths.filter(fs.existsSync).map((pathname) => prepareAuthProfileSourceReceipt({
				pathname,
				targetDatabasePath,
				targetTable: pathname === candidate.statePath ? "auth_profile_state" : sharedStateTarget ? "auth_profile_stores" : "auth_profile_store",
				targetStoreKey: sharedStateTarget ? "shared" : "primary",
				now,
				env
			}));
			sourceReceipts = sourceReceipts.filter((receipt) => !archivePreviouslyMigratedAuthProfileSource(receipt, result));
			assertAuthProfileMigrationSourcesUnchanged(candidate, sourceReceipts);
			if (sourceReceipts.length === 0 && !configStore) continue;
			const receiptByPath = new Map(sourceReceipts.map((receipt) => [receipt.sourcePath, receipt]));
			const rawStore = parseAuthProfileMigrationSource(receiptByPath.get(path.resolve(candidate.authPath)));
			const importedAliasProfileIds = new Set(isRecord(rawStore) && isRecord(rawStore.profiles) ? Object.keys(rawStore.profiles) : []);
			const rawState = parseAuthProfileMigrationSource(receiptByPath.get(path.resolve(candidate.statePath)));
			for (const id of [
				...importedAliasProfileIds,
				...collectRawAuthRotationProfileIds(rawStore),
				...collectRawAuthRotationProfileIds(rawState),
				...configOwnerCandidate && configStore ? Object.keys(configStore.profiles) : []
			]) candidateProfileIds.add(id);
			const openAIProviderRepair = canonicalizeLegacyAuthStore(rawStore, rawState, openAIProfileIdMap);
			const unresolvedSidecarProfileIds = new Set(collectUnresolvedLegacyOAuthSidecarProfileIds(rawStore));
			const unresolvedSidecarWarning = unresolvedSidecarProfileIds.size > 0 ? `Migrated ${unresolvedSidecarProfileIds.size} legacy OAuth sidecar profile${unresolvedSidecarProfileIds.size === 1 ? "" : "s"} from ${shortenHomePath(candidate.authPath)} into SQLite as configured-unavailable without credentials; re-authenticate ${unresolvedSidecarProfileIds.size === 1 ? "this profile" : "these profiles"} to restore access.` : void 0;
			const rawProfiles = isRecord(rawStore) && isRecord(rawStore.profiles) ? rawStore.profiles : void 0;
			const awsSdkMarkers = rawProfiles ? readAwsSdkAuthProfileMarkers(candidate) : null;
			if (rawProfiles && awsSdkMarkers) for (const { profileId } of awsSdkMarkers) delete rawProfiles[profileId];
			const canonicalizedSecretRefs = normalizeLegacyAuthProfileFields(rawStore);
			const maybeCanonicalStore = coerceLegacyAuthProfileStore(rawStore) ?? coerceLegacyFlatAuthProfileStore(rawStore) ?? null;
			const canonicalStore = hasImportableAuthProfileStore(maybeCanonicalStore) ? maybeCanonicalStore : null;
			const configCanonicalStore = configStore && configOwnerCandidate ? structuredClone(configStore) : null;
			if (configCanonicalStore) {
				Object.keys(configCanonicalStore.profiles).forEach((id) => importedAliasProfileIds.add(id));
				canonicalizeLegacyAuthStore(configCanonicalStore, null, openAIProfileIdMap);
			}
			const legacyStore = coerceLegacyAuthStore(parseAuthProfileMigrationSource(receiptByPath.get(path.resolve(candidate.legacyPath))));
			const state = coerceAuthProfileState(rawState);
			if (!canonicalStore && !configCanonicalStore && !legacyStore && !hasAuthProfileState(state) && !awsSdkMarkers) {
				if (sourceReceipts.length > 0) {
					const archived = sourceReceipts.map((receipt) => {
						finalizeAuthProfileMigrationSource(receipt, "archived-unparsed");
						return receipt.archivePath;
					});
					result.warnings.push(unresolvedSidecarWarning ?? `Archived unparseable auth profile input without import for ${shortenHomePath(candidate.authPath)} (${archived.map(shortenHomePath).join(", ")}).`);
					continue;
				}
				result.warnings.push(`Left auth profile JSON in place for ${shortenHomePath(candidate.authPath)} because no importable auth profiles or state were found.`);
				continue;
			}
			const existing = loadAuthProfileMigrationTargetStore(candidate.agentDir, void 0, env);
			const existingProfileIds = new Set(Object.keys(existing.profiles));
			const existingState = coerceAuthProfileState(existing);
			let next = { ...existing };
			let verifiedStore = existing;
			const importedProfileIds = /* @__PURE__ */ new Set();
			const legacyAsStore = {
				version: 1,
				profiles: {}
			};
			if (legacyStore) {
				applyLegacyAuthStore(legacyAsStore, legacyStore);
				Object.keys(legacyAsStore.profiles).forEach((id) => importedAliasProfileIds.add(id));
				Object.keys(legacyAsStore.profiles).forEach((id) => candidateProfileIds.add(id));
				canonicalizeLegacyAuthStore(legacyAsStore, null, openAIProfileIdMap);
			}
			for (const imported of [
				legacyAsStore,
				canonicalStore,
				configCanonicalStore
			]) {
				if (!imported) continue;
				Object.keys(imported.profiles).forEach((id) => importedProfileIds.add(id));
				const fromConfig = imported === configCanonicalStore;
				next = mergeImportedAuthProfiles({
					store: next,
					profiles: imported.profiles,
					existingProfileIds: fromConfig ? new Set(Object.keys(next.profiles)) : existingProfileIds,
					replaceExistingWithoutCredential: fromConfig
				});
				if (imported === canonicalStore) {
					next.version = Math.max(next.version, imported.version);
					next = mergeImportedAuthProfileState({
						store: next,
						state: coerceAuthProfileState(imported),
						existingState
					});
				}
			}
			if (hasAuthProfileState(state)) next = mergeImportedAuthProfileState({
				store: next,
				state,
				existingState
			});
			if (canonicalStore || configCanonicalStore || legacyStore || hasAuthProfileState(state)) {
				const stateProfileIds = [
					state,
					canonicalStore,
					configCanonicalStore
				].flatMap((store) => store ? collectAuthProfileStateProfileIds(coerceAuthProfileState(store)) : []);
				try {
					assertAuthProfileMigrationSourcesUnchanged(candidate, sourceReceipts);
					verifiedStore = runWithAuthAliasMigrationReceipt(recordAuthAliasMigration({
						profileIdMap: openAIProfileIdMap,
						stores: [{
							databasePath: targetDatabasePath,
							store: existing,
							migratedStore: next
						}],
						importedProfileIds: importedAliasProfileIds,
						sources: sourceReceipts.filter((receipt) => receipt.sourcePath !== path.resolve(candidate.statePath)).map((receipt) => ({
							path: receipt.sourcePath,
							sha256: receipt.sourceSha256
						})),
						env
					}), env, () => runAuthProfileWriteTransaction(transactionAgentDir, (database, owner) => {
						const authoritative = loadAuthProfileMigrationTargetStore(candidate.agentDir, database);
						if (!isDeepStrictEqual(authoritative, existing)) throw new Error("canonical auth profile store changed during legacy migration");
						saveAuthProfileStoreWithPreparedOwner(next, candidate.agentDir, {
							filterExternalAuthProfiles: false,
							preserveStateProfileIds: stateProfileIds,
							syncExternalCli: false
						}, database, owner);
						const loaded = loadPersistedAuthProfileStore(candidate.agentDir, { database });
						const isMainStore = resolveMigrationTargetDatabasePath(candidate.agentDir, env) === resolveSharedAuthStorePath(env);
						const persistedStores = {
							isMainStore,
							localStore: loaded,
							mainStore: isMainStore ? loaded : loadPersistedSharedAuthProfileStore(env)
						};
						const verifiableProfileIds = new Set([...importedProfileIds].filter((profileId) => {
							const credential = next.profiles[profileId];
							return !(credential !== void 0 && !loaded?.profiles[profileId] && isInheritedMainOAuthCredentialFromStores({
								profileId,
								credential,
								persistedStores
							}));
						}));
						const verificationFailure = formatMissingAuthProfileSqliteVerification({
							expected: next,
							importedProfileIds: verifiableProfileIds,
							loaded
						});
						const mismatchedCredential = [...verifiableProfileIds].some((profileId) => {
							if (existingProfileIds.has(profileId)) return false;
							return !isDeepStrictEqual(loaded?.profiles[profileId], next.profiles[profileId]);
						});
						if (verificationFailure || mismatchedCredential || !loaded) throw new AuthProfileMigrationVerificationError(verificationFailure);
						return loaded;
					}, { env }));
				} catch (error) {
					if (!(error instanceof AuthProfileMigrationVerificationError)) throw error;
					result.warnings.push(`Left auth profile JSON in place for ${shortenHomePath(candidate.authPath)} because SQLite verification failed${error.detail ? ` (${error.detail})` : ""}.`);
					continue;
				}
			}
			const expectedProfileSha256 = Object.fromEntries([...importedProfileIds].flatMap((profileId) => {
				const profileValue = verifiedStore.profiles[profileId];
				return profileValue ? [[profileId, digestAuthProfileMigrationValue(profileValue)]] : [];
			}));
			const expectedStateSha256 = digestAuthProfileMigrationValue(candidate.agentDir ? readPersistedAuthProfileStateRaw(candidate.agentDir) : readPersistedSharedAuthProfileStateRaw(env));
			const canonicalSourceCarriesState = canonicalStore ? hasAuthProfileState(coerceAuthProfileState(canonicalStore)) : false;
			for (const receipt of sourceReceipts) {
				if (receipt.targetTable !== "auth_profile_state") receipt.expectedProfileSha256 = expectedProfileSha256;
				if (receipt.targetTable === "auth_profile_state" || receipt.sourcePath === candidate.authPath && canonicalSourceCarriesState) receipt.expectedStateSha256 = expectedStateSha256;
			}
			assertAuthProfileMigrationSourcesUnchanged(candidate, sourceReceipts);
			const archives = sourceReceipts.map((receipt) => {
				finalizeAuthProfileMigrationSource(receipt, "completed");
				return receipt.archivePath;
			});
			for (const id of [
				...importedAliasProfileIds,
				...importedProfileIds,
				...collectAuthProfileStateProfileIds(state),
				...collectAuthProfileStateProfileIds(coerceAuthProfileState(canonicalStore)),
				...collectAuthProfileStateProfileIds(coerceAuthProfileState(configCanonicalStore))
			]) migratedProfileIds.add(id);
			if (configStore && configOwnerCandidate && stripImportedConfigAuthProfileCredentials(params.cfg, configStore)) result.configChanged = true;
			if (awsSdkMarkers) {
				const configProfiles = ensureConfigAuthProfiles(params.cfg);
				for (const marker of awsSdkMarkers) configProfiles[marker.profileId] = {
					provider: marker.provider,
					mode: "aws-sdk",
					...marker.email ? { email: marker.email } : {},
					...marker.displayName ? { displayName: marker.displayName } : {}
				};
				result.configChanged = true;
			}
			const archiveText = archives.length > 0 ? `archive${archives.length === 1 ? "" : "s"}: ${archives.map(shortenHomePath).join(", ")}` : "no legacy JSON backup needed";
			result.changes.push(`Migrated auth profile JSON for ${shortenHomePath(candidate.authPath)} into SQLite (${archiveText}).`);
			if (canonicalizedSecretRefs > 0) result.changes.push(`Canonicalized ${canonicalizedSecretRefs} auth SecretRef(s) to source/provider/id; unsupported fields are preserved in the verified source archives (${archiveText}).`);
			completed = true;
			if (unresolvedSidecarWarning) result.warnings.push(unresolvedSidecarWarning);
			if (openAIProviderRepair !== null) result.changes.push(`Migrated retired auth profile identifiers in ${shortenHomePath(candidate.authPath)}.`);
			if (awsSdkMarkers) result.changes.push(`Moved aws-sdk profile metadata from ${shortenHomePath(candidate.authPath)} to auth.profiles before removing the legacy auth profile JSON.`);
		} catch (err) {
			if (candidateProfileIds.size === 0) openAIProfileIdMap.forEach((_target, id) => blockedProfileIds.add(id));
			result.warnings.push(`Failed to migrate auth profile JSON for ${shortenHomePath(candidate.authPath)}: ${String(err)}`);
		} finally {
			if (!completed) candidateProfileIds.forEach((id) => blockedProfileIds.add(id));
			releaseSources?.();
		}
	}
	clearRuntimeAuthProfileStoreSnapshots();
	clearAuthProfileMigrationDiagnostics();
	return result;
}
function readAwsSdkAuthProfileMarkers(candidate) {
	if (!fs.existsSync(candidate.authPath)) return null;
	const raw = loadJsonFileThroughSymlink(candidate.authPath);
	if (!isRecord(raw) || !isRecord(raw.profiles)) return null;
	const markers = [];
	for (const [profileId, value] of Object.entries(raw.profiles)) {
		if (!isRecord(value)) continue;
		if ((readNonBlankString(value.type) ?? readNonBlankString(value.mode)) !== "aws-sdk") continue;
		const provider = readNonBlankString(value.provider) ?? extractProviderPrefix(profileId, ":");
		if (!provider || !isSafeLegacyProviderKey(provider)) continue;
		markers.push({
			profileId,
			provider,
			...readNonBlankString(value.email) ? { email: readNonBlankString(value.email) } : {},
			...readNonBlankString(value.displayName) ? { displayName: readNonBlankString(value.displayName) } : {}
		});
	}
	return markers.length > 0 ? markers : null;
}
function rewriteMappedAuthProfileRefs(config, profileIdMap) {
	let changed = false;
	const rewrite = (owner, key) => {
		if (!isRecord(owner) || typeof owner[key] !== "string") return;
		let profileId = owner[key];
		if (key === "apiKey") profileId = normalizeSecretInput(profileId);
		else if (key === "authProfileId") profileId = profileId.trim();
		const replacement = profileIdMap.get(profileId);
		if (replacement && replacement !== owner[key]) {
			owner[key] = replacement;
			changed = true;
		}
	};
	for (const provider of Object.values(config.models?.providers ?? {})) rewrite(provider, "apiKey");
	for (const model of config.tools?.media?.models ?? []) {
		rewrite(model, "profile");
		rewrite(model, "preferredProfile");
	}
	for (const server of Object.values(config.mcp?.servers ?? {})) rewrite(server.oauth, "authProfileId");
	const agents = [config.agents?.defaults, ...listMutableCodexRouteAgentEntries(config).map(({ agent }) => agent)];
	for (const agent of agents) {
		if (!isRecord(agent) || !isRecord(agent.models)) continue;
		for (const model of Object.values(agent.models)) rewrite(isRecord(model) ? model.agentRuntime : void 0, "authProfileId");
	}
	return changed;
}
/**
* Canonicalizes config references for retired provider and profile identifiers.
*
* The optional map lets config and store repairs share deterministic profile ids when both surfaces
* contain the same legacy profile.
*/
function maybeRepairOpenAICodexAuthConfig(cfg, options) {
	let config = structuredClone(cfg);
	const root = config;
	const auth = isRecord(root.auth) ? root.auth : void 0;
	const profileIdMap = new Map(options?.profileIdMap);
	let changed = false;
	if (isRecord(auth?.profiles)) {
		const rewrite = canonicalizeLegacyAuthProfileEntries(auth.profiles, {
			profileIdMap,
			preserveUnmappedLegacyIds: options?.profileIdMap !== void 0
		});
		for (const [from, to] of rewrite.profileIdMap) profileIdMap.set(from, to);
		changed ||= rewrite.changed;
	}
	if (auth) {
		const orderChanged = canonicalizeLegacyAuthOrder(auth, profileIdMap, { preserveUnmappedLegacyIds: options?.profileIdMap !== void 0 });
		changed ||= orderChanged;
	}
	if (profileIdMap.size > 0 && rewriteMappedAuthProfileRefs(config, profileIdMap)) changed = true;
	if (profileIdMap.size > 0) {
		const models = repairRetiredConfigModelRefs(config, ({ modelRef }) => repairModelRefAuthProfile(modelRef, profileIdMap));
		config = models.config;
		changed ||= models.changes.length > 0;
		const pluginsChanged = rewritePluginAuthProfileRefs(config, profileIdMap);
		changed ||= pluginsChanged;
	}
	return {
		config,
		changes: changed ? ["Migrated legacy auth profile config to canonical providers."] : [],
		warnings: []
	};
}
/** Normalize already-SQLite stores under their current owners after legacy import. */
async function maybeRepairLegacyAuthProfileStores(params) {
	const env = params.env ?? process.env;
	const warnings = [];
	let incompleteCensus = false;
	const warnUnavailable = (pathname) => {
		incompleteCensus = true;
		warnings.push(`Skipped auth-profile alias migration because ${shortenHomePath(pathname)} is unavailable.`);
	};
	const candidates = listAuthProfileRepairCandidates(params.cfg, env, warnUnavailable);
	const stores = [];
	const planned = [];
	for (const [databasePath, agentDir] of listAuthProfileMigrationTargets(candidates, env)) {
		let identity;
		try {
			identity = readDatabasePathIdentitySync(databasePath);
		} catch {
			warnUnavailable(databasePath);
			continue;
		}
		const store = agentDir ? inspectPersistedAuthProfileStoreRaw(agentDir) : inspectPersistedSharedAuthProfileStoreRaw(env);
		const state = agentDir ? inspectPersistedAuthProfileStateRaw(agentDir) : inspectPersistedSharedAuthProfileStateRaw(env);
		if (store.status === "unreadable" || agentDir !== void 0 && inspectAuthDatabaseFiles(agentDir) === "unreadable" || store.status === "readable" && (!isRecord(store.raw) || !isRecord(store.raw.profiles))) {
			incompleteCensus = true;
			warnings.push(`Skipped auth-profile alias migration because ${shortenHomePath(databasePath)} is unreadable or invalid.`);
			continue;
		}
		stores.push({
			databasePath,
			store: store.status === "readable" ? store.raw : null
		});
		if (store.status === "readable" || state.status === "readable" || state.status === "unreadable") {
			assertExistingDatabaseIdentity(databasePath, identity.key, identity.birthtime);
			const canReadRotationState = state.status === "missing" || state.status === "readable" && isReadableAuthAliasState(state.raw);
			const canRenameAliases = (store.status !== "readable" || isReadableAuthAliasStore(store.raw)) && canReadRotationState;
			if (!canRenameAliases) warnings.push(`Skipped auth-profile alias renames because ${shortenHomePath(databasePath)} is unreadable or invalid; supported credential fields can still be repaired.`);
			const unreadableStateJson = state.status === "unreadable" ? readAuthProfileStateJsonTextReadOnly({
				path: databasePath,
				kind: agentDir === void 0 && resolveSharedAuthStoreOwnership(env).location === "state-db" ? "shared-state" : "agent",
				env
			}) : void 0;
			assertExistingDatabaseIdentity(databasePath, identity.key, identity.birthtime);
			if (state.status === "unreadable" && unreadableStateJson === void 0) {
				incompleteCensus = true;
				warnings.push(`Skipped auth-profile field repair because ${shortenHomePath(databasePath)} has no stable rotation-state source.`);
				continue;
			}
			planned.push({
				databasePath,
				identity,
				canRenameAliases,
				canReadRotationState,
				agentDir,
				store: store.status === "readable" ? store.raw : null,
				state: state.status === "readable" ? state.raw : null,
				...unreadableStateJson !== void 0 ? { unreadableStateJson } : {}
			});
		}
	}
	const profileIdMap = new Map(incompleteCensus ? [] : params.profileIdMap);
	if (incompleteCensus && params.profileIdMap.size > 0) warnings.push("Deferred auth profile aliases because an owner could not be inspected; repair that owner and rerun Doctor.");
	for (const target of planned) {
		if (target.canRenameAliases) continue;
		const references = collectAuthOwnerProfileIds(target.store, target.state);
		for (const [from, to] of profileIdMap) if (!target.canReadRotationState || references.has(from) || references.has(to)) {
			profileIdMap.delete(from);
			warnings.push(`Deferred auth profile alias ${from} because ${shortenHomePath(target.databasePath)} cannot safely rename its credential owner.`);
		}
	}
	const recovery = recoverAuthAliasMigration({
		stores,
		env,
		archivedMappings: recoverArchivedAuthProfileMappings({
			candidates,
			env
		})
	});
	const migrationMap = params.renameProfileIds === false ? /* @__PURE__ */ new Map() : profileIdMap;
	const unresolvedProfileIds = new Set(Object.entries(params.cfg.auth?.profiles ?? {}).filter(([id, profile]) => !profileIdMap.has(id) && (isLegacyAuthProfileId(id) || typeof profile.provider === "string" && canonicalLegacyAuthProvider(profile.provider) !== profile.provider)).map(([id]) => id));
	for (const target of planned) {
		for (const id of [...collectRawAuthRotationProfileIds(target.store), ...collectRawAuthRotationProfileIds(target.state)]) if (isLegacyAuthProfileId(id) && !profileIdMap.has(id)) unresolvedProfileIds.add(id);
		if (!isRecord(target.store) || !isRecord(target.store.profiles)) continue;
		for (const [profileId, profile] of Object.entries(target.store.profiles)) {
			const provider = isRecord(profile) && typeof profile.provider === "string" ? profile.provider.trim().toLowerCase() : void 0;
			if (!profileIdMap.has(profileId) && (isLegacyAuthProfileId(profileId) || provider !== void 0 && canonicalLegacyAuthProvider(provider) !== provider)) unresolvedProfileIds.add(profileId);
		}
	}
	for (const profileId of unresolvedProfileIds) warnings.push(`Kept auth profile ${profileId} unchanged because its provider realm or identity is unresolved.`);
	for (const target of planned) {
		const occupied = collectAuthOwnerProfileIds(target.store, target.state);
		for (const [from, to] of profileIdMap) if (from !== to && occupied.has(to) && (occupied.has(from) || recovery.recovered.get(from) !== to)) {
			profileIdMap.delete(from);
			warnings.push(`Deferred stale auth profile alias ${from}; the target is occupied.`);
		}
	}
	for (const from of profileIdMap.keys()) if (recovery.blocked.has(from)) {
		profileIdMap.delete(from);
		warnings.push(`Kept auth profile ${from} unchanged because its recorded account changed; reconcile the migration before retrying.`);
	}
	const migrated = planned.map((target) => {
		const migratedStore = structuredClone(target.store);
		const migratedState = structuredClone(target.state);
		if (target.canRenameAliases) canonicalizeLegacyAuthStore(migratedStore, migratedState, migrationMap);
		const canonicalizedSecretRefs = normalizeLegacyAuthProfileFields(migratedStore);
		return Object.assign(target, {
			migratedStore,
			migratedState,
			canonicalizedSecretRefs
		});
	});
	const changed = migrated.filter((target) => !isDeepStrictEqual(target.store, target.migratedStore) || !isDeepStrictEqual(target.state, target.migratedState));
	if (changed.length === 0 && migrationMap.size === 0) return {
		changes: [],
		warnings,
		profileIdMap
	};
	const maintenance = getOpenClawDatabaseMaintenanceScope();
	const assertTargetCurrent = (target, database) => {
		maintenance?.assertOwnerCurrent();
		assertExistingDatabaseIdentity(target.databasePath, target.identity.key, target.identity.birthtime);
		if (database) {
			const native = "agentId" in database ? readOpenClawAgentDatabaseIdentity(database) : void 0;
			const identity = native ? {
				key: `file:${String(native.identity)}`,
				birthtime: native.birthtime
			} : requireOpenClawStateDatabaseIdentity(database);
			if (identity.key !== target.identity.key) throw new Error("Auth profile database generation changed after backup; retry Doctor.");
			assertExistingDatabaseIdentity(database.path, identity.key, identity.birthtime);
		}
	};
	const changes = [];
	const backupId = randomUUID();
	for (const target of changed) {
		assertTargetCurrent(target);
		const kind = target.agentDir === void 0 && resolveSharedAuthStoreOwnership(env).location === "state-db" ? "shared-state" : "agent";
		const backup = await createVerifiedSqliteSnapshot({
			sourcePath: target.databasePath,
			targetPath: `${target.databasePath}.auth-profile-migration-${backupId}.bak`,
			preserveRowIds: true,
			beforePublish: () => assertTargetCurrent(target),
			validate: (database) => {
				for (const field of ["store", "state"]) {
					if (field === "state" && target.unreadableStateJson !== void 0) {
						if (readAuthProfileJsonCellText(database, "state", kind) !== target.unreadableStateJson) throw new Error("Auth profile backup differs from the planned rotation-state source; retry Doctor.");
						continue;
					}
					const row = inspectAuthProfileJsonCell(database, field, kind);
					if (row.status === "unreadable" || !isDeepStrictEqual(row.status === "readable" ? row.raw : null, target[field])) throw new Error("Auth profile backup differs from the planned source; retry Doctor.");
				}
			}
		});
		assertTargetCurrent(target);
		changes.push(`Saved auth profile migration backup: ${shortenHomePath(backup.path)}.`);
	}
	const assertSourceCurrent = (target, database) => {
		assertTargetCurrent(target, database);
		if (target.unreadableStateJson !== void 0 && readAuthProfileJsonCellText(database.db, "state", "agentId" in database ? "agent" : "shared-state") !== target.unreadableStateJson) throw new Error("Auth profile rotation-state source changed during migration; retry Doctor.");
		if (!isDeepStrictEqual(readPersistedAuthProfileStoreRaw(target.agentDir, database), target.store) || !isDeepStrictEqual(readPersistedAuthProfileStateRaw(target.agentDir, database), target.state)) throw new Error("auth profile store or rotation state changed during alias migration");
	};
	for (const target of migrated) runAuthProfileWriteTransaction(target.agentDir, (database) => assertSourceCurrent(target, database), { env });
	maintenance?.assertOwnerCurrent();
	const receiptSha256 = recordAuthAliasMigration({
		profileIdMap: migrationMap,
		stores: migrated,
		env,
		normalizeCredentialFields: true
	});
	const locked = [];
	const migrate = (index, sharedDatabase) => {
		const nextTarget = migrated[index];
		if (nextTarget) {
			runAuthProfileWriteTransaction(nextTarget.agentDir, (database) => {
				assertSourceCurrent(nextTarget, database);
				locked.push({
					database,
					target: nextTarget
				});
				migrate(index + 1, sharedDatabase);
			}, { env });
			return;
		}
		maintenance?.assertOwnerCurrent();
		const renamedLinks = renameUserProfileAuthLinks(migrationMap, {
			env,
			database: sharedDatabase
		});
		if (renamedLinks > 0) changes.push(`Updated renamed auth profiles in ${renamedLinks} personal account selection record(s).`);
		for (const { database, target } of locked) {
			const store = target.migratedStore;
			const state = target.migratedState;
			const storeChanged = !isDeepStrictEqual(store, target.store);
			const stateChanged = !isDeepStrictEqual(state, target.state);
			if (storeChanged) {
				writePersistedAuthProfileStoreRaw(store, target.agentDir, database);
				if (target.canonicalizedSecretRefs > 0) changes.push(`Canonicalized ${target.canonicalizedSecretRefs} auth SecretRef(s) in ${shortenHomePath(target.databasePath)} to source/provider/id; unsupported fields are preserved in the verified migration backup.`);
			}
			if (stateChanged) writePersistedAuthProfileStateRaw(state, target.agentDir, database);
			if (storeChanged || stateChanged) changes.push(`Migrated stored auth profile aliases in ${shortenHomePath(target.databasePath)}.`);
		}
	};
	runWithAuthAliasMigrationReceipt(receiptSha256, env, (database) => migrate(0, database));
	if (changes.length > 0) clearRuntimeAuthProfileStoreSnapshots();
	return {
		changes,
		warnings,
		profileIdMap
	};
}
function recoverArchivedAuthProfileMappings(params) {
	const recovered = /* @__PURE__ */ new Map();
	const ambiguous = /* @__PURE__ */ new Set();
	const agentDirs = [resolveSharedMainAuthAgentDir(params.env), ...params.candidates.flatMap((candidate) => candidate.agentDir ? [candidate.agentDir] : [])];
	const archives = listLegacyAuthProfileArchives({
		agentDirs,
		env: params.env
	}).filter((archive) => archive.kind === "auth-profiles" || archive.kind === "legacy-auth");
	for (const candidate of params.candidates) {
		const canonicalProfiles = coerceLegacyAuthProfileStore(candidate.agentDir ? readPersistedAuthProfileStoreRaw(candidate.agentDir) : readPersistedSharedAuthProfileStoreRaw(params.env))?.profiles;
		if (!canonicalProfiles) continue;
		const sourcePaths = [candidate.authPath, resolveLegacyFlatAuthPath(path.dirname(candidate.authPath))];
		for (const archive of archives) {
			const sourcePath = sourcePaths.find((source) => archive.path.startsWith(`${source}.migrated-`));
			if (!sourcePath) continue;
			try {
				const sourceBytes = fs.readFileSync(archive.path);
				const sourceSha256 = createHash("sha256").update(sourceBytes).digest("hex");
				const sourceKey = `auth-profile-v2:${createHash("sha256").update(`${path.resolve(sourcePath)}\0${sourceSha256}`).digest("hex")}`;
				const receipt = readLegacyMigrationReceipt(sourceKey, params.env);
				if (!receipt?.removedSource || receipt.sourceSha256 !== sourceSha256) continue;
				const report = JSON.parse(receipt.reportJson);
				const sharedStateTarget = candidate.agentDir === void 0 && resolveSharedAuthStoreOwnership(params.env).location === "state-db";
				if (!isRecord(report) || report.format !== "auth-profile-json-to-sqlite-v2" || report.completionStatus !== "completed" || report.targetTable !== (sharedStateTarget ? "auth_profile_stores" : "auth_profile_store") || typeof report.archivePath !== "string" || path.resolve(report.archivePath) !== path.resolve(archive.path) || typeof report.targetDatabasePath !== "string" || path.resolve(report.targetDatabasePath) !== path.resolve(resolveMigrationTargetDatabasePath(candidate.agentDir, params.env)) || !isRecord(report.expectedProfileSha256)) continue;
				const archivedStore = JSON.parse(sourceBytes.toString("utf8"));
				const sourceStore = coerceLegacyAuthProfileStore(archivedStore) ?? coerceLegacyFlatAuthProfileStore(archivedStore);
				if (!sourceStore) continue;
				for (const [legacyProfileId, rawCredential] of Object.entries(sourceStore.profiles)) {
					const target = legacyAuthProfileTarget(legacyProfileId);
					if (!target) continue;
					const archivedCredential = parseLegacyCredentialEntry({
						...rawCredential,
						provider: target.provider
					}, target.provider);
					if (!archivedCredential) continue;
					const matches = Object.entries(report.expectedProfileSha256).flatMap(([canonicalProfileId, expectedSha256]) => {
						const credential = canonicalProfiles[canonicalProfileId];
						return typeof expectedSha256 === "string" && credential?.provider === target.provider && (archivedCredential.type === "oauth" && credential.type === "oauth" ? hasMatchingOAuthIdentity(archivedCredential, credential) || areOAuthCredentialsEquivalent(archivedCredential, credential) : isDeepStrictEqual(archivedCredential, credential)) ? [canonicalProfileId] : [];
					});
					if (matches.length !== 1) continue;
					const canonicalProfileId = matches[0];
					const previous = recovered.get(legacyProfileId);
					if (previous && previous.profileId !== canonicalProfileId) {
						recovered.delete(legacyProfileId);
						ambiguous.add(legacyProfileId);
					} else if (!ambiguous.has(legacyProfileId)) recovered.set(legacyProfileId, {
						profileId: canonicalProfileId,
						origins: [...previous?.origins ?? [], {
							sourcePath: path.resolve(sourcePath),
							sourceSha256,
							databasePath: resolveMigrationTargetDatabasePath(candidate.agentDir, params.env)
						}]
					});
				}
			} catch {}
		}
	}
	return recovered;
}
/** Collects collision-safe retired profile ids across config, SQLite, and legacy agent stores. */
function collectOpenAICodexAuthProfileStoreIdMap(params) {
	const env = params.env ?? process.env;
	const occupied = /* @__PURE__ */ new Set(["openai:codex-cli"]);
	const eligible = /* @__PURE__ */ new Set();
	const blocked = /* @__PURE__ */ new Set();
	const profileIdMap = /* @__PURE__ */ new Map();
	const sqliteStores = [];
	let incompleteCensus = false;
	const candidates = listAuthProfileRepairCandidates(params.cfg, env, () => {
		incompleteCensus = true;
	});
	if (incompleteCensus) return profileIdMap;
	const configuredProviders = new Set(Object.keys(params.cfg.models?.providers ?? {}).map((provider) => provider.trim().toLowerCase()));
	const collectReferences = (raw) => {
		for (const id of collectRawAuthRotationProfileIds(raw)) occupied.add(id);
	};
	const collectProfiles = (raw) => {
		if (!isRecord(raw) || !isRecord(raw.profiles)) return false;
		for (const [profileId, value] of Object.entries(raw.profiles)) {
			occupied.add(profileId);
			const target = legacyAuthProfileTarget(profileId);
			const provider = isRecord(value) && typeof value.provider === "string" ? value.provider.trim().toLowerCase() : void 0;
			const canonical = provider === void 0 ? void 0 : canonicalLegacyAuthProvider(provider);
			if (!target && canonical === provider) continue;
			const legacyPrefix = profileId.slice(0, profileId.indexOf(":")).trim().toLowerCase();
			const changesRealm = provider !== canonical;
			const explicitRealm = isRecord(value) && changesRealm && [
				"enterpriseUrl",
				"tokenEndpoint",
				"deviceAuthorizationEndpoint",
				"issuer"
			].some((field) => value[field] !== void 0);
			if (provider === void 0 || canonical === void 0 || target !== null && target.provider !== canonical || target !== null && configuredProviders.has(legacyPrefix) || changesRealm && configuredProviders.has(provider) || explicitRealm) blocked.add(profileId);
			else eligible.add(profileId);
		}
		collectReferences(raw);
		return true;
	};
	collectProfiles({
		profiles: params.cfg.auth?.profiles ?? {},
		order: params.cfg.auth?.order
	});
	for (const [databasePath, agentDir] of listAuthProfileMigrationTargets(candidates, env)) {
		if (agentDir && inspectAuthDatabaseFiles(agentDir) === "unreadable") return profileIdMap;
		const inspection = agentDir ? inspectPersistedAuthProfileStoreRaw(agentDir) : inspectPersistedSharedAuthProfileStoreRaw(env);
		const state = agentDir ? inspectPersistedAuthProfileStateRaw(agentDir) : inspectPersistedSharedAuthProfileStateRaw(env);
		if (inspection.status === "unreadable" || state.status === "unreadable") return profileIdMap;
		sqliteStores.push({
			databasePath,
			store: inspection.status === "readable" ? inspection.raw : null
		});
		if (inspection.status === "readable") {
			if (!collectProfiles(inspection.raw)) return profileIdMap;
			if (!isReadableAuthAliasStore(inspection.raw) && isRecord(inspection.raw) && isRecord(inspection.raw.profiles)) Object.keys(inspection.raw.profiles).forEach((id) => blocked.add(id));
		}
		if (state.status === "readable") {
			if (!isRecord(state.raw)) return profileIdMap;
			collectReferences(state.raw);
			if (!isReadableAuthAliasState(state.raw) && inspection.status === "readable" && isRecord(inspection.raw) && isRecord(inspection.raw.profiles)) Object.keys(inspection.raw.profiles).forEach((id) => blocked.add(id));
		}
	}
	for (const candidate of candidates) {
		if (fs.existsSync(candidate.authPath) && !collectProfiles(loadJsonFileThroughSymlink(candidate.authPath))) return profileIdMap;
		const legacyPath = resolveLegacyFlatAuthPath(path.dirname(candidate.authPath));
		if (fs.existsSync(legacyPath)) {
			const legacy = coerceLegacyAuthStore(loadJsonFileThroughSymlink(legacyPath));
			if (!legacy) return profileIdMap;
			const store = {
				version: 1,
				profiles: {}
			};
			applyLegacyAuthStore(store, legacy);
			collectProfiles(store);
		}
		const statePath = resolveLegacyAuthStatePath(path.dirname(candidate.authPath));
		if (fs.existsSync(statePath)) {
			const raw = loadJsonFileThroughSymlink(statePath);
			if (!isRecord(raw)) return profileIdMap;
			collectReferences(raw);
		}
	}
	const archivedMappings = recoverArchivedAuthProfileMappings({
		candidates,
		env
	});
	const recovery = recoverAuthAliasMigration({
		stores: sqliteStores,
		env,
		archivedMappings
	});
	for (const profileId of recovery.blocked) blocked.add(profileId);
	for (const [from, to] of recovery.recovered) if (!blocked.has(from)) {
		profileIdMap.set(from, to);
		if (archivedMappings.get(from)?.profileId === to) params.recoveredProfileIds?.add(from);
	}
	for (const profileId of [...eligible].toSorted((left, right) => left.localeCompare(right))) if (!blocked.has(profileId) && !profileIdMap.has(profileId)) profileIdMap.set(profileId, isLegacyAuthProfileId(profileId) ? allocateLegacyAuthProfileId(profileId, occupied) : profileId);
	for (const [legacyProfileId, archive] of archivedMappings) if (sqliteStores.every(({ databasePath, store }) => !isRecord(store) || !isRecord(store.profiles) || store.profiles[archive.profileId] === void 0 || archive.origins.some((origin) => origin.databasePath === databasePath)) && !profileIdMap.has(legacyProfileId) && !blocked.has(legacyProfileId)) {
		profileIdMap.set(legacyProfileId, archive.profileId);
		params.recoveredProfileIds?.add(legacyProfileId);
	}
	return profileIdMap;
}
//#endregion
//#region src/commands/doctor/auth-profile-repair.ts
/** Complete only verified imports or explicitly requested auth repairs through the same owners. */
async function repairAuthProfileMigration(params) {
	const env = params.env ?? process.env;
	const planned = params.profileIdMap ?? collectOpenAICodexAuthProfileStoreIdMap({
		cfg: params.cfg,
		env
	});
	const config = structuredClone(params.cfg);
	const imported = await maybeMigrateAuthProfileJsonStoresToSqlite({
		cfg: config,
		env,
		prompter: { confirmAutoFix: params.prompter.confirmAutoFix },
		openAICodexAuthProfileIdMap: planned
	});
	const recoveredProfileIds = /* @__PURE__ */ new Set();
	const recovered = imported.detected.length === 0 ? collectOpenAICodexAuthProfileStoreIdMap({
		cfg: config,
		env,
		recoveredProfileIds
	}) : /* @__PURE__ */ new Map();
	const authorized = new Map([...planned, ...[...recovered].filter(([from]) => recoveredProfileIds.has(from))].filter(([from, to]) => !imported.blockedProfileIds.has(from) && !imported.blockedProfileIds.has(to) && (params.prompter.shouldRepair || recoveredProfileIds.has(from) && imported.detected.length === 0 || imported.migratedProfileIds.has(from) || imported.migratedProfileIds.has(to))));
	const aliases = params.prompter.shouldRepair || authorized.size > 0 ? await maybeRepairLegacyAuthProfileStores({
		cfg: config,
		env,
		profileIdMap: authorized
	}) : {
		profileIdMap: authorized,
		changes: [],
		warnings: []
	};
	const repaired = maybeRepairOpenAICodexAuthConfig(config, { profileIdMap: aliases.profileIdMap });
	return {
		config: repaired.config,
		changes: [...repaired.changes, ...imported.configChanged ? ["Auth profile SQLite migration updated auth.profiles."] : []],
		storeChanges: [...imported.changes, ...aliases.changes],
		warnings: [
			...imported.warnings,
			...aliases.warnings,
			...repaired.warnings
		],
		profileIdMap: aliases.profileIdMap
	};
}
//#endregion
export { collectOpenAICodexAuthProfileStoreIdMap as n, maybeRepairLegacyAuthProfileStores as r, repairAuthProfileMigration as t };