- load-inst-035.js: Load precedent database rule to MongoDB - Fixes collection name (governanceRules vs governance_rules) - Eliminates "Precedent database rule not found" warning - migrate-value-pluralism-docs.js: Migrate docs to MongoDB - Generate ToC from markdown headings - Create search indexes - Add full metadata (quadrant, persistence, audience, tags) - Proper MongoDB integration for docs.html - generate-markdown-pdfs.js: Generate PDFs using Puppeteer - Workaround for missing pandoc PDF engines - Styled PDFs with proper typography - 3 value pluralism documents All scripts support production deployment workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
200 lines
5.8 KiB
JavaScript
200 lines
5.8 KiB
JavaScript
/**
|
|
* Migrate Value Pluralism Documents to MongoDB
|
|
* Adds three new value pluralism documents to the documents collection
|
|
*/
|
|
|
|
const mongoose = require('mongoose');
|
|
const marked = require('marked');
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const config = require('../src/config/app.config');
|
|
|
|
// Document structure from existing documents
|
|
const documentsToMigrate = [
|
|
{
|
|
file: 'docs/research/pluralistic-values-research-foundations.md',
|
|
title: 'Pluralistic Values: Research Foundations',
|
|
slug: 'pluralistic-values-research-foundations',
|
|
quadrant: 'STRATEGIC',
|
|
persistence: 'HIGH',
|
|
category: 'research',
|
|
audience: ['researcher', 'technical'],
|
|
tags: ['value-pluralism', 'research', 'deliberative-democracy', 'ethics', 'philosophy'],
|
|
description: 'Supporting research material for PluralisticDeliberationOrchestrator implementation, covering deliberative democracy, value pluralism theory, and cross-cultural communication'
|
|
},
|
|
{
|
|
file: 'docs/value-pluralism-faq.md',
|
|
title: 'Value Pluralism in Tractatus: Frequently Asked Questions',
|
|
slug: 'value-pluralism-faq',
|
|
quadrant: null,
|
|
persistence: 'HIGH',
|
|
category: 'documentation',
|
|
audience: ['general'],
|
|
tags: ['value-pluralism', 'faq', 'documentation', 'ethics'],
|
|
description: 'Accessible explanation of how Tractatus handles moral disagreement without imposing hierarchy'
|
|
},
|
|
{
|
|
file: 'docs/pluralistic-values-deliberation-plan-v2.md',
|
|
title: 'Pluralistic Values Deliberation Enhancement Plan',
|
|
slug: 'pluralistic-values-deliberation-plan-v2',
|
|
quadrant: 'OPERATIONAL',
|
|
persistence: 'HIGH',
|
|
category: 'implementation-guide',
|
|
audience: ['implementer', 'researcher'],
|
|
tags: ['value-pluralism', 'implementation', 'deliberation', 'planning'],
|
|
description: 'Technical design document for implementing non-hierarchical moral reasoning in the Tractatus Framework'
|
|
}
|
|
];
|
|
|
|
/**
|
|
* Generate table of contents from markdown
|
|
*/
|
|
function generateToC(markdown) {
|
|
const toc = [];
|
|
const lines = markdown.split('\n');
|
|
|
|
for (const line of lines) {
|
|
const match = line.match(/^(#{1,6})\s+(.+)$/);
|
|
if (match) {
|
|
const level = match[1].length;
|
|
const title = match[2].trim();
|
|
const slug = title
|
|
.toLowerCase()
|
|
.replace(/[^\w\s-]/g, '')
|
|
.replace(/\s+/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.trim();
|
|
|
|
toc.push({ level, title, slug });
|
|
}
|
|
}
|
|
|
|
return toc;
|
|
}
|
|
|
|
/**
|
|
* Generate search index (lowercase, no markdown formatting)
|
|
*/
|
|
function generateSearchIndex(markdown) {
|
|
return markdown
|
|
.toLowerCase()
|
|
.replace(/```[\s\S]*?```/g, '') // Remove code blocks
|
|
.replace(/`[^`]+`/g, '') // Remove inline code
|
|
.replace(/[#*_\[\]()]/g, '') // Remove markdown formatting
|
|
.replace(/\n+/g, '\n') // Collapse multiple newlines
|
|
.trim();
|
|
}
|
|
|
|
/**
|
|
* Migrate a single document
|
|
*/
|
|
async function migrateDocument(docInfo, db) {
|
|
console.log(`\nMigrating: ${docInfo.title}`);
|
|
|
|
// Read markdown file
|
|
const markdownPath = path.join(__dirname, '..', docInfo.file);
|
|
const markdown = await fs.readFile(markdownPath, 'utf-8');
|
|
|
|
// Convert to HTML
|
|
const html = marked.parse(markdown);
|
|
|
|
// Generate ToC
|
|
const toc = generateToC(markdown);
|
|
console.log(` ✓ Generated ToC (${toc.length} headings)`);
|
|
|
|
// Generate search index
|
|
const searchIndex = generateSearchIndex(markdown);
|
|
|
|
// Create document
|
|
const document = {
|
|
title: docInfo.title,
|
|
slug: docInfo.slug,
|
|
quadrant: docInfo.quadrant,
|
|
persistence: docInfo.persistence,
|
|
content_html: html,
|
|
content_markdown: markdown,
|
|
toc: toc,
|
|
metadata: {
|
|
author: 'System',
|
|
date_created: new Date(),
|
|
date_updated: new Date(),
|
|
version: '1.0',
|
|
document_code: null,
|
|
related_documents: [],
|
|
tags: docInfo.tags,
|
|
category: docInfo.category,
|
|
audience: docInfo.audience,
|
|
description: docInfo.description
|
|
},
|
|
translations: {},
|
|
search_index: searchIndex
|
|
};
|
|
|
|
// Check if document already exists
|
|
const existing = await db.collection('documents').findOne({ slug: docInfo.slug });
|
|
|
|
if (existing) {
|
|
console.log(` ⚠ Document already exists, updating...`);
|
|
await db.collection('documents').updateOne(
|
|
{ slug: docInfo.slug },
|
|
{ $set: document }
|
|
);
|
|
console.log(` ✓ Updated`);
|
|
} else {
|
|
await db.collection('documents').insertOne(document);
|
|
console.log(` ✓ Inserted`);
|
|
}
|
|
|
|
return docInfo.slug;
|
|
}
|
|
|
|
/**
|
|
* Main migration function
|
|
*/
|
|
async function main() {
|
|
console.log('=== Value Pluralism Documents Migration ===\n');
|
|
|
|
let client;
|
|
|
|
try {
|
|
// Connect to MongoDB
|
|
console.log('Connecting to MongoDB...');
|
|
client = await mongoose.connect(config.mongodb.uri, config.mongodb.options);
|
|
const db = mongoose.connection.db;
|
|
console.log('✓ Connected\n');
|
|
|
|
// Migrate each document
|
|
const migratedSlugs = [];
|
|
for (const docInfo of documentsToMigrate) {
|
|
const slug = await migrateDocument(docInfo, db);
|
|
migratedSlugs.push(slug);
|
|
}
|
|
|
|
// Summary
|
|
console.log('\n=== Migration Complete ===\n');
|
|
console.log(`✓ Migrated ${migratedSlugs.length} documents:`);
|
|
migratedSlugs.forEach(slug => console.log(` - ${slug}`));
|
|
console.log('\nDocuments are now available in docs.html');
|
|
console.log('PDFs available at:');
|
|
migratedSlugs.forEach(slug =>
|
|
console.log(` - /downloads/${slug}.pdf`)
|
|
);
|
|
|
|
} catch (error) {
|
|
console.error('\n✗ Migration failed:', error.message);
|
|
console.error(error.stack);
|
|
process.exit(1);
|
|
} finally {
|
|
if (client) {
|
|
await mongoose.connection.close();
|
|
console.log('\n✓ Database connection closed');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run migration
|
|
if (require.main === module) {
|
|
main();
|
|
}
|
|
|
|
module.exports = { migrateDocument, generateToC, generateSearchIndex };
|