/**
 * NERF Skill Discovery
 *
 * Detects skills installed during auto-mode by comparing the current
 * skills directory against a snapshot taken at auto-mode start.
 *
 * New skills are injected into the system prompt via before_agent_start,
 * making them visible to all subsequent units without requiring a reload.
 */
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";
/** Industry-standard skills.sh global skills directory */
const SKILLS_DIR = join(homedir(), ".agents", "skills");
/** Snapshot of skill names at auto-mode start */
let baselineSkills = null;
/**
 * Snapshot the current skills directory. Call at auto-mode start.
 */
export function snapshotSkills() {
    baselineSkills = new Set(listSkillDirs());
}
/**
 * Clear the snapshot. Call when auto-mode stops.
 */
export function clearSkillSnapshot() {
    baselineSkills = null;
}
/**
 * Check if a snapshot is active (auto-mode is running with discovery).
 */
export function hasSkillSnapshot() {
    return baselineSkills !== null;
}
/**
 * Detect skills installed since the snapshot was taken.
 * Returns skill metadata for any new skills found.
 */
export function detectNewSkills() {
    if (!baselineSkills)
        return [];
    const current = listSkillDirs();
    const newSkills = [];
    for (const dir of current) {
        if (baselineSkills.has(dir))
            continue;
        const skillMdPath = join(SKILLS_DIR, dir, "SKILL.md");
        if (!existsSync(skillMdPath))
            continue;
        const meta = parseSkillFrontmatter(skillMdPath);
        if (meta) {
            newSkills.push({
                name: meta.name || dir,
                description: meta.description || `Skill: ${dir}`,
                location: skillMdPath,
            });
        }
    }
    return newSkills;
}
/**
 * Format discovered skills as an XML block matching pi's <available_skills> format.
 * This can be appended to the system prompt so the LLM sees them naturally.
 */
export function formatSkillsXml(skills) {
    if (skills.length === 0)
        return "";
    const entries = skills.map(s => `  <skill>
    <name>${escapeXml(s.name)}</name>
    <description>${escapeXml(s.description)}</description>
    <location>${escapeXml(s.location)}</location>
  </skill>`).join("\n");
    return `\n<newly_discovered_skills>
The following skills were installed during this auto-mode session.
Use the read tool to load a skill's file when the task matches its description.

${entries}
</newly_discovered_skills>`;
}
// ─── Internals ────────────────────────────────────────────────────────────────
function listSkillDirs() {
    if (!existsSync(SKILLS_DIR))
        return [];
    try {
        return readdirSync(SKILLS_DIR, { withFileTypes: true })
            .filter(d => d.isDirectory())
            .map(d => d.name);
    }
    catch {
        return [];
    }
}
function parseSkillFrontmatter(path) {
    try {
        const content = readFileSync(path, "utf-8");
        // Use indexOf instead of [\s\S]*? regex to avoid backtracking (#468)
        if (!content.startsWith('---\n'))
            return null;
        const endIdx = content.indexOf('\n---', 4);
        if (endIdx === -1)
            return null;
        const fm = content.slice(4, endIdx);
        const result = {};
        const nameMatch = fm.match(/^name:\s*(.+)$/m);
        if (nameMatch)
            result.name = nameMatch[1].trim();
        const descMatch = fm.match(/^description:\s*(.+)$/m);
        if (descMatch)
            result.description = descMatch[1].trim();
        return result;
    }
    catch {
        return null;
    }
}
function escapeXml(text) {
    return text
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
}
