import { r as ux } from "./cli-B86kvKcR.mjs";
import { a as loadAnvilManifest, i as getCatalogProviderDeclaration, s as parseInstallReference } from "./manifest-CslkSMd8.mjs";
import { l as resolveCatalogPathFromProvider, u as resolveCatalogProviderByKey } from "./catalog-BN_wLtPe.mjs";
import { a as resolvePluginsFromSource, r as installResolvedPlugins, t as createPluginLockEntryFromResolved } from "./plugins-DtsrBxYU.mjs";
import { a as applySyncPrunePlan, c as createEmptySyncReport, d as mergeSyncReports, f as prunePlanToUndeclaredSection, i as anvilSync, n as addUndeclaredSyncReportItems, o as collectSyncPrunePlan, p as writeProjectLockSnapshot, r as anvilGlobalSyncStandalone, s as collectUndeclaredDeployedSkillNames, t as addSyncReportItems } from "./sync-PxvZXhSt.mjs";
import { existsSync } from "node:fs";
import path from "node:path";
import process from "node:process";
import { defineCommand } from "citty";
import { readdir } from "node:fs/promises";
import pc from "picocolors";
//#region src/lib/sync-report.ts
const primaryKinds = [
	"blocks",
	"rules",
	"skills",
	"references",
	"commands",
	"plugins"
];
const allKinds = [...primaryKinds, "agents"];
const labels = {
	agents: "Agents",
	blocks: "Blocks",
	commands: "Commands",
	plugins: "Plugins",
	references: "References",
	rules: "Rules",
	skills: "Skills"
};
function formatSyncReport(report) {
	const lines = [pc.bold("Deployed"), ...formatSection(report.deployed, primaryKinds, true, pc.green)];
	if (hasItems(report.skipped)) lines.push("", pc.bold("Skipped"), ...formatSection(report.skipped, allKinds, false, pc.yellow));
	if (hasItems(report.undeclared)) lines.push("", pc.bold("Undeclared"), ...formatUndeclaredSection(report.undeclared, allKinds, pc.yellow));
	return lines.join("\n");
}
function formatUndeclaredSection(section, kinds, color) {
	const lines = [];
	for (const kind of kinds) {
		const itemsByLocation = section[kind];
		if (Object.keys(itemsByLocation).length === 0) continue;
		lines.push(`• ${pc.dim(labels[kind])}:`);
		for (const [location, items] of Object.entries(itemsByLocation)) lines.push(`  • ${pc.dim(location)}: ${items.length === 0 ? pc.dim("none") : formatItems(items, color)}`);
	}
	return lines;
}
function formatSection(section, kinds, includeEmpty, color) {
	const lines = [];
	for (const kind of kinds) {
		const items = section[kind];
		if (!includeEmpty && items.length === 0) continue;
		if (items.length === 0) {
			lines.push(`• ${pc.dim(labels[kind])}: ${pc.dim("none")}`);
			continue;
		}
		lines.push(`• ${pc.dim(labels[kind])}: ${formatItems(items, color)}`);
	}
	return lines;
}
function formatItems(items, color) {
	return items.map((item) => color(item)).join(pc.dim(", "));
}
function hasItems(section) {
	if (isUndeclaredSection(section)) return allKinds.some((kind) => Object.keys(section[kind]).length > 0);
	return allKinds.some((kind) => section[kind].length > 0);
}
function isUndeclaredSection(section) {
	return allKinds.every((kind) => {
		const value = section[kind];
		return !Array.isArray(value);
	});
}
//#endregion
//#region src/commands/sync.ts
const deployedHeadingRegex = /^Deployed\n?/;
async function runSyncCommand(options = {}) {
	try {
		ux.intro("Sync");
		if (options.prune) {
			const prunePlan = await collectSyncPrunePlan({
				cwd: process.cwd(),
				global: options.global ?? false
			});
			if (prunePlan.targets.length > 0) {
				const confirmed = await ux.confirm({
					initialValue: false,
					message: formatPruneConfirmationMessage(prunePlan)
				});
				if (ux.handleCancel(confirmed, "Prune cancelled.")) return;
				if (!confirmed) {
					ux.log.info("Prune cancelled.");
					return;
				}
				await ux.running("Pruning undeclared targets", async () => applySyncPrunePlan(prunePlan));
			}
		}
		const result = await ux.running(getSyncSpinnerLabel(options), async () => {
			if (options.global) {
				if (options.dryRun) throw new Error("Global dry-run is not supported yet.");
				return anvilGlobalSyncStandalone();
			}
			const loadedManifest = loadAnvilManifest(process.cwd());
			if (!loadedManifest) throw new Error("No anvil.yaml found.");
			if (options.dryRun) {
				const report = createEmptySyncReport();
				addSyncReportItems(report, "deployed", "plugins", Object.keys(loadedManifest.manifest.plugins ?? {}).map((skillRef) => resolveProviderBackedRef(loadedManifest, skillRef).item));
				addSyncReportItems(report, "deployed", "skills", Object.keys(loadedManifest.manifest.skills ?? {}).map((skillRef) => resolveProviderBackedRef(loadedManifest, skillRef).item));
				return { report };
			}
			const syncResult = await anvilSync(loadedManifest);
			const plugins = loadedManifest.manifest.plugins ?? {};
			const skills = loadedManifest.manifest.skills ?? {};
			const externalPlugins = {};
			const syncedPlugins = [];
			for (const [pluginRef, installValue] of Object.entries(plugins)) {
				const resolvedSource = resolvePluginSourceSpec(loadedManifest, pluginRef);
				if (!resolvedSource) continue;
				const resolved = await resolvePluginsFromSource(resolvedSource, { pluginNames: [resolveProviderBackedRef(loadedManifest, pluginRef).item] });
				try {
					const installedPlugins = await installResolvedPlugins(resolved, {
						cwd: loadedManifest.directory,
						global: false
					});
					syncedPlugins.push(...installedPlugins.map((plugin) => plugin.name));
					for (const plugin of resolved.plugins) externalPlugins[pluginRef] = createProjectExternalLockEntry(await createPluginLockEntryFromResolved(plugin, resolved, loadedManifest.directory, "project"));
				} finally {
					await resolved.cleanup?.();
				}
			}
			const declaredProjectSkills = new Set(Object.keys(skills).map((skillRef) => resolveProviderBackedRef(loadedManifest, skillRef).item));
			for (const skillName of await getBlockManagedSkillNames(loadedManifest.directory)) declaredProjectSkills.add(skillName);
			for (const skillName of await getProjectAuthoredSkillNames(loadedManifest.directory)) declaredProjectSkills.add(skillName);
			await writeProjectLockSnapshot(loadedManifest, {
				externalPlugins,
				externalSkills: {},
				stagedBlocks: syncResult.stagedBlocks
			});
			const report = mergeSyncReports(syncResult.report);
			addSyncReportItems(report, "deployed", "plugins", syncedPlugins);
			addUndeclaredSyncReportItems(report, "skills", await collectUndeclaredDeployedSkillNames({
				cwd: loadedManifest.directory,
				declaredSkillNames: [...declaredProjectSkills],
				global: false
			}));
			return { report };
		});
		ux.log.success(options.global ? "Global sync complete." : "Project sync complete.");
		ux.note(formatSyncReport(result.report), "Sync Report", { format: (line) => line });
		ux.outro();
		return result;
	} catch (error) {
		ux.handleError(error);
		return;
	}
}
function getSyncSpinnerLabel(options) {
	if (options.global) return options.dryRun ? "Planning global sync" : "Syncing global";
	return options.dryRun ? "Planning project sync" : "Syncing project";
}
function createProjectExternalLockEntry(entry) {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	return {
		...entry,
		installedAt: now,
		updatedAt: now
	};
}
var sync_default = defineCommand({
	meta: {
		name: "sync",
		description: "Sync AI harness files and declared skills"
	},
	args: {
		dryRun: {
			alias: "d",
			type: "boolean",
			description: "Preview sync actions without writing files"
		},
		global: {
			alias: "g",
			type: "boolean",
			description: "Sync the standalone global Anvil manifest"
		},
		prune: {
			type: "boolean",
			description: "Remove undeclared tool-target content before syncing"
		}
	},
	async run({ args }) {
		await runSyncCommand({
			dryRun: args.dryRun,
			global: args.global,
			prune: args.prune
		});
		if (!process.exitCode) process.exit(0);
	}
});
function resolveProviderBackedRef(loadedManifest, rawRef) {
	const parsed = parseInstallReference(rawRef);
	if (parsed.provider) return parsed;
	const providerKey = loadedManifest.manifest.catalogs?.anvil ? "anvil" : Object.keys(loadedManifest.manifest.catalogs ?? {})[0];
	if (!providerKey) return parsed;
	return {
		...parsed,
		provider: providerKey,
		raw: `${providerKey}:${parsed.item}`
	};
}
function formatPruneConfirmationMessage(plan) {
	const report = createEmptySyncReport();
	report.undeclared = prunePlanToUndeclaredSection(plan);
	return [
		"Prune undeclared items before sync?",
		"",
		formatSyncReport(report).replace(deployedHeadingRegex, "").trim()
	].join("\n");
}
function resolvePluginSourceSpec(loadedManifest, rawRef) {
	const ref = resolveProviderBackedRef(loadedManifest, rawRef);
	if (!ref.provider) return null;
	const provider = resolveCatalogProviderByKey(loadedManifest, ref.provider);
	if (provider) {
		const pluginPath = resolveCatalogPathFromProvider(provider, path.join("plugins", ref.item, "content"));
		if (pluginPath) return `local:${pluginPath}`;
	}
	const providerDeclaration = getCatalogProviderDeclaration(loadedManifest, ref.provider);
	if (!providerDeclaration) throw new Error(`Unknown plugin provider: ${ref.provider}`);
	return typeof providerDeclaration === "string" ? providerDeclaration : providerDeclaration.source;
}
async function getBlockManagedSkillNames(cwd) {
	const skillsDir = path.join(cwd, ".anvil", "skills");
	if (!existsSync(skillsDir)) return [];
	return (await readdir(skillsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
}
async function getProjectAuthoredSkillNames(cwd) {
	const skillsDir = path.join(cwd, ".ai", "skills");
	if (!existsSync(skillsDir)) return [];
	return (await readdir(skillsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
}
//#endregion
export { sync_default as n, runSyncCommand as t };

//# sourceMappingURL=sync-X-wbEroJ.mjs.map