// SPEC-597-EXEMPT: canonical mapping (npm-package↔framework, keyword catalogue)
// — must enumerate framework names by design; no detection logic to migrate.
// tools/skill-bootstrap-handler.ts — SPEC-439: Multi-Source Skill Auto-Bootstrap handlers
// SPEC-607: Adds project-aware skill generation via Agent Skills spec + multi-agent writer.
import { z } from 'zod';
import { getSkillBootstrapConfig, saveSkillBootstrapConfig, saveLastSkillBootstrapResult, } from '../storage/skill-bootstrap-store.js';
import { fetchAvailableTechs, fetchSkillContent, } from '../engine/skill-bootstrap/registry-fetcher.js';
import { detectProjectStack, matchTechsToAvailable, } from '../engine/skill-bootstrap/stack-matcher.js';
import { formatSkillsForTarget, writeSkillFile } from '../engine/skill-bootstrap/skill-writer.js';
import { formatAsAgentSkill } from '../engine/skill-generation/agent-skills-formatter.js';
import { generateSkillContent, listSupportedSkillTypes, } from '../engine/skill-generation/stack-content-generator.js';
import { writeSkillToAllAgents } from '../engine/skill-generation/multi-agent-writer.js';
// ---------------------------------------------------------------------------
// Zod schemas (exported for use in register file)
// ---------------------------------------------------------------------------
export const DiscoverSkillsInputSchema = {
    projectPath: z.string().describe('Absolute path to the project to detect the stack from'),
    stack: z
        .array(z.string())
        .optional()
        .describe('Override auto-detected stack with explicit tech names (e.g. ["nextjs", "tailwind"])'),
    sources: z
        .array(z
        .enum(['awesome-cursorrules', 'skills-sh', 'github-custom'])
        .describe('Registry source type. Values: awesome-cursorrules=PatrickJS GitHub repo, skills-sh=skills.sh registry, github-custom=custom GitHub repo'))
        .optional()
        .describe('Filter to specific registry sources only. Default: all enabled sources'),
};
export const BootstrapSkillsInputSchema = {
    projectPath: z.string().describe('Absolute path to the project where skills will be installed'),
    stack: z
        .array(z.string())
        .optional()
        .describe('Override auto-detected stack with explicit tech names'),
    targets: z
        .array(z
        .enum([
        'cursorrules',
        'windsurfrules',
        'claude-md',
        'kiro-steering',
        'agents-md',
        'clinerules',
    ])
        .describe('Target AI tool file. Values: cursorrules=Cursor, windsurfrules=Windsurf, claude-md=Claude Code, kiro-steering=Kiro, agents-md=AGENTS.md universal, clinerules=Cline'))
        .optional()
        .describe('Target files to write. Default: all configured targets'),
    dryRun: z
        .boolean()
        .optional()
        .default(false)
        .describe('If true, show what would be installed without writing any files'),
};
export const ConfigureSkillRegistriesInputSchema = {
    projectPath: z.string().describe('Absolute path to the project'),
    addSource: z
        .object({
        type: z.literal('github-custom'),
        name: z.string().describe('Display name for this source'),
        repo: z.string().describe('GitHub repo in owner/repo format'),
        subdir: z
            .string()
            .optional()
            .describe('Subdirectory inside the repo that contains tech folders. Default: rules'),
    })
        .optional()
        .describe('Add a custom GitHub registry source'),
    removeSource: z.string().optional().describe('Name of the source to remove'),
    enableSource: z.string().optional().describe('Name of the source to enable'),
    disableSource: z.string().optional().describe('Name of the source to disable'),
    setTargets: z
        .array(z
        .enum([
        'cursorrules',
        'windsurfrules',
        'claude-md',
        'kiro-steering',
        'agents-md',
        'clinerules',
    ])
        .describe('Target AI tool file. Values: cursorrules=Cursor, windsurfrules=Windsurf, claude-md=Claude Code, kiro-steering=Kiro, agents-md=AGENTS.md universal, clinerules=Cline'))
        .optional()
        .describe('Set the list of target files to write during bootstrap'),
    setAutoMerge: z
        .boolean()
        .optional()
        .describe('Set auto-merge mode. True=append to existing files, false=overwrite'),
};
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
async function discoverSkillsForSources(sources, detectedStack) {
    const skills = [];
    const skippedSources = [];
    for (const source of sources) {
        if (!source.enabled) {
            continue;
        }
        const availableTechs = await fetchAvailableTechs(source);
        if (availableTechs.length === 0 && source.type !== 'skills-sh') {
            skippedSources.push(source.name);
            continue;
        }
        const matched = matchTechsToAvailable(detectedStack, availableTechs);
        // For skills-sh, try directly with detected stack since no list available
        const techsToFetch = source.type === 'skills-sh' ? detectedStack : matched;
        for (const tech of techsToFetch) {
            const content = await fetchSkillContent(source, tech);
            if (content) {
                skills.push({
                    tech,
                    source: source.type,
                    sourceName: source.name,
                    content,
                    fetchedAt: new Date().toISOString(),
                    url: source.type === 'awesome-cursorrules'
                        ? `https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/master/rules/${tech}/.cursorrules`
                        : source.type === 'github-custom' && source.repo
                            ? `https://raw.githubusercontent.com/${source.repo}/HEAD/${source.subdir ?? 'rules'}/${tech}/.cursorrules`
                            : `https://registry.skills.sh/api/skills?q=${encodeURIComponent(tech)}`,
                });
            }
        }
    }
    return { skills, skippedSources };
}
// ---------------------------------------------------------------------------
// Handlers
// ---------------------------------------------------------------------------
export async function handleDiscoverSkillsFromRegistries(input) {
    const config = await getSkillBootstrapConfig(input.projectPath);
    const detectedStack = input.stack ?? (await detectProjectStack(input.projectPath));
    const sourcesToUse = input.sources
        ? config.sources.filter((s) => input.sources?.includes(s.type))
        : config.sources;
    const { skills, skippedSources } = await discoverSkillsForSources(sourcesToUse, detectedStack);
    const lines = [
        `Detected stack: ${detectedStack.length > 0 ? detectedStack.join(', ') : '(none)'}`,
        `Discovered ${skills.length} skill(s) across ${sourcesToUse.filter((s) => s.enabled).length} source(s).`,
    ];
    if (skippedSources.length > 0) {
        lines.push(`Skipped (unreachable): ${skippedSources.join(', ')}`);
    }
    if (skills.length > 0) {
        lines.push('');
        for (const skill of skills) {
            const preview = skill.content.slice(0, 100).replace(/\n/g, ' ');
            lines.push(`- [${skill.sourceName}] ${skill.tech}: ${preview}${skill.content.length > 100 ? '...' : ''}`);
        }
    }
    return {
        content: [{ type: 'text', text: lines.join('\n') }],
    };
}
// ---------------------------------------------------------------------------
// SPEC-607: Project-aware skill generation helpers
// ---------------------------------------------------------------------------
/** Generate and write project-specific skills using the Agent Skills spec. */
async function generateProjectSkills(projectPath, detectedStack) {
    const supportedTypes = listSupportedSkillTypes();
    const stackInfo = {
        frameworks: detectedStack,
        language: detectedStack.includes('typescript') ? 'typescript' : 'javascript',
        testRunner: detectedStack.find((t) => t === 'vitest' || t === 'jest' || t === 'pytest') ?? null,
        bundler: detectedStack.find((t) => t === 'vite' || t === 'webpack' || t === 'esbuild') ?? null,
    };
    const writtenPaths = [];
    for (const skillType of supportedTypes) {
        const generated = await generateSkillContent(skillType, stackInfo);
        const skillName = `project-${skillType}`;
        const metadata = {
            name: skillName,
            description: generated.title,
            version: '1.0.0',
            compatibility: ['claude-code', 'cursor', 'copilot', 'gemini'],
            allowedTools: generated.suggestedAllowedTools,
            triggers: generated.suggestedTriggers,
        };
        const skillContent = formatAsAgentSkill(metadata, generated.body);
        const written = await writeSkillToAllAgents(skillContent, metadata, projectPath);
        writtenPaths.push(...written.map((w) => w.path));
    }
    return writtenPaths;
}
export async function handleBootstrapSkills(input) {
    const config = await getSkillBootstrapConfig(input.projectPath);
    const detectedStack = input.stack ?? (await detectProjectStack(input.projectPath));
    const targets = input.targets ?? config.targets;
    const { skills, skippedSources } = await discoverSkillsForSources(config.sources, detectedStack);
    if (input.dryRun) {
        const lines = [
            `[Dry Run] Detected stack: ${detectedStack.join(', ')}`,
            `[Dry Run] Would install ${skills.length} skill(s) into ${targets.length} target file(s):`,
            ...targets.map((t) => `  - ${t}`),
            '[Dry Run] Would also generate project-aware skills (testing, deployment, error-handling)',
        ];
        if (skippedSources.length > 0) {
            lines.push(`Skipped sources: ${skippedSources.join(', ')}`);
        }
        return { content: [{ type: 'text', text: lines.join('\n') }] };
    }
    const installedFiles = [];
    for (const target of targets) {
        if (skills.length === 0) {
            continue;
        }
        const content = formatSkillsForTarget(skills, target);
        const filePath = await writeSkillFile(input.projectPath, target, content, config.autoMerge);
        installedFiles.push({ target, path: filePath, skillsCount: skills.length });
    }
    // SPEC-607: Generate project-aware skills using Agent Skills spec
    const generatedPaths = await generateProjectSkills(input.projectPath, detectedStack);
    const result = {
        detectedStack,
        discoveredSkills: skills,
        installedFiles,
        skippedSources,
        bootstrappedAt: new Date().toISOString(),
    };
    await saveLastSkillBootstrapResult(input.projectPath, result);
    const lines = [
        `Bootstrap complete. Stack: ${detectedStack.join(', ')}`,
        `Skills discovered: ${skills.length}`,
        `Files written: ${installedFiles.length}`,
    ];
    for (const f of installedFiles) {
        lines.push(`  + ${f.target} → ${f.path} (${f.skillsCount} skill(s))`);
    }
    if (generatedPaths.length > 0) {
        lines.push(`Project-aware skills generated: ${generatedPaths.length}`);
    }
    if (skippedSources.length > 0) {
        lines.push(`Skipped sources: ${skippedSources.join(', ')}`);
    }
    return { content: [{ type: 'text', text: lines.join('\n') }] };
}
export async function handleConfigureSkillRegistries(input) {
    const config = await getSkillBootstrapConfig(input.projectPath);
    const changes = [];
    if (input.addSource) {
        const { type, name, repo, subdir } = input.addSource;
        config.sources.push({ type, name, repo, subdir, enabled: true });
        changes.push(`Added source: ${name} (${repo})`);
    }
    if (input.removeSource) {
        const before = config.sources.length;
        config.sources = config.sources.filter((s) => s.name !== input.removeSource);
        if (config.sources.length < before) {
            changes.push(`Removed source: ${input.removeSource}`);
        }
    }
    if (input.enableSource) {
        const source = config.sources.find((s) => s.name === input.enableSource);
        if (source) {
            source.enabled = true;
            changes.push(`Enabled source: ${input.enableSource}`);
        }
    }
    if (input.disableSource) {
        const source = config.sources.find((s) => s.name === input.disableSource);
        if (source) {
            source.enabled = false;
            changes.push(`Disabled source: ${input.disableSource}`);
        }
    }
    if (input.setTargets) {
        config.targets = input.setTargets;
        changes.push(`Targets set to: ${input.setTargets.join(', ')}`);
    }
    if (input.setAutoMerge !== undefined) {
        config.autoMerge = input.setAutoMerge;
        changes.push(`Auto-merge set to: ${String(input.setAutoMerge)}`);
    }
    config.configuredAt = new Date().toISOString();
    await saveSkillBootstrapConfig(input.projectPath, config);
    const text = changes.length > 0
        ? `Skill registry configuration updated:\n${changes.map((c) => `  - ${c}`).join('\n')}`
        : 'No changes applied to skill registry configuration.';
    return { content: [{ type: 'text', text }] };
}
//# sourceMappingURL=skill-bootstrap-handler.js.map