/** * Research PDF Generation Script * Generates PDFs from standalone markdown research documents */ const puppeteer = require('puppeteer'); const marked = require('marked'); const fs = require('fs').promises; const path = require('path'); const RESEARCH_DIR = path.join(__dirname, '../docs/research'); const OUTPUT_DIR = path.join(__dirname, '../public/downloads'); /** * HTML template for research PDFs */ function generatePdfHtml(title, content, metadata = {}) { return ` ${title}

${title}

${metadata.version ? `

Version: ${metadata.version}

` : ''} ${metadata.date ? `

Date: ${metadata.date}

` : ''} ${metadata.type ? `

Document Type: ${metadata.type}

` : ''}

Tractatus AI Safety Framework

https://agenticgovernance.digital

${content}
`; } /** * Extract metadata from markdown frontmatter or header */ function extractMetadata(markdown) { const lines = markdown.split('\n'); const metadata = {}; // Look for title in first H1 const h1Match = markdown.match(/^#\s+(.+)$/m); if (h1Match) { metadata.title = h1Match[1]; } // Look for version const versionMatch = markdown.match(/\*\*Version:\*\*\s+(.+)/); if (versionMatch) { metadata.version = versionMatch[1]; } // Look for date const dateMatch = markdown.match(/\*\*Date:\*\*\s+(.+)/); if (dateMatch) { metadata.date = dateMatch[1]; } return metadata; } /** * Generate PDF from markdown file */ async function generatePdfFromMarkdown(inputFile, outputFilename, browser) { try { console.log(`\nProcessing: ${path.basename(inputFile)}`); // Read markdown const markdown = await fs.readFile(inputFile, 'utf-8'); // Extract metadata const metadata = extractMetadata(markdown); const title = metadata.title || path.basename(inputFile, '.md'); console.log(` Title: ${title}`); // Convert markdown to HTML const contentHtml = marked.parse(markdown); // Generate full HTML const html = generatePdfHtml(title, contentHtml, { version: metadata.version, date: metadata.date, type: 'Research Paper' }); // Create page const page = await browser.newPage(); await page.setContent(html, { waitUntil: 'networkidle0' }); // Generate PDF const outputPath = path.join(OUTPUT_DIR, outputFilename); await page.pdf({ path: outputPath, format: 'A4', printBackground: true, margin: { top: '2cm', right: '2cm', bottom: '2cm', left: '2cm' }, displayHeaderFooter: true, headerTemplate: '
', footerTemplate: `
/
` }); await page.close(); console.log(` ✓ Generated: ${outputFilename}`); return { success: true, filename: outputFilename }; } catch (error) { console.error(` ✗ Failed: ${error.message}`); return { success: false, error: error.message }; } } /** * Main execution */ async function main() { console.log('=== Research PDF Generation ==='); let browser; try { // Ensure output directory exists await fs.mkdir(OUTPUT_DIR, { recursive: true }); console.log(`Output directory: ${OUTPUT_DIR}`); // Launch browser console.log('\nLaunching browser...'); browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); console.log('✓ Browser ready'); // Generate PDFs const results = []; // Full research paper results.push(await generatePdfFromMarkdown( path.join(RESEARCH_DIR, 'tractatus-inflection-point-2025.md'), 'structural-governance-for-agentic-ai-tractatus-inflection-point.pdf', browser )); // Executive summary results.push(await generatePdfFromMarkdown( path.join(RESEARCH_DIR, 'executive-summary-tractatus-inflection-point.md'), 'executive-summary-tractatus-inflection-point.pdf', browser )); // Summary console.log('\n=== Generation Complete ===\n'); const successful = results.filter(r => r.success).length; const failed = results.filter(r => !r.success).length; console.log(`✓ Successful: ${successful}`); if (failed > 0) { console.log(`✗ Failed: ${failed}`); } console.log(`\nPDFs saved to: ${OUTPUT_DIR}`); } catch (error) { console.error('\n✗ Error:', error.message); process.exit(1); } finally { if (browser) await browser.close(); } } // Run if called directly if (require.main === module) { main(); } module.exports = { generatePdfFromMarkdown, generatePdfHtml };