"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolvePackInfo = resolvePackInfo;
exports.skillList = skillList;
exports.skillInfo = skillInfo;
exports.skillRemove = skillRemove;
exports.skillAdd = skillAdd;
exports.skillInit = skillInit;
exports.findPackageRoot = findPackageRoot;
exports.resolveSource = resolveSource;
// packages/cli/src/commands/skill.ts
const fs_1 = require("fs");
const path_1 = require("path");
const child_process_1 = require("child_process");
const os_1 = require("os");
const gray_matter_1 = __importDefault(require("gray-matter"));
const js_yaml_1 = __importDefault(require("js-yaml"));
// ── Pack Resolution ──
function resolvePackInfo(packName, projectPath) {
    // 1. Try built-in pack at {packageRoot}/skills/{packName}/
    const builtInDir = (0, path_1.join)(findPackageRoot(), 'skills', packName);
    const builtInPackYaml = (0, path_1.join)(builtInDir, 'pack.yaml');
    if ((0, fs_1.existsSync)(builtInPackYaml)) {
        return readPackInfo(builtInDir, builtInPackYaml);
    }
    // 2. Try installed pack.yaml at .claude/skills/{packName}/pack.yaml
    const installedPackYaml = (0, path_1.join)(projectPath, '.claude', 'skills', packName, 'pack.yaml');
    if ((0, fs_1.existsSync)(installedPackYaml)) {
        return readPackInfo((0, path_1.join)(projectPath, '.claude', 'skills', packName), installedPackYaml);
    }
    const skillsRoot = (0, path_1.join)(findPackageRoot(), 'skills');
    const available = (0, fs_1.readdirSync)(skillsRoot)
        .filter(d => (0, fs_1.existsSync)((0, path_1.join)(skillsRoot, d, 'pack.yaml')))
        .join(', ');
    throw new Error(`Pack "${packName}" not found. Available built-in packs: ${available}`);
}
function readPackInfo(packDir, packYamlPath) {
    let packData;
    try {
        packData = js_yaml_1.default.load((0, fs_1.readFileSync)(packYamlPath, 'utf-8'));
    }
    catch (err) {
        throw new Error(`Invalid pack.yaml at ${packYamlPath}: ${err.message}`);
    }
    const skillNames = packData.skills ?? [];
    const bundledNames = packData.bundled ?? [];
    // Read workflows from pack's workflows/ directory
    const workflows = {};
    const workflowsDir = (0, path_1.join)(packDir, 'workflows');
    if ((0, fs_1.existsSync)(workflowsDir)) {
        for (const file of (0, fs_1.readdirSync)(workflowsDir).filter(f => f.endsWith('.yaml'))) {
            workflows[file] = (0, fs_1.readFileSync)((0, path_1.join)(workflowsDir, file), 'utf-8');
        }
    }
    return { skillNames, bundledNames, workflows };
}
// ── List ──
function skillList(projectPath) {
    const skillsDir = (0, path_1.join)(projectPath, '.claude', 'skills');
    if (!(0, fs_1.existsSync)(skillsDir))
        return [];
    const linkedMap = scanLinkedCommands(projectPath);
    const entries = (0, fs_1.readdirSync)(skillsDir);
    const results = [];
    for (const entry of entries) {
        const skillDir = (0, path_1.join)(skillsDir, entry);
        const skillFile = (0, path_1.join)(skillDir, 'SKILL.md');
        if (!(0, fs_1.statSync)(skillDir).isDirectory() || !(0, fs_1.existsSync)(skillFile))
            continue;
        const { data } = (0, gray_matter_1.default)((0, fs_1.readFileSync)(skillFile, 'utf-8'));
        const fileCount = countFiles(skillDir);
        results.push({
            name: data.name ?? entry,
            description: data.description ?? '',
            fileCount,
            linkedCommand: linkedMap.get(entry),
        });
    }
    return results;
}
// ── Info ──
function skillInfo(name, projectPath) {
    if (name.includes('..') || name.includes('/') || name.includes('\\')) {
        throw new Error(`Invalid skill name: "${name}" — path traversal blocked`);
    }
    const skillDir = (0, path_1.join)(projectPath, '.claude', 'skills', name);
    const skillFile = (0, path_1.join)(skillDir, 'SKILL.md');
    if (!(0, fs_1.existsSync)(skillFile)) {
        throw new Error(`Skill not found: "${name}"`);
    }
    const { data } = (0, gray_matter_1.default)((0, fs_1.readFileSync)(skillFile, 'utf-8'));
    const files = listFilesRecursive(skillDir, '');
    const linkedCommands = findLinkedCommands(name, projectPath);
    return {
        name: data.name ?? name,
        description: data.description ?? '',
        version: data.version,
        author: data.author,
        files,
        linkedCommands,
    };
}
// ── Remove ──
function skillRemove(name, projectPath) {
    if (name.includes('..') || name.includes('/') || name.includes('\\')) {
        throw new Error(`Invalid skill name: "${name}" — path traversal blocked`);
    }
    const skillDir = (0, path_1.join)(projectPath, '.claude', 'skills', name);
    if (!(0, fs_1.existsSync)(skillDir)) {
        throw new Error(`Skill not found: "${name}"`);
    }
    const warnings = findLinkedCommands(name, projectPath);
    (0, fs_1.rmSync)(skillDir, { recursive: true, force: true });
    return { removed: name, warnings };
}
// ── Add ──
function skillAdd(source, projectPath, options) {
    const skillsDir = (0, path_1.join)(projectPath, '.claude', 'skills');
    (0, fs_1.mkdirSync)(skillsDir, { recursive: true });
    const resolvedSource = resolveSource(source);
    const detected = detectSkillType(resolvedSource);
    const result = { added: [], skipped: [] };
    if (detected.type === 'single') {
        const name = getSkillName(resolvedSource);
        installSkill(resolvedSource, name, skillsDir, options, result);
    }
    else {
        for (const subdir of detected.skills) {
            if (options.only && !options.only.includes(subdir))
                continue;
            const subPath = (0, path_1.join)(resolvedSource, subdir);
            installSkill(subPath, subdir, skillsDir, options, result);
        }
    }
    // Clean up temp dir if we cloned from git
    if (resolvedSource !== (0, path_1.resolve)(source) && resolvedSource.startsWith((0, os_1.tmpdir)())) {
        (0, fs_1.rmSync)(resolvedSource, { recursive: true, force: true });
    }
    return result;
}
// ── Init (scaffold) ──
function skillInit(packName, projectPath, skillNames, options) {
    const commandsDir = (0, path_1.join)(projectPath, '.vsaf', 'commands');
    const workflowsDir = (0, path_1.join)(projectPath, '.vsaf', 'workflows', packName);
    (0, fs_1.mkdirSync)(commandsDir, { recursive: true });
    const result = { commandsCreated: [], commandsSkipped: [], workflowsCreated: [] };
    // Scaffold commands
    for (const name of skillNames) {
        const cmdFile = (0, path_1.join)(commandsDir, `${name}.md`);
        if ((0, fs_1.existsSync)(cmdFile)) {
            result.commandsSkipped.push(name);
            continue;
        }
        const skillDir = (0, path_1.join)(projectPath, '.claude', 'skills', name);
        const skillFile = (0, path_1.join)(skillDir, 'SKILL.md');
        let description = name;
        if ((0, fs_1.existsSync)(skillFile)) {
            const { data } = (0, gray_matter_1.default)((0, fs_1.readFileSync)(skillFile, 'utf-8'));
            description = data.description ?? name;
        }
        const content = `---\ndescription: ${description}\nskill: ${name}\n---\n\n## Project context\n<!-- Add your project-specific context here -->\n`;
        (0, fs_1.writeFileSync)(cmdFile, content, 'utf-8');
        result.commandsCreated.push(name);
    }
    // Scaffold workflows
    if (options?.workflows && Object.keys(options.workflows).length > 0) {
        (0, fs_1.mkdirSync)(workflowsDir, { recursive: true });
        for (const [filename, yamlContent] of Object.entries(options.workflows)) {
            const wfFile = (0, path_1.join)(workflowsDir, filename);
            if (!(0, fs_1.existsSync)(wfFile)) {
                (0, fs_1.writeFileSync)(wfFile, yamlContent, 'utf-8');
                result.workflowsCreated.push(`${packName}/${filename}`);
            }
        }
    }
    return result;
}
// ── Internal helpers ──
function findPackageRoot() {
    // Navigate up from packages/cli/src/commands/ to monorepo root
    return (0, path_1.resolve)(__dirname, '..', '..', '..', '..');
}
function resolveSource(source) {
    if (source.startsWith('http://') || source.startsWith('https://') || source.startsWith('git@')) {
        const tempDir = (0, path_1.join)((0, os_1.tmpdir)(), `vsaf-clone-${Date.now()}`);
        (0, child_process_1.execFileSync)('git', ['clone', '--depth', '1', source, tempDir], { stdio: 'pipe' });
        return tempDir;
    }
    // Check if source is a built-in pack name (no path separators, not a relative/absolute path)
    if (!source.includes('/') && !source.includes('\\') && !source.startsWith('.')) {
        const builtInPath = (0, path_1.join)(findPackageRoot(), 'skills', source);
        if ((0, fs_1.existsSync)(builtInPath)) {
            return builtInPath;
        }
    }
    return (0, path_1.resolve)(source);
}
function detectSkillType(dir) {
    if ((0, fs_1.existsSync)((0, path_1.join)(dir, 'SKILL.md'))) {
        return { type: 'single' };
    }
    const skills = [];
    for (const entry of (0, fs_1.readdirSync)(dir)) {
        const full = (0, path_1.join)(dir, entry);
        if ((0, fs_1.statSync)(full).isDirectory() && (0, fs_1.existsSync)((0, path_1.join)(full, 'SKILL.md'))) {
            skills.push(entry);
        }
    }
    if (skills.length === 0) {
        throw new Error(`No valid skill found at ${dir}. Expected SKILL.md or subdirectories with SKILL.md.`);
    }
    return { type: 'pack', skills };
}
function getSkillName(skillDir) {
    const skillFile = (0, path_1.join)(skillDir, 'SKILL.md');
    const { data } = (0, gray_matter_1.default)((0, fs_1.readFileSync)(skillFile, 'utf-8'));
    return data.name ?? (0, path_1.basename)(skillDir);
}
function installSkill(sourceDir, name, skillsDir, options, result) {
    const targetDir = (0, path_1.join)(skillsDir, name);
    if ((0, fs_1.existsSync)(targetDir)) {
        if (options.force) {
            (0, fs_1.rmSync)(targetDir, { recursive: true, force: true });
        }
        else {
            result.skipped.push(name);
            return;
        }
    }
    (0, fs_1.cpSync)(sourceDir, targetDir, { recursive: true });
    result.added.push(name);
}
function scanLinkedCommands(projectPath) {
    const commandsDir = (0, path_1.join)(projectPath, '.vsaf', 'commands');
    const map = new Map();
    if (!(0, fs_1.existsSync)(commandsDir))
        return map;
    for (const file of (0, fs_1.readdirSync)(commandsDir).filter(f => f.endsWith('.md'))) {
        const raw = (0, fs_1.readFileSync)((0, path_1.join)(commandsDir, file), 'utf-8');
        const { data } = (0, gray_matter_1.default)(raw);
        if (data.skill) {
            map.set(data.skill, `commands/${file}`);
        }
    }
    return map;
}
function findLinkedCommands(skillName, projectPath) {
    const commandsDir = (0, path_1.join)(projectPath, '.vsaf', 'commands');
    if (!(0, fs_1.existsSync)(commandsDir))
        return [];
    const linked = [];
    for (const file of (0, fs_1.readdirSync)(commandsDir).filter(f => f.endsWith('.md'))) {
        const raw = (0, fs_1.readFileSync)((0, path_1.join)(commandsDir, file), 'utf-8');
        const { data } = (0, gray_matter_1.default)(raw);
        if (data.skill === skillName) {
            linked.push(`commands/${file}`);
        }
    }
    return linked;
}
function countFiles(dir) {
    let count = 0;
    for (const entry of (0, fs_1.readdirSync)(dir)) {
        const full = (0, path_1.join)(dir, entry);
        if ((0, fs_1.statSync)(full).isDirectory()) {
            count += countFiles(full);
        }
        else {
            count++;
        }
    }
    return count;
}
function listFilesRecursive(dir, prefix) {
    const files = [];
    for (const entry of (0, fs_1.readdirSync)(dir)) {
        const full = (0, path_1.join)(dir, entry);
        const relative = prefix ? `${prefix}/${entry}` : entry;
        if ((0, fs_1.statSync)(full).isDirectory()) {
            files.push(...listFilesRecursive(full, relative));
        }
        else {
            files.push(relative);
        }
    }
    return files;
}
//# sourceMappingURL=skill.js.map