// engine/skills/skills-fetcher.ts — SPEC-022: skills.sh catalog fetcher
// Business logic for fetching and recommending AI agent skills.
// Lives in engine/ so engine/ modules can import it without violating architecture.
// SPEC-198: design/marketing skill detection added.
import { fetchUrl } from '../web-fetcher/http-client.js';
const MARKETING_DIR_KEYWORDS = ['landing', 'marketing', 'brand', 'assets/brand', 'brand-assets'];
const MARKETING_STACK_KEYWORDS = ['landing', 'saas', 'startup', 'website', 'brand', 'marketing'];
/** Returns true when the project has signals of product identity / marketing content. */
export function hasMarketingSignals(knowledge) {
    const stackLower = knowledge.stack.map((s) => s.toLowerCase());
    if (MARKETING_STACK_KEYWORDS.some((k) => stackLower.some((s) => s.includes(k)))) {
        return true;
    }
    const projectPathLower = knowledge.projectPath.toLowerCase();
    if (MARKETING_DIR_KEYWORDS.some((k) => projectPathLower.includes(k))) {
        return true;
    }
    const apps = Array.isArray(knowledge.apps) ? knowledge.apps : [];
    if (apps.some((a) => MARKETING_DIR_KEYWORDS.some((k) => a.name.toLowerCase().includes(k)))) {
        return true;
    }
    const conventionsStr = Object.values(knowledge.conventions).join(' ').toLowerCase();
    return MARKETING_STACK_KEYWORDS.some((k) => conventionsStr.includes(k));
}
export function isMcpServer(knowledge) {
    const stackLower = knowledge.stack.map((s) => s.toLowerCase());
    const toolingStr = JSON.stringify(knowledge.tooling).toLowerCase();
    return (stackLower.some((s) => s.includes('mcp') || s.includes('@modelcontextprotocol')) ||
        toolingStr.includes('modelcontextprotocol') ||
        toolingStr.includes('@modelcontextprotocol'));
}
export async function fetchRecommendedSkills(knowledge) {
    const skills = [];
    // SPEC-198: add design/marketing skills when project has brand/marketing signals
    if (hasMarketingSignals(knowledge)) {
        skills.push({
            name: 'brand-design-kit',
            description: 'Logo, banner, OG image, and brand identity generation for product projects',
            installCommand: 'npx skills add brand-design-kit',
            justification: 'Marketing/brand signals detected in project (landing page, brand assets, or product keywords)',
        });
    }
    // Always add mcp-builder first for MCP server projects
    if (isMcpServer(knowledge)) {
        skills.push({
            name: 'mcp-builder',
            description: 'Best practices and conventions for building high-quality MCP servers',
            installCommand: 'npx skills add mcp-builder',
            justification: 'Project detected as an MCP server (@modelcontextprotocol detected in stack/tooling)',
        });
    }
    // Fetch skills.sh catalog in real time (with graceful fallback to hardcoded skills)
    const catalogSkills = await fetchSkillsShCatalog(knowledge.stack, knowledge.language);
    if (catalogSkills.length > 0) {
        skills.push(...catalogSkills);
    }
    else {
        // Fallback: use hardcoded relevant skills when catalog is unavailable or empty
        skills.push(...buildFallbackSkills(knowledge));
    }
    // Deduplicate by name
    const seen = new Set();
    return skills.filter((s) => {
        if (seen.has(s.name)) {
            return false;
        }
        seen.add(s.name);
        return true;
    });
}
async function fetchSkillsShCatalog(stack, language) {
    const stackParam = encodeURIComponent([...stack, language].join(',').toLowerCase());
    const url = `https://skills.sh/api/catalog?stack=${stackParam}`;
    try {
        const response = await fetchUrl(url);
        if (!response) {
            return [];
        }
        const parsed = JSON.parse(response.content);
        return (parsed.skills ?? []).slice(0, 5).map((s) => ({
            name: s.name,
            description: s.description ?? `Skill: ${s.name}`,
            installCommand: s.installCommand ?? `npx skills add ${s.name}`,
            justification: `Relevant to your ${language} stack`,
        }));
    }
    catch {
        /* v8 ignore next */ // JSON.parse errors are unlikely with mocked fetchUrl in tests
        return [];
    }
}
function buildFallbackSkills(knowledge) {
    const skills = [];
    const stackLower = knowledge.stack.map((s) => s.toLowerCase());
    const lang = knowledge.language.toLowerCase();
    if (lang === 'typescript' || lang === 'javascript') {
        skills.push({
            name: 'typescript-patterns',
            description: 'TypeScript best practices, strict mode patterns, and type safety conventions',
            installCommand: 'npx skills add typescript-patterns',
            justification: `Project uses ${knowledge.language}`,
        });
    }
    if (stackLower.some((s) => s.includes('react'))) {
        skills.push({
            name: 'react-patterns',
            description: 'React component patterns, hooks best practices, and performance optimization',
            installCommand: 'npx skills add react-patterns',
            justification: 'React detected in project stack',
        });
    }
    if (stackLower.some((s) => s.includes('next'))) {
        skills.push({
            name: 'nextjs-patterns',
            description: 'Next.js App Router patterns, server components, and deployment best practices',
            installCommand: 'npx skills add nextjs-patterns',
            justification: 'Next.js detected in project stack',
        });
    }
    if (stackLower.some((s) => s.includes('python')) ||
        knowledge.language.toLowerCase() === 'python') {
        skills.push({
            name: 'python-patterns',
            description: 'Python best practices, type hints, async patterns, and testing conventions',
            installCommand: 'npx skills add python-patterns',
            justification: 'Python detected in project stack',
        });
    }
    if (hasMarketingSignals(knowledge)) {
        skills.push({
            name: 'og-image-generator',
            description: 'Generate Open Graph images, social media banners, and favicon sets',
            installCommand: 'npx skills add og-image-generator',
            justification: 'Marketing/brand signals detected — visual assets are typically needed',
        });
    }
    return skills;
}
//# sourceMappingURL=skills-fetcher.js.map