export const skillNamePattern = /^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/u;
const skillDirNamePattern = /^[a-z0-9][a-z0-9_-]{1,63}$/u;
export function isRecord(value) {
    return typeof value === "object" && value !== null && !Array.isArray(value);
}
export function stringValue(value) {
    return typeof value === "string" ? value.trim() : undefined;
}
export function booleanValue(value) {
    return typeof value === "boolean" ? value : undefined;
}
export function integerValue(value) {
    return typeof value === "number" && Number.isInteger(value) ? value : undefined;
}
export function stringArrayValue(value) {
    if (!Array.isArray(value))
        return undefined;
    const values = [];
    for (const item of value) {
        if (typeof item !== "string")
            return undefined;
        const trimmed = item.trim();
        if (trimmed.length > 0)
            values.push(trimmed);
    }
    return [...new Set(values)];
}
export function dryRunEnabled(context) {
    return context?.dryRun !== false;
}
export function normalizeRoot(root) {
    const trimmed = root.trim();
    return trimmed === "/" ? trimmed : trimmed.replace(/\/+$/u, "");
}
export function unsafePath(value) {
    return value.includes("\0") || value.split("/").some((segment) => segment === "..");
}
export function joinPath(root, ...segments) {
    return [normalizeRoot(root), ...segments.map((segment) => segment.replace(/^\/+|\/+$/gu, ""))]
        .filter((segment) => segment.length > 0)
        .join("/");
}
export function relativeSkillPath(path) {
    return path.length > 0 && !path.startsWith("/") && !unsafePath(path);
}
export function isSafeSkillName(skillId) {
    return skillNamePattern.test(skillId) && !unsafePath(skillId);
}
export function isSafeSkillDirectoryName(skillName) {
    return skillDirNamePattern.test(skillName) && !unsafePath(skillName);
}
export function isInsideAllowedRoots(targetPath, allowedRoots) {
    if (allowedRoots === undefined || allowedRoots.length === 0)
        return true;
    const target = normalizeRoot(targetPath);
    return allowedRoots.map(normalizeRoot).some((root) => target === root || target.startsWith(`${root}/`));
}
export function isAllowedSkillId(skillId, allowedSkillIds) {
    return skillId === undefined || allowedSkillIds === undefined || allowedSkillIds.includes(skillId);
}
export function affirmativeGuard(context) {
    return context?.guard?.accepted === true || context?.guard?.allowed === true;
}
export function createAuditEvent(toolId, type, context, targetRef, metadata) {
    return {
        type,
        toolId,
        invocationId: context?.invocationId ?? `${toolId}:dry-run`,
        dryRun: dryRunEnabled(context),
        targetRef,
        metadata: {
            ...(context?.auditMetadata ?? {}),
            ...(metadata ?? {}),
        },
    };
}
export function failure(toolId, code, message, boundary, context, targetRef) {
    return {
        ok: false,
        toolId,
        error: {
            code,
            message,
            boundary,
            publicSafe: true,
            safeForRuntimeInspection: true,
            internalDetailExposed: false,
        },
        audit: [createAuditEvent(toolId, `agentCore.basicTool.${toolId}.rejected`, context, targetRef, { code })],
        events: [`basicTool.${toolId}.rejected`],
    };
}
export function ensureRealExecutionAllowed(toolId, context, targetRef) {
    if (dryRunEnabled(context))
        return undefined;
    if (!affirmativeGuard(context)) {
        return failure(toolId, "GOVERNANCE_REJECTED", context?.guard?.reason ?? `${toolId} real execution requires an affirmative runtime guard`, "governance", context, targetRef);
    }
    return undefined;
}
export function ensurePermissions(toolId, required, context, targetRef) {
    if (dryRunEnabled(context))
        return undefined;
    const granted = context?.grantedPermissions ?? [];
    const missing = required.filter((permission) => !granted.includes(permission));
    if (missing.length === 0)
        return undefined;
    return failure(toolId, "PERMISSION_DENIED", `${toolId} is missing permissions: ${missing.join(", ")}`, "permission", context, targetRef);
}
export function parseSkillFrontmatter(content, fallbackName) {
    const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/u);
    const metadata = {};
    let name = fallbackName;
    let description = "";
    if (match !== null) {
        for (const line of match[1].split(/\r?\n/u)) {
            const field = line.match(/^([A-Za-z0-9_.:-]+):\s*(.*)$/u);
            if (field === null)
                continue;
            const key = field[1];
            const value = field[2].replace(/^["']|["']$/gu, "").trim();
            metadata[key] = value;
            if (key === "name" && value.length > 0)
                name = value;
            if (key === "description" && value.length > 0)
                description = value;
        }
    }
    if (description.length === 0) {
        const heading = content.match(/^#\s+(.+)$/mu)?.[1]?.trim();
        description = heading ?? "Skill instructions";
    }
    return { name, description, metadata };
}
export async function listSkillResources(provider, skillRoot, maxEntries = 200) {
    if (provider?.list === undefined) {
        return { root: skillRoot, entries: [], truncated: false };
    }
    const result = await provider.list({
        path: skillRoot,
        maxEntries,
        depth: 4,
        includeGlobs: ["SKILL.md", "scripts/**", "references/**", "assets/**", "examples/**"],
        excludeGlobs: ["node_modules/**", ".git/**"],
    });
    return {
        root: skillRoot,
        entries: result.entries.slice(0, maxEntries),
        truncated: result.entries.length > maxEntries,
    };
}
export function buildSkillMarkdown(name, description, purpose, tags) {
    const tagLine = tags.length > 0 ? `\ntags: ${tags.join(", ")}` : "";
    return `---\nname: ${name}\ndescription: ${description || purpose}${tagLine}\n---\n\n# ${name}\n\n## Goal\n${purpose}\n\n## Steps\n- Follow this skill when the task matches the description.\n`;
}
export function sourcePreview(content, limit = 260) {
    return content.replace(/\s+/gu, " ").trim().slice(0, limit);
}
