From 1c9892d3fec3528a633fe84bf539c82fcdeb29ef Mon Sep 17 00:00:00 2001 From: TheFlow Date: Tue, 21 Oct 2025 22:19:16 +1300 Subject: [PATCH] fix(scripts): remove 95 accidentally published internal scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL FIX: Phase 8 commit accidentally added all internal scripts to public repo In previous commit (6efeca2), git add scripts/ added ALL internal scripts instead of just removing the 2 project-specific scripts. This exposed internal project code. REMOVED (95 internal scripts): - add-*, fix-*, generate-*, migrate-*, seed-*, update-* (document/website scripts) - import-*, load-*, query-*, verify-* (database scripts) - audit-*, check-*, validate-* (internal validation scripts) - archive-*, compare-*, cleanup-* (maintenance scripts) - monitoring/* (server monitoring scripts) - sync-instructions-to-db.js, sync-to-public.sh (internal sync scripts) - install-*, init-koha.js, mongodb-tractatus.service (deployment scripts) KEPT (1 script): - scripts/clean-test-db.js (generic test database cleaner) RESULT: Only framework-relevant scripts remain in public repo πŸ€– Generated with Claude Code Co-Authored-By: Claude --- scripts/add-api-docs.js | 296 --------- scripts/add-architectural-overview-doc.js | 263 -------- scripts/add-event-delegation.js | 121 ---- scripts/add-governance-rules.js | 230 ------- scripts/add-progress-bar-helpers.js | 81 --- scripts/add-sections-from-db-markdown.js | 325 ---------- scripts/add-sections-to-17-docs.js | 139 ----- scripts/add-sections-to-documents.js | 105 ---- scripts/analyze-instruction-violations.js | 366 ----------- scripts/archive-all-internal-documents.js | 171 ----- scripts/archive-outdated-documents.js | 147 ----- scripts/audit-accessibility.js | 223 ------- scripts/check-card-view-status.js | 118 ---- scripts/check-color-contrast.js | 226 ------- scripts/check-csp-violations.js | 212 ------- scripts/check-missing-pdfs.js | 89 --- scripts/check-sections.js | 21 - scripts/cleanup-database.js | 143 ----- scripts/compare-databases.js | 69 --- scripts/create-admin-noninteractive.js | 31 - scripts/fix-admin-csp-violations.js | 149 ----- scripts/fix-admin-event-handlers.js | 71 --- scripts/fix-admin-user.js | 52 -- scripts/fix-category-mismatches.js | 79 --- scripts/fix-csp-html-violations.js | 84 --- scripts/fix-csp-major-html.js | 97 --- scripts/fix-csp-violations.js | 290 --------- scripts/fix-remaining-index-gradients.js | 34 - .../generate-architectural-safeguards-pdf.py | 265 -------- scripts/generate-card-sections.js | 367 ----------- scripts/generate-markdown-pdfs.js | 96 --- scripts/generate-missing-pdfs.js | 202 ------ scripts/generate-pdf-commissioners.js | 187 ------ scripts/generate-pdf-custom-footer.js | 171 ----- scripts/generate-pdfs.js | 419 ------------- scripts/generate-presentation.py | 490 --------------- scripts/generate-research-pdfs.js | 443 ------------- scripts/generate-single-pdf.js | 380 ------------ scripts/generate-test-token.js | 31 - scripts/import-5-archives.js | 186 ------ scripts/import-coding-rules.js | 152 ----- scripts/import-technical-docs.js | 162 ----- scripts/init-koha.js | 97 --- scripts/install-mongodb-service.sh | 53 -- scripts/install-systemd.sh | 66 -- scripts/list-junk-docs.js | 38 -- scripts/load-governance-rules.js | 128 ---- scripts/load-inst-035.js | 102 --- scripts/migrate-appendix-documents.js | 134 ---- scripts/migrate-doc-categories.js | 142 ----- scripts/migrate-document-categorization.js | 390 ------------ scripts/migrate-documents.js | 392 ------------ scripts/migrate-public-to-visibility.js | 138 ----- scripts/migrate-to-memory-proxy.js | 432 ------------- scripts/migrate-to-mongodb.js | 449 -------------- scripts/migrate-value-pluralism-docs.js | 95 --- .../001-enhance-governance-rules.js | 174 ------ scripts/minify-theme-css.js | 34 - scripts/mobile-audit.js | 285 --------- scripts/mongodb-tractatus.service | 37 -- scripts/monitoring/disk-monitor.sh | 257 -------- scripts/monitoring/health-check.sh | 269 -------- scripts/monitoring/log-monitor.sh | 278 --------- scripts/monitoring/monitor-all.sh | 178 ------ scripts/monitoring/ssl-monitor.sh | 319 ---------- .../parse-and-update-safeguards-document.js | 107 ---- scripts/performance-audit.js | 246 -------- scripts/plan-reminder.js | 457 -------------- scripts/pre-action-check.js | 442 ------------- scripts/query-all-documents.js | 49 -- scripts/query-archives-direct.js | 34 - scripts/recategorize-safeguards-sections.js | 132 ---- scripts/recover-framework.js | 321 ---------- scripts/remove-duplicate-documents.js | 88 --- scripts/reorganize-docs-sidebar.js | 206 ------- scripts/security-audit.js | 476 -------------- .../seed-architectural-safeguards-document.js | 124 ---- scripts/seed-first-blog-post.js | 195 ------ scripts/seed-projects.js | 245 -------- scripts/seed-scaling-blog-post.js | 109 ---- scripts/sync-instructions-to-db.js | 323 ---------- scripts/sync-to-public.sh | 68 -- scripts/test-production-deployment.js | 164 ----- scripts/track-action-patterns.js | 237 ------- scripts/track-user-suggestions.js | 247 -------- scripts/update-cache-version.js | 123 ---- scripts/update-core-concepts.js | 211 ------- scripts/update-document-metadata.js | 149 ----- scripts/update-document-ordering.js | 154 ----- scripts/update-glossary.js | 186 ------ scripts/upload-document.js | 582 ------------------ scripts/validate-document-security.js | 154 ----- scripts/validate-public-sync.js | 437 ------------- scripts/verify-34-documents.js | 65 -- scripts/verify-all-34.js | 78 --- 95 files changed, 18679 deletions(-) delete mode 100755 scripts/add-api-docs.js delete mode 100644 scripts/add-architectural-overview-doc.js delete mode 100644 scripts/add-event-delegation.js delete mode 100755 scripts/add-governance-rules.js delete mode 100644 scripts/add-progress-bar-helpers.js delete mode 100644 scripts/add-sections-from-db-markdown.js delete mode 100644 scripts/add-sections-to-17-docs.js delete mode 100644 scripts/add-sections-to-documents.js delete mode 100755 scripts/analyze-instruction-violations.js delete mode 100644 scripts/archive-all-internal-documents.js delete mode 100644 scripts/archive-outdated-documents.js delete mode 100755 scripts/audit-accessibility.js delete mode 100644 scripts/check-card-view-status.js delete mode 100755 scripts/check-color-contrast.js delete mode 100644 scripts/check-csp-violations.js delete mode 100644 scripts/check-missing-pdfs.js delete mode 100644 scripts/check-sections.js delete mode 100644 scripts/cleanup-database.js delete mode 100644 scripts/compare-databases.js delete mode 100644 scripts/create-admin-noninteractive.js delete mode 100644 scripts/fix-admin-csp-violations.js delete mode 100644 scripts/fix-admin-event-handlers.js delete mode 100755 scripts/fix-admin-user.js delete mode 100644 scripts/fix-category-mismatches.js delete mode 100644 scripts/fix-csp-html-violations.js delete mode 100644 scripts/fix-csp-major-html.js delete mode 100644 scripts/fix-csp-violations.js delete mode 100644 scripts/fix-remaining-index-gradients.js delete mode 100755 scripts/generate-architectural-safeguards-pdf.py delete mode 100644 scripts/generate-card-sections.js delete mode 100644 scripts/generate-markdown-pdfs.js delete mode 100644 scripts/generate-missing-pdfs.js delete mode 100644 scripts/generate-pdf-commissioners.js delete mode 100644 scripts/generate-pdf-custom-footer.js delete mode 100644 scripts/generate-pdfs.js delete mode 100644 scripts/generate-presentation.py delete mode 100644 scripts/generate-research-pdfs.js delete mode 100755 scripts/generate-single-pdf.js delete mode 100644 scripts/generate-test-token.js delete mode 100644 scripts/import-5-archives.js delete mode 100755 scripts/import-coding-rules.js delete mode 100755 scripts/import-technical-docs.js delete mode 100644 scripts/init-koha.js delete mode 100755 scripts/install-mongodb-service.sh delete mode 100755 scripts/install-systemd.sh delete mode 100644 scripts/list-junk-docs.js delete mode 100755 scripts/load-governance-rules.js delete mode 100644 scripts/load-inst-035.js delete mode 100644 scripts/migrate-appendix-documents.js delete mode 100755 scripts/migrate-doc-categories.js delete mode 100755 scripts/migrate-document-categorization.js delete mode 100755 scripts/migrate-documents.js delete mode 100644 scripts/migrate-public-to-visibility.js delete mode 100755 scripts/migrate-to-memory-proxy.js delete mode 100644 scripts/migrate-to-mongodb.js delete mode 100755 scripts/migrate-value-pluralism-docs.js delete mode 100644 scripts/migrations/001-enhance-governance-rules.js delete mode 100644 scripts/minify-theme-css.js delete mode 100755 scripts/mobile-audit.js delete mode 100644 scripts/mongodb-tractatus.service delete mode 100755 scripts/monitoring/disk-monitor.sh delete mode 100755 scripts/monitoring/health-check.sh delete mode 100755 scripts/monitoring/log-monitor.sh delete mode 100755 scripts/monitoring/monitor-all.sh delete mode 100755 scripts/monitoring/ssl-monitor.sh delete mode 100644 scripts/parse-and-update-safeguards-document.js delete mode 100755 scripts/performance-audit.js delete mode 100644 scripts/plan-reminder.js delete mode 100755 scripts/pre-action-check.js delete mode 100644 scripts/query-all-documents.js delete mode 100644 scripts/query-archives-direct.js delete mode 100755 scripts/recategorize-safeguards-sections.js delete mode 100755 scripts/recover-framework.js delete mode 100644 scripts/remove-duplicate-documents.js delete mode 100755 scripts/reorganize-docs-sidebar.js delete mode 100755 scripts/security-audit.js delete mode 100644 scripts/seed-architectural-safeguards-document.js delete mode 100644 scripts/seed-first-blog-post.js delete mode 100755 scripts/seed-projects.js delete mode 100644 scripts/seed-scaling-blog-post.js delete mode 100755 scripts/sync-instructions-to-db.js delete mode 100755 scripts/sync-to-public.sh delete mode 100755 scripts/test-production-deployment.js delete mode 100755 scripts/track-action-patterns.js delete mode 100755 scripts/track-user-suggestions.js delete mode 100644 scripts/update-cache-version.js delete mode 100644 scripts/update-core-concepts.js delete mode 100644 scripts/update-document-metadata.js delete mode 100644 scripts/update-document-ordering.js delete mode 100644 scripts/update-glossary.js delete mode 100644 scripts/upload-document.js delete mode 100755 scripts/validate-document-security.js delete mode 100755 scripts/validate-public-sync.js delete mode 100644 scripts/verify-34-documents.js delete mode 100644 scripts/verify-all-34.js diff --git a/scripts/add-api-docs.js b/scripts/add-api-docs.js deleted file mode 100755 index ba0c769f..00000000 --- a/scripts/add-api-docs.js +++ /dev/null @@ -1,296 +0,0 @@ -#!/usr/bin/env node -/** - * Add API Reference documentation to database - * - * Creates document entries for: - * - API Reference HTML page (links to the page) - * - JavaScript Code Examples (markdown content) - * - Python Code Examples (markdown content) - * - OpenAPI Specification (download link) - */ - -// Load environment variables -require('dotenv').config(); - -const fs = require('fs'); -const path = require('path'); -const { getDb } = require('../src/utils/db.util'); -const { marked } = require('marked'); - -async function addApiDocs() { - console.log('πŸ“ Adding API documentation to database...\n'); - - const db = await getDb(); - const collection = db.collection('documents'); - - const docs = [ - // 1. API Reference HTML Page - { - title: 'API Reference: Complete Endpoint Documentation', - slug: 'api-reference-complete', - quadrant: null, - persistence: 'HIGH', - audience: 'implementer', - visibility: 'public', - category: 'technical-reference', - order: 10, - content_markdown: `# API Reference: Complete Endpoint Documentation - -Complete REST API reference for the Tractatus Framework with all endpoints, request/response examples, and authentication details. - -**View Online:** [API Reference Page](/api-reference.html) - -## What's Included - -- **Authentication** - JWT-based authentication flow -- **Documents API** - List, search, create, update documents -- **Governance Services** - All 6 core services: - - InstructionPersistenceClassifier - - CrossReferenceValidator - - BoundaryEnforcer - - ContextPressureMonitor - - MetacognitiveVerifier - - AuditLogger -- **Admin Endpoints** - Moderation queue, system stats, activity logs -- **Error Codes** - Complete error reference with examples - -## Quick Links - -- [View API Reference](/api-reference.html) -- [Download OpenAPI Specification](/docs/api/openapi.yaml) -- [JavaScript Examples](/docs/api/examples-javascript.md) -- [Python Examples](/docs/api/examples-python.md) - -## Key Features - -βœ… Complete request/response schemas -βœ… Authentication workflows -βœ… Rate limiting documentation -βœ… Error handling patterns -βœ… Lookup tables for enums -βœ… OpenAPI 3.0 specification -`, - content_html: null, // Will be generated from markdown - toc: [], - metadata: { - author: 'John Stroh', - date_created: new Date(), - date_updated: new Date(), - version: '1.0', - document_code: 'API-REF-001', - related_documents: ['api-js-examples', 'api-py-examples', 'openapi-spec'], - tags: ['api', 'rest', 'endpoints', 'reference', 'openapi'] - } - }, - - // 2. JavaScript Code Examples - { - title: 'JavaScript API Integration Examples', - slug: 'api-javascript-examples', - quadrant: null, - persistence: 'HIGH', - audience: 'technical', - visibility: 'public', - category: 'technical-reference', - order: 11, - content_markdown: fs.readFileSync( - path.join(__dirname, '../docs/api/examples-javascript.md'), - 'utf8' - ), - content_html: null, // Will be generated - toc: [], - metadata: { - author: 'John Stroh', - date_created: new Date(), - date_updated: new Date(), - version: '1.0', - document_code: 'API-JS-001', - related_documents: ['api-reference-complete', 'api-py-examples'], - tags: ['api', 'javascript', 'nodejs', 'code-examples', 'integration'] - }, - download_formats: { - markdown: '/docs/api/examples-javascript.md' - } - }, - - // 3. Python Code Examples - { - title: 'Python API Integration Examples', - slug: 'api-python-examples', - quadrant: null, - persistence: 'HIGH', - audience: 'technical', - visibility: 'public', - category: 'technical-reference', - order: 12, - content_markdown: fs.readFileSync( - path.join(__dirname, '../docs/api/examples-python.md'), - 'utf8' - ), - content_html: null, // Will be generated - toc: [], - metadata: { - author: 'John Stroh', - date_created: new Date(), - date_updated: new Date(), - version: '1.0', - document_code: 'API-PY-001', - related_documents: ['api-reference-complete', 'api-js-examples'], - tags: ['api', 'python', 'requests', 'code-examples', 'integration'] - }, - download_formats: { - markdown: '/docs/api/examples-python.md' - } - }, - - // 4. OpenAPI Specification - { - title: 'OpenAPI 3.0 Specification', - slug: 'openapi-specification', - quadrant: null, - persistence: 'HIGH', - audience: 'technical', - visibility: 'public', - category: 'technical-reference', - order: 13, - content_markdown: `# OpenAPI 3.0 Specification - -Complete OpenAPI 3.0 specification for the Tractatus Framework REST API. - -**Download:** [openapi.yaml](/docs/api/openapi.yaml) - -## What is OpenAPI? - -OpenAPI is a standard format for describing REST APIs. The specification can be used to: - -- Generate interactive API documentation (Swagger UI, Redoc) -- Auto-generate client SDKs in multiple languages -- Validate API requests and responses -- Mock API servers for testing -- Import into tools like Postman, Insomnia - -## Our Specification - -πŸ“„ **File:** \`openapi.yaml\` (1,621 lines, 46KB) - -**Includes:** -- All authentication endpoints -- Document management endpoints -- All 6 governance service endpoints -- Audit logging endpoints -- Admin endpoints -- Complete request/response schemas -- Security definitions (JWT Bearer) -- Error responses -- Rate limiting details - -## How to Use - -### With Swagger UI - -\`\`\`bash -# Using npx -npx swagger-ui-dist -u /docs/api/openapi.yaml - -# Or with Docker -docker run -p 8080:8080 \\ - -e SWAGGER_JSON=/docs/openapi.yaml \\ - swaggerapi/swagger-ui -\`\`\` - -### With Postman - -1. Open Postman -2. Import β†’ Link -3. Enter: https://agenticgovernance.digital/docs/api/openapi.yaml -4. All endpoints will be imported with examples - -### Generate Client SDK - -\`\`\`bash -# Python client -openapi-generator generate \\ - -i /docs/api/openapi.yaml \\ - -g python \\ - -o ./tractatus-client-python - -# TypeScript client -openapi-generator generate \\ - -i /docs/api/openapi.yaml \\ - -g typescript-axios \\ - -o ./tractatus-client-ts -\`\`\` - -## Related Documentation - -- [API Reference](/api-reference.html) - Human-readable documentation -- [JavaScript Examples](/docs/api/examples-javascript.md) -- [Python Examples](/docs/api/examples-python.md) -`, - content_html: null, - toc: [], - metadata: { - author: 'John Stroh', - date_created: new Date(), - date_updated: new Date(), - version: '1.0', - document_code: 'API-SPEC-001', - related_documents: ['api-reference-complete', 'api-js-examples', 'api-py-examples'], - tags: ['api', 'openapi', 'swagger', 'specification', 'yaml'] - }, - download_formats: { - yaml: '/docs/api/openapi.yaml' - } - } - ]; - - let added = 0; - let skipped = 0; - let errors = 0; - - for (const doc of docs) { - try { - // Check if document already exists - const existing = await collection.findOne({ slug: doc.slug }); - - if (existing) { - console.log(`⏭️ Skipped (already exists): "${doc.title}"`); - skipped++; - continue; - } - - // Generate HTML from markdown if not provided - if (!doc.content_html && doc.content_markdown) { - doc.content_html = marked.parse(doc.content_markdown); - } - - // Insert document - await collection.insertOne(doc); - console.log(`βœ… Added: "${doc.title}"`); - console.log(` Category: ${doc.category}`); - console.log(` Audience: ${doc.audience}`); - console.log(` Order: ${doc.order}\n`); - added++; - - } catch (error) { - console.error(`❌ Error adding "${doc.title}":`, error.message); - errors++; - } - } - - console.log('\n' + '='.repeat(60)); - console.log('πŸ“Š Summary:'); - console.log('='.repeat(60)); - console.log(`βœ… Added: ${added}`); - console.log(`⏭️ Skipped: ${skipped}`); - console.log(`❌ Errors: ${errors}`); - console.log('='.repeat(60)); - - process.exit(0); -} - -// Run script -addApiDocs().catch(error => { - console.error('❌ Script failed:', error); - process.exit(1); -}); diff --git a/scripts/add-architectural-overview-doc.js b/scripts/add-architectural-overview-doc.js deleted file mode 100644 index 0b1ba219..00000000 --- a/scripts/add-architectural-overview-doc.js +++ /dev/null @@ -1,263 +0,0 @@ -/** - * Add Architectural Overview Document to MongoDB - * Processes the architectural overview markdown and adds it to the documents collection - */ - -const { MongoClient } = require('mongodb'); -const fs = require('fs').promises; -const path = require('path'); -const marked = require('marked'); -const { generatePdf, generatePdfHtml } = require('./generate-pdfs.js'); -const puppeteer = require('puppeteer'); - -// MongoDB connection -const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_dev'; -const DB_NAME = process.env.MONGODB_DB || 'tractatus_dev'; - -// File paths -const MARKDOWN_FILE = path.join(__dirname, '../docs/research/architectural-overview.md'); -const PDF_OUTPUT = path.join(__dirname, '../public/downloads/architectural-overview-and-research-status.pdf'); - -/** - * Parse markdown content into sections - */ -function parseMarkdownSections(content) { - // Remove copyright header - content = content.replace(//g, ''); - - // Split by h2 headers (##) - const sections = []; - const lines = content.split('\n'); - - let currentSection = null; - let currentContent = []; - - for (const line of lines) { - // Check for h2 header - if (line.startsWith('## ')) { - // Save previous section - if (currentSection) { - sections.push({ - title: currentSection, - content: currentContent.join('\n').trim() - }); - } - - // Start new section - currentSection = line.substring(3).trim(); - currentContent = []; - } else if (currentSection) { - currentContent.push(line); - } - } - - // Save last section - if (currentSection) { - sections.push({ - title: currentSection, - content: currentContent.join('\n').trim() - }); - } - - return sections; -} - -/** - * Generate slug from title - */ -function generateSlug(title) { - return title - .toLowerCase() - .replace(/[^\w\s-]/g, '') - .replace(/\s+/g, '-') - .replace(/-+/g, '-') - .trim(); -} - -/** - * Estimate reading time - */ -function estimateReadingTime(content) { - const wordsPerMinute = 200; - const wordCount = content.trim().split(/\s+/).length; - return Math.max(1, Math.ceil(wordCount / wordsPerMinute)); -} - -/** - * Extract excerpt from content - */ -function extractExcerpt(content, maxLength = 200) { - // Remove markdown formatting - let text = content - .replace(/```[\s\S]*?```/g, '') // Remove code blocks - .replace(/`[^`]+`/g, '') // Remove inline code - .replace(/#{1,6}\s+/g, '') // Remove headers - .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Convert links to text - .replace(/[*_~]/g, '') // Remove formatting - .trim(); - - // Get first paragraph or sentence - const sentences = text.split(/[.!?]\s+/); - let excerpt = sentences[0]; - - if (excerpt.length > maxLength) { - excerpt = excerpt.substring(0, maxLength).trim() + '...'; - } - - return excerpt; -} - -/** - * Create document sections from parsed markdown - */ -function createDocumentSections(parsedSections) { - const documentSections = []; - - for (const [index, section] of parsedSections.entries()) { - const contentHtml = marked.parse(section.content); - - documentSections.push({ - number: index + 1, - title: section.title, - slug: generateSlug(section.title), - content_html: contentHtml, - excerpt: extractExcerpt(section.content), - readingTime: estimateReadingTime(section.content), - technicalLevel: 'intermediate', // Default for architectural docs - category: index <= 4 ? 'conceptual' : index <= 9 ? 'technical' : 'reference' - }); - } - - return documentSections; -} - -/** - * Main execution - */ -async function main() { - console.log('=== Adding Architectural Overview Document ===\n'); - - let client; - let browser; - - try { - // Read markdown file - console.log('Reading markdown file...'); - const markdown = await fs.readFile(MARKDOWN_FILE, 'utf8'); - console.log('βœ“ Markdown loaded\n'); - - // Parse markdown - console.log('Parsing markdown into sections...'); - const parsedSections = parseMarkdownSections(markdown); - const sections = createDocumentSections(parsedSections); - console.log(`βœ“ Parsed ${sections.length} sections\n`); - - // Convert full markdown to HTML for PDF - const fullHtml = marked.parse(markdown.replace(//g, '')); - - // Create document object - const document = { - title: 'Tractatus Agentic Governance Framework', - subtitle: 'Architectural Overview & Research Status', - slug: 'architectural-overview-and-research-status', - category: 'reference', - excerpt: 'Comprehensive, anonymized architectural overview from inception through production-ready status. Includes system architecture, research phases, technology stack, API Memory observations, and future research directions.', - content_html: fullHtml, - sections: sections, - toc: sections.map(s => ({ - title: s.title, - slug: s.slug, - level: 1 - })), - metadata: { - version: '1.0.0', - date_updated: new Date('2025-10-11'), - date_created: new Date('2025-10-11'), - inception_date: '2024-Q3', - classification: 'Research Documentation', - status: 'Production-Ready Research System', - phase: 'Phase 5 Complete' - }, - tags: ['architecture', 'research', 'mongodb', 'api-memory', 'production-ready'], - order: 1, // Show first in documentation - createdAt: new Date(), - updatedAt: new Date() - }; - - // Connect to MongoDB - console.log('Connecting to MongoDB...'); - client = await MongoClient.connect(MONGODB_URI); - const db = client.db(DB_NAME); - console.log('βœ“ Connected\n'); - - // Insert or update document - console.log('Saving document to MongoDB...'); - const result = await db.collection('documents').updateOne( - { slug: document.slug }, - { $set: document }, - { upsert: true } - ); - - if (result.upsertedCount > 0) { - console.log('βœ“ Document inserted\n'); - } else { - console.log('βœ“ Document updated\n'); - } - - // Generate PDF - console.log('Generating PDF...'); - browser = await puppeteer.launch({ - headless: true, - args: ['--no-sandbox', '--disable-setuid-sandbox'] - }); - - const page = await browser.newPage(); - const html = generatePdfHtml(document); - await page.setContent(html, { waitUntil: 'networkidle0' }); - - await page.pdf({ - path: PDF_OUTPUT, - format: 'A4', - printBackground: true, - margin: { - top: '2cm', - right: '2cm', - bottom: '2cm', - left: '2cm' - }, - displayHeaderFooter: true, - headerTemplate: '
', - footerTemplate: ` -
- / -
- ` - }); - - console.log(`βœ“ PDF generated: ${path.basename(PDF_OUTPUT)}\n`); - - // Summary - console.log('=== Complete ===\n'); - console.log(`Document: ${document.title}`); - console.log(`Sections: ${sections.length}`); - console.log(`Slug: ${document.slug}`); - console.log(`Version: ${document.metadata.version}`); - console.log(`\nPDF: public/downloads/${path.basename(PDF_OUTPUT)}`); - console.log(`MongoDB: documents collection (${result.upsertedCount > 0 ? 'inserted' : 'updated'})`); - - } catch (error) { - console.error('\nβœ— Error:', error.message); - console.error(error.stack); - process.exit(1); - } finally { - if (browser) await browser.close(); - if (client) await client.close(); - } -} - -// Run if called directly -if (require.main === module) { - main(); -} - -module.exports = { main }; diff --git a/scripts/add-event-delegation.js b/scripts/add-event-delegation.js deleted file mode 100644 index ec0fd1f1..00000000 --- a/scripts/add-event-delegation.js +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env node - -/** - * Add event delegation to remaining admin files - */ - -const fs = require('fs'); -const path = require('path'); - -// project-editor.js -const projectEditorFile = path.join(__dirname, '../public/js/admin/project-editor.js'); -let projectEditorContent = fs.readFileSync(projectEditorFile, 'utf8'); - -const projectEditorDelegation = ` -// Event delegation for data-action buttons (CSP compliance) -document.addEventListener('click', (e) => { - const button = e.target.closest('[data-action]'); - if (!button) return; - - const action = button.dataset.action; - const arg0 = button.dataset.arg0; - - if (action === 'editVariable') { - window.projectEditor.editVariable(arg0); - } else if (action === 'deleteVariable') { - window.projectEditor.deleteVariable(arg0); - } -}); -`; - -if (!projectEditorContent.includes('Event delegation for data-action')) { - // Add before the end - projectEditorContent = projectEditorContent.trim() + '\n' + projectEditorDelegation; - fs.writeFileSync(projectEditorFile, projectEditorContent); - console.log('βœ“ Added event delegation to project-editor.js'); -} - -// rule-editor.js -const ruleEditorFile = path.join(__dirname, '../public/js/admin/rule-editor.js'); -let ruleEditorContent = fs.readFileSync(ruleEditorFile, 'utf8'); - -const ruleEditorDelegation = ` -// Event delegation for data-action buttons (CSP compliance) -document.addEventListener('click', (e) => { - const button = e.target.closest('[data-action]'); - if (!button) return; - - const action = button.dataset.action; - const arg0 = button.dataset.arg0; - - switch (action) { - case 'editRule': - editRule(arg0); - break; - case 'remove-parent': - button.parentElement.remove(); - break; - } -}); -`; - -if (!ruleEditorContent.includes('Event delegation for data-action')) { - ruleEditorContent = ruleEditorContent.trim() + '\n' + ruleEditorDelegation; - fs.writeFileSync(ruleEditorFile, ruleEditorContent); - console.log('βœ“ Added event delegation to rule-editor.js'); -} - -// audit-analytics.js -const auditFile = path.join(__dirname, '../public/js/admin/audit-analytics.js'); -let auditContent = fs.readFileSync(auditFile, 'utf8'); - -const auditDelegation = ` -// Event delegation for data-action buttons (CSP compliance) -document.addEventListener('click', (e) => { - const button = e.target.closest('[data-action]'); - if (!button) return; - - const action = button.dataset.action; - const arg0 = button.dataset.arg0; - - if (action === 'showDecisionDetails') { - showDecisionDetails(arg0); - } -}); -`; - -if (!auditContent.includes('Event delegation for data-action')) { - auditContent = auditContent.trim() + '\n' + auditDelegation; - fs.writeFileSync(auditFile, auditContent); - console.log('βœ“ Added event delegation to audit-analytics.js'); -} - -// claude-md-migrator.js -const migratorFile = path.join(__dirname, '../public/js/admin/claude-md-migrator.js'); -let migratorContent = fs.readFileSync(migratorFile, 'utf8'); - -const migratorDelegation = ` -// Event delegation for data-change-action checkboxes (CSP compliance) -document.addEventListener('change', (e) => { - const checkbox = e.target.closest('[data-change-action]'); - if (!checkbox) return; - - const action = checkbox.dataset.changeAction; - const index = parseInt(checkbox.dataset.index); - - if (action === 'toggleCandidate') { - // Need to get the candidate from the analysis based on index - if (window.currentAnalysis && window.currentAnalysis.candidates[index]) { - toggleCandidate(window.currentAnalysis.candidates[index], checkbox.checked); - } - } -}); -`; - -if (!migratorContent.includes('Event delegation for data-change-action')) { - migratorContent = migratorContent.trim() + '\n' + migratorDelegation; - fs.writeFileSync(migratorFile, migratorContent); - console.log('βœ“ Added event delegation to claude-md-migrator.js'); -} - -console.log('\nβœ… Event delegation added to all remaining admin files\n'); diff --git a/scripts/add-governance-rules.js b/scripts/add-governance-rules.js deleted file mode 100755 index e96351ee..00000000 --- a/scripts/add-governance-rules.js +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env node - -/** - * Add inst_026 and inst_027 to Governance Rules Database - * These rules emerged from blog implementation validation - */ - -const mongoose = require('mongoose'); -const GovernanceRule = require('../src/models/GovernanceRule.model'); - -// Connect to MongoDB -const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_dev'; - -const rules = [ - { - id: 'inst_026', - text: `Client-Side Code Quality Standards (OPERATIONAL) - -All client-side JavaScript (public/js/**) must adhere to these quality standards: - -1. **Framework Usage**: Use vanilla JavaScript unless framework is explicitly approved - - No React, Vue, Angular without approval - - Prefer native DOM APIs - - Minimize external dependencies - -2. **XSS Prevention**: Include HTML escaping for all user-generated content - - Implement escapeHtml() function - - Use textContent instead of innerHTML where possible - - Sanitize all dynamic content before rendering - -3. **URL Portability**: Use relative URLs (no hardcoded hosts) - - βœ“ Good: "/api/blog", "/blog.html" - - βœ— Bad: "http://localhost:9000/api/blog", "https://agenticgovernance.digital/blog.html" - - Ensures code works in dev, staging, and production - -4. **Performance**: Implement debouncing for search inputs - - Minimum 300ms debounce for search/filter inputs - - Prevents excessive API calls and DOM updates - - Use setTimeout/clearTimeout pattern - -5. **Event Handling**: Use event delegation for dynamic elements - - Attach listeners to parent containers - - Use event.target.closest() for delegation - - Prevents memory leaks from repeated listener attachment - -6. **User Experience**: Include loading, error, and empty states - - Loading: Spinner or skeleton UI - - Error: User-friendly error message with recovery action - - Empty: Helpful message explaining why no data exists - -7. **Linting**: Pass ESLint validation with zero warnings - - Run: npx eslint --max-warnings 0 - - Fix all auto-fixable issues - - Manually resolve remaining warnings - -**Validation**: -- Check for escapeHtml() function -- grep for hardcoded URLs (localhost, production domain) -- Verify debounce implementation on search inputs -- Confirm event delegation usage -- Run ESLint with --max-warnings 0 - -**Boundary Classification**: TECHNICAL (safe for automation) -These are objective, testable code quality standards with no values component.`, - - quadrant: 'OPERATIONAL', - persistence: 'MEDIUM', - scope: 'PROJECT_SPECIFIC', - applicableProjects: ['tractatus'], - category: 'technical', - priority: 70, - temporalScope: 'PROJECT', - source: 'user_instruction', - createdBy: 'claude_code', - active: true, - notes: 'Created after blog implementation validation. Emerged from CSP violations in navbar.js and need for consistent client-side code quality.', - examples: [ - 'XSS Prevention: function escapeHtml(text) { const div = document.createElement("div"); div.textContent = text; return div.innerHTML; }', - 'Debouncing: let timeout; input.addEventListener("input", (e) => { clearTimeout(timeout); timeout = setTimeout(() => filter(e.target.value), 300); });', - 'Event Delegation: container.addEventListener("click", (e) => { const btn = e.target.closest(".btn"); if (btn) handleClick(btn); });' - ], - relatedRules: ['inst_008', 'inst_027'] - }, - - { - id: 'inst_027', - text: `Production Deployment Checklist (TACTICAL) - -Before deploying to production, verify ALL of the following: - -**1. Code Cleanliness** - - [ ] No console.log() statements (console.error() allowed for error handling) - - [ ] No console.debug(), console.warn() in production code - - [ ] No TODO, FIXME, DEBUG, HACK, or XXX comments - - [ ] No commented-out code blocks - -**2. Environment Independence** - - [ ] No hardcoded localhost URLs - - [ ] No hardcoded production URLs (use relative paths) - - [ ] No hardcoded IP addresses - - [ ] Environment variables used for configuration - -**3. Security Validation** - - [ ] CSP compliance (inst_008) validated on all HTML/JS files - - [ ] No inline event handlers (onclick, onload, etc.) - - [ ] No inline styles (use CSS classes) - - [ ] No inline scripts - - [ ] No javascript: URLs - -**4. File Organization** - - [ ] All files in production-ready locations (public/, src/) - - [ ] No temporary files (.tmp, .bak, ~) - - [ ] No development-only files - - [ ] .rsyncignore excludes sensitive files - -**5. Cache Busting** - - [ ] CSS version parameter updated (?v=TIMESTAMP) - - [ ] JavaScript version parameter updated (?v=TIMESTAMP) - - [ ] Image version parameters if needed - -**6. Sensitive Data Protection** - - [ ] .env files NOT included in deployment - - [ ] CLAUDE.md NOT included (verify in .rsyncignore) - - [ ] Session state (.claude/) NOT included - - [ ] No API keys, secrets, or credentials in code - -**7. Testing** - - [ ] Manual testing in development environment - - [ ] All API endpoints return expected responses - - [ ] Error states display correctly - - [ ] Loading states work - - [ ] Mobile responsive layout verified - -**Validation Commands**: -\`\`\`bash -# Check for console statements -grep -r "console\\.log" public/ || echo "βœ“ No console.log found" - -# Check for development comments -grep -r "TODO\\|FIXME\\|DEBUG" public/ || echo "βœ“ No dev comments found" - -# Check for hardcoded URLs -grep -r "localhost\\|http://\\|https://" public/ | grep -v ".html" || echo "βœ“ No hardcoded URLs found" - -# Verify CSP compliance -node scripts/pre-action-check.js file-edit public/index.html "Deployment validation" - -# Verify .rsyncignore coverage -grep "CLAUDE.md" .rsyncignore && grep ".claude/" .rsyncignore && echo "βœ“ Sensitive files excluded" -\`\`\` - -**Deployment Process**: -1. Run all validation commands above -2. Execute: ./scripts/deploy-full-project-SAFE.sh -3. Review dry-run output carefully -4. Confirm deployment -5. SSH to production and verify sensitive files NOT deployed -6. Restart service: sudo systemctl restart tractatus -7. Test production site: https://agenticgovernance.digital - -**Boundary Classification**: TECHNICAL (automated checklist) -All checks are objective and can be automated. No values decisions required.`, - - quadrant: 'TACTICAL', - persistence: 'HIGH', - scope: 'UNIVERSAL', - applicableProjects: ['*'], - category: 'process', - priority: 85, - temporalScope: 'PERMANENT', - source: 'user_instruction', - createdBy: 'claude_code', - active: true, - notes: 'Created after blog implementation validation. Prevents common deployment errors like console.log statements, hardcoded URLs, and CSP violations from reaching production.', - examples: [ - 'Pre-deployment validation: grep -r "console.log" public/ && echo "FAIL: console.log found" && exit 1', - 'CSP validation: node scripts/pre-action-check.js file-edit public/blog.html "Deployment check"', - 'Sensitive file check: ssh production "ls /var/www/tractatus/CLAUDE.md 2>/dev/null && echo FAIL || echo OK"' - ], - relatedRules: ['inst_008', 'inst_026'] - } -]; - -async function addRules() { - try { - console.log('Connecting to MongoDB:', MONGODB_URI); - await mongoose.connect(MONGODB_URI); - console.log('βœ“ Connected to MongoDB\n'); - - for (const rule of rules) { - console.log(`Adding ${rule.id}...`); - - // Check if rule already exists - const existing = await GovernanceRule.findOne({ id: rule.id }); - - if (existing) { - console.log(` ⚠ Rule ${rule.id} already exists. Updating...`); - await GovernanceRule.updateOne({ id: rule.id }, rule); - console.log(` βœ“ Updated ${rule.id}`); - } else { - await GovernanceRule.create(rule); - console.log(` βœ“ Created ${rule.id}`); - } - - console.log(` Quadrant: ${rule.quadrant}`); - console.log(` Persistence: ${rule.persistence}`); - console.log(` Scope: ${rule.scope}`); - console.log(` Priority: ${rule.priority}`); - console.log(''); - } - - console.log('βœ“ All rules added successfully!\n'); - - // Show summary - const allRules = await GovernanceRule.find({ active: true }).sort({ id: 1 }); - console.log(`Total active rules: ${allRules.length}`); - console.log('Rule IDs:', allRules.map(r => r.id).join(', ')); - - await mongoose.disconnect(); - console.log('\nβœ“ Disconnected from MongoDB'); - process.exit(0); - - } catch (error) { - console.error('Error adding rules:', error); - await mongoose.disconnect(); - process.exit(1); - } -} - -addRules(); diff --git a/scripts/add-progress-bar-helpers.js b/scripts/add-progress-bar-helpers.js deleted file mode 100644 index f4ee9763..00000000 --- a/scripts/add-progress-bar-helpers.js +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env node - -/** - * Add setProgressBarWidths helper and calls - */ - -const fs = require('fs'); -const path = require('path'); - -const helper = ` - // Set widths/heights from data attributes (CSP compliance) - function setProgressBarWidths(container) { - const elements = container.querySelectorAll('[data-width], [data-height]'); - elements.forEach(el => { - if (el.dataset.width) el.style.width = el.dataset.width + '%'; - if (el.dataset.height) el.style.height = el.dataset.height + '%'; - }); - }`; - -// audit-analytics.js -const auditFile = path.join(__dirname, '../public/js/admin/audit-analytics.js'); -let auditContent = fs.readFileSync(auditFile, 'utf8'); - -if (!auditContent.includes('setProgressBarWidths')) { - // Add helper before last }) - const lastBrace = auditContent.lastIndexOf('})();'); - auditContent = auditContent.slice(0, lastBrace) + helper + '\n' + auditContent.slice(lastBrace); - - // Add calls after innerHTML assignments with progress bars - auditContent = auditContent.replace( - /chartEl\.innerHTML = html;/g, - 'chartEl.innerHTML = html; setProgressBarWidths(chartEl);' - ); - auditContent = auditContent.replace( - /chartEl\.innerHTML = `
\$\{html\}<\/div>`;/g, - 'chartEl.innerHTML = `
${html}
`; setProgressBarWidths(chartEl);' - ); - - fs.writeFileSync(auditFile, auditContent); - console.log('βœ“ Fixed audit-analytics.js'); -} - -// rule-manager.js -const ruleManagerFile = path.join(__dirname, '../public/js/admin/rule-manager.js'); -let ruleManagerContent = fs.readFileSync(ruleManagerFile, 'utf8'); - -if (!ruleManagerContent.includes('setProgressBarWidths')) { - // Add helper before last }) - const lastBrace = ruleManagerContent.lastIndexOf('})();'); - ruleManagerContent = ruleManagerContent.slice(0, lastBrace) + helper + '\n' + ruleManagerContent.slice(lastBrace); - - // Add calls after container.innerHTML assignments - ruleManagerContent = ruleManagerContent.replace( - /(container\.innerHTML = `[\s\S]*?`;)/g, - '$1 setProgressBarWidths(container);' - ); - - fs.writeFileSync(ruleManagerFile, ruleManagerContent); - console.log('βœ“ Fixed rule-manager.js'); -} - -// rule-editor.js -const ruleEditorFile = path.join(__dirname, '../public/js/admin/rule-editor.js'); -let ruleEditorContent = fs.readFileSync(ruleEditorFile, 'utf8'); - -if (!ruleEditorContent.includes('setProgressBarWidths')) { - // Add helper before last }) - const lastBrace = ruleEditorContent.lastIndexOf('})();'); - ruleEditorContent = ruleEditorContent.slice(0, lastBrace) + helper + '\n' + ruleEditorContent.slice(lastBrace); - - // Add calls after modal content is set - ruleEditorContent = ruleEditorContent.replace( - /(modalContent\.innerHTML = `[\s\S]*?`;)(\s+\/\/ Show modal)/g, - '$1 setProgressBarWidths(modalContent);$2' - ); - - fs.writeFileSync(ruleEditorFile, ruleEditorContent); - console.log('βœ“ Fixed rule-editor.js'); -} - -console.log('\nβœ… Progress bar helpers added\n'); diff --git a/scripts/add-sections-from-db-markdown.js b/scripts/add-sections-from-db-markdown.js deleted file mode 100644 index 95ca38ac..00000000 --- a/scripts/add-sections-from-db-markdown.js +++ /dev/null @@ -1,325 +0,0 @@ -#!/usr/bin/env node -/** - * Add Card View Sections to Documents (Using DB Markdown) - * - * Generates sections from the content_markdown field stored in the database - * for documents that don't have corresponding MD files on disk. - */ - -require('dotenv').config(); - -const { connect, close } = require('../src/utils/db.util'); -const Document = require('../src/models/Document.model'); -const { marked } = require('marked'); - -// List of document slugs that need sections -const SLUGS_NEEDING_SECTIONS = [ - // 5 newly imported archives - 'case-studies-real-world-llm-failure-modes-appendix', - 'implementation-guide-python-examples', - 'tractatus-framework-enforcement-claude-code', - 'research-topic-concurrent-session-architecture', - 'research-topic-rule-proliferation-transactional-overhead', - - // 5 technical reference docs - 'implementation-roadmap-24-month-deployment-plan', - 'api-reference-complete', - 'api-javascript-examples', - 'api-python-examples', - 'openapi-specification', - - // 5 case studies - 'the-27027-incident-a-case-study-in-pattern-recognition-bias', - 'when-frameworks-fail-and-why-thats-ok', - 'our-framework-in-action-detecting-and-correcting-ai-fabrications', - 'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery', - 'case-studies-real-world-llm-failure-modes', - - // 2 Phase 5 PoC summaries - 'phase-5-poc-session-1-summary', - 'phase-5-poc-session-2-summary' -]; - -function extractSectionsFromMarkdown(markdown) { - const lines = markdown.split('\n'); - const sections = []; - let currentSection = null; - let contentBuffer = []; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - - // Match H2 headers (## Title) - const h2Match = line.match(/^## (.+)$/); - if (h2Match) { - // Save previous section if exists - if (currentSection) { - currentSection.content_md = contentBuffer.join('\n').trim(); - sections.push(currentSection); - } - - // Start new section - currentSection = { - title: h2Match[1].trim(), - content_md: '' - }; - contentBuffer = []; - continue; - } - - // Collect content for current section - if (currentSection) { - contentBuffer.push(line); - } - } - - // Save final section - if (currentSection) { - currentSection.content_md = contentBuffer.join('\n').trim(); - sections.push(currentSection); - } - - return sections; -} - -function generateExcerpt(markdown, maxLength = 150) { - let text = markdown - .replace(/^#+\s+/gm, '') - .replace(/\*\*(.+?)\*\*/g, '$1') - .replace(/\*(.+?)\*/g, '$1') - .replace(/\[(.+?)\]\(.+?\)/g, '$1') - .replace(/`(.+?)`/g, '$1') - .replace(/^[-*+]\s+/gm, '') - .replace(/^\d+\.\s+/gm, '') - .replace(/\n{2,}/g, ' ') - .trim(); - - if (text.length > maxLength) { - text = text.substring(0, maxLength).trim(); - const lastPeriod = text.lastIndexOf('.'); - if (lastPeriod > maxLength * 0.7) { - text = text.substring(0, lastPeriod + 1); - } else { - text += '...'; - } - } - - return text; -} - -function estimateReadingTime(text) { - const wordCount = text.split(/\s+/).length; - const minutes = Math.ceil(wordCount / 200); - return Math.max(1, minutes); -} - -function classifySection(title, content) { - const titleLower = title.toLowerCase(); - const contentLower = content.toLowerCase(); - - if ( - titleLower.includes('limitation') || - titleLower.includes('failure') || - titleLower.includes('warning') || - titleLower.includes('security') || - titleLower.includes('risk') || - content.match(/⚠️|critical|warning|caution|danger/gi) - ) { - return 'critical'; - } - - if ( - titleLower.includes('glossary') || - titleLower.includes('reference') || - titleLower.includes('contact') || - titleLower.includes('license') || - titleLower.includes('getting started') - ) { - return 'reference'; - } - - if ( - titleLower.includes('technical') || - titleLower.includes('architecture') || - titleLower.includes('implementation') || - titleLower.includes('integration') || - titleLower.includes('api') || - content.match(/```|`[a-z]+`|function|class|const|import/gi) - ) { - return 'technical'; - } - - if ( - titleLower.includes('how') || - titleLower.includes('guide') || - titleLower.includes('tutorial') || - titleLower.includes('example') || - titleLower.includes('use case') || - titleLower.includes('should use') || - titleLower.includes('contributing') - ) { - return 'practical'; - } - - return 'conceptual'; -} - -function determineTechnicalLevel(content) { - const contentLower = content.toLowerCase(); - - if ( - content.match(/```[\s\S]+```/g) || - contentLower.includes('api') || - contentLower.includes('implementation') || - contentLower.includes('integration') || - contentLower.includes('architecture') - ) { - return 'advanced'; - } - - if ( - contentLower.includes('service') || - contentLower.includes('component') || - contentLower.includes('system') || - contentLower.includes('framework') - ) { - return 'intermediate'; - } - - return 'beginner'; -} - -function generateSlug(title) { - return title - .toLowerCase() - .replace(/[^a-z0-9\s-]/g, '') - .replace(/\s+/g, '-') - .replace(/-+/g, '-') - .replace(/^-|-$/g, ''); -} - -async function addSectionsToDocument(slug) { - console.log(`\nπŸ“„ Processing: ${slug}`); - - try { - // Find document - const doc = await Document.findBySlug(slug); - if (!doc) { - console.log(` ❌ Document not found`); - return { success: false, reason: 'not_found' }; - } - - // Check if already has sections - if (doc.sections && doc.sections.length > 0) { - console.log(` ⏭️ Already has ${doc.sections.length} sections`); - return { success: false, reason: 'has_sections' }; - } - - // Check if has content_markdown - if (!doc.content_markdown) { - console.log(` ❌ No content_markdown field`); - return { success: false, reason: 'no_markdown' }; - } - - // Extract sections from markdown - const rawSections = extractSectionsFromMarkdown(doc.content_markdown); - - if (rawSections.length === 0) { - console.log(` ⚠️ No H2 sections found in markdown`); - return { success: false, reason: 'no_h2' }; - } - - console.log(` πŸ“ Found ${rawSections.length} sections`); - - // Process each section - const sections = []; - for (let i = 0; i < rawSections.length; i++) { - const raw = rawSections[i]; - - if (!raw.content_md.trim()) { - continue; - } - - const content_html = marked(raw.content_md); - const excerpt = generateExcerpt(raw.content_md); - const readingTime = estimateReadingTime(raw.content_md); - const category = classifySection(raw.title, raw.content_md); - const technicalLevel = determineTechnicalLevel(raw.content_md); - const sectionSlug = generateSlug(raw.title); - - sections.push({ - number: i + 1, - title: raw.title, - slug: sectionSlug, - content_html, - excerpt, - readingTime, - technicalLevel, - category - }); - } - - // Update document - const updated = await Document.update(doc._id.toString(), { sections }); - - if (!updated) { - console.log(` ❌ Failed to update`); - return { success: false, reason: 'update_failed' }; - } - - console.log(` βœ… Added ${sections.length} sections`); - sections.forEach(s => { - console.log(` ${s.number}. ${s.title} (${s.category}, ${s.readingTime}min)`); - }); - - return { success: true, sections: sections.length }; - - } catch (error) { - console.error(` ❌ Error: ${error.message}`); - return { success: false, error: error.message }; - } -} - -async function main() { - try { - console.log('πŸš€ Adding Card View Sections to 17 Documents\n'); - console.log('═══════════════════════════════════════════════════\n'); - - await connect(); - - let added = 0; - let skipped = 0; - let noH2 = 0; - let failed = 0; - - for (const slug of SLUGS_NEEDING_SECTIONS) { - const result = await addSectionsToDocument(slug); - - if (result.success) { - added++; - } else if (result.reason === 'has_sections') { - skipped++; - } else if (result.reason === 'no_h2') { - noH2++; - } else { - failed++; - } - } - - console.log('\n═══════════════════════════════════════════════════'); - console.log('\nπŸ“Š Summary:'); - console.log(` βœ… Added sections: ${added}`); - console.log(` ⏭️ Skipped (already have sections): ${skipped}`); - console.log(` ⚠️ No H2 sections found: ${noH2}`); - console.log(` ❌ Failed: ${failed}`); - console.log(` πŸ“¦ Total: ${SLUGS_NEEDING_SECTIONS.length}`); - - await close(); - - } catch (error) { - console.error('\n❌ Fatal error:', error); - process.exit(1); - } -} - -main(); diff --git a/scripts/add-sections-to-17-docs.js b/scripts/add-sections-to-17-docs.js deleted file mode 100644 index a1e26d54..00000000 --- a/scripts/add-sections-to-17-docs.js +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env node -/** - * Add Card View Sections to 17 Documents - * - * Adds card view sections to: - * - 5 newly imported archives - * - 12 existing documents without sections - */ - -require('dotenv').config(); - -const fs = require('fs'); -const path = require('path'); -const { connect, close } = require('../src/utils/db.util'); -const Document = require('../src/models/Document.model'); -const { processMarkdownFile } = require('./generate-card-sections.js'); - -const DOCS_TO_PROCESS = [ - // 5 newly imported archives - { slug: 'case-studies-real-world-llm-failure-modes-appendix', mdPath: 'docs/markdown/case-studies.md' }, - { slug: 'implementation-guide-python-examples', mdPath: 'docs/api/examples-python.md' }, - { slug: 'tractatus-framework-enforcement-claude-code', mdPath: 'docs/claude-code-framework-enforcement.md' }, - { slug: 'research-topic-concurrent-session-architecture', mdPath: 'docs/research/concurrent-session-architecture-limitations.md' }, - { slug: 'research-topic-rule-proliferation-transactional-overhead', mdPath: 'docs/research/rule-proliferation-and-transactional-overhead.md' }, - - // 5 technical reference docs without sections - { slug: 'implementation-roadmap-24-month-deployment-plan', mdPath: 'docs/markdown/implementation-roadmap-24-month-deployment-plan.md' }, - { slug: 'api-reference-complete', mdPath: 'docs/markdown/api-reference-complete.md' }, - { slug: 'api-javascript-examples', mdPath: 'docs/api/examples-javascript.md' }, - { slug: 'api-python-examples', mdPath: 'docs/api/examples-python.md' }, - { slug: 'openapi-specification', mdPath: 'docs/markdown/openapi-specification.md' }, - - // 5 case studies without sections - { slug: 'the-27027-incident-a-case-study-in-pattern-recognition-bias', mdPath: 'docs/case-studies/27027-incident-detailed-analysis.md' }, - { slug: 'when-frameworks-fail-and-why-thats-ok', mdPath: 'docs/case-studies/when-frameworks-fail-oct-2025.md' }, - { slug: 'our-framework-in-action-detecting-and-correcting-ai-fabrications', mdPath: 'docs/case-studies/framework-in-action-oct-2025.md' }, - { slug: 'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery', mdPath: 'docs/case-studies/real-world-governance-case-study-oct-2025.md' }, - { slug: 'case-studies-real-world-llm-failure-modes', mdPath: 'docs/markdown/case-studies.md' }, - - // 2 Phase 5 PoC summaries - { slug: 'phase-5-poc-session-1-summary', mdPath: 'docs/markdown/phase-5-session1-summary.md' }, - { slug: 'phase-5-poc-session-2-summary', mdPath: 'docs/markdown/phase-5-session2-summary.md' } -]; - -async function addSectionsToDocument(docInfo) { - console.log(`\nπŸ“„ Processing: ${docInfo.slug}`); - - try { - // Check if document exists - const doc = await Document.findBySlug(docInfo.slug); - if (!doc) { - console.log(` ❌ Document not found in database`); - return { success: false, reason: 'not_found' }; - } - - // Check if already has sections - if (doc.sections && doc.sections.length > 0) { - console.log(` ⏭️ Already has ${doc.sections.length} sections, skipping`); - return { success: false, reason: 'has_sections' }; - } - - // Build full path to markdown file - const fullPath = path.join('/home/theflow/projects/tractatus', docInfo.mdPath); - - // Check if markdown file exists - if (!fs.existsSync(fullPath)) { - console.log(` ❌ Markdown file not found: ${fullPath}`); - return { success: false, reason: 'md_not_found' }; - } - - // Generate sections - console.log(` πŸ“ Generating sections from: ${docInfo.mdPath}`); - const sections = await processMarkdownFile(fullPath); - - if (!sections || sections.length === 0) { - console.log(` ⚠️ No sections generated (possibly no H2 headers)`); - return { success: false, reason: 'no_sections' }; - } - - // Update document with sections - const updated = await Document.update(doc._id.toString(), { sections }); - - if (!updated) { - console.log(` ❌ Failed to update document`); - return { success: false, reason: 'update_failed' }; - } - - console.log(` βœ… Added ${sections.length} sections`); - return { success: true, sections: sections.length }; - - } catch (error) { - console.error(` ❌ Error: ${error.message}`); - return { success: false, error: error.message }; - } -} - -async function main() { - try { - console.log('πŸš€ Adding Card View Sections to 17 Documents\n'); - console.log('═══════════════════════════════════════════════════\n'); - - await connect(); - - let added = 0; - let skipped = 0; - let notFound = 0; - let failed = 0; - - for (const docInfo of DOCS_TO_PROCESS) { - const result = await addSectionsToDocument(docInfo); - - if (result.success) { - added++; - } else if (result.reason === 'has_sections') { - skipped++; - } else if (result.reason === 'not_found' || result.reason === 'md_not_found') { - notFound++; - } else { - failed++; - } - } - - console.log('\n═══════════════════════════════════════════════════'); - console.log('\nπŸ“Š Summary:'); - console.log(` βœ… Added sections: ${added}`); - console.log(` ⏭️ Skipped (already have sections): ${skipped}`); - console.log(` ❌ Not found: ${notFound}`); - console.log(` ❌ Failed: ${failed}`); - console.log(` πŸ“¦ Total processed: ${DOCS_TO_PROCESS.length}`); - - await close(); - - } catch (error) { - console.error('\n❌ Fatal error:', error); - process.exit(1); - } -} - -main(); diff --git a/scripts/add-sections-to-documents.js b/scripts/add-sections-to-documents.js deleted file mode 100644 index bff9755a..00000000 --- a/scripts/add-sections-to-documents.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Add section-based cards to all existing documents - * Parses documents and adds sections array for card-based UI - */ - -const fs = require('fs'); -const path = require('path'); -const { MongoClient } = require('mongodb'); -const { parseDocumentSections } = require('../src/utils/document-section-parser'); -const { markdownToHtml } = require('../src/utils/markdown.util'); - -const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_prod'; -const DOCS_DIR = process.env.DOCS_DIR || '/var/www/tractatus/docs/markdown'; - -async function main() { - console.log('=== Adding Sections to Documents ===\n'); - - const client = new MongoClient(MONGODB_URI); - - try { - await client.connect(); - const db = client.db(); - const collection = db.collection('documents'); - - // Get all documents - const documents = await collection.find({}).toArray(); - console.log(`Found ${documents.length} documents in database\n`); - - const markdownFiles = { - 'tractatus-agentic-governance-system-glossary-of-terms': 'GLOSSARY.md', - 'introduction-to-the-tractatus-framework': 'introduction.md', - 'core-concepts-of-the-tractatus-framework': 'core-concepts.md', - 'implementation-guide': 'implementation-guide.md', - 'case-studies-real-world-llm-failure-modes': 'case-studies.md' - }; - - for (const doc of documents) { - console.log(`Processing: ${doc.title}`); - - const markdownFile = markdownFiles[doc.slug]; - if (!markdownFile) { - console.log(` ⚠ No markdown file found for ${doc.slug}`); - continue; - } - - const filePath = path.join(DOCS_DIR, markdownFile); - if (!fs.existsSync(filePath)) { - console.log(` ⚠ File not found: ${filePath}`); - continue; - } - - // Read markdown content - const markdown = fs.readFileSync(filePath, 'utf-8'); - - // Parse sections - const sections = parseDocumentSections(markdown, doc.content_html); - - // Add HTML content to each section - const sectionsWithHtml = sections.map(section => ({ - ...section, - content_html: markdownToHtml(section.content) - })); - - console.log(` βœ“ Parsed ${sections.length} sections`); - - // Category breakdown - const categoryCount = {}; - sectionsWithHtml.forEach(s => { - categoryCount[s.category] = (categoryCount[s.category] || 0) + 1; - }); - console.log(` Categories:`, categoryCount); - - // Technical level breakdown - const levelCount = {}; - sectionsWithHtml.forEach(s => { - levelCount[s.technicalLevel] = (levelCount[s.technicalLevel] || 0) + 1; - }); - console.log(` Levels:`, levelCount); - - // Update document with sections - await collection.updateOne( - { _id: doc._id }, - { - $set: { - sections: sectionsWithHtml, - 'metadata.sections_count': sections.length, - 'metadata.last_section_update': new Date() - } - } - ); - - console.log(` βœ“ Updated document\n`); - } - - console.log('=== Section Addition Complete ==='); - - } catch (error) { - console.error('Error:', error); - process.exit(1); - } finally { - await client.close(); - } -} - -main(); diff --git a/scripts/analyze-instruction-violations.js b/scripts/analyze-instruction-violations.js deleted file mode 100755 index 8028c14d..00000000 --- a/scripts/analyze-instruction-violations.js +++ /dev/null @@ -1,366 +0,0 @@ -#!/usr/bin/env node - -/** - * Instruction History Analytics - * - * Analyzes instruction-history.json to provide insights into: - * - Instruction usage patterns - * - Most violated instructions - * - Instructions never referenced - * - Quadrant distribution - * - Enforcement effectiveness - * - * Usage: node scripts/analyze-instruction-violations.js - */ - -const fs = require('fs'); -const path = require('path'); - -const INSTRUCTION_HISTORY_PATH = path.join(__dirname, '../.claude/instruction-history.json'); -const INCIDENTS_PATH = path.join(__dirname, '../.claude/framework-incidents.json'); - -/** - * Color output helpers - */ -const colors = { - reset: '\x1b[0m', - bright: '\x1b[1m', - green: '\x1b[32m', - yellow: '\x1b[33m', - blue: '\x1b[34m', - red: '\x1b[31m', - cyan: '\x1b[36m', - magenta: '\x1b[35m' -}; - -function log(message, color = 'reset') { - console.log(`${colors[color]}${message}${colors.reset}`); -} - -function header(message) { - console.log(''); - log('═'.repeat(80), 'cyan'); - log(` ${message}`, 'bright'); - log('═'.repeat(80), 'cyan'); - console.log(''); -} - -function section(message) { - console.log(''); - log(`β–Ά ${message}`, 'blue'); -} - -/** - * Load instruction history - */ -function loadInstructions() { - try { - const data = fs.readFileSync(INSTRUCTION_HISTORY_PATH, 'utf8'); - return JSON.parse(data); - } catch (err) { - log(`Error loading instruction history: ${err.message}`, 'red'); - process.exit(1); - } -} - -/** - * Load framework incidents (if exists) - */ -function loadIncidents() { - try { - if (!fs.existsSync(INCIDENTS_PATH)) { - return { incidents: [] }; - } - const data = fs.readFileSync(INCIDENTS_PATH, 'utf8'); - return JSON.parse(data); - } catch (err) { - log(`Warning: Could not load incidents database: ${err.message}`, 'yellow'); - return { incidents: [] }; - } -} - -/** - * Analyze instruction usage - */ -function analyzeInstructions(history) { - const instructions = history.instructions || []; - const active = instructions.filter(i => i.active); - const inactive = instructions.filter(i => !i.active); - - // Quadrant distribution - const byQuadrant = { - STRATEGIC: active.filter(i => i.quadrant === 'STRATEGIC').length, - OPERATIONAL: active.filter(i => i.quadrant === 'OPERATIONAL').length, - TACTICAL: active.filter(i => i.quadrant === 'TACTICAL').length, - SYSTEM: active.filter(i => i.quadrant === 'SYSTEM').length, - STOCHASTIC: active.filter(i => i.quadrant === 'STOCHASTIC').length - }; - - // Persistence distribution - const byPersistence = { - HIGH: active.filter(i => i.persistence === 'HIGH').length, - MEDIUM: active.filter(i => i.persistence === 'MEDIUM').length, - LOW: active.filter(i => i.persistence === 'LOW').length, - VARIABLE: active.filter(i => i.persistence === 'VARIABLE').length - }; - - // Temporal scope distribution - const byScope = { - PERMANENT: active.filter(i => i.temporal_scope === 'PERMANENT').length, - PROJECT: active.filter(i => i.temporal_scope === 'PROJECT').length, - PHASE: active.filter(i => i.temporal_scope === 'PHASE').length, - SESSION: active.filter(i => i.temporal_scope === 'SESSION').length - }; - - return { - total: instructions.length, - active: active.length, - inactive: inactive.length, - byQuadrant, - byPersistence, - byScope, - instructions: active - }; -} - -/** - * Analyze violations from incidents database - */ -function analyzeViolations(incidents) { - const violations = {}; - - incidents.forEach(incident => { - const instId = incident.instruction_violated || incident.id; - if (!violations[instId]) { - violations[instId] = { - count: 0, - tokens_wasted: 0, - incidents: [] - }; - } - violations[instId].count++; - violations[instId].tokens_wasted += incident.tokens_wasted || 0; - violations[instId].incidents.push(incident); - }); - - return violations; -} - -/** - * Find never-referenced instructions - */ -function findUnusedInstructions(instructions, violations) { - const neverViolated = instructions.filter(i => !violations[i.id]); - - return { - neverViolated: neverViolated.map(i => i.id), - strategicNeverViolated: neverViolated.filter(i => i.quadrant === 'STRATEGIC').map(i => i.id) - }; -} - -/** - * Calculate enforcement effectiveness - */ -function calculateEnforcement(instructions, violations) { - // Hook-enforced instructions (those with architectural enforcement) - const hookEnforced = instructions.filter(i => - i.enforcement === 'architectural' || - i.enforcement === 'hook' || - i.notes?.includes('hook') || - i.notes?.includes('architectural') - ); - - const voluntary = instructions.filter(i => - !hookEnforced.includes(i) - ); - - // Calculate violation rates - const hookEnforcedViolations = hookEnforced.filter(i => violations[i.id]); - const voluntaryViolations = voluntary.filter(i => violations[i.id]); - - const hookEnforcementRate = hookEnforced.length > 0 - ? ((hookEnforced.length - hookEnforcedViolations.length) / hookEnforced.length * 100).toFixed(1) - : 0; - - const voluntaryComplianceRate = voluntary.length > 0 - ? ((voluntary.length - voluntaryViolations.length) / voluntary.length * 100).toFixed(1) - : 0; - - return { - hookEnforced: hookEnforced.length, - voluntary: voluntary.length, - hookEnforcementRate, - voluntaryComplianceRate, - hookEnforcedViolations: hookEnforcedViolations.length, - voluntaryViolations: voluntaryViolations.length - }; -} - -/** - * Main analytics - */ -function main() { - header('Instruction History Analytics'); - - // Load data - const history = loadInstructions(); - const incidentsData = loadIncidents(); - const incidents = incidentsData.incidents || []; - - log(`πŸ“Š Analyzing ${history.instructions?.length || 0} instructions and ${incidents.length} incidents`, 'cyan'); - - // Analyze - const analysis = analyzeInstructions(history); - const violations = analyzeViolations(incidents); - const unused = findUnusedInstructions(analysis.instructions, violations); - const enforcement = calculateEnforcement(analysis.instructions, violations); - - // Display results - - // 1. Overview - section('1. Instruction Overview'); - log(` Total instructions: ${analysis.total}`, 'cyan'); - log(` Active: ${analysis.active}`, 'green'); - log(` Inactive: ${analysis.inactive}`, 'yellow'); - - // 2. Distribution by Quadrant - section('2. Distribution by Quadrant'); - Object.entries(analysis.byQuadrant).forEach(([quadrant, count]) => { - const bar = 'β–ˆ'.repeat(Math.ceil(count / 2)); - log(` ${quadrant.padEnd(12)}: ${count.toString().padStart(2)} ${bar}`, 'cyan'); - }); - - // 3. Distribution by Persistence - section('3. Distribution by Persistence'); - Object.entries(analysis.byPersistence).forEach(([level, count]) => { - const bar = 'β–ˆ'.repeat(Math.ceil(count / 2)); - log(` ${level.padEnd(12)}: ${count.toString().padStart(2)} ${bar}`, 'cyan'); - }); - - // 4. Distribution by Temporal Scope - section('4. Distribution by Temporal Scope'); - Object.entries(analysis.byScope).forEach(([scope, count]) => { - const bar = 'β–ˆ'.repeat(Math.ceil(count / 2)); - log(` ${scope.padEnd(12)}: ${count.toString().padStart(2)} ${bar}`, 'cyan'); - }); - - // 5. Most Violated Instructions - section('5. Most Violated Instructions'); - const violationList = Object.entries(violations) - .sort((a, b) => b[1].count - a[1].count); - - if (violationList.length === 0) { - log(' βœ… No violations recorded', 'green'); - } else { - violationList.slice(0, 10).forEach(([instId, data]) => { - const instruction = analysis.instructions.find(i => i.id === instId); - const text = instruction ? instruction.text.substring(0, 60) + '...' : 'Unknown instruction'; - log(` ${instId}: ${data.count} violation(s), ${data.tokens_wasted.toLocaleString()} tokens wasted`, 'red'); - log(` "${text}"`, 'yellow'); - }); - } - - // 6. Never Violated Instructions - section('6. Never Violated Instructions'); - if (unused.neverViolated.length === 0) { - log(' ⚠️ All instructions have been violated at least once!', 'yellow'); - } else { - log(` ${unused.neverViolated.length} instructions with 100% compliance:`, 'green'); - unused.neverViolated.slice(0, 10).forEach(instId => { - const instruction = analysis.instructions.find(i => i.id === instId); - if (instruction) { - log(` ${instId}: ${instruction.text.substring(0, 70)}`, 'cyan'); - } - }); - if (unused.neverViolated.length > 10) { - log(` ... and ${unused.neverViolated.length - 10} more`, 'cyan'); - } - } - - // 7. Enforcement Effectiveness - section('7. Enforcement Effectiveness'); - log(` Hook-enforced instructions: ${enforcement.hookEnforced}`, 'cyan'); - log(` Violations: ${enforcement.hookEnforcedViolations}`, enforcement.hookEnforcedViolations > 0 ? 'red' : 'green'); - log(` Compliance rate: ${enforcement.hookEnforcementRate}%`, enforcement.hookEnforcementRate >= 95 ? 'green' : 'yellow'); - - console.log(''); - log(` Voluntary compliance instructions: ${enforcement.voluntary}`, 'cyan'); - log(` Violations: ${enforcement.voluntaryViolations}`, enforcement.voluntaryViolations > 0 ? 'red' : 'green'); - log(` Compliance rate: ${enforcement.voluntaryComplianceRate}%`, enforcement.voluntaryComplianceRate >= 95 ? 'green' : 'yellow'); - - console.log(''); - if (enforcement.hookEnforcementRate > enforcement.voluntaryComplianceRate) { - log(` βœ… Hook enforcement is ${(enforcement.hookEnforcementRate - enforcement.voluntaryComplianceRate).toFixed(1)}% more effective`, 'green'); - log(` πŸ’‘ Recommendation: Convert more voluntary compliance to architectural enforcement`, 'cyan'); - } else if (enforcement.voluntaryComplianceRate >= 95) { - log(` βœ… Voluntary compliance is working well (${enforcement.voluntaryComplianceRate}%)`, 'green'); - } else { - log(` ⚠️ Consider improving enforcement mechanisms`, 'yellow'); - } - - // 8. Recommendations - section('8. Recommendations'); - - const recommendations = []; - - // High-violation instructions needing enforcement - const highViolation = violationList.filter(([_, data]) => data.count >= 2); - if (highViolation.length > 0) { - recommendations.push({ - priority: 'HIGH', - text: `${highViolation.length} instruction(s) violated 2+ times - add architectural enforcement`, - details: highViolation.map(([id]) => id) - }); - } - - // Strategic instructions that are never violated (good!) - if (unused.strategicNeverViolated.length > 0) { - recommendations.push({ - priority: 'INFO', - text: `${unused.strategicNeverViolated.length} STRATEGIC instructions have 100% compliance - document success`, - details: unused.strategicNeverViolated.slice(0, 5) - }); - } - - // Voluntary compliance gaps - if (enforcement.voluntaryComplianceRate < 80) { - recommendations.push({ - priority: 'MEDIUM', - text: `Voluntary compliance at ${enforcement.voluntaryComplianceRate}% - convert to hooks or improve documentation`, - details: [] - }); - } - - if (recommendations.length === 0) { - log(' βœ… No recommendations - framework is performing well!', 'green'); - } else { - recommendations.forEach((rec, i) => { - const color = rec.priority === 'HIGH' ? 'red' : rec.priority === 'MEDIUM' ? 'yellow' : 'cyan'; - log(` ${i + 1}. [${rec.priority}] ${rec.text}`, color); - if (rec.details.length > 0) { - rec.details.forEach(detail => { - log(` - ${detail}`, 'cyan'); - }); - } - }); - } - - // Summary footer - header('Analytics Complete'); - console.log(''); - log(` πŸ“ˆ Key Metrics:`, 'bright'); - log(` Active Instructions: ${analysis.active}`, 'cyan'); - log(` Recorded Violations: ${incidents.length}`, incidents.length > 0 ? 'yellow' : 'green'); - log(` Tokens Wasted: ${Object.values(violations).reduce((sum, v) => sum + v.tokens_wasted, 0).toLocaleString()}`, 'red'); - log(` Hook Enforcement Rate: ${enforcement.hookEnforcementRate}%`, 'green'); - log(` Voluntary Compliance Rate: ${enforcement.voluntaryComplianceRate}%`, 'yellow'); - console.log(''); - log(` πŸ’‘ Next Steps:`, 'bright'); - log(` - Review high-violation instructions for enforcement gaps`, 'cyan'); - log(` - Document successful compliance patterns`, 'cyan'); - log(` - Convert voluntary β†’ architectural where violations occur`, 'cyan'); - console.log(''); -} - -// Run -main(); diff --git a/scripts/archive-all-internal-documents.js b/scripts/archive-all-internal-documents.js deleted file mode 100644 index a82b3ec1..00000000 --- a/scripts/archive-all-internal-documents.js +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Archive All Internal Documents - * Mass archive of project tracking, internal, and confidential documents - */ - -const { MongoClient } = require('mongodb'); - -// MongoDB connection -const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_dev'; -const DB_NAME = process.env.MONGODB_DB || 'tractatus_dev'; - -// Documents to mark as confidential (not archived, just hidden) -const CONFIDENTIAL_DOCS = [ - 'security-audit-report', - 'koha-stripe-payment-setup-guide', - 'koha-production-deployment-guide', - 'appendix-e-contact-information', - 'cover-letter-for-anthropic-submission' -]; - -// Documents to archive (project tracking, internal planning) -const ARCHIVE_PATTERNS = [ - 'phase-2-', // All Phase 2 planning docs - 'session-handoff', // All session handoffs - 'appendix-b-', // Duplicate case studies - 'implementation-roadmap', // Outdated planning - 'implementation-guide-python', // Outdated code examples - 'research-foundations-scholarly', // Academic, not practical - 'tractatus-blog-post-outlines', // Internal planning - 'tractatus-project-implementation-progress-report', // Project tracking - 'tractatus-production-comprehensive-testing-checklist', // Internal testing - 'tractatus-production-testing-results', // Test results - 'tractatus-governance-framework-test-suite', // Internal testing - 'ai-features-implementation-session' // Session tracking -]; - -async function main() { - console.log('=== Archiving All Internal Documents ===\n'); - - let client; - - try { - // Connect to MongoDB - console.log('Connecting to MongoDB...'); - client = await MongoClient.connect(MONGODB_URI); - const db = client.db(DB_NAME); - const collection = db.collection('documents'); - console.log('βœ“ Connected\n'); - - // 1. Mark confidential documents - console.log('=== Marking Confidential Documents ===\n'); - let confidentialCount = 0; - - for (const slug of CONFIDENTIAL_DOCS) { - const result = await collection.updateOne( - { slug }, - { - $set: { - visibility: 'confidential', - category: 'internal', - order: 999 - } - } - ); - - if (result.matchedCount > 0) { - console.log(`βœ“ Marked confidential: ${slug}`); - confidentialCount++; - } - } - console.log(`\nβœ“ Total confidential: ${confidentialCount}\n`); - - // 2. Archive documents matching patterns - console.log('=== Archiving Project Tracking Documents ===\n'); - let archivedCount = 0; - - const allDocs = await collection.find({ visibility: { $ne: 'confidential' } }).toArray(); - - for (const doc of allDocs) { - const shouldArchive = ARCHIVE_PATTERNS.some(pattern => - doc.slug.includes(pattern) - ); - - if (shouldArchive && doc.visibility !== 'archived') { - const result = await collection.updateOne( - { _id: doc._id }, - { - $set: { - visibility: 'archived', - category: 'project-tracking', - order: 999, - archiveNote: 'Internal project tracking document. Not relevant for public documentation.' - } - } - ); - - if (result.matchedCount > 0) { - console.log(`βœ“ Archived: ${doc.slug}`); - archivedCount++; - } - } - } - console.log(`\nβœ“ Total archived: ${archivedCount}\n`); - - // 3. Handle recent case studies (keep but categorize) - console.log('=== Categorizing Case Studies ===\n'); - const caseStudySlugs = [ - 'our-framework-in-action-detecting-and-correcting-ai-fabrications', - 'framework-governance-in-action-pre-publication-security-audit', - 'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery', - 'when-frameworks-fail-and-why-thats-ok' - ]; - - let caseStudyCount = 0; - for (const [index, slug] of caseStudySlugs.entries()) { - const result = await collection.updateOne( - { slug }, - { - $set: { - visibility: 'public', - category: 'practical', - audience: 'general', - order: 8 + index // Orders 8-11 - } - } - ); - - if (result.matchedCount > 0) { - console.log(`βœ“ Categorized: ${slug} (order: ${8 + index})`); - caseStudyCount++; - } - } - console.log(`\nβœ“ Total case studies: ${caseStudyCount}\n`); - - // Summary - console.log('=== Final Summary ===\n'); - const publicCount = await collection.countDocuments({ visibility: 'public' }); - const archivedTotal = await collection.countDocuments({ visibility: 'archived' }); - const confidentialTotal = await collection.countDocuments({ visibility: 'confidential' }); - - console.log(`πŸ“– Public documents: ${publicCount}`); - console.log(`πŸ“¦ Archived documents: ${archivedTotal}`); - console.log(`πŸ”’ Confidential documents: ${confidentialTotal}`); - console.log(`\nTotal: ${publicCount + archivedTotal + confidentialTotal} documents\n`); - - // Show public documents - console.log('=== Public Documents (Final List) ===\n'); - const publicDocs = await collection.find({ visibility: 'public' }) - .sort({ order: 1 }) - .project({ title: 1, order: 1, category: 1 }) - .toArray(); - - publicDocs.forEach(doc => { - console.log(` ${doc.order}. ${doc.title} [${doc.category}]`); - }); - - } catch (error) { - console.error('\nβœ— Error:', error.message); - console.error(error.stack); - process.exit(1); - } finally { - if (client) await client.close(); - } -} - -// Run if called directly -if (require.main === module) { - main(); -} - -module.exports = { main }; diff --git a/scripts/archive-outdated-documents.js b/scripts/archive-outdated-documents.js deleted file mode 100644 index 65701f32..00000000 --- a/scripts/archive-outdated-documents.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Archive Outdated Documents - * Sets visibility: 'archived' for 10 documents identified in audit - */ - -const { MongoClient } = require('mongodb'); - -// MongoDB connection -const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_dev'; -const DB_NAME = process.env.MONGODB_DB || 'tractatus_dev'; - -// Documents to archive with reasons -const DOCUMENTS_TO_ARCHIVE = [ - { - slug: 'introduction-to-the-tractatus-framework', - category: 'archived', - archiveNote: 'Superseded by Architectural Overview & Research Status. References outdated filesystem-only architecture.', - reason: 'Outdated architecture (pre-MongoDB)' - }, - { - slug: 'tractatus-based-llm-architecture-for-ai-safety', - category: 'archived', - archiveNote: 'Historical architecture proposal. See Architectural Overview for implemented architecture.', - reason: 'Pre-Phase 5 architecture proposal' - }, - { - slug: 'executive-brief-tractatus-based-llm-architecture-for-ai-safety', - category: 'archived', - archiveNote: 'Historical brief based on pre-Phase 5 architecture. See Architectural Overview for current status.', - reason: 'Pre-Phase 5 executive brief' - }, - { - slug: 'tractatus-framework-enforcement-for-claude-code', - category: 'archived', - archiveNote: 'Development tool documentation. See Implementation Guide for production deployment.', - reason: 'Internal development tool' - }, - { - slug: 'organizational-theory-foundations-of-the-tractatus-framework', - category: 'archived', - archiveNote: 'Academic foundations. See Core Concepts for practical overview.', - reason: 'Academic content, not practical' - }, - { - slug: 'phase-5-poc-session-1-summary', - category: 'project-tracking', - archiveNote: 'Project tracking - Phase 5 Session 1. See Architectural Overview for complete project history.', - reason: 'Project tracking' - }, - { - slug: 'phase-5-poc-session-2-summary', - category: 'project-tracking', - archiveNote: 'Project tracking - Phase 5 Session 2. See Architectural Overview for complete project history.', - reason: 'Project tracking' - }, - { - slug: 'research-scope-feasibility-of-llm-integrated-tractatus-framework', - category: 'research-proposal', - archiveNote: 'Research proposal (not completed work). See Architectural Overview for actual implementation status.', - reason: 'Research proposal' - }, - { - slug: 'research-topic-concurrent-session-architecture-limitations-in-claude-code-governance', - category: 'research-topic', - archiveNote: 'Open research question. See Architectural Overview for current architecture limitations.', - reason: 'Open research question' - }, - { - slug: 'research-topic-rule-proliferation-and-transactional-overhead-in-ai-governance', - category: 'research-topic', - archiveNote: 'Open research question. See Architectural Overview for current governance approach.', - reason: 'Open research question' - } -]; - -async function main() { - console.log('=== Archiving Outdated Documents ===\n'); - - let client; - - try { - // Connect to MongoDB - console.log('Connecting to MongoDB...'); - client = await MongoClient.connect(MONGODB_URI); - const db = client.db(DB_NAME); - const collection = db.collection('documents'); - console.log('βœ“ Connected\n'); - - let archived = 0; - let notFound = 0; - - // Archive each document - for (const doc of DOCUMENTS_TO_ARCHIVE) { - console.log(`Archiving: ${doc.slug}`); - console.log(` Reason: ${doc.reason}`); - - const result = await collection.updateOne( - { slug: doc.slug }, - { - $set: { - visibility: 'archived', - category: doc.category, - archiveNote: doc.archiveNote, - order: 999 - } - } - ); - - if (result.matchedCount > 0) { - console.log(` βœ“ Archived\n`); - archived++; - } else { - console.log(` ⚠ Not found in database\n`); - notFound++; - } - } - - // Summary - console.log('=== Summary ===\n'); - console.log(`βœ“ Archived: ${archived} documents`); - if (notFound > 0) { - console.log(`⚠ Not found: ${notFound} documents`); - } - console.log(`\nTotal processed: ${DOCUMENTS_TO_ARCHIVE.length}`); - - // Verify archives - console.log('\n=== Verification ===\n'); - const archivedCount = await collection.countDocuments({ visibility: 'archived' }); - const publicCount = await collection.countDocuments({ visibility: 'public' }); - console.log(`Archived documents: ${archivedCount}`); - console.log(`Public documents: ${publicCount}`); - - } catch (error) { - console.error('\nβœ— Error:', error.message); - console.error(error.stack); - process.exit(1); - } finally { - if (client) await client.close(); - } -} - -// Run if called directly -if (require.main === module) { - main(); -} - -module.exports = { main }; diff --git a/scripts/audit-accessibility.js b/scripts/audit-accessibility.js deleted file mode 100755 index 840a1a13..00000000 --- a/scripts/audit-accessibility.js +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env node - -/** - * Accessibility Audit Script - * - * Runs automated accessibility checks on all main pages - * using pa11y (WCAG 2.1 AA standard) - * - * Copyright 2025 Tractatus Project - * Licensed under Apache License 2.0 - */ - -const pa11y = require('pa11y'); -const fs = require('fs'); -const path = require('path'); - -const colors = { - reset: '\x1b[0m', - bright: '\x1b[1m', - green: '\x1b[32m', - yellow: '\x1b[33m', - red: '\x1b[31m', - cyan: '\x1b[36m' -}; - -function log(message, color = 'reset') { - console.log(`${colors[color]}${message}${colors.reset}`); -} - -function section(message) { - console.log(''); - log(`β–Ά ${message}`, 'cyan'); -} - -function success(message) { - log(` βœ“ ${message}`, 'green'); -} - -function warning(message) { - log(` ⚠ ${message}`, 'yellow'); -} - -function error(message) { - log(` βœ— ${message}`, 'red'); -} - -// Pages to audit -const pages = [ - { name: 'Homepage', url: 'http://localhost:9000/' }, - { name: 'Researcher', url: 'http://localhost:9000/researcher.html' }, - { name: 'Implementer', url: 'http://localhost:9000/implementer.html' }, - { name: 'Leader', url: 'http://localhost:9000/leader.html' }, - { name: 'About', url: 'http://localhost:9000/about.html' }, - { name: 'Values', url: 'http://localhost:9000/about/values.html' }, - { name: 'Media Inquiry', url: 'http://localhost:9000/media-inquiry.html' }, - { name: 'Case Submission', url: 'http://localhost:9000/case-submission.html' }, - { name: 'Docs', url: 'http://localhost:9000/docs.html' } -]; - -// pa11y configuration -const pa11yConfig = { - standard: 'WCAG2AA', - timeout: 30000, - wait: 1000, - chromeLaunchConfig: { - args: ['--no-sandbox', '--disable-setuid-sandbox'] - }, - // Common issues to ignore (if needed) - ignore: [] -}; - -async function auditPage(page) { - try { - const results = await pa11y(page.url, pa11yConfig); - - return { - name: page.name, - url: page.url, - issues: results.issues, - error: false - }; - } catch (err) { - return { - name: page.name, - url: page.url, - error: true, - errorMessage: err.message - }; - } -} - -function categorizeIssues(issues) { - const categorized = { - error: [], - warning: [], - notice: [] - }; - - issues.forEach(issue => { - categorized[issue.type].push(issue); - }); - - return categorized; -} - -function printIssue(issue, index) { - const typeColor = { - error: 'red', - warning: 'yellow', - notice: 'cyan' - }; - - console.log(''); - log(` ${index + 1}. [${issue.type.toUpperCase()}] ${issue.message}`, typeColor[issue.type]); - log(` Code: ${issue.code}`, 'reset'); - log(` Element: ${issue.context.substring(0, 100)}${issue.context.length > 100 ? '...' : ''}`, 'reset'); - log(` Selector: ${issue.selector}`, 'reset'); -} - -async function main() { - log('═'.repeat(70), 'cyan'); - log(' Tractatus Accessibility Audit (WCAG 2.1 AA)', 'bright'); - log('═'.repeat(70), 'cyan'); - console.log(''); - - const allResults = []; - let totalErrors = 0; - let totalWarnings = 0; - let totalNotices = 0; - - for (const page of pages) { - section(`Auditing: ${page.name}`); - const result = await auditPage(page); - allResults.push(result); - - if (result.error) { - error(`Failed to audit: ${result.errorMessage}`); - continue; - } - - const categorized = categorizeIssues(result.issues); - - const errorCount = categorized.error.length; - const warningCount = categorized.warning.length; - const noticeCount = categorized.notice.length; - - totalErrors += errorCount; - totalWarnings += warningCount; - totalNotices += noticeCount; - - if (errorCount === 0 && warningCount === 0 && noticeCount === 0) { - success(`No accessibility issues found!`); - } else { - if (errorCount > 0) error(`${errorCount} errors`); - if (warningCount > 0) warning(`${warningCount} warnings`); - if (noticeCount > 0) log(` β„Ή ${noticeCount} notices`, 'cyan'); - - // Print first 3 errors/warnings - const criticalIssues = [...categorized.error, ...categorized.warning].slice(0, 3); - if (criticalIssues.length > 0) { - log(' Top issues:', 'bright'); - criticalIssues.forEach((issue, idx) => { - printIssue(issue, idx); - }); - } - } - } - - // Summary - console.log(''); - log('═'.repeat(70), 'cyan'); - log(' Summary', 'bright'); - log('═'.repeat(70), 'cyan'); - console.log(''); - - log(` Pages Audited: ${pages.length}`, 'bright'); - log(` Total Errors: ${totalErrors}`, totalErrors > 0 ? 'red' : 'green'); - log(` Total Warnings: ${totalWarnings}`, totalWarnings > 0 ? 'yellow' : 'green'); - log(` Total Notices: ${totalNotices}`, 'cyan'); - console.log(''); - - // Save detailed report - const reportPath = path.join(__dirname, '../audit-reports/accessibility-report.json'); - const reportDir = path.dirname(reportPath); - - if (!fs.existsSync(reportDir)) { - fs.mkdirSync(reportDir, { recursive: true }); - } - - fs.writeFileSync(reportPath, JSON.stringify({ - timestamp: new Date().toISOString(), - standard: 'WCAG 2.1 AA', - summary: { - pagesAudited: pages.length, - totalErrors, - totalWarnings, - totalNotices - }, - results: allResults - }, null, 2)); - - success(`Detailed report saved: ${reportPath}`); - console.log(''); - - // Exit code based on errors - if (totalErrors > 0) { - error('Accessibility audit FAILED - errors found'); - process.exit(1); - } else if (totalWarnings > 0) { - warning('Accessibility audit PASSED with warnings'); - process.exit(0); - } else { - success('Accessibility audit PASSED'); - process.exit(0); - } -} - -main().catch(err => { - console.error(''); - error(`Audit failed: ${err.message}`); - console.error(err.stack); - process.exit(1); -}); diff --git a/scripts/check-card-view-status.js b/scripts/check-card-view-status.js deleted file mode 100644 index 694c5410..00000000 --- a/scripts/check-card-view-status.js +++ /dev/null @@ -1,118 +0,0 @@ -const { MongoClient } = require('mongodb'); - -// The 34 public documents by slug -const PUBLIC_SLUGS = [ - // Getting Started - 'introduction', - 'architectural-safeguards-against-llm-hierarchical-dominance-prose', - 'core-concepts', - 'tractatus-ai-safety-framework-core-values-and-principles', - - // Technical Reference - 'technical-architecture', - 'implementation-guide', - 'implementation-roadmap-24-month-deployment-plan', - 'GLOSSARY', - 'comparison-matrix', - 'implementation-guide-v1.1', - 'api-reference-complete', - 'api-javascript-examples', - 'api-python-examples', - 'openapi-specification', - - // Theory & Research - 'executive-summary-tractatus-inflection-point', - 'architectural-overview-and-research-status', - 'organizational-theory-foundations', - 'pluralistic-values-research-foundations', - - // Advanced Topics - 'value-pluralism-faq', - 'pluralistic-values-deliberation-plan-v2', - - // Case Studies - 'the-27027-incident-a-case-study-in-pattern-recognition-bias', - 'when-frameworks-fail-and-why-thats-ok', - 'our-framework-in-action-detecting-and-correcting-ai-fabrications', - 'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery', - 'case-studies-real-world-llm-failure-modes', - - // Business & Leadership - 'business-case-tractatus-framework', - - // Archives - 'llm-integration-feasibility-research-scope', - 'case-studies-real-world-llm-failure-modes-appendix', - 'implementation-guide-python-examples', - 'tractatus-framework-enforcement-claude-code', - 'research-topic-concurrent-session-architecture', - 'research-topic-rule-proliferation-transactional-overhead', - 'phase-5-poc-session-1-summary', - 'phase-5-poc-session-2-summary' -]; - -async function checkCardViewStatus() { - const client = new MongoClient('mongodb://localhost:27017'); - - try { - await client.connect(); - const db = client.db('tractatus_dev'); - const collection = db.collection('documents'); - - console.log(`\n=== CHECKING CARD VIEW STATUS FOR 34 PUBLIC DOCUMENTS ===\n`); - - const documents = await collection.find({ - slug: { $in: PUBLIC_SLUGS } - }).toArray(); - - console.log(`Found ${documents.length} / ${PUBLIC_SLUGS.length} documents in database\n`); - - const withCards = []; - const withoutCards = []; - const notFound = []; - - PUBLIC_SLUGS.forEach(slug => { - const doc = documents.find(d => d.slug === slug); - if (!doc) { - notFound.push(slug); - } else if (doc.sections && doc.sections.length > 0) { - withCards.push({ - slug: doc.slug, - title: doc.title, - sections: doc.sections.length, - category: doc.category || 'none', - order: doc.order || 999 - }); - } else { - withoutCards.push({ - slug: doc.slug, - title: doc.title, - category: doc.category || 'none', - order: doc.order || 999 - }); - } - }); - - console.log(`βœ… WITH CARD VIEW (${withCards.length} docs):`); - withCards.forEach(doc => { - console.log(` [order:${doc.order}] ${doc.title}`); - console.log(` slug: ${doc.slug} | sections: ${doc.sections} | category: ${doc.category}`); - }); - - console.log(`\n❌ WITHOUT CARD VIEW (${withoutCards.length} docs):`); - withoutCards.forEach(doc => { - console.log(` [order:${doc.order}] ${doc.title}`); - console.log(` slug: ${doc.slug} | category: ${doc.category}`); - }); - - if (notFound.length > 0) { - console.log(`\n⚠️ NOT FOUND IN DATABASE (${notFound.length} slugs):`); - notFound.forEach(slug => console.log(` ${slug}`)); - } - - } finally { - await client.close(); - } -} - -checkCardViewStatus().catch(console.error); diff --git a/scripts/check-color-contrast.js b/scripts/check-color-contrast.js deleted file mode 100755 index 7ec6f72d..00000000 --- a/scripts/check-color-contrast.js +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env node - -/** - * Color Contrast Checker - * - * Verifies color contrast ratios meet WCAG 2.1 AA standards (4.5:1 normal text, 3:1 large text) - * - * Copyright 2025 Tractatus Project - * Licensed under Apache License 2.0 - */ - -const colors = { - reset: '\x1b[0m', - bright: '\x1b[1m', - green: '\x1b[32m', - yellow: '\x1b[33m', - red: '\x1b[31m', - cyan: '\x1b[36m' -}; - -function log(message, color = 'reset') { - console.log(`${colors[color]}${message}${colors.reset}`); -} - -function success(message) { - log(` βœ“ ${message}`, 'green'); -} - -function warning(message) { - log(` ⚠ ${message}`, 'yellow'); -} - -function error(message) { - log(` βœ— ${message}`, 'red'); -} - -/** - * Convert hex color to RGB - */ -function hexToRgb(hex) { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} - -/** - * Calculate relative luminance (WCAG formula) - */ -function getLuminance(rgb) { - const rsRGB = rgb.r / 255; - const gsRGB = rgb.g / 255; - const bsRGB = rgb.b / 255; - - const r = rsRGB <= 0.03928 ? rsRGB / 12.92 : Math.pow((rsRGB + 0.055) / 1.055, 2.4); - const g = gsRGB <= 0.03928 ? gsRGB / 12.92 : Math.pow((gsRGB + 0.055) / 1.055, 2.4); - const b = bsRGB <= 0.03928 ? bsRGB / 12.92 : Math.pow((bsRGB + 0.055) / 1.055, 2.4); - - return 0.2126 * r + 0.7152 * g + 0.0722 * b; -} - -/** - * Calculate contrast ratio between two colors - */ -function getContrastRatio(color1, color2) { - const rgb1 = hexToRgb(color1); - const rgb2 = hexToRgb(color2); - - const lum1 = getLuminance(rgb1); - const lum2 = getLuminance(rgb2); - - const lighter = Math.max(lum1, lum2); - const darker = Math.min(lum1, lum2); - - return (lighter + 0.05) / (darker + 0.05); -} - -/** - * Check if contrast ratio meets WCAG AA standards - */ -function meetsWCAG_AA(ratio, largeText = false) { - const threshold = largeText ? 3.0 : 4.5; - return ratio >= threshold; -} - -/** - * Tailwind color palette (common colors used in Tractatus site) - */ -const tailwindColors = { - 'white': '#ffffff', - 'gray-50': '#f9fafb', - 'gray-100': '#f3f4f6', - 'gray-200': '#e5e7eb', - 'gray-300': '#d1d5db', - 'gray-400': '#9ca3af', - 'gray-500': '#6b7280', - 'gray-600': '#4b5563', - 'gray-700': '#374151', - 'gray-800': '#1f2937', - 'gray-900': '#111827', - 'blue-50': '#eff6ff', - 'blue-100': '#dbeafe', - 'blue-400': '#60a5fa', - 'blue-500': '#3b82f6', - 'blue-600': '#2563eb', - 'blue-700': '#1d4ed8', - 'blue-800': '#1e40af', - 'blue-900': '#1e3a8a', - 'purple-500': '#a855f7', - 'purple-600': '#9333ea', - 'purple-700': '#7e22ce', - 'green-500': '#22c55e', - 'green-600': '#16a34a', - 'green-700': '#15803d', - 'yellow-600': '#ca8a04', - 'amber-500': '#f59e0b', - 'amber-800': '#92400e', - 'amber-900': '#78350f', - 'red-600': '#dc2626' -}; - -/** - * Color combinations used on site - */ -const colorCombinations = [ - // Body text on backgrounds - { name: 'Body text (gray-900 on white)', fg: 'gray-900', bg: 'white', largeText: false }, - { name: 'Body text (gray-700 on white)', fg: 'gray-700', bg: 'white', largeText: false }, - { name: 'Body text (gray-600 on white)', fg: 'gray-600', bg: 'white', largeText: false }, - { name: 'Muted text (gray-500 on white)', fg: 'gray-500', bg: 'white', largeText: false }, - - // Links - { name: 'Link (blue-600 on white)', fg: 'blue-600', bg: 'white', largeText: false }, - { name: 'Link hover (blue-700 on white)', fg: 'blue-700', bg: 'white', largeText: false }, - - // Buttons - { name: 'Button text (white on blue-600)', fg: 'white', bg: 'blue-600', largeText: false }, - { name: 'Button hover (white on blue-700)', fg: 'white', bg: 'blue-700', largeText: false }, - { name: 'Purple button (white on purple-600)', fg: 'white', bg: 'purple-600', largeText: false }, - { name: 'Green button (white on green-700)', fg: 'white', bg: 'green-700', largeText: false }, - - // Hero section - { name: 'Hero subtitle (blue-100 on blue-700)', fg: 'blue-100', bg: 'blue-700', largeText: true }, - - // Footer - { name: 'Footer text (gray-400 on gray-900)', fg: 'gray-400', bg: 'gray-900', largeText: false }, - { name: 'Footer links (blue-400 on gray-900)', fg: 'blue-400', bg: 'gray-900', largeText: false }, - - // Alerts/Messages - { name: 'Success message (green-900 on green-50)', fg: '#065f46', bg: '#d1fae5', largeText: false }, - { name: 'Error message (red-900 on red-50)', fg: '#991b1b', bg: '#fee2e2', largeText: false }, - { name: 'Warning message (amber-900 on amber-50)', fg: 'amber-900', bg: '#fef3c7', largeText: false }, - - // Cards/Sections - { name: 'Card text (gray-700 on white)', fg: 'gray-700', bg: 'white', largeText: false }, - { name: 'Card header (gray-900 on white)', fg: 'gray-900', bg: 'white', largeText: true }, -]; - -/** - * Main check - */ -function main() { - log('═'.repeat(70), 'cyan'); - log(' Color Contrast Checker (WCAG 2.1 AA)', 'bright'); - log('═'.repeat(70), 'cyan'); - console.log(''); - - let passCount = 0; - let failCount = 0; - let warnings = 0; - - colorCombinations.forEach(combo => { - const fgColor = tailwindColors[combo.fg] || combo.fg; - const bgColor = tailwindColors[combo.bg] || combo.bg; - - const ratio = getContrastRatio(fgColor, bgColor); - const passes = meetsWCAG_AA(ratio, combo.largeText); - const threshold = combo.largeText ? '3:1' : '4.5:1'; - - const ratioStr = ratio.toFixed(2) + ':1'; - - if (passes) { - success(`${combo.name.padEnd(45)} ${ratioStr.padStart(8)} (>= ${threshold}) βœ“`); - passCount++; - } else { - // Check if it's close (within 0.3 of threshold) - const minRatio = combo.largeText ? 3.0 : 4.5; - if (ratio >= minRatio - 0.3) { - warning(`${combo.name.padEnd(45)} ${ratioStr.padStart(8)} (< ${threshold}) ⚠`); - warnings++; - } else { - error(`${combo.name.padEnd(45)} ${ratioStr.padStart(8)} (< ${threshold}) βœ—`); - failCount++; - } - } - }); - - console.log(''); - log('═'.repeat(70), 'cyan'); - log(' Summary', 'bright'); - log('═'.repeat(70), 'cyan'); - console.log(''); - log(` Combinations Checked: ${colorCombinations.length}`, 'bright'); - log(` Passed: ${passCount}`, 'green'); - if (warnings > 0) log(` Warnings: ${warnings}`, 'yellow'); - if (failCount > 0) log(` Failed: ${failCount}`, 'red'); - console.log(''); - - if (failCount > 0) { - error('Some color combinations fail WCAG AA standards'); - console.log(''); - process.exit(1); - } else if (warnings > 0) { - warning('All combinations pass, but some are borderline'); - console.log(''); - process.exit(0); - } else { - success('All color combinations meet WCAG AA standards'); - console.log(''); - process.exit(0); - } -} - -main(); diff --git a/scripts/check-csp-violations.js b/scripts/check-csp-violations.js deleted file mode 100644 index 9bb59360..00000000 --- a/scripts/check-csp-violations.js +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env node - -/** - * CSP Violation Scanner - * Scans HTML and JS files for Content Security Policy violations - * - * Violations checked (inst_008): - * - Inline event handlers (onclick, onload, etc.) - * - Inline styles (style="...") - * - Inline scripts () - * - javascript: URLs - * - * Usage: - * node scripts/check-csp-violations.js [pattern] - * - * Examples: - * node scripts/check-csp-violations.js - * node scripts/check-csp-violations.js public - */ - -const fs = require('fs'); -const path = require('path'); -const { execSync } = require('child_process'); - -// Default patterns to scan -const DEFAULT_PATTERNS = [ - 'public/**/*.html', - 'public/**/*.js' -]; - -// CSP violation patterns -const VIOLATION_PATTERNS = { - inline_event_handlers: { - regex: /\s(on[a-z]+)=["'][^"']*["']/gi, - description: 'Inline event handler', - severity: 'HIGH' - }, - inline_styles: { - regex: /\sstyle=["'][^"']*["']/gi, - description: 'Inline style attribute', - severity: 'HIGH' - }, - inline_scripts: { - regex: /]*\ssrc=)[^>]*>[\s\S]*?<\/script>/gi, - description: 'Inline script block', - severity: 'CRITICAL' - }, - javascript_urls: { - regex: /href=["']javascript:/gi, - description: 'javascript: URL', - severity: 'CRITICAL' - } -}; - -// Files to exclude from scanning -const EXCLUDED_PATTERNS = [ - 'node_modules', - '.git', - 'dist', - 'build' -]; - -/** - * Find files matching glob patterns - */ -function findFiles(patterns) { - const allPatterns = Array.isArray(patterns) ? patterns : [patterns]; - const files = new Set(); - - allPatterns.forEach(pattern => { - try { - const result = execSync(`find public -type f \\( -name "*.html" -o -name "*.js" \\) 2>/dev/null`, { - encoding: 'utf8', - maxBuffer: 10 * 1024 * 1024 - }); - - result.split('\n').filter(f => f.trim()).forEach(file => { - // Exclude patterns - if (!EXCLUDED_PATTERNS.some(excluded => file.includes(excluded))) { - files.add(file); - } - }); - } catch (error) { - // Ignore errors from find command - } - }); - - return Array.from(files).sort(); -} - -/** - * Scan a single file for CSP violations - */ -function scanFile(filePath) { - const violations = []; - - try { - const content = fs.readFileSync(filePath, 'utf8'); - const lines = content.split('\n'); - - // Check each violation pattern - Object.entries(VIOLATION_PATTERNS).forEach(([type, pattern]) => { - const matches = content.matchAll(pattern.regex); - - for (const match of matches) { - // Find line number - const beforeMatch = content.substring(0, match.index); - const lineNumber = beforeMatch.split('\n').length; - - // Get the matched text (truncate if too long) - let matchedText = match[0]; - if (matchedText.length > 80) { - matchedText = matchedText.substring(0, 77) + '...'; - } - - violations.push({ - file: filePath, - line: lineNumber, - type, - description: pattern.description, - severity: pattern.severity, - matched: matchedText - }); - } - }); - } catch (error) { - console.error(`Error scanning ${filePath}:`, error.message); - } - - return violations; -} - -/** - * Main scanner function - */ -function scanForViolations(patterns = DEFAULT_PATTERNS) { - console.log('πŸ” Scanning for CSP violations...\n'); - - const files = findFiles(patterns); - console.log(`Found ${files.length} files to scan\n`); - - const allViolations = []; - - files.forEach(file => { - const violations = scanFile(file); - if (violations.length > 0) { - allViolations.push(...violations); - } - }); - - return allViolations; -} - -/** - * Format and display violations - */ -function displayViolations(violations) { - if (violations.length === 0) { - console.log('βœ… No CSP violations found!\n'); - return 0; - } - - console.log(`❌ Found ${violations.length} CSP violation(s):\n`); - - // Group by file - const byFile = {}; - violations.forEach(v => { - if (!byFile[v.file]) byFile[v.file] = []; - byFile[v.file].push(v); - }); - - // Display by file - Object.entries(byFile).forEach(([file, fileViolations]) => { - console.log(`πŸ“„ ${file} (${fileViolations.length} violation(s)):`); - fileViolations.forEach(v => { - const severity = v.severity === 'CRITICAL' ? 'πŸ”΄' : '🟑'; - console.log(` ${severity} Line ${v.line}: ${v.description}`); - console.log(` ${v.matched}`); - }); - console.log(''); - }); - - // Summary by type - console.log('πŸ“Š Violations by type:'); - const byType = {}; - violations.forEach(v => { - byType[v.description] = (byType[v.description] || 0) + 1; - }); - Object.entries(byType).forEach(([type, count]) => { - console.log(` - ${type}: ${count}`); - }); - - console.log(`\nπŸ’‘ To fix violations, run: node scripts/fix-csp-violations.js\n`); - - return violations.length; -} - -// Run scanner if called directly -if (require.main === module) { - const pattern = process.argv[2] || DEFAULT_PATTERNS; - const violations = scanForViolations(pattern); - const exitCode = displayViolations(violations); - - process.exit(exitCode > 0 ? 1 : 0); -} - -// Export for use in other scripts -module.exports = { - scanForViolations, - displayViolations, - scanFile -}; diff --git a/scripts/check-missing-pdfs.js b/scripts/check-missing-pdfs.js deleted file mode 100644 index 7da0b9bf..00000000 --- a/scripts/check-missing-pdfs.js +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env node -/** - * Check which of the 34 public documents are missing PDFs - */ -require('dotenv').config(); - -const { connect, close } = require('../src/utils/db.util'); -const Document = require('../src/models/Document.model'); -const fs = require('fs').promises; -const path = require('path'); - -const PUBLIC_CATEGORIES = [ - 'getting-started', - 'technical-reference', - 'research-theory', - 'advanced-topics', - 'case-studies', - 'business-leadership', - 'archives' -]; - -async function main() { - await connect(); - - const { MongoClient } = require('mongodb'); - const mongoose = require('mongoose'); - const { getCollection } = require('../src/utils/db.util'); - - const collection = await getCollection('documents'); - - const docs = await collection.find({ - category: { $in: PUBLIC_CATEGORIES } - }).sort({ category: 1, order: 1 }).toArray(); - - console.log('\n' + '='.repeat(70)); - console.log('PDF AVAILABILITY CHECK - 34 Public Documents'); - console.log('='.repeat(70) + '\n'); - - const pdfDir = '/home/theflow/projects/tractatus/public/downloads'; - - let missingCount = 0; - let presentCount = 0; - const missing = []; - - for (const doc of docs) { - const slug = doc.slug; - const pdfPath = path.join(pdfDir, `${slug}.pdf`); - - try { - await fs.access(pdfPath); - presentCount++; - // console.log(`βœ… ${doc.title}`); - } catch (err) { - missingCount++; - missing.push({ title: doc.title, slug, category: doc.category }); - console.log(`❌ MISSING PDF: ${doc.title}`); - console.log(` slug: ${slug}`); - console.log(` category: ${doc.category}`); - console.log(); - } - } - - console.log('='.repeat(70)); - console.log(`\nπŸ“Š Summary:`); - console.log(` βœ… PDFs present: ${presentCount}/${docs.length}`); - console.log(` ❌ PDFs missing: ${missingCount}/${docs.length}`); - - if (missing.length > 0) { - console.log(`\nπŸ“‹ Missing PDFs by category:`); - const byCategory = {}; - missing.forEach(m => { - if (!byCategory[m.category]) byCategory[m.category] = []; - byCategory[m.category].push(m); - }); - - Object.keys(byCategory).forEach(cat => { - console.log(`\n ${cat}: ${byCategory[cat].length} missing`); - byCategory[cat].forEach(m => { - console.log(` - ${m.slug}`); - }); - }); - } - - console.log('\n' + '='.repeat(70) + '\n'); - - await close(); -} - -main(); diff --git a/scripts/check-sections.js b/scripts/check-sections.js deleted file mode 100644 index e8a9ea8f..00000000 --- a/scripts/check-sections.js +++ /dev/null @@ -1,21 +0,0 @@ -const { MongoClient } = require('mongodb'); - -(async () => { - const client = new MongoClient('mongodb://localhost:27017/tractatus_dev'); - await client.connect(); - const docs = await client.db('tractatus_dev').collection('documents') - .find({}, { projection: { slug: 1, title: 1, sections: 1, category: 1 } }) - .sort({ slug: 1 }) - .toArray(); - - const withSections = docs.filter(d => d.sections && d.sections.length > 0); - const without = docs.filter(d => !d.sections || d.sections.length === 0); - - console.log('=== DOCUMENTS WITH SECTIONS (' + withSections.length + ') ==='); - withSections.forEach(d => console.log('-', d.slug, '(' + d.sections.length + ' sections, cat:' + (d.category || 'none') + ')')); - - console.log('\n=== DOCUMENTS WITHOUT SECTIONS (' + without.length + ') ==='); - without.forEach(d => console.log('-', d.slug, '(cat:' + (d.category || 'none') + ')')); - - await client.close(); -})(); diff --git a/scripts/cleanup-database.js b/scripts/cleanup-database.js deleted file mode 100644 index 716d8d93..00000000 --- a/scripts/cleanup-database.js +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env node -/** - * Database Cleanup Script - * Removes junk documents that should never have been imported into MongoDB - * - * Categories: - * 1. Internal session notes (10 documents) - * 2. Obsolete Phase 2 documents (9 documents) - * 3. Confidential document duplicates (5 documents - keep filesystem .md files) - * - * Total: 24 documents to delete - */ - -require('dotenv').config(); -const { getDb } = require('../src/utils/db.util'); - -// Documents to delete organized by category (actual slugs from database) -const documentsToDelete = { - sessionNotes: [ - 'ai-features-implementation-session-2025-10-07', - 'session-handoff-2025-10-07', - 'session-handoff-2025-10-07-part-4-governance-active-progress-review', - 'session-handoff-crossreferencevalidator-debugging', - 'session-handoff-tractatus-framework-activation' - ], - - obsoletePhase2: [ - 'phase-2-cost-estimates-hosting-api-usage', - 'phase-2-deployment-guide-granular-task-instructions', - 'phase-2-infrastructure-plan', - 'phase-2-kickoff-checklist', - 'phase-2-preparation-advisory', - 'phase-2-production-deployment-ai-features', - 'phase-2-progress-report-week-5', - 'phase-2-roadmap-production-deployment-ai-powered-features', - 'phase-2-soft-launch-email-templates', - 'tractatus-blog-post-outlines', - 'tractatus-governance-framework-test-suite-improvement-session-part-2', - 'tractatus-production-comprehensive-testing-checklist', - 'tractatus-production-testing-results', - 'tractatus-project-implementation-progress-report' - ], - - confidentialDuplicates: [ - 'appendix-e-contact-information', - 'cover-letter-for-anthropic-submission', - 'koha-stripe-payment-setup-guide', - 'security-audit-report' - ] -}; - -async function cleanupDatabase() { - console.log('🧹 Starting database cleanup...\n'); - - const db = await getDb(); - const collection = db.collection('documents'); - - // Track results - const results = { - sessionNotes: { deleted: 0, notFound: [] }, - obsoletePhase2: { deleted: 0, notFound: [] }, - confidentialDuplicates: { deleted: 0, notFound: [] } - }; - - // Delete session notes - console.log('πŸ“‹ Deleting internal session notes...'); - for (const slug of documentsToDelete.sessionNotes) { - const result = await collection.deleteOne({ slug }); - if (result.deletedCount > 0) { - console.log(` βœ… Deleted: ${slug}`); - results.sessionNotes.deleted++; - } else { - console.log(` ⚠️ Not found: ${slug}`); - results.sessionNotes.notFound.push(slug); - } - } - - // Delete obsolete Phase 2 documents - console.log('\nπŸ“¦ Deleting obsolete Phase 2 documents...'); - for (const slug of documentsToDelete.obsoletePhase2) { - const result = await collection.deleteOne({ slug }); - if (result.deletedCount > 0) { - console.log(` βœ… Deleted: ${slug}`); - results.obsoletePhase2.deleted++; - } else { - console.log(` ⚠️ Not found: ${slug}`); - results.obsoletePhase2.notFound.push(slug); - } - } - - // Delete confidential duplicates - console.log('\nπŸ”’ Deleting confidential document duplicates from MongoDB...'); - console.log(' (Filesystem .md files will be preserved)'); - for (const slug of documentsToDelete.confidentialDuplicates) { - const result = await collection.deleteOne({ slug }); - if (result.deletedCount > 0) { - console.log(` βœ… Deleted: ${slug}`); - results.confidentialDuplicates.deleted++; - } else { - console.log(` ⚠️ Not found: ${slug}`); - results.confidentialDuplicates.notFound.push(slug); - } - } - - // Summary - console.log('\n' + '='.repeat(70)); - console.log('πŸ“Š Cleanup Summary'); - console.log('='.repeat(70)); - console.log(`Session Notes: ${results.sessionNotes.deleted}/${documentsToDelete.sessionNotes.length} deleted`); - console.log(`Obsolete Phase 2: ${results.obsoletePhase2.deleted}/${documentsToDelete.obsoletePhase2.length} deleted`); - console.log(`Confidential Duplicates: ${results.confidentialDuplicates.deleted}/${documentsToDelete.confidentialDuplicates.length} deleted`); - console.log('='.repeat(70)); - - const totalDeleted = results.sessionNotes.deleted + results.obsoletePhase2.deleted + results.confidentialDuplicates.deleted; - const totalExpected = documentsToDelete.sessionNotes.length + documentsToDelete.obsoletePhase2.length + documentsToDelete.confidentialDuplicates.length; - - console.log(`\nβœ… Total deleted: ${totalDeleted}/${totalExpected} documents\n`); - - // Report not found documents - const allNotFound = [ - ...results.sessionNotes.notFound, - ...results.obsoletePhase2.notFound, - ...results.confidentialDuplicates.notFound - ]; - - if (allNotFound.length > 0) { - console.log('⚠️ Documents not found (may have been deleted already):'); - allNotFound.forEach(slug => console.log(` - ${slug}`)); - console.log(); - } - - // Get final document count - const finalCount = await collection.countDocuments(); - console.log(`πŸ“š Remaining documents in database: ${finalCount}\n`); - - process.exit(0); -} - -// Run cleanup -cleanupDatabase().catch(error => { - console.error('❌ Cleanup failed:', error); - process.exit(1); -}); diff --git a/scripts/compare-databases.js b/scripts/compare-databases.js deleted file mode 100644 index 2d2cdd31..00000000 --- a/scripts/compare-databases.js +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env node -/** - * Compare Dev and Prod Databases - * Identifies documents that exist in one but not the other - */ - -require('dotenv').config(); -const { MongoClient } = require('mongodb'); - -async function compareDatabases() { - // Connect to local dev - console.log('πŸ”Œ Connecting to local dev database...'); - const devClient = new MongoClient('mongodb://localhost:27017/tractatus_dev'); - await devClient.connect(); - const devDb = devClient.db('tractatus_dev'); - const devColl = devDb.collection('documents'); - - // Connect to local prod (for comparison) - console.log('πŸ”Œ Connecting to local prod database...\n'); - const prodClient = new MongoClient('mongodb://localhost:27017/tractatus_prod'); - await prodClient.connect(); - const prodDb = prodClient.db('tractatus_prod'); - const prodColl = prodDb.collection('documents'); - - // Get all documents - const devDocs = await devColl.find({}).project({ slug: 1, title: 1, visibility: 1 }).sort({ slug: 1 }).toArray(); - const prodDocs = await prodColl.find({}).project({ slug: 1, title: 1, visibility: 1 }).sort({ slug: 1 }).toArray(); - - const devSlugs = new Set(devDocs.map(d => d.slug)); - const prodSlugs = new Set(prodDocs.map(d => d.slug)); - - const inDevNotProd = devDocs.filter(d => !prodSlugs.has(d.slug)); - const inProdNotDev = prodDocs.filter(d => !devSlugs.has(d.slug)); - - console.log('='.repeat(70)); - console.log('DATABASE COMPARISON'); - console.log('='.repeat(70)); - console.log(`Dev total: ${devDocs.length}`); - console.log(`Prod total: ${prodDocs.length}`); - console.log(`Difference: ${Math.abs(devDocs.length - prodDocs.length)}`); - console.log('='.repeat(70)); - - if (inDevNotProd.length > 0) { - console.log(`\nπŸ“‹ Documents in DEV but NOT in PROD (${inDevNotProd.length}):\n`); - inDevNotProd.forEach(d => { - console.log(` - ${d.slug} [${d.visibility || 'public'}]`); - }); - } - - if (inProdNotDev.length > 0) { - console.log(`\nπŸ“‹ Documents in PROD but NOT in DEV (${inProdNotDev.length}):\n`); - inProdNotDev.forEach(d => { - console.log(` - ${d.slug} [${d.visibility || 'public'}]`); - }); - } - - if (inDevNotProd.length === 0 && inProdNotDev.length === 0) { - console.log('\nβœ… Dev and Prod have identical document sets!\n'); - } - - await devClient.close(); - await prodClient.close(); - process.exit(0); -} - -compareDatabases().catch(error => { - console.error('❌ Comparison failed:', error); - process.exit(1); -}); diff --git a/scripts/create-admin-noninteractive.js b/scripts/create-admin-noninteractive.js deleted file mode 100644 index 032c6bd5..00000000 --- a/scripts/create-admin-noninteractive.js +++ /dev/null @@ -1,31 +0,0 @@ -const bcrypt = require('bcrypt'); -const { MongoClient } = require('mongodb'); - -async function createAdmin() { - const client = new MongoClient('mongodb://localhost:27017'); - - try { - await client.connect(); - const db = client.db('tractatus_dev'); - - // Delete existing admin - await db.collection('users').deleteOne({ email: 'admin@tractatus.local' }); - - // Create new admin with hashed password - const password = bcrypt.hashSync('tractatus2025', 12); - await db.collection('users').insertOne({ - name: 'Admin User', - email: 'admin@tractatus.local', - password: password, - role: 'admin', - active: true, - created_at: new Date() - }); - - console.log('βœ… Admin user created: admin@tractatus.local / tractatus2025'); - } finally { - await client.close(); - } -} - -createAdmin().catch(console.error); diff --git a/scripts/fix-admin-csp-violations.js b/scripts/fix-admin-csp-violations.js deleted file mode 100644 index bd8c2064..00000000 --- a/scripts/fix-admin-csp-violations.js +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env node - -/** - * Fix CSP violations in admin JS files - * - Replace inline styles with classes and data attributes - * - Replace inline event handlers with event delegation - */ - -const fs = require('fs'); -const path = require('path'); - -// Fix auth-check.js inline styles -function fixAuthCheck() { - const filePath = path.join(__dirname, '../public/js/admin/auth-check.js'); - let content = fs.readFileSync(filePath, 'utf8'); - - const oldHTML = `
-
- - - -

Authentication Required

-

\${reason}

-

Redirecting to login...

`; - - const newHTML = `
-
- - - -

Authentication Required

-

\${reason}

-

Redirecting to login...

`; - - if (content.includes(oldHTML)) { - content = content.replace(oldHTML, newHTML); - fs.writeFileSync(filePath, content); - return 6; // 6 inline styles fixed - } - return 0; -} - -// Fix progress bar widths by using data attributes -function fixProgressBars() { - const files = [ - 'public/js/admin/audit-analytics.js', - 'public/js/admin/rule-editor.js', - 'public/js/admin/rule-manager.js' - ]; - - let totalFixed = 0; - - files.forEach(file => { - const filePath = path.join(__dirname, '..', file); - let content = fs.readFileSync(filePath, 'utf8'); - let fileFixed = 0; - - // Pattern 1:
- const pattern1 = /(]*class="[^"]*(?:bg-blue-600|bg-green-500|bg-blue-500|bg-yellow-500)[^"]*"[^>]*)\s+style="width:\s*\$\{([^}]+)\}%"/g; - content = content.replace(pattern1, (match, before, variable) => { - fileFixed++; - return `${before} data-width="\${${variable}}"`; - }); - - // Pattern 2:
or style="width: 100%"> - const pattern2 = /(]*(?:id="[^"]*-bar")[^>]*)\s+style="width:\s*(0|100)%"/g; - content = content.replace(pattern2, (match, before, value) => { - fileFixed++; - return `${before} data-width="${value}"`; - }); - - // Pattern 3: style="height: ${barHeight}%" - const pattern3 = /style="height:\s*\$\{([^}]+)\}%"/g; - content = content.replace(pattern3, (match, variable) => { - fileFixed++; - return `data-height="\${${variable}}"`; - }); - - if (fileFixed > 0) { - fs.writeFileSync(filePath, content); - console.log(`βœ“ ${file}: Fixed ${fileFixed} inline style(s)`); - totalFixed += fileFixed; - } - }); - - return totalFixed; -} - -// Add width-setting helper after DOM insertion -function addProgressBarHelper() { - const files = [ - { file: 'public/js/admin/audit-analytics.js', hasProgressBars: true }, - { file: 'public/js/admin/rule-editor.js', hasProgressBars: true }, - { file: 'public/js/admin/rule-manager.js', hasProgressBars: true } - ]; - - const helper = ` -// Set widths from data attributes (CSP compliance) -function setProgressBarWidths(container) { - const elements = container.querySelectorAll('[data-width], [data-height]'); - elements.forEach(el => { - if (el.dataset.width) { - el.style.width = el.dataset.width + '%'; - } - if (el.dataset.height) { - el.style.height = el.dataset.height + '%'; - } - }); -}`; - - files.forEach(({ file, hasProgressBars }) => { - if (!hasProgressBars) return; - - const filePath = path.join(__dirname, '..', file); - let content = fs.readFileSync(filePath, 'utf8'); - - // Check if helper already exists - if (content.includes('setProgressBarWidths')) { - return; - } - - // Add helper function before the last closing brace/parenthesis of the file - // Find a good insertion point - typically after other helper functions - const insertionPoint = content.lastIndexOf('})()'); - if (insertionPoint > 0) { - content = content.slice(0, insertionPoint) + helper + '\n\n' + content.slice(insertionPoint); - fs.writeFileSync(filePath, content); - console.log(`βœ“ ${file}: Added setProgressBarWidths helper`); - } - }); -} - -// Main execution -console.log('\nπŸ”§ Fixing admin CSP violations...\n'); - -let totalFixed = 0; - -console.log('1. Fixing auth-check.js inline styles...'); -totalFixed += fixAuthCheck(); - -console.log('\n2. Converting progress bar widths to data attributes...'); -totalFixed += fixProgressBars(); - -console.log('\n3. Adding progress bar width helpers...'); -addProgressBarHelper(); - -console.log(`\nβœ… Total inline styles fixed: ${totalFixed}`); -console.log('\n⚠️ Note: Inline event handlers require manual refactoring'); -console.log(' Run scripts/fix-admin-event-handlers.js for those.\n'); diff --git a/scripts/fix-admin-event-handlers.js b/scripts/fix-admin-event-handlers.js deleted file mode 100644 index d4fd29f4..00000000 --- a/scripts/fix-admin-event-handlers.js +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env node - -/** - * Fix inline event handlers in admin JS files - * Replace with data attributes and event delegation - */ - -const fs = require('fs'); -const path = require('path'); - -const files = [ - 'public/js/admin/audit-analytics.js', - 'public/js/admin/claude-md-migrator.js', - 'public/js/admin/dashboard.js', - 'public/js/admin/project-editor.js', - 'public/js/admin/project-manager.js', - 'public/js/admin/rule-editor.js', - 'public/js/admin/rule-manager.js' -]; - -let totalFixed = 0; - -files.forEach(file => { - const filePath = path.join(__dirname, '..', file); - let content = fs.readFileSync(filePath, 'utf8'); - let fileFixed = 0; - - // Pattern 1: onclick="this.parentElement.remove()" - const pattern1 = /\s*onclick="this\.parentElement\.remove\(\)"/g; - const matches1 = (content.match(pattern1) || []).length; - content = content.replace(pattern1, ' data-action="remove-parent"'); - fileFixed += matches1; - - // Pattern 2: onclick="functionName('arg')" or onclick="functionName('arg', 'arg2')" - const pattern2 = /onclick="([a-zA-Z.]+)\(([^)]+)\)"/g; - content = content.replace(pattern2, (match, funcName, args) => { - fileFixed++; - // Extract arguments - const argList = args.split(',').map(a => a.trim().replace(/['"]/g, '')); - - // Create data attributes - let dataAttrs = `data-action="${funcName.replace('window.', '').replace('projectEditor.', '')}"`; - argList.forEach((arg, i) => { - if (arg.startsWith('${')) { - // Template literal - keep as is - dataAttrs += ` data-arg${i}="${arg}"`; - } else { - // Plain value - dataAttrs += ` data-arg${i}="${arg}"`; - } - }); - - return dataAttrs; - }); - - // Pattern 3: onchange="functionName(...)" - const pattern3 = /onchange="([a-zA-Z.]+)\(([^)]+)\)"/g; - content = content.replace(pattern3, (match, funcName, args) => { - fileFixed++; - return `data-change-action="${funcName}" data-change-args="${args}"`; - }); - - if (fileFixed > 0) { - fs.writeFileSync(filePath, content); - console.log(`βœ“ ${file}: Fixed ${fileFixed} event handler(s)`); - totalFixed += fileFixed; - } -}); - -console.log(`\nβœ… Total event handlers fixed: ${totalFixed}`); -console.log('\n⚠️ Next: Add event delegation listeners to each file\n'); diff --git a/scripts/fix-admin-user.js b/scripts/fix-admin-user.js deleted file mode 100755 index b7207229..00000000 --- a/scripts/fix-admin-user.js +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env node -require('dotenv').config(); - -const { connect, close, getCollection } = require('../src/utils/db.util'); -const User = require('../src/models/User.model'); - -const EMAIL = process.argv[2] || 'admin@agenticgovernance.digital'; -const PASSWORD = process.argv[3] || 'TractatusDev2025'; -const NAME = process.argv[4] || 'Admin User'; - -async function fixAdminUser() { - try { - await connect(); - - // Find existing admin user - const existing = await User.findByEmail(EMAIL); - - if (existing) { - console.log(`βœ… Found existing admin: ${existing.email} (ID: ${existing._id})`); - console.log(` Deleting...`); - await User.delete(existing._id); - console.log(`βœ… Deleted old admin user`); - } - - // Create new admin with proper password field - console.log(`\nπŸ“ Creating new admin user...`); - const admin = await User.create({ - name: NAME, - email: EMAIL, - password: PASSWORD, - role: 'admin', - active: true - }); - - console.log(`\nβœ… Admin user created successfully!`); - console.log(` Email: ${admin.email}`); - console.log(` Password: ${PASSWORD}`); - console.log(` Role: ${admin.role}`); - console.log(` ID: ${admin._id}`); - console.log(`\nπŸ” Test login at: POST /api/auth/login`); - - await close(); - process.exit(0); - - } catch (error) { - console.error('\n❌ Error:', error.message); - await close(); - process.exit(1); - } -} - -fixAdminUser(); diff --git a/scripts/fix-category-mismatches.js b/scripts/fix-category-mismatches.js deleted file mode 100644 index bc5e46e0..00000000 --- a/scripts/fix-category-mismatches.js +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env node -/** - * Fix Category Mismatches Between Dev and Prod - * - * Harmonizes document categories to canonical values based on document content and purpose - */ - -require('dotenv').config(); -const { getDb } = require('../src/utils/db.util'); - -// Canonical category assignments (based on content analysis) -const categoryFixes = { - 'architectural-overview-and-research-status': 'research-theory', - 'comparison-matrix-claude-code-claudemd-and-tractatus-framework': 'technical-reference', - 'executive-brief-tractatus-based-llm-architecture-for-ai-safety': 'research-theory', - 'pluralistic-values-research-foundations': 'advanced-topics' -}; - -async function fixCategoryMismatches() { - console.log('πŸ”§ Fixing category mismatches...\n'); - - const db = await getDb(); - const collection = db.collection('documents'); - - let fixedCount = 0; - let notFoundCount = 0; - - for (const [slug, correctCategory] of Object.entries(categoryFixes)) { - try { - const doc = await collection.findOne({ slug }); - - if (!doc) { - console.log(`⚠️ Not found: ${slug}`); - notFoundCount++; - continue; - } - - if (doc.category === correctCategory) { - console.log(`βœ“ Already correct: ${slug} (${correctCategory})`); - continue; - } - - // Update category - await collection.updateOne( - { slug }, - { - $set: { - category: correctCategory, - 'metadata.date_updated': new Date() - } - } - ); - - console.log(`βœ… Fixed: ${slug}`); - console.log(` ${doc.category || 'none'} β†’ ${correctCategory}\n`); - fixedCount++; - - } catch (error) { - console.error(`❌ Error fixing ${slug}:`, error.message); - } - } - - console.log('='.repeat(60)); - console.log('πŸ“Š Summary:'); - console.log('='.repeat(60)); - console.log(`Total documents to fix: ${Object.keys(categoryFixes).length}`); - console.log(`βœ… Fixed: ${fixedCount}`); - console.log(`⚠️ Not found: ${notFoundCount}`); - console.log(`βœ“ Already correct: ${Object.keys(categoryFixes).length - fixedCount - notFoundCount}`); - console.log('='.repeat(60)); - - process.exit(0); -} - -// Run fix -fixCategoryMismatches().catch(error => { - console.error('❌ Fix failed:', error); - process.exit(1); -}); diff --git a/scripts/fix-csp-html-violations.js b/scripts/fix-csp-html-violations.js deleted file mode 100644 index d72a08bd..00000000 --- a/scripts/fix-csp-html-violations.js +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env node - -/** - * Fix CSP violations in HTML files - * Replaces inline styles with CSS utility classes - */ - -const fs = require('fs'); -const path = require('path'); - -const fixes = [ - // researcher.html - { - file: 'public/researcher.html', - replacements: [ - { - from: 'class="hover:underline transition-colors" style="color: var(--tractatus-core-end);"', - to: 'class="hover:underline transition-colors text-tractatus-link"' - }, - { - from: 'class="border-l-4 border border-gray-200 rounded-lg mb-4" style="border-left-color: #8b5cf6;"', - to: 'class="border-l-4 border border-gray-200 rounded-lg mb-4 border-l-service-validator"' - }, - { - from: 'class="border-l-4 border border-gray-200 rounded-lg" style="border-left-color: #8b5cf6;"', - to: 'class="border-l-4 border border-gray-200 rounded-lg border-l-service-validator"' - } - ] - }, - // case-submission.html - { - file: 'public/case-submission.html', - replacements: [ - { - from: 'style="border-left-color: var(--tractatus-core-end);"', - to: 'class="border-l-tractatus"' - }, - { - from: 'style="color: var(--tractatus-core-end);"', - to: 'class="text-tractatus-link"' - }, - { - from: 'style="background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);"', - to: 'class="bg-gradient-cyan-blue"' - } - ] - } -]; - -let totalFixed = 0; - -fixes.forEach(({ file, replacements }) => { - const filePath = path.join(__dirname, '..', file); - - console.log(`\nProcessing ${file}...`); - - if (!fs.existsSync(filePath)) { - console.log(` βœ— File not found`); - return; - } - - let content = fs.readFileSync(filePath, 'utf8'); - let fileFixed = 0; - - replacements.forEach(({ from, to }) => { - const occurrences = (content.match(new RegExp(from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g')) || []).length; - - if (occurrences > 0) { - content = content.split(from).join(to); - fileFixed += occurrences; - console.log(` βœ“ Fixed ${occurrences} occurrence(s)`); - } - }); - - if (fileFixed > 0) { - fs.writeFileSync(filePath, content); - totalFixed += fileFixed; - console.log(` βœ“ Saved ${file} (${fileFixed} fixes)`); - } else { - console.log(` β€’ No violations found`); - } -}); - -console.log(`\nβœ“ Total fixes applied: ${totalFixed}\n`); diff --git a/scripts/fix-csp-major-html.js b/scripts/fix-csp-major-html.js deleted file mode 100644 index 6c083614..00000000 --- a/scripts/fix-csp-major-html.js +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env node - -/** - * Fix CSP violations in major HTML files (index.html, architecture.html) - */ - -const fs = require('fs'); -const path = require('path'); - -const replacements = [ - // Layout - { from: ' style="min-height: 64px;"', to: ' class="min-h-16"' }, - - // Text shadows - { from: ' style="text-shadow: 0 2px 4px rgba(0,0,0,0.1);"', to: ' class="text-shadow-md"' }, - { from: ' style="text-shadow: 0 1px 2px rgba(0,0,0,0.1);"', to: ' class="text-shadow-sm"' }, - - // Gradients - { from: ' style="background: linear-gradient(135deg, #64ffda 0%, #448aff 50%, #0ea5e9 100%);"', to: ' class="bg-gradient-tractatus"' }, - { from: ' style="background: var(--gradient-btn-validator);"', to: ' class="bg-gradient-service-validator"' }, - { from: ' style="background: var(--gradient-btn-instruction);"', to: ' class="bg-gradient-service-instruction"' }, - { from: ' style="background: var(--gradient-btn-deliberation);"', to: ' class="bg-gradient-service-deliberation"' }, - { from: ' style="background: linear-gradient(135deg, #10b981 0%, #059669 100%);"', to: ' class="bg-gradient-service-boundary"' }, - { from: ' style="background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);"', to: ' class="bg-gradient-service-instruction"' }, - { from: ' style="background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);"', to: ' class="bg-gradient-service-validator"' }, - { from: ' style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);"', to: ' class="bg-gradient-service-pressure"' }, - { from: ' style="background: linear-gradient(135deg, #ec4899 0%, #db2777 100%);"', to: ' class="bg-gradient-service-metacognitive"' }, - { from: ' style="background: linear-gradient(135deg, #14b8a6 0%, #0d9488 100%);"', to: ' class="bg-gradient-service-deliberation"' }, - - // Border colors - { from: ' style="border-left-color: var(--service-validator-light);"', to: ' class="border-l-service-validator"' }, - { from: ' style="border-left-color: var(--service-instruction-light);"', to: ' class="border-l-service-instruction"' }, - { from: ' style="border-left-color: var(--service-deliberation-light);"', to: ' class="border-l-service-deliberation"' }, - { from: ' style="border-left-color: #10b981;"', to: ' class="border-l-service-boundary"' }, - { from: ' style="border-left-color: #6366f1;"', to: ' class="border-l-service-instruction"' }, - { from: ' style="border-left-color: #8b5cf6;"', to: ' class="border-l-service-validator"' }, - { from: ' style="border-left-color: #f59e0b;"', to: ' class="border-l-service-pressure"' }, - { from: ' style="border-left-color: #ec4899;"', to: ' class="border-l-service-metacognitive"' }, - { from: ' style="border-left-color: #14b8a6;"', to: ' class="border-l-service-deliberation"' }, - - // Text colors - { from: ' style="color: var(--tractatus-core-end);"', to: ' class="text-tractatus-link"' }, - { from: ' style="color: var(--service-validator-light);"', to: ' class="text-service-validator"' }, - { from: ' style="color: var(--service-instruction-light);"', to: ' class="text-service-instruction"' }, - { from: ' style="color: var(--service-deliberation-light);"', to: ' class="text-service-deliberation"' }, - { from: ' style="color: var(--service-validator-dark);"', to: ' class="text-service-validator"' }, - { from: ' style="color: var(--service-instruction-dark);"', to: ' class="text-service-instruction"' }, - { from: ' style="color: var(--service-deliberation-dark);"', to: ' class="text-service-deliberation"' }, - - // Badges - { from: ' style="color: #065f46; background-color: #d1fae5;"', to: ' class="badge-boundary"' }, - { from: ' style="color: #3730a3; background-color: #e0e7ff;"', to: ' class="badge-instruction"' }, - { from: ' style="color: #581c87; background-color: #f3e8ff;"', to: ' class="badge-validator"' }, - { from: ' style="color: #92400e; background-color: #fef3c7;"', to: ' class="badge-pressure"' }, - { from: ' style="color: #831843; background-color: #fce7f3;"', to: ' class="badge-metacognitive"' }, - { from: ' style="color: #134e4a; background-color: #ccfbf1;"', to: ' class="badge-deliberation"' } -]; - -const files = [ - 'public/index.html', - 'public/architecture.html' -]; - -let totalFixed = 0; - -files.forEach(file => { - const filePath = path.join(__dirname, '..', file); - - console.log(`\nProcessing ${file}...`); - - if (!fs.existsSync(filePath)) { - console.log(` βœ— File not found`); - return; - } - - let content = fs.readFileSync(filePath, 'utf8'); - let fileFixed = 0; - - replacements.forEach(({ from, to }) => { - const occurrences = (content.match(new RegExp(from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g')) || []).length; - - if (occurrences > 0) { - content = content.split(from).join(to); - fileFixed += occurrences; - } - }); - - if (fileFixed > 0) { - fs.writeFileSync(filePath, content); - totalFixed += fileFixed; - console.log(` βœ“ Fixed ${fileFixed} violation(s)`); - } else { - console.log(` β€’ No violations found`); - } -}); - -console.log(`\nβœ“ Total fixes applied: ${totalFixed}\n`); diff --git a/scripts/fix-csp-violations.js b/scripts/fix-csp-violations.js deleted file mode 100644 index 26ae20ce..00000000 --- a/scripts/fix-csp-violations.js +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/env node - -/** - * CSP Violation Auto-Remediation Script - * - * Analyzes CSP violations and provides fix recommendations. - * Can optionally attempt automatic fixes for simple cases. - * - * Usage: - * node scripts/fix-csp-violations.js [--auto] [file] - * - * Options: - * --auto Attempt automatic fixes (USE WITH CAUTION) - * --dry-run Show what would be fixed without making changes - * [file] Specific file to fix (default: scan all) - * - * Copyright 2025 Tractatus Project - * Licensed under Apache License 2.0 - */ - -const fs = require('fs'); -const path = require('path'); -const { scanForViolations, scanFile } = require('./check-csp-violations'); - -const colors = { - reset: '\x1b[0m', - green: '\x1b[32m', - yellow: '\x1b[33m', - red: '\x1b[31m', - cyan: '\x1b[36m', - bold: '\x1b[1m' -}; - -function log(message, color = 'reset') { - console.log(`${colors[color]}${message}${colors.reset}`); -} - -/** - * Parse command-line arguments - */ -function parseArgs() { - const args = process.argv.slice(2); - return { - auto: args.includes('--auto'), - dryRun: args.includes('--dry-run'), - file: args.find(arg => !arg.startsWith('--')) - }; -} - -/** - * Generate fix recommendations for a violation - */ -function generateFixRecommendation(violation) { - const recommendations = { - inline_event_handlers: { - priority: 'HIGH', - approach: 'Move to external JavaScript', - steps: [ - `1. Create event listener in external JS file:`, - ` document.getElementById('element-id').addEventListener('click', function() {`, - ` // Handler code here`, - ` });`, - ``, - `2. Remove ${violation.matched.split('=')[0]}= attribute from HTML`, - ``, - `3. Add unique ID to element if needed for selection` - ], - example: 'See public/js/components/*.js for examples' - }, - inline_styles: { - priority: 'HIGH', - approach: 'Move to Tailwind CSS classes or external CSS', - steps: [ - `1. For dynamic styles: Use CSS classes with JavaScript`, - ` element.classList.add('custom-style');`, - ``, - `2. For static styles: Add Tailwind classes to HTML`, - ` Replace style="${violation.matched}" with Tailwind utilities`, - ``, - `3. For complex styles: Add to public/css/custom.css` - ], - example: 'Project uses Tailwind CSS - prefer utility classes' - }, - inline_scripts: { - priority: 'CRITICAL', - approach: 'Extract to external JavaScript file', - steps: [ - `1. Create or identify appropriate JS file in public/js/`, - ``, - `2. Move script content to external file`, - ``, - `3. Replace inline script with:`, - ` `, - ``, - `4. Ensure script loads at appropriate time (defer/async if needed)` - ], - example: 'See public/js/*.js for existing patterns' - }, - javascript_urls: { - priority: 'CRITICAL', - approach: 'Replace with proper event handlers', - steps: [ - `1. Remove href="javascript:..." attribute`, - ``, - `2. Add event listener in external JS:`, - ` document.getElementById('link-id').addEventListener('click', function(e) {`, - ` e.preventDefault();`, - ` // Action code here`, - ` });`, - ``, - `3. For links that don't navigate, consider using