/**
 * NERF Skill Telemetry — Track which skills are loaded per unit (#599)
 *
 * Captures skill names at dispatch time for inclusion in UnitMetrics.
 * Distinguishes between "available" skills (in system prompt) and
 * "actively loaded" skills (read via tool calls during execution).
 *
 * Data flow:
 *   1. At dispatch, captureAvailableSkills() records skills from the system prompt
 *   2. During execution, recordSkillRead() tracks explicit SKILL.md reads
 *   3. At unit completion, getAndClearSkills() returns the loaded list for metrics
 */
import { existsSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";
// ─── In-memory state ──────────────────────────────────────────────────────────
/** Skills available in the system prompt for the current unit */
let availableSkills = [];
/** Skills explicitly read (SKILL.md loaded) during the current unit */
const activelyLoadedSkills = new Set();
// ─── Public API ───────────────────────────────────────────────────────────────
/**
 * Capture the list of available skill names at dispatch time.
 * Called before each unit starts.
 */
export function captureAvailableSkills() {
    const skillsDir = join(homedir(), ".agents", "skills");
    const legacyDir = join(homedir(), ".nerf", "agent", "skills");
    const names = listSkillNames(skillsDir);
    // Include skills still in the legacy directory only if migration hasn't completed
    const legacyMigrated = existsSync(join(legacyDir, ".migrated-to-agents"));
    const legacyNames = legacyMigrated ? [] : listSkillNames(legacyDir);
    const all = new Set([...names, ...legacyNames]);
    availableSkills = [...all];
    activelyLoadedSkills.clear();
}
/**
 * Record that a skill was actively loaded (its SKILL.md was read).
 * Call this when the agent reads a SKILL.md file.
 */
export function recordSkillRead(skillName) {
    activelyLoadedSkills.add(skillName);
}
/**
 * Get the skill names for the current unit and clear state.
 * Returns actively loaded skills if any, otherwise available skills.
 * This gives the most useful signal: if the agent read specific skills,
 * report those; otherwise report what was available.
 */
export function getAndClearSkills() {
    const result = activelyLoadedSkills.size > 0
        ? Array.from(activelyLoadedSkills)
        : [...availableSkills];
    availableSkills = [];
    activelyLoadedSkills.clear();
    return result;
}
/**
 * Reset all telemetry state. Called when auto-mode stops.
 */
export function resetSkillTelemetry() {
    availableSkills = [];
    activelyLoadedSkills.clear();
}
/**
 * Get last-used timestamps for all skills from metrics data.
 * Returns a Map from skill name to most recent ms timestamp.
 */
export function getSkillLastUsed(units) {
    const lastUsed = new Map();
    for (const u of units) {
        if (!u.skills)
            continue;
        for (const skill of u.skills) {
            const existing = lastUsed.get(skill) ?? 0;
            if (u.finishedAt > existing) {
                lastUsed.set(skill, u.finishedAt);
            }
        }
    }
    return lastUsed;
}
/**
 * Detect stale skills — those not used within the given threshold (in days).
 * Returns skill names that should be deprioritized.
 */
export function detectStaleSkills(units, thresholdDays) {
    if (thresholdDays <= 0)
        return [];
    const lastUsed = getSkillLastUsed(units);
    const cutoff = Date.now() - (thresholdDays * 24 * 60 * 60 * 1000);
    const stale = [];
    // Check all installed skills, not just those with usage data
    const skillsDir = join(homedir(), ".agents", "skills");
    const legacyDir = join(homedir(), ".nerf", "agent", "skills");
    const legacyMigrated = existsSync(join(legacyDir, ".migrated-to-agents"));
    const legacyNames = legacyMigrated ? [] : listSkillNames(legacyDir);
    const installedSet = new Set([...listSkillNames(skillsDir), ...legacyNames]);
    const installed = [...installedSet];
    for (const skill of installed) {
        const lastTs = lastUsed.get(skill);
        if (lastTs === undefined || lastTs < cutoff) {
            stale.push(skill);
        }
    }
    return stale;
}
// ─── Internals ────────────────────────────────────────────────────────────────
function listSkillNames(skillsDir) {
    if (!existsSync(skillsDir))
        return [];
    try {
        return readdirSync(skillsDir, { withFileTypes: true })
            .filter(d => d.isDirectory() && !d.name.startsWith("."))
            .filter(d => existsSync(join(skillsDir, d.name, "SKILL.md")))
            .map(d => d.name);
    }
    catch {
        return [];
    }
}
