import { t as formatCliCommand } from "./command-format-CKGmlpAQ.js";
import { r as writeRuntimeJson } from "./runtime-B4lgFmsS.js";
import { n as promptYesNo } from "./prompt-DRobZewb.js";
import { i as getRuntimeConfig } from "./io-CHZy8A_F.js";
import "./config-CP7xGHZu.js";
import { r as withProgress } from "./progress-CN3xUiCO.js";
import { n as stylePromptMessage, r as stylePromptTitle, t as stylePromptHint } from "./prompt-style-BQVvtDcR.js";
import { g as redactMigrationPlan } from "./migration-CRXv-K-p.js";
import { r as resolvePluginMigrationProviders, t as ensureStandaloneMigrationProviderRegistryLoaded } from "./migration-provider-runtime-BliNz64E.js";
import { i as formatMigrationPreview } from "./output-CloVf0af.js";
import { C as resolveInteractiveMigrationPluginSelection, E as resolveMigrationProvider, S as reconcileInteractiveMigrationSkillToggleValues, T as createMigrationPlan, _ as getMigrationSkillSelectionValue, a as MIGRATION_SELECTION_TOGGLE_ALL_ON, b as reconcileInteractiveMigrationEnterValues, c as applyMigrationSelectedSkillItemIds, d as formatMigrationPluginSelectionLabel, f as formatMigrationSkillSelectionHint, g as getMigrationPluginSelectionValue, h as getDefaultMigrationSkillSelectionValues, i as MIGRATION_SELECTION_TOGGLE_ALL_OFF, l as applyMigrationSkillSelection, m as getDefaultMigrationPluginSelectionValues, n as runMigrationApply, o as applyMigrationPluginSelection, p as formatMigrationSkillSelectionLabel, r as MIGRATION_SELECTION_ACCEPT, s as applyMigrationSelectedPluginItemIds, u as formatMigrationPluginSelectionHint, v as getSelectableMigrationPluginItems, w as resolveInteractiveMigrationSkillSelection, x as reconcileInteractiveMigrationShortcutValues, y as getSelectableMigrationSkillItems } from "./apply-De2OwykW.js";
import { styleText } from "node:util";
import { S_BAR, S_BAR_END, S_CHECKBOX_ACTIVE, S_CHECKBOX_INACTIVE, S_CHECKBOX_SELECTED, cancel, confirm, isCancel, limitOptions, log, symbol, symbolBar } from "@clack/prompts";
import { MultiSelectPrompt, settings, wrapTextWithPrefix } from "@clack/core";
//#region src/commands/migrate/skill-selection-prompt.ts
/** Custom Clack multi-select prompt for Codex migration skill/plugin choices. */
function formatOption(option, state) {
	const label = option.label ?? option.value;
	const withHint = option.hint ? `${label} ${styleText("dim", `(${option.hint})`)}` : label;
	switch (state) {
		case "active": return `${styleText("cyan", S_CHECKBOX_ACTIVE)} ${withHint}`;
		case "active-selected": return `${styleText("green", S_CHECKBOX_SELECTED)} ${withHint}`;
		case "cancelled": return styleText(["strikethrough", "dim"], label);
		case "disabled": return `${styleText("gray", S_CHECKBOX_INACTIVE)} ${styleText(["strikethrough", "gray"], label)}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
		case "selected": return `${styleText("green", S_CHECKBOX_SELECTED)} ${styleText("dim", withHint)}`;
		case "submitted": return styleText("dim", label);
		case "inactive": return `${styleText("dim", S_CHECKBOX_INACTIVE)} ${styleText("dim", withHint)}`;
	}
	return withHint;
}
/** Prompts for migration selection values and reconciles all/none/recommended shortcuts. */
function promptMigrationSkillSelectionValues(opts) {
	const required = opts.required ?? true;
	const prompt = new MultiSelectPrompt({
		options: opts.options,
		signal: opts.signal,
		input: opts.input,
		output: opts.output,
		initialValues: opts.initialValues,
		required,
		cursorAt: opts.cursorAt,
		validate(value) {
			if (required && (value === void 0 || value.length === 0)) return "Please select at least one option.";
		},
		render() {
			const withGuide = opts.withGuide ?? settings.withGuide;
			const message = wrapTextWithPrefix(opts.output, opts.message, withGuide ? `${symbolBar(this.state)}  ` : "", `${symbol(this.state)}  `);
			const header = `${withGuide ? `${styleText("gray", S_BAR)}\n` : ""}${message}\n`;
			const value = this.value ?? [];
			const optionState = (option, active) => {
				if (option.disabled) return formatOption(option, "disabled");
				const selected = value.includes(option.value);
				if (active && selected) return formatOption(option, "active-selected");
				if (selected) return formatOption(option, "selected");
				return formatOption(option, active ? "active" : "inactive");
			};
			switch (this.state) {
				case "submit": {
					const label = this.options.filter((option) => value.includes(option.value)).map((option) => formatOption(option, "submitted")).join(styleText("dim", ", ")) || styleText("dim", "none");
					return `${header}${wrapTextWithPrefix(opts.output, label, withGuide ? `${styleText("gray", S_BAR)}  ` : "")}`;
				}
				case "cancel": {
					const selected = this.options.filter((option) => value.includes(option.value)).map((option) => formatOption(option, "cancelled")).join(styleText("dim", ", "));
					if (selected.trim() === "") return `${header}${styleText("gray", S_BAR)}`;
					return `${header}${wrapTextWithPrefix(opts.output, selected, withGuide ? `${styleText("gray", S_BAR)}  ` : "")}${withGuide ? `\n${styleText("gray", S_BAR)}` : ""}`;
				}
				case "error": {
					const prefix = withGuide ? `${styleText("yellow", S_BAR)}  ` : "";
					return `${header}${prefix}${limitOptions({
						output: opts.output,
						options: this.options,
						cursor: this.cursor,
						maxItems: opts.maxItems,
						columnPadding: prefix.length,
						rowPadding: header.split("\n").length + this.error.split("\n").length + 1,
						style: optionState
					}).join(`\n${prefix}`)}\n${this.error.split("\n").map((line, index) => index === 0 ? `${withGuide ? `${styleText("yellow", S_BAR_END)}  ` : ""}${styleText("yellow", line)}` : `   ${line}`).join("\n")}\n`;
				}
				default: {
					const prefix = withGuide ? `${styleText("cyan", S_BAR)}  ` : "";
					return `${header}${prefix}${limitOptions({
						output: opts.output,
						options: this.options,
						cursor: this.cursor,
						maxItems: opts.maxItems,
						columnPadding: prefix.length,
						rowPadding: header.split("\n").length + (withGuide ? 2 : 1),
						style: optionState
					}).join(`\n${prefix}`)}\n${withGuide ? styleText("cyan", S_BAR_END) : ""}\n`;
				}
			}
		}
	});
	let lastSelectedValues = [...prompt.value ?? []];
	let lastSpaceDeselectedValue;
	prompt.on("cursor", (key) => {
		if (key !== "space") {
			lastSpaceDeselectedValue = void 0;
			return;
		}
		const activatedValue = prompt.options[prompt.cursor]?.value;
		if (activatedValue === "__openclaw_migrate_accept_recommended__") {
			prompt.value = [...opts.initialValues ?? []];
			lastSpaceDeselectedValue = void 0;
			lastSelectedValues = [...prompt.value ?? []];
			return;
		}
		const previousValues = lastSelectedValues;
		prompt.value = reconcileInteractiveMigrationSkillToggleValues(prompt.value ?? [], activatedValue, opts.selectableValues);
		lastSpaceDeselectedValue = activatedValue !== void 0 && opts.selectableValues.includes(activatedValue) && previousValues.includes(activatedValue) && !(prompt.value ?? []).includes(activatedValue) ? activatedValue : void 0;
		lastSelectedValues = [...prompt.value ?? []];
	});
	prompt.on("key", (key, info) => {
		if (info.name === "return") {
			const activatedOption = prompt.options[prompt.cursor];
			const activatedValue = activatedOption?.disabled ? void 0 : activatedOption?.value;
			if (activatedValue === "__openclaw_migrate_accept_recommended__") {
				prompt.value = [...opts.initialValues ?? []];
				lastSpaceDeselectedValue = void 0;
				lastSelectedValues = [...prompt.value ?? []];
				return;
			}
			prompt.value = reconcileInteractiveMigrationEnterValues(prompt.value ?? [], activatedValue, opts.selectableValues, { preserveDeselectedActivatedValue: activatedValue !== void 0 && activatedValue === lastSpaceDeselectedValue && !(prompt.value ?? []).includes(activatedValue) });
			lastSpaceDeselectedValue = void 0;
			lastSelectedValues = [...prompt.value ?? []];
			return;
		}
		if (key !== "a" && key !== "i") return;
		prompt.value = reconcileInteractiveMigrationShortcutValues(lastSelectedValues, prompt.value ?? [], opts.selectableValues, key);
		lastSpaceDeselectedValue = void 0;
		lastSelectedValues = [...prompt.value ?? []];
	});
	return prompt.prompt();
}
//#endregion
//#region src/commands/migrate.ts
/** CLI command orchestration for migration list, plan, and apply flows. */
function selectMigrationItems(plan, opts) {
	return applyMigrationPluginSelection(applyMigrationSkillSelection(plan, opts.skills), opts.plugins);
}
function hasAuthCredentialCandidate(plan) {
	return plan.items.some((item) => item.kind === "auth" || item.kind === "secret" || item.sensitive === true);
}
function hasPlannedAuthCredentialItem(plan) {
	return plan.items.some((item) => item.status === "planned" && (item.kind === "auth" || item.kind === "secret" || item.sensitive === true));
}
function resolveDefaultIncludeSecrets(opts) {
	if (opts.authCredentials === false) return {
		...opts,
		includeSecrets: false
	};
	if (opts.includeSecrets !== void 0) return opts;
	return opts;
}
function shouldPromptForAuthCredentials(opts) {
	return opts.includeSecrets === void 0 && opts.authCredentials !== false && !opts.yes && !opts.json && process.stdin.isTTY;
}
async function createMigrationPlanWithProgress(runtime, opts) {
	const createPlan = async () => await createMigrationPlan(runtime, opts);
	if (opts.json) return selectMigrationItems(await createPlan(), opts);
	return selectMigrationItems(await withProgress({
		label: `Scanning ${opts.provider} migration…`,
		indeterminate: true
	}, async (progress) => {
		progress.setLabel("Reading migration source…");
		const planLocal = await createPlan();
		progress.tick();
		return planLocal;
	}), opts);
}
async function createInteractiveMigrationPlanWithAuthPrompt(runtime, opts) {
	if (!shouldPromptForAuthCredentials(opts)) return await migratePlanCommand(runtime, resolveDefaultIncludeSecrets(opts));
	const initialPlan = await migratePlanCommand(runtime, {
		...opts,
		includeSecrets: false,
		suppressPlanLog: true
	});
	if (!hasAuthCredentialCandidate(initialPlan)) {
		if (!opts.suppressPlanLog) log.message(formatMigrationPreview(initialPlan).join("\n"));
		return initialPlan;
	}
	const includeSecrets = await confirm({
		message: stylePromptMessage("Do you want to migrate your auth credentials as well?"),
		initialValue: true
	});
	if (isCancel(includeSecrets)) {
		cancel(stylePromptTitle("Migration cancelled.") ?? "Migration cancelled.");
		runtime.exit(0);
		throw new Error("unreachable");
	}
	const finalPlan = includeSecrets ? await migratePlanCommand(runtime, {
		...opts,
		includeSecrets: true,
		suppressPlanLog: true
	}) : initialPlan;
	if (!opts.suppressPlanLog) log.message(formatMigrationPreview(finalPlan).join("\n"));
	return finalPlan;
}
function assertVerifyPluginAppsProvider(providerId, opts) {
	if (opts.verifyPluginApps && providerId !== "codex") throw new Error("--verify-plugin-apps is only supported for Codex migrations.");
}
async function promptCodexMigrationSkillSelection(runtime, plan, opts) {
	if (plan.providerId !== "codex" || opts.yes || opts.json || opts.skills !== void 0 || !process.stdin.isTTY) return plan;
	const skillItems = getSelectableMigrationSkillItems(plan);
	if (skillItems.length === 0) return plan;
	const selected = await promptMigrationSkillSelectionValues({
		message: stylePromptMessage("Select Codex skills to migrate into this agent"),
		options: [
			{
				value: MIGRATION_SELECTION_ACCEPT,
				label: "Accept recommended",
				hint: "Migrate every recommended skill"
			},
			...skillItems.map((item) => {
				const hint = formatMigrationSkillSelectionHint(item);
				return {
					value: getMigrationSkillSelectionValue(item),
					label: formatMigrationSkillSelectionLabel(item),
					hint: hint === void 0 ? void 0 : stylePromptHint(hint)
				};
			}),
			{
				value: MIGRATION_SELECTION_TOGGLE_ALL_ON,
				label: "Toggle all on"
			},
			{
				value: MIGRATION_SELECTION_TOGGLE_ALL_OFF,
				label: "Toggle all off"
			}
		],
		initialValues: getDefaultMigrationSkillSelectionValues(skillItems),
		required: false,
		selectableValues: skillItems.map(getMigrationSkillSelectionValue),
		cursorAt: MIGRATION_SELECTION_ACCEPT
	});
	if (isCancel(selected)) {
		cancel(stylePromptTitle("Migration cancelled.") ?? "Migration cancelled.");
		runtime.log("Migration cancelled.");
		return null;
	}
	const selection = resolveInteractiveMigrationSkillSelection(skillItems, selected ?? []);
	const selectedPlan = applyMigrationSelectedSkillItemIds(plan, selection.selectedItemIds);
	runtime.log(`Selected ${selection.selectedItemIds.size} of ${skillItems.length} Codex skills for migration.`);
	return selectedPlan;
}
async function promptCodexMigrationPluginSelection(runtime, plan, opts) {
	if (plan.providerId !== "codex" || opts.yes || opts.json || opts.plugins !== void 0 || !process.stdin.isTTY) return plan;
	const pluginItems = getSelectableMigrationPluginItems(plan);
	if (pluginItems.length === 0) return plan;
	const selected = await promptMigrationSkillSelectionValues({
		message: stylePromptMessage("Select native Codex plugins to activate in this agent"),
		options: [
			{
				value: MIGRATION_SELECTION_ACCEPT,
				label: "Accept recommended",
				hint: "Migrate every recommended plugin"
			},
			...pluginItems.map((item) => {
				const hint = formatMigrationPluginSelectionHint(item);
				return {
					value: getMigrationPluginSelectionValue(item),
					label: formatMigrationPluginSelectionLabel(item),
					hint: hint === void 0 ? void 0 : stylePromptHint(hint)
				};
			}),
			{
				value: MIGRATION_SELECTION_TOGGLE_ALL_ON,
				label: "Toggle all on"
			},
			{
				value: MIGRATION_SELECTION_TOGGLE_ALL_OFF,
				label: "Toggle all off"
			}
		],
		initialValues: getDefaultMigrationPluginSelectionValues(pluginItems),
		required: false,
		selectableValues: pluginItems.map(getMigrationPluginSelectionValue),
		cursorAt: MIGRATION_SELECTION_ACCEPT
	});
	if (isCancel(selected)) {
		cancel(stylePromptTitle("Migration cancelled.") ?? "Migration cancelled.");
		runtime.log("Migration cancelled.");
		return null;
	}
	const selection = resolveInteractiveMigrationPluginSelection(pluginItems, selected ?? []);
	const selectedPlan = applyMigrationSelectedPluginItemIds(plan, selection.selectedItemIds);
	runtime.log(`Selected ${selection.selectedItemIds.size} of ${pluginItems.length} native Codex plugins for activation.`);
	return selectedPlan;
}
async function promptCodexMigrationSelections(runtime, plan, opts) {
	const skillSelectedPlan = await promptCodexMigrationSkillSelection(runtime, plan, opts);
	if (!skillSelectedPlan) return null;
	return await promptCodexMigrationPluginSelection(runtime, skillSelectedPlan, opts);
}
function hasSelectedCodexMigrationWork(plan) {
	return plan.items.some((item) => item.status === "planned" && (item.kind === "auth" || item.kind === "secret" || item.kind === "skill" && item.action === "copy" || item.kind === "plugin" && item.action === "install"));
}
function shouldSkipCodexApplyAfterInteractiveSelection(plan) {
	return plan.providerId === "codex" && !hasSelectedCodexMigrationWork(plan);
}
function hasCodexSubscriptionRequiredPlugin(plan) {
	if (plan.providerId !== "codex") return false;
	return plan.items.some((item) => item.reason === "codex_subscription_required");
}
function readCodexSubscriptionWarning(plan) {
	return plan.warnings?.find((warning) => warning.includes("Codex app-backed plugin migration requires"));
}
function logNoCodexSelection(runtime, plan) {
	if (hasCodexSubscriptionRequiredPlugin(plan)) {
		const warning = readCodexSubscriptionWarning(plan);
		if (warning) runtime.log(warning);
		runtime.log("No Codex skills selected; native Codex plugins are not eligible for migration in this run.");
		return;
	}
	runtime.log("No Codex skills or native Codex plugins selected for migration.");
}
/** Lists available migration providers as JSON or terse terminal rows. */
async function migrateListCommand(runtime, opts = {}) {
	const cfg = getRuntimeConfig();
	ensureStandaloneMigrationProviderRegistryLoaded({ cfg });
	const providers = resolvePluginMigrationProviders({ cfg }).map((provider) => ({
		id: provider.id,
		label: provider.label,
		description: provider.description
	}));
	if (opts.json) {
		writeRuntimeJson(runtime, { providers });
		return;
	}
	if (providers.length === 0) {
		runtime.log(`No migration providers found. Run ${formatCliCommand("openclaw plugins list")} to verify provider plugins are installed and enabled.`);
		return;
	}
	runtime.log(providers.map((provider) => provider.description ? `${provider.id}\t${provider.label} - ${provider.description}` : `${provider.id}\t${provider.label}`).join("\n"));
}
/** Creates and prints a migration plan without applying it. */
async function migratePlanCommand(runtime, opts) {
	const providerId = opts.provider?.trim();
	if (!providerId) throw new Error(`Migration provider is required. Run ${formatCliCommand("openclaw migrate list")} to choose one.`);
	const resolvedOpts = resolveDefaultIncludeSecrets(opts);
	assertVerifyPluginAppsProvider(providerId, resolvedOpts);
	const plan = await createMigrationPlanWithProgress(runtime, {
		...resolvedOpts,
		provider: providerId
	});
	if (resolvedOpts.json) writeRuntimeJson(runtime, redactMigrationPlan(plan));
	else if (resolvedOpts.suppressPlanLog !== true) log.message(formatMigrationPreview(plan).join("\n"));
	return plan;
}
async function migrateApplyCommand(runtime, opts) {
	const providerId = opts.provider?.trim();
	if (!providerId) throw new Error(`Migration provider is required. Run ${formatCliCommand("openclaw migrate list")} to choose one.`);
	assertVerifyPluginAppsProvider(providerId, opts);
	if (opts.noBackup && !opts.force) throw new Error("--no-backup requires --force because it skips the automatic rollback copy.");
	if (!opts.yes && !process.stdin.isTTY) throw new Error(`openclaw migrate apply requires --yes in non-interactive mode. Preview first with ${formatCliCommand("openclaw migrate plan --provider <provider>")}.`);
	const provider = resolveMigrationProvider(providerId, opts.configOverride);
	if (!opts.yes) {
		const plan = await createInteractiveMigrationPlanWithAuthPrompt(runtime, {
			...opts,
			provider: providerId,
			json: opts.json
		});
		if (opts.json) return plan;
		const selectedPlan = await promptCodexMigrationSelections(runtime, plan, opts);
		if (!selectedPlan) return plan;
		if (shouldSkipCodexApplyAfterInteractiveSelection(selectedPlan)) {
			logNoCodexSelection(runtime, selectedPlan);
			return selectedPlan;
		}
		if (!await promptYesNo("Apply this migration now?", false)) {
			runtime.log("Migration cancelled.");
			return selectedPlan;
		}
		return await runMigrationApply({
			runtime,
			opts: {
				...opts,
				provider: providerId,
				yes: true,
				includeSecrets: opts.includeSecrets ?? hasPlannedAuthCredentialItem(selectedPlan),
				preflightPlan: selectedPlan
			},
			providerId,
			provider
		});
	}
	return await runMigrationApply({
		runtime,
		opts: resolveDefaultIncludeSecrets(opts),
		providerId,
		provider
	});
}
/** Default migrate command: list providers, plan, dry-run, or apply based on flags. */
async function migrateDefaultCommand(runtime, opts) {
	const providerId = opts.provider?.trim();
	if (!providerId) {
		await migrateListCommand(runtime, { json: opts.json });
		return {
			providerId: "list",
			source: "",
			summary: {
				total: 0,
				planned: 0,
				migrated: 0,
				skipped: 0,
				conflicts: 0,
				errors: 0,
				sensitive: 0
			},
			items: []
		};
	}
	assertVerifyPluginAppsProvider(providerId, opts);
	const resolvedOpts = resolveDefaultIncludeSecrets(opts);
	const plan = opts.json && opts.yes && !opts.dryRun ? selectMigrationItems(await createMigrationPlan(runtime, {
		...resolvedOpts,
		provider: providerId
	}), resolvedOpts) : !opts.yes && process.stdin.isTTY ? await createInteractiveMigrationPlanWithAuthPrompt(runtime, {
		...opts,
		provider: providerId,
		json: opts.json && (opts.dryRun || !opts.yes)
	}) : await migratePlanCommand(runtime, {
		...resolvedOpts,
		provider: providerId,
		json: opts.json && (opts.dryRun || !opts.yes)
	});
	if (opts.dryRun) return plan;
	if (opts.json && !opts.yes) return plan;
	if (!opts.yes) {
		if (!process.stdin.isTTY) {
			runtime.log("Re-run with --yes to apply this migration non-interactively.");
			return plan;
		}
		const selectedPlan = await promptCodexMigrationSelections(runtime, plan, opts);
		if (!selectedPlan) return plan;
		if (shouldSkipCodexApplyAfterInteractiveSelection(selectedPlan)) {
			logNoCodexSelection(runtime, selectedPlan);
			return selectedPlan;
		}
		if (!await promptYesNo("Apply this migration now?", false)) {
			runtime.log("Migration cancelled.");
			return selectedPlan;
		}
		return await migrateApplyCommand(runtime, {
			...opts,
			provider: providerId,
			yes: true,
			includeSecrets: opts.includeSecrets ?? hasPlannedAuthCredentialItem(selectedPlan),
			json: opts.json,
			preflightPlan: selectedPlan
		});
	}
	return await migrateApplyCommand(runtime, {
		...resolvedOpts,
		provider: providerId,
		yes: true,
		json: opts.json,
		preflightPlan: plan
	});
}
//#endregion
export { migratePlanCommand as i, migrateDefaultCommand as n, migrateListCommand as r, migrateApplyCommand as t };
