#!/usr/bin/env bun import { intelPath, listProducts, loadCompetitorConfig, readJson, readPilotDoc, sourcePath, sourceStatus, writeJson, now, slug } from './lib/intel-utils' const competitors = loadCompetitorConfig() for (const product of listProducts()) { const sku = product.sku const { aspects, sw } = readPilotDoc(sku) const seededBenefits = product.metafields?.pdpProductBenefits || [] const rows = competitors.map((c: any, index: number) => { const doc = readJson(sourcePath('competitor-pdps', `${slug(c.brand)}.json`), null) const okPages = (doc?.pages || []).filter((p: any) => p.ok) return { rank: index + 1, brand: c.brand, domain: c.domain, sourceCoverage: okPages.length ? `${okPages.length}/${(doc?.pages || []).length} URLs fetched` : 'pending crawl/import', priceSignal: '', format: '', dose: '', claims: '', whitespace: okPages.length ? 'Homepage/PDP probe captured. Needs product-specific extraction before final comparison.' : 'Pending competitor PDP/Amazon/Trustpilot evidence. Do not use for final copy yet.', status: okPages.length ? 'source_probe_available' : 'needs_ingestion' } }) const jvSignals = (sw.items || []).length ? sw.items.slice(0, 5).map((item: any) => ({ rank: item.rank, signal: item.insight, source: 'Feefo strengths/weaknesses' })) : seededBenefits.slice(0, 5).map((benefit: string, index: number) => ({ rank: index + 1, signal: benefit, source: 'product content benefits seed; needs competitor validation' })) writeJson(intelPath(sku, 'competitor-comparison.json'), { sku, name: aspects.name || product.name || sku, generatedAt: now(), generatedBy: 'build-competitor-comparison.ts', n: rows.length, sourceStatus: { competitorPdp: sourceStatus('competitor-pdps'), amazon: sourceStatus('amazon'), trustpilot: sourceStatus('trustpilot') }, coverage: (sw.items || []).length ? 'pilot_feefo_plus_competitor_probes' : 'catalogue_queue_seeded_from_product_content_and_competitor_probes', competitors: rows, jvSignals }) console.log(`${sku}: wrote competitor comparison for ${rows.length} brands`) }