// engine/ecosystem-absorber/platform-crawler.ts — Crawls external sources for capability signals
const GITHUB_API_BASE = 'https://api.github.com';
const CAPABILITY_SIGNALS = {
    api: ['endpoint', 'api', 'rest', 'graphql', 'webhook', 'http'],
    sdk: ['sdk', 'library', 'package', 'client', 'integration'],
    'tool-use': ['tool', 'function calling', 'tool_use', 'mcp', 'tool call'],
    agent: ['agent', 'autonomous', 'agentic', 'multi-agent', 'swarm'],
    skill: ['skill', 'capability', 'plugin', 'extension', 'addon'],
    pattern: ['pattern', 'best practice', 'workflow', 'architecture', 'design'],
};
/**
 * Detect category from text content using signal keywords.
 */
function detectCategory(text) {
    const lower = text.toLowerCase();
    for (const [cat, signals] of Object.entries(CAPABILITY_SIGNALS)) {
        if (signals.some((s) => lower.includes(s))) {
            return cat;
        }
    }
    return 'pattern';
}
/**
 * Extract capability signals from raw HTML/text content.
 */
function extractCapabilities(content, source) {
    const capabilities = [];
    const now = new Date().toISOString();
    // Extract headings and nearby text as capability signals
    const headingPattern = /<h[1-4][^>]*>([^<]{5,120})<\/h[1-4]>/gi;
    let match;
    while ((match = headingPattern.exec(content)) !== null) {
        const rawName = match[1];
        if (!rawName) {
            continue;
        }
        const name = rawName.replace(/\s+/g, ' ').trim();
        if (name.length < 5 || name.length > 120) {
            continue;
        }
        const category = detectCategory(name);
        const id = `${source.id}:${name.toLowerCase().replace(/\W+/g, '-').slice(0, 60)}`;
        capabilities.push({
            id,
            source: source.id,
            category,
            name,
            description: `Discovered from ${source.name}: ${name}`,
            url: source.url,
            discoveredAt: now,
            relevance: 0.5,
            actionable: category !== 'pattern',
        });
    }
    return capabilities.slice(0, 20);
}
/**
 * Fetch a URL with timeout, returning null on any error.
 */
async function safeFetch(url, timeoutMs = 8000) {
    try {
        const controller = new AbortController();
        const timer = setTimeout(() => {
            controller.abort();
        }, timeoutMs);
        const res = await fetch(url, { signal: controller.signal });
        clearTimeout(timer);
        if (!res.ok) {
            return null;
        }
        return await res.text();
    }
    catch {
        return null;
    }
}
/**
 * Crawl a docs-type source and return discovered capabilities.
 * Never throws — returns empty array on any error.
 */
export async function crawlDocsSource(source) {
    const content = await safeFetch(source.url);
    if (!content) {
        return [];
    }
    return extractCapabilities(content, source);
}
/**
 * Crawl a GitHub-type source using the public API.
 * Never throws — returns empty array on any error.
 */
export async function crawlGitHubSource(source) {
    // Extract owner/repo from URL if present
    const repoMatch = /github\.com\/([^/]+)\/([^/]+)/.exec(source.url);
    if (!repoMatch) {
        return crawlDocsSource(source);
    }
    const owner = repoMatch[1];
    const repo = repoMatch[2];
    const apiUrl = `${GITHUB_API_BASE}/repos/${owner}/${repo}/readme`;
    const now = new Date().toISOString();
    try {
        const res = await fetch(apiUrl, {
            headers: { Accept: 'application/vnd.github.raw+json', 'User-Agent': 'planu-ecosystem' },
            signal: AbortSignal.timeout(10_000),
        });
        if (!res.ok) {
            return [];
        }
        const text = await res.text();
        const category = detectCategory(text);
        return [
            {
                id: `${source.id}:readme`,
                source: source.id,
                category,
                name: `${repo} — README`,
                description: text.slice(0, 200).replace(/\s+/g, ' ').trim(),
                url: source.url,
                discoveredAt: now,
                relevance: 0.6,
                actionable: true,
                suggestion: `Review ${source.name} for integration opportunities`,
            },
        ];
    }
    catch {
        return [];
    }
}
//# sourceMappingURL=platform-crawler.js.map