import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js";
import { i as CONFIG_DIR } from "./agent-paths-BySKyq9I.js";
import { F as createSubsystemLogger, Ml as openVerifiedFileSync } from "./agent-scope-CLn_Ws3B.js";
import { _ as parseFrontmatter, c as resolveBundledSkillsDir, f as isBundledSkillAllowed, g as resolveSkillSource, h as resolveSkillConfig, i as loadWorkspaceSkillEntries, m as resolveBundledAllowlist, p as isConfigPathTruthy, t as resolveSkillsInstallPreferences, v as resolveSkillInvocationPolicy } from "./skills-D1Qdj69-.js";
import { r as hasBinary } from "./config-eval-CuVkTCse.js";
import { t as resolveBrewExecutable } from "./brew-C52GeCeh.js";
import { t as evaluateEntryRequirementsForCurrentPlatform } from "./entry-status-6TakHgsQ.js";
import fs from "node:fs";
import path from "node:path";

//#region src/agents/skills-install-plan.ts
const SAFE_BREW_FORMULA_RE = /^[A-Za-z0-9][A-Za-z0-9._@/+:-]*$/u;
const SAFE_NODE_PACKAGE_RE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:@[A-Za-z0-9._~^*:+-]+)?$/u;
const SAFE_TOOL_PACKAGE_RE = /^[A-Za-z0-9][A-Za-z0-9._@/:+~-]*$/u;
function quoteCommandPart(part) {
	if (/^[A-Za-z0-9_./:@%+=,-]+$/u.test(part)) return part;
	return JSON.stringify(part);
}
function formatCommand(argv) {
	if (!argv || argv.length === 0) return "handled internally";
	return argv.map(quoteCommandPart).join(" ");
}
function buildNodeInstallCommand(packageName, prefs) {
	switch (prefs.nodeManager) {
		case "pnpm": return [
			"pnpm",
			"add",
			"-g",
			"--ignore-scripts",
			packageName
		];
		case "yarn": return [
			"yarn",
			"global",
			"add",
			"--ignore-scripts",
			packageName
		];
		case "bun": return [
			"bun",
			"add",
			"-g",
			"--ignore-scripts",
			packageName
		];
		default: return [
			"npm",
			"install",
			"-g",
			"--ignore-scripts",
			packageName
		];
	}
}
function buildSkillInstallCommand(spec, prefs) {
	switch (spec.kind) {
		case "brew":
			if (!spec.formula) return {
				argv: null,
				error: "missing brew formula"
			};
			if (!SAFE_BREW_FORMULA_RE.test(spec.formula)) return {
				argv: null,
				error: "unsafe brew formula"
			};
			return { argv: [
				"brew",
				"install",
				spec.formula
			] };
		case "node":
			if (!spec.package) return {
				argv: null,
				error: "missing node package"
			};
			if (!SAFE_NODE_PACKAGE_RE.test(spec.package)) return {
				argv: null,
				error: "unsafe node package"
			};
			return { argv: buildNodeInstallCommand(spec.package, prefs) };
		case "go":
			if (!spec.module) return {
				argv: null,
				error: "missing go module"
			};
			if (!SAFE_TOOL_PACKAGE_RE.test(spec.module)) return {
				argv: null,
				error: "unsafe go module"
			};
			return { argv: [
				"go",
				"install",
				spec.module
			] };
		case "uv":
			if (!spec.package) return {
				argv: null,
				error: "missing uv package"
			};
			if (!SAFE_TOOL_PACKAGE_RE.test(spec.package)) return {
				argv: null,
				error: "unsafe uv package"
			};
			return { argv: [
				"uv",
				"tool",
				"install",
				spec.package
			] };
		case "download": return {
			argv: null,
			error: void 0
		};
	}
}
function candidateSkillBinPaths(bin) {
	const home = process.env.HOME?.trim();
	const npmPrefixes = [process.env.NPM_CONFIG_PREFIX?.trim(), process.env.npm_config_prefix?.trim()].filter((prefix) => Boolean(prefix));
	const candidates = [
		process.env.GOBIN ? path.join(process.env.GOBIN, bin) : "",
		home ? path.join(home, "go", "bin", bin) : "",
		home ? path.join(home, ".local", "bin", bin) : "",
		home ? path.join(home, ".npm-global", "bin", bin) : "",
		...npmPrefixes.map((prefix) => path.join(prefix, "bin", bin)),
		"/home/linuxbrew/.linuxbrew/bin",
		"/opt/homebrew/bin",
		"/usr/local/bin"
	].filter(Boolean).map((candidate) => candidate.endsWith(bin) ? candidate : path.join(candidate, bin));
	return Array.from(new Set(candidates));
}
function findSkillBinaryOutsidePath(bin) {
	for (const candidate of candidateSkillBinPaths(bin)) try {
		if (fs.existsSync(candidate)) return candidate;
	} catch {}
}
function packageRefForInstallSpec(spec) {
	switch (spec.kind) {
		case "brew": return spec.formula ?? "";
		case "go": return spec.module ?? "";
		case "node":
		case "uv": return spec.package ?? "";
		case "download": return spec.url ?? "";
	}
}
function managerForInstallSpec(spec, prefs) {
	switch (spec.kind) {
		case "node": return prefs.nodeManager;
		case "brew": return "brew";
		case "go": return "go";
		case "uv": return "uv";
		case "download": return "download";
	}
}
function resolveToolchain(spec, argv) {
	if (spec.kind === "download") return { available: true };
	if (spec.kind === "brew") {
		if (hasBinary("brew") || resolveBrewExecutable()) return { available: true };
		return {
			available: false,
			message: process.platform === "linux" ? "Homebrew/Linuxbrew is not installed. Use a Linux package manager manually or install Homebrew first." : "Homebrew is not installed."
		};
	}
	const executable = argv?.[0]?.trim();
	if (!executable) return {
		available: false,
		message: "Installer command is not available."
	};
	if (hasBinary(executable)) return { available: true };
	if (spec.kind === "node") return {
		available: false,
		message: `${executable} is not installed or is not visible to the gateway PATH.`
	};
	if (spec.kind === "go") return {
		available: false,
		message: "go is not installed or is not visible to the gateway PATH."
	};
	if (spec.kind === "uv") return {
		available: false,
		message: "uv is not installed or is not visible to the gateway PATH."
	};
	return {
		available: false,
		message: `${executable} is not visible to the gateway PATH.`
	};
}
function resolveSkillInstallPlan(spec, prefs) {
	const command = buildSkillInstallCommand(spec, prefs);
	const bins = (spec.bins ?? []).map((bin) => ({
		bin,
		available: hasBinary(bin),
		outsidePath: findSkillBinaryOutsidePath(bin),
		pathTargets: candidateSkillBinPaths(bin)
	}));
	const pathTargets = Array.from(new Set(bins.flatMap((entry) => entry.pathTargets)));
	const toolchain = command.error ? {
		available: false,
		message: command.error
	} : resolveToolchain(spec, command.argv);
	return {
		manager: managerForInstallSpec(spec, prefs),
		packageRef: packageRefForInstallSpec(spec),
		command: command.argv,
		commandPreview: spec.kind === "download" && spec.url ? `download and verify ${spec.url}` : formatCommand(command.argv),
		toolchainAvailable: toolchain.available,
		toolchainMessage: toolchain.message,
		pathTargets,
		bins
	};
}

//#endregion
//#region src/agents/skills-install-trust.ts
const EXACT_VERSION_RE = /^v?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/u;
const UV_EXACT_PIN_RE = /^[A-Za-z0-9_.-]+==[A-Za-z0-9][A-Za-z0-9._!+~-]*$/u;
function trim(value) {
	return value?.trim() ?? "";
}
function hasIntegrity(spec) {
	return Boolean(trim(spec.integrity) || trim(spec.sha256) || trim(spec.shasum));
}
function extractNodeVersion(spec) {
	const value = spec.trim();
	if (!value) return "";
	if (value.startsWith("@")) {
		const slashIndex = value.indexOf("/");
		if (slashIndex < 0) return "";
		const versionIndex = value.indexOf("@", slashIndex + 1);
		return versionIndex >= 0 ? value.slice(versionIndex + 1).trim() : "";
	}
	const versionIndex = value.lastIndexOf("@");
	return versionIndex > 0 ? value.slice(versionIndex + 1).trim() : "";
}
function isNodePinned(spec) {
	return EXACT_VERSION_RE.test(extractNodeVersion(spec));
}
function isGoPinned(moduleSpec) {
	const value = moduleSpec.trim();
	const versionIndex = value.lastIndexOf("@");
	if (versionIndex < 0) return false;
	return EXACT_VERSION_RE.test(value.slice(versionIndex + 1).trim());
}
function isUvPinned(packageSpec) {
	return UV_EXACT_PIN_RE.test(packageSpec.trim());
}
function summarizeSkillInstallTrust(spec) {
	const integrityPinned = hasIntegrity(spec);
	let pinned = false;
	const warnings = [];
	switch (spec.kind) {
		case "node":
			pinned = isNodePinned(trim(spec.package));
			warnings.push("external package manager install: review the npm package source before running");
			break;
		case "go":
			pinned = isGoPinned(trim(spec.module));
			warnings.push("external package manager install: review the Go module source before running");
			break;
		case "uv":
			pinned = isUvPinned(trim(spec.package));
			warnings.push("external package manager install: review the Python package source before running");
			break;
		case "brew":
			pinned = false;
			warnings.push("external package manager install: review the Homebrew formula before running");
			break;
		case "download":
			pinned = integrityPinned;
			warnings.push("external download install: review the archive source before running");
			break;
	}
	if (!pinned) warnings.push("package version is not pinned to an exact immutable version");
	if (!integrityPinned) warnings.push("source integrity is not pinned with integrity, sha256, or shasum metadata");
	return {
		external: true,
		pinned,
		integrityPinned,
		warnings
	};
}

//#endregion
//#region src/agents/skills/skill-contract.ts
function createSyntheticSourceInfo(path, options) {
	return {
		path,
		source: options.source,
		scope: options.scope ?? "temporary",
		origin: options.origin ?? "top-level",
		baseDir: options.baseDir
	};
}

//#endregion
//#region src/agents/skills/local-loader.ts
function isPathWithinRoot(rootRealPath, candidatePath) {
	const relative = path.relative(rootRealPath, candidatePath);
	return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
}
function readSkillFileSync(params) {
	const opened = openVerifiedFileSync({
		filePath: params.filePath,
		rejectPathSymlink: true,
		maxBytes: params.maxBytes
	});
	if (!opened.ok) return null;
	try {
		if (!isPathWithinRoot(params.rootRealPath, opened.path)) return null;
		return fs.readFileSync(opened.fd, "utf8");
	} finally {
		fs.closeSync(opened.fd);
	}
}
function loadSingleSkillDirectory(params) {
	const skillFilePath = path.join(params.skillDir, "SKILL.md");
	const raw = readSkillFileSync({
		rootRealPath: params.rootRealPath,
		filePath: skillFilePath,
		maxBytes: params.maxBytes
	});
	if (!raw) return null;
	let frontmatter;
	try {
		frontmatter = parseFrontmatter(raw);
	} catch {
		return null;
	}
	const fallbackName = path.basename(params.skillDir).trim();
	const name = frontmatter.name?.trim() || fallbackName;
	const description = frontmatter.description?.trim();
	if (!name || !description) return null;
	const invocation = resolveSkillInvocationPolicy(frontmatter);
	const filePath = path.resolve(skillFilePath);
	const baseDir = path.resolve(params.skillDir);
	return {
		name,
		description,
		filePath,
		baseDir,
		source: params.source,
		sourceInfo: createSyntheticSourceInfo(filePath, {
			source: params.source,
			baseDir,
			scope: "project",
			origin: "top-level"
		}),
		disableModelInvocation: invocation.disableModelInvocation
	};
}
function listCandidateSkillDirs(dir) {
	try {
		return fs.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules").map((entry) => path.join(dir, entry.name)).sort((left, right) => left.localeCompare(right));
	} catch {
		return [];
	}
}
function loadSkillsFromDirSafe(params) {
	const rootDir = path.resolve(params.dir);
	let rootRealPath;
	try {
		rootRealPath = fs.realpathSync(rootDir);
	} catch {
		return { skills: [] };
	}
	const rootSkill = loadSingleSkillDirectory({
		skillDir: rootDir,
		source: params.source,
		rootRealPath,
		maxBytes: params.maxBytes
	});
	if (rootSkill) return { skills: [rootSkill] };
	return { skills: listCandidateSkillDirs(rootDir).map((skillDir) => loadSingleSkillDirectory({
		skillDir,
		source: params.source,
		rootRealPath,
		maxBytes: params.maxBytes
	})).filter((skill) => skill !== null) };
}

//#endregion
//#region src/agents/skills/bundled-context.ts
const skillsLogger = createSubsystemLogger("skills");
let hasWarnedMissingBundledDir = false;
let cachedBundledContext = null;
function resolveBundledSkillsContext(opts = {}) {
	const dir = resolveBundledSkillsDir(opts);
	const names = /* @__PURE__ */ new Set();
	if (!dir) {
		if (!hasWarnedMissingBundledDir) {
			hasWarnedMissingBundledDir = true;
			skillsLogger.warn("Bundled skills directory could not be resolved; built-in skills may be missing.");
		}
		return {
			dir,
			names
		};
	}
	if (cachedBundledContext?.dir === dir) return {
		dir,
		names: new Set(cachedBundledContext.names)
	};
	const result = loadSkillsFromDirSafe({
		dir,
		source: "fased-bundled"
	});
	for (const skill of result.skills) if (skill.name.trim()) names.add(skill.name);
	cachedBundledContext = {
		dir,
		names: new Set(names)
	};
	return {
		dir,
		names
	};
}

//#endregion
//#region src/agents/skills-status.ts
var skills_status_exports = /* @__PURE__ */ __exportAll({ buildWorkspaceSkillStatus: () => buildWorkspaceSkillStatus });
function resolveSkillKey(entry) {
	return entry.metadata?.skillKey ?? entry.skill.name;
}
function selectPreferredInstallSpec(install, prefs) {
	if (install.length === 0) return;
	const indexed = install.map((spec, index) => ({
		spec,
		index
	}));
	const findKind = (kind) => indexed.find((item) => item.spec.kind === kind);
	const brewSpec = findKind("brew");
	const nodeSpec = findKind("node");
	const goSpec = findKind("go");
	const uvSpec = findKind("uv");
	const downloadSpec = findKind("download");
	const brewAvailable = hasBinary("brew");
	const pickers = [
		() => prefs.preferBrew && brewAvailable ? brewSpec : void 0,
		() => uvSpec,
		() => nodeSpec,
		() => brewAvailable ? brewSpec : void 0,
		() => goSpec,
		() => downloadSpec,
		() => brewSpec,
		() => indexed[0]
	];
	for (const pick of pickers) {
		const selected = pick();
		if (selected) return selected;
	}
}
function normalizeInstallOptions(entry, prefs) {
	const requiredOs = entry.metadata?.os ?? [];
	if (requiredOs.length > 0 && !requiredOs.includes(process.platform)) return [];
	const install = entry.metadata?.install ?? [];
	if (install.length === 0) return [];
	const platform = process.platform;
	const filtered = install.filter((spec) => {
		const osList = spec.os ?? [];
		return osList.length === 0 || osList.includes(platform);
	});
	if (filtered.length === 0) return [];
	const toOption = (spec, index) => {
		const id = (spec.id ?? `${spec.kind}-${index}`).trim();
		const bins = spec.bins ?? [];
		let label = (spec.label ?? "").trim();
		if (spec.kind === "node" && spec.package) label = `Install ${spec.package} (${prefs.nodeManager})`;
		if (!label) if (spec.kind === "brew" && spec.formula) label = `Install ${spec.formula} (brew)`;
		else if (spec.kind === "node" && spec.package) label = `Install ${spec.package} (${prefs.nodeManager})`;
		else if (spec.kind === "go" && spec.module) label = `Install ${spec.module} (go)`;
		else if (spec.kind === "uv" && spec.package) label = `Install ${spec.package} (uv)`;
		else if (spec.kind === "download" && spec.url) {
			const url = spec.url.trim();
			const last = url.split("/").pop();
			label = `Download ${last && last.length > 0 ? last : url}`;
		} else label = "Run installer";
		const trust = summarizeSkillInstallTrust(spec);
		return {
			id,
			kind: spec.kind,
			label,
			bins,
			external: trust.external,
			pinned: trust.pinned,
			integrityPinned: trust.integrityPinned,
			trustWarnings: trust.warnings,
			plan: resolveSkillInstallPlan(spec, prefs)
		};
	};
	if (filtered.every((spec) => spec.kind === "download")) return filtered.map((spec, index) => toOption(spec, index));
	const preferred = selectPreferredInstallSpec(filtered, prefs);
	if (!preferred) return [];
	return [toOption(preferred.spec, preferred.index)];
}
function readSkillMarketplaceStatus(skillDir) {
	const candidates = [path.join(skillDir, ".clawhub", "origin.json"), path.join(skillDir, ".clawdhub", "origin.json")];
	for (const candidate of candidates) try {
		const raw = JSON.parse(fs.readFileSync(candidate, "utf8"));
		if (raw.version !== 1 || typeof raw.registry !== "string" || typeof raw.slug !== "string" || typeof raw.installedVersion !== "string" || typeof raw.installedAt !== "number") continue;
		const permissions = raw.permissions && typeof raw.permissions === "object" && !Array.isArray(raw.permissions) ? raw.permissions : void 0;
		const walletActions = permissions?.walletActions && typeof permissions.walletActions === "object" && !Array.isArray(permissions.walletActions) ? permissions.walletActions : void 0;
		const install = permissions?.install && typeof permissions.install === "object" && !Array.isArray(permissions.install) ? permissions.install : void 0;
		const installScan = raw.installScan && typeof raw.installScan === "object" && !Array.isArray(raw.installScan) ? raw.installScan : void 0;
		const findings = Array.isArray(installScan?.findings) ? installScan.findings : [];
		const scanWarnings = findings.filter((finding) => finding && typeof finding === "object" && finding.severity === "warn").length;
		const scanBlocks = findings.filter((finding) => finding && typeof finding === "object" && finding.severity === "block").length;
		const lastUpdateReview = raw.lastUpdateReview && typeof raw.lastUpdateReview === "object" && !Array.isArray(raw.lastUpdateReview) ? raw.lastUpdateReview : void 0;
		return {
			source: "clawhub",
			registry: raw.registry,
			slug: raw.slug,
			installedVersion: raw.installedVersion,
			installedAt: raw.installedAt,
			requestedRisky: permissions?.risky === true,
			requestedWalletActions: Boolean(walletActions),
			requestedToolAccess: Array.isArray(permissions?.toolAccess) ? permissions.toolAccess.filter((item) => typeof item === "string") : [],
			requestedInstallKinds: Array.isArray(install?.kinds) ? install.kinds.filter((item) => typeof item === "string") : [],
			scanBlocked: installScan?.blocked === true,
			scanWarnings,
			scanBlocks,
			updateApprovalRequired: lastUpdateReview?.approvalRequired === true,
			updateReviewReasons: Array.isArray(lastUpdateReview?.reasons) ? lastUpdateReview.reasons.filter((item) => typeof item === "string") : []
		};
	} catch {}
}
function buildSkillStatus(entry, config, prefs, eligibility, bundledNames) {
	const skillKey = resolveSkillKey(entry);
	const skillConfig = resolveSkillConfig(config, skillKey);
	const disabled = skillConfig?.enabled === false;
	const blockedByAllowlist = !isBundledSkillAllowed(entry, resolveBundledAllowlist(config));
	const always = entry.metadata?.always === true;
	const isEnvSatisfied = (envName) => Boolean(process.env[envName] || skillConfig?.env?.[envName] || skillConfig?.apiKey && entry.metadata?.primaryEnv === envName);
	const isConfigSatisfied = (pathStr) => isConfigPathTruthy(config, pathStr);
	const skillSource = resolveSkillSource(entry.skill);
	const bundled = skillSource === "fased-bundled" || skillSource === "unknown" && bundledNames?.has(entry.skill.name) === true;
	const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } = evaluateEntryRequirementsForCurrentPlatform({
		always,
		entry,
		hasLocalBin: hasBinary,
		remote: eligibility?.remote,
		isEnvSatisfied,
		isConfigSatisfied
	});
	const eligible = !disabled && !blockedByAllowlist && requirementsSatisfied;
	return {
		name: entry.skill.name,
		description: entry.skill.description,
		source: skillSource,
		bundled,
		filePath: entry.skill.filePath,
		baseDir: entry.skill.baseDir,
		skillKey,
		primaryEnv: entry.metadata?.primaryEnv,
		emoji,
		homepage,
		always,
		disabled,
		blockedByAllowlist,
		eligible,
		requirements: required,
		missing,
		configChecks,
		configFields: entry.metadata?.configFields ?? [],
		install: normalizeInstallOptions(entry, prefs ?? resolveSkillsInstallPreferences(config)),
		marketplace: readSkillMarketplaceStatus(entry.skill.baseDir)
	};
}
function buildWorkspaceSkillStatus(workspaceDir, opts) {
	const managedSkillsDir = opts?.managedSkillsDir ?? path.join(CONFIG_DIR, "skills");
	const bundledContext = resolveBundledSkillsContext();
	const skillEntries = opts?.entries ?? loadWorkspaceSkillEntries(workspaceDir, {
		config: opts?.config,
		managedSkillsDir,
		bundledSkillsDir: bundledContext.dir
	});
	const prefs = resolveSkillsInstallPreferences(opts?.config);
	return {
		workspaceDir,
		managedSkillsDir,
		skills: skillEntries.map((entry) => buildSkillStatus(entry, opts?.config, prefs, opts?.eligibility, bundledContext.names))
	};
}

//#endregion
export { skills_status_exports as n, summarizeSkillInstallTrust as r, buildWorkspaceSkillStatus as t };