import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
import { resolveStateDir } from "../../config/paths-state.js";
import { init_paths } from "../../config/paths.js";
import { parseFrontmatter } from "../../markdown/frontmatter.js";
import { findInstallSpec, getDefaultInstallerPreferences, hasBinary, init_installer, installSkill } from "./installer.js";
import { applySkillEnvOverrides, createSkillConfigManager, getSkillEnvironment, isSkillEnabled, resolveSkillConfig, validateSkillConfig } from "./config.js";
import { parseSkillToolConditions } from "./skill-tool-gating.js";
import { parseRequiredEnvVarNames } from "./required-env-vars.js";
import { parseSkillMetadata } from "./parse-skill-metadata.js";
import { collectSkillInstallWarnings, formatScanSummary, scanSkillDirectory } from "./scanner.js";
import { formatSkillsForPrompt } from "./format-skills-prompt.js";
import { SkillTestFramework, SkillTestRunner, formatTestResults, formatTestResultsJson, formatTestResultsTap } from "./test-framework.js";
import { basename, dirname, join, relative, sep } from "path";
import { existsSync, readFileSync, readdirSync } from "fs";
//#region src/agent/skills/index.ts
init_paths();
init_logger();
init_installer();
const log = createLogger("SkillLoader");
const IGNORE_FILES = [
	".gitignore",
	".ignore",
	".fdignore"
];
function toPosixPath(p) {
	return p.split(sep).join("/");
}
function prefixIgnorePattern(line, prefix) {
	const trimmed = line.trim();
	if (!trimmed) return null;
	if (trimmed.startsWith("#") && !trimmed.startsWith("\\#")) return null;
	let pattern = line;
	let negated = false;
	if (pattern.startsWith("!")) {
		negated = true;
		pattern = pattern.slice(1);
	} else if (pattern.startsWith("\\!")) pattern = pattern.slice(1);
	if (pattern.startsWith("/")) pattern = pattern.slice(1);
	const prefixed = prefix ? `${prefix}${pattern}` : pattern;
	return negated ? `!${prefixed}` : prefixed;
}
function loadIgnoreRules(dir, rootDir) {
	const ignoredPaths = /* @__PURE__ */ new Set();
	const relativeDir = relative(rootDir, dir);
	const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : "";
	for (const filename of IGNORE_FILES) {
		const ignorePath = join(dir, filename);
		if (!existsSync(ignorePath)) continue;
		try {
			const content = readFileSync(ignorePath, "utf-8");
			for (const line of content.split(/\r?\n/)) {
				const pattern = prefixIgnorePattern(line, prefix);
				if (pattern) {
					const fullPattern = pattern.startsWith("!") ? `!${prefix}${pattern.slice(1)}` : `${prefix}${pattern}`;
					ignoredPaths.add(fullPattern);
				}
			}
		} catch {}
	}
	return ignoredPaths;
}
function shouldIgnore(path, ignoredPaths) {
	for (const pattern of ignoredPaths) if (pattern.startsWith("!")) {
		const positive = pattern.slice(1);
		if (path === positive || path.startsWith(`${positive}/`)) return false;
	} else if (path === pattern || path.startsWith(`${pattern}/`)) return true;
	return false;
}
function discoverSkills(dir, source) {
	const skills = [];
	if (!existsSync(dir)) return skills;
	function scan(currentDir, currentIgnoredPaths) {
		try {
			const entries = readdirSync(currentDir, { withFileTypes: true });
			for (const entry of entries) {
				if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
				const fullPath = join(currentDir, entry.name);
				const relPath = toPosixPath(relative(dir, fullPath));
				if (shouldIgnore(relPath, currentIgnoredPaths)) continue;
				if (entry.isDirectory()) {
					const skillMdPath = join(fullPath, "SKILL.md");
					const skillRelPath = `${relPath}/`;
					const subIgnoredPaths = new Set(currentIgnoredPaths);
					if (existsSync(join(fullPath, ".gitignore"))) {
						const subRules = loadIgnoreRules(fullPath, dir);
						for (const rule of subRules) subIgnoredPaths.add(`${skillRelPath}${rule}`);
					}
					if (existsSync(skillMdPath) && !shouldIgnore(skillRelPath, currentIgnoredPaths)) {
						const skill = loadSkillFromFile(skillMdPath, source, dir);
						if (skill) skills.push(skill);
					}
					scan(fullPath, subIgnoredPaths);
				}
			}
		} catch {}
	}
	scan(dir, loadIgnoreRules(dir, dir));
	return skills;
}
function loadSkillFromFile(filePath, source, rootDir) {
	try {
		const { frontmatter, content } = parseFrontmatter(readFileSync(filePath, "utf-8"));
		const skillDir = dirname(filePath);
		const parentDirName = basename(skillDir);
		const name = frontmatter.name || parentDirName;
		const description = frontmatter.description;
		if (!description?.trim()) return null;
		let category;
		if (rootDir) {
			const segments = toPosixPath(relative(rootDir, skillDir)).split("/");
			if (segments.length > 1) category = segments[0];
		}
		const metadata = parseSkillMetadata(frontmatter);
		const toolConditions = parseSkillToolConditions(frontmatter);
		const requiredEnvVarNames = parseRequiredEnvVarNames(frontmatter);
		return {
			name,
			description: description.trim(),
			category,
			filePath,
			baseDir: skillDir,
			source,
			disableModelInvocation: frontmatter["disable-model-invocation"] === true,
			metadata,
			toolConditions,
			requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : void 0,
			content
		};
	} catch {
		return null;
	}
}
function loadSkills(options) {
	const { workspaceDir, builtinDir, extraDirs = [] } = options;
	const skillMap = /* @__PURE__ */ new Map();
	const diagnostics = [];
	if (builtinDir) for (const skill of discoverSkills(builtinDir, "builtin")) {
		const existing = skillMap.get(skill.name);
		if (existing) diagnostics.push({
			type: "collision",
			skillName: skill.name,
			message: `Skill "${skill.name}" collision: ${existing.source} overrides ${skill.source}`,
			path: skill.filePath
		});
		else skillMap.set(skill.name, skill);
	}
	const globalDirs = [options.globalDir, join(resolveStateDir(), "skills")].filter((d) => !!d && existsSync(d));
	for (const dir of globalDirs) for (const skill of discoverSkills(dir, "global")) {
		const existing = skillMap.get(skill.name);
		if (existing) diagnostics.push({
			type: "collision",
			skillName: skill.name,
			message: `Skill "${skill.name}" collision: ${skill.source} overrides ${existing.source}`,
			path: skill.filePath
		});
		skillMap.set(skill.name, skill);
	}
	if (workspaceDir) {
		const workspaceSkills = discoverSkills(join(workspaceDir, "skills"), "workspace");
		for (const skill of workspaceSkills) {
			const existing = skillMap.get(skill.name);
			if (existing) diagnostics.push({
				type: "collision",
				skillName: skill.name,
				message: `Skill "${skill.name}" collision: ${skill.source} overrides ${existing.source}`,
				path: skill.filePath
			});
			skillMap.set(skill.name, skill);
		}
	}
	for (const extraDir of extraDirs) if (existsSync(extraDir)) for (const skill of discoverSkills(extraDir, "global")) {
		const existing = skillMap.get(skill.name);
		if (existing) diagnostics.push({
			type: "collision",
			skillName: skill.name,
			message: `Skill "${skill.name}" collision: ${existing.source} overrides ${skill.source}`,
			path: skill.filePath
		});
		else skillMap.set(skill.name, skill);
	}
	const skillsConfig = createSkillConfigManager(resolveStateDir()).load();
	const merged = Array.from(skillMap.values());
	return {
		skills: merged,
		prompt: formatSkillsForPrompt(merged, skillsConfig),
		diagnostics
	};
}
function createSkillLoader() {
	let cachedSkills = [];
	let cachedPrompt = "";
	let cachedDiagnostics = [];
	let lastLoadTime = 0;
	let workspaceDir;
	let builtinDir;
	let extraDirs = [];
	function updateCache(result) {
		cachedSkills = result.skills;
		cachedPrompt = result.prompt;
		cachedDiagnostics = result.diagnostics;
		lastLoadTime = Date.now();
		return result;
	}
	return {
		init: (workspace, builtin) => {
			workspaceDir = workspace;
			builtinDir = builtin || void 0;
			return updateCache(loadSkills({
				workspaceDir,
				builtinDir,
				extraDirs
			}));
		},
		load: () => {
			return updateCache(loadSkills({
				workspaceDir,
				builtinDir,
				extraDirs
			}));
		},
		reload: () => {
			log.info("Reloading skills");
			return updateCache(loadSkills({
				workspaceDir,
				builtinDir,
				extraDirs
			}));
		},
		refreshPromptFromConfig: () => {
			const skillsConfig = createSkillConfigManager(resolveStateDir()).load();
			cachedPrompt = formatSkillsForPrompt(cachedSkills, skillsConfig);
			lastLoadTime = Date.now();
		},
		getSkills: () => cachedSkills,
		getPrompt: () => cachedPrompt,
		getDiagnostics: () => cachedDiagnostics,
		getLastLoadTime: () => lastLoadTime,
		getSkillByName: (name) => {
			return cachedSkills.find((s) => s.name === name);
		},
		getEnabledSkills: (entries) => {
			const skillsConfig = entries !== void 0 ? { entries } : createSkillConfigManager(resolveStateDir()).load();
			return cachedSkills.filter((skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig));
		}
	};
}
//#endregion
export { SkillTestFramework, SkillTestRunner, applySkillEnvOverrides, collectSkillInstallWarnings, createSkillConfigManager, createSkillLoader, findInstallSpec, formatScanSummary, formatTestResults, formatTestResultsJson, formatTestResultsTap, getDefaultInstallerPreferences, getSkillEnvironment, hasBinary, installSkill, isSkillEnabled, loadSkills, resolveSkillConfig, scanSkillDirectory, validateSkillConfig };

//# sourceMappingURL=index.js.map