UNPKG

defect-inspection-tools-mcp-server

Version:

Defect inspection tools server handling defect detection, analysis, and reporting with AI/ML capabilities for quality control

407 lines 18.2 kB
import { logger } from './logger.js'; import { SanitizationMiddleware } from '../middleware/sanitization-middleware.js'; export class MarkdownProcessor { // Parse markdown content into structured document static parseMarkdown(content, options = {}) { try { const opts = { ...MarkdownProcessor.DEFAULT_OPTIONS, ...options }; logger.debug('Parsing markdown content', { contentLength: content.length, options: opts }); // Sanitize content if requested let processedContent = content; if (opts.sanitize) { processedContent = SanitizationMiddleware.sanitizeString(content, opts.maxLength, opts.allowHtml); } // Limit content length if (processedContent.length > opts.maxLength) { processedContent = processedContent.substring(0, opts.maxLength); } const document = { title: this.extractTitle(processedContent), sections: this.extractSections(processedContent, opts), tables: this.extractTables(processedContent), links: this.extractLinks(processedContent), images: this.extractImages(processedContent), codeBlocks: this.extractCodeBlocks(processedContent) }; logger.debug('Markdown parsing completed', { title: document.title, sectionsCount: document.sections.length, tablesCount: document.tables.length, linksCount: document.links.length, imagesCount: document.images.length, codeBlocksCount: document.codeBlocks.length }); return document; } catch (error) { logger.error('Markdown parsing failed', { error: error.message, contentLength: content.length }); throw error; } } // Convert structured document to markdown static generateMarkdown(document) { try { let markdown = ''; // Add title if (document.title) { markdown += `# ${document.title}\n\n`; } // Add sections for (const section of document.sections) { markdown += this.generateSectionMarkdown(section); } // Add tables for (const table of document.tables) { markdown += this.generateTableMarkdown(table); } // Add code blocks for (const codeBlock of document.codeBlocks) { markdown += this.generateCodeBlockMarkdown(codeBlock); } logger.debug('Markdown generation completed', { outputLength: markdown.length }); return markdown; } catch (error) { logger.error('Markdown generation failed', { error: error.message }); throw error; } } // Generate maritime inspection report in markdown format static generateInspectionReport(vesselData, inspectionData, defects = []) { try { const sanitizedVesselData = SanitizationMiddleware.sanitizeToolArguments(vesselData); const sanitizedInspectionData = SanitizationMiddleware.sanitizeToolArguments(inspectionData); const sanitizedDefects = defects.map(d => SanitizationMiddleware.sanitizeToolArguments(d)); let report = ''; // Title report += `# Maritime Inspection Report\n\n`; // Vessel Information report += `## Vessel Information\n\n`; report += `| Property | Value |\n`; report += `|----------|-------|\n`; report += `| Vessel Name | ${sanitizedVesselData.vessel_name || 'N/A'} |\n`; report += `| IMO Number | ${sanitizedVesselData.imo_number || 'N/A'} |\n`; report += `| Vessel Type | ${sanitizedVesselData.vessel_type || 'N/A'} |\n`; report += `| Flag State | ${sanitizedVesselData.flag_state || 'N/A'} |\n`; report += `| Classification Society | ${sanitizedVesselData.class_society || 'N/A'} |\n`; report += `| Built Year | ${sanitizedVesselData.built_year || 'N/A'} |\n\n`; // Inspection Details report += `## Inspection Details\n\n`; report += `| Property | Value |\n`; report += `|----------|-------|\n`; report += `| Inspection Date | ${sanitizedInspectionData.inspection_date || 'N/A'} |\n`; report += `| Inspector | ${sanitizedInspectionData.inspector || 'N/A'} |\n`; report += `| Port | ${sanitizedInspectionData.port || 'N/A'} |\n`; report += `| Inspection Type | ${sanitizedInspectionData.inspection_type || 'N/A'} |\n`; report += `| Status | ${sanitizedInspectionData.status || 'N/A'} |\n\n`; // Executive Summary report += `## Executive Summary\n\n`; report += `This inspection report covers the ${sanitizedInspectionData.inspection_type || 'routine'} inspection of the vessel ${sanitizedVesselData.vessel_name || 'Unknown'} conducted on ${sanitizedInspectionData.inspection_date || 'N/A'}.\n\n`; // Defects Summary if (sanitizedDefects.length > 0) { report += `## Defects Summary\n\n`; report += `Total defects found: **${sanitizedDefects.length}**\n\n`; // Defects by severity const severityCount = this.countDefectsBySeverity(sanitizedDefects); report += `### Defects by Severity\n\n`; report += `| Severity | Count |\n`; report += `|----------|-------|\n`; Object.entries(severityCount).forEach(([severity, count]) => { report += `| ${severity} | ${count} |\n`; }); report += `\n`; // Detailed defects report += `## Detailed Defects\n\n`; sanitizedDefects.forEach((defect, index) => { report += `### Defect ${index + 1}: ${defect.defect_type || 'Unknown'}\n\n`; report += `| Property | Value |\n`; report += `|----------|-------|\n`; report += `| Location | ${defect.location || 'N/A'} |\n`; report += `| Severity | ${defect.severity || 'N/A'} |\n`; report += `| Status | ${defect.status || 'N/A'} |\n`; report += `| Description | ${defect.description || 'N/A'} |\n`; report += `| Corrective Action | ${defect.corrective_action || 'N/A'} |\n`; report += `| Due Date | ${defect.due_date || 'N/A'} |\n\n`; }); } else { report += `## Defects Summary\n\n`; report += `No defects were found during this inspection.\n\n`; } // Recommendations report += `## Recommendations\n\n`; if (sanitizedDefects.length > 0) { report += `Based on the inspection findings, the following recommendations are made:\n\n`; report += `1. Address all critical and high-severity defects immediately\n`; report += `2. Implement corrective actions as specified for each defect\n`; report += `3. Establish a monitoring system for recurring issues\n`; report += `4. Conduct follow-up inspections to verify corrections\n`; report += `5. Review and update maintenance procedures as necessary\n\n`; } else { report += `The vessel appears to be in good condition. Continue with regular maintenance schedules and monitoring.\n\n`; } // Compliance Status report += `## Compliance Status\n\n`; const complianceStatus = this.determineComplianceStatus(sanitizedDefects); report += `Overall compliance status: **${complianceStatus}**\n\n`; // Footer report += `## Report Information\n\n`; report += `| Property | Value |\n`; report += `|----------|-------|\n`; report += `| Report Generated | ${new Date().toISOString()} |\n`; report += `| Generated By | Defect Inspection Tools MCP Server |\n`; report += `| Report Version | 1.0 |\n\n`; logger.info('Maritime inspection report generated', { vesselName: sanitizedVesselData.vessel_name, defectCount: sanitizedDefects.length, reportLength: report.length }); return report; } catch (error) { logger.error('Maritime inspection report generation failed', { error: error.message }); throw error; } } // Generate compliance summary in markdown format static generateComplianceSummary(complianceData) { try { const sanitizedData = complianceData.map(d => SanitizationMiddleware.sanitizeToolArguments(d)); let summary = ''; // Title summary += `# Maritime Compliance Summary\n\n`; // Overview summary += `## Overview\n\n`; summary += `This summary covers compliance status for ${sanitizedData.length} vessel(s) or inspection(s).\n\n`; // Compliance Statistics const stats = this.calculateComplianceStatistics(sanitizedData); summary += `## Compliance Statistics\n\n`; summary += `| Metric | Value |\n`; summary += `|--------|-------|\n`; summary += `| Total Vessels/Inspections | ${stats.total} |\n`; summary += `| Compliant | ${stats.compliant} |\n`; summary += `| Non-Compliant | ${stats.nonCompliant} |\n`; summary += `| Compliance Rate | ${stats.complianceRate.toFixed(1)}% |\n\n`; // Detailed Compliance Data summary += `## Detailed Compliance Data\n\n`; summary += `| Vessel/Inspection | Status | Defects | Last Inspection |\n`; summary += `|------------------|--------|---------|----------------|\n`; sanitizedData.forEach(item => { const status = item.compliance_status || 'Unknown'; const defects = item.defect_count || 0; const lastInspection = item.last_inspection_date || 'N/A'; const name = item.vessel_name || item.inspection_id || 'Unknown'; summary += `| ${name} | ${status} | ${defects} | ${lastInspection} |\n`; }); summary += `\n`; // Recommendations summary += `## Recommendations\n\n`; if (stats.nonCompliant > 0) { summary += `### Priority Actions\n\n`; summary += `1. **Immediate attention required** for ${stats.nonCompliant} non-compliant vessel(s)\n`; summary += `2. **Conduct detailed inspections** to identify root causes\n`; summary += `3. **Implement corrective action plans** with clear timelines\n`; summary += `4. **Establish monitoring systems** for ongoing compliance\n\n`; } summary += `### General Recommendations\n\n`; summary += `1. **Maintain regular inspection schedules** for all vessels\n`; summary += `2. **Update compliance procedures** based on latest regulations\n`; summary += `3. **Provide training** on compliance requirements\n`; summary += `4. **Monitor industry best practices** and regulatory changes\n\n`; // Footer summary += `## Summary Information\n\n`; summary += `| Property | Value |\n`; summary += `|----------|-------|\n`; summary += `| Summary Generated | ${new Date().toISOString()} |\n`; summary += `| Generated By | Defect Inspection Tools MCP Server |\n`; summary += `| Data Points | ${sanitizedData.length} |\n\n`; logger.info('Compliance summary generated', { dataPoints: sanitizedData.length, complianceRate: stats.complianceRate, summaryLength: summary.length }); return summary; } catch (error) { logger.error('Compliance summary generation failed', { error: error.message }); throw error; } } // Private helper methods static extractTitle(content) { const titleMatch = content.match(/^#\s+(.+)$/m); return titleMatch ? titleMatch[1].trim() : ''; } static extractSections(content, options) { const sections = []; const headingRegex = /^(#{1,6})\s+(.+)$/gm; let match; while ((match = headingRegex.exec(content)) !== null) { const level = match[1].length; if (options.headingLevels?.includes(level)) { sections.push({ level, title: match[2].trim(), content: '', subsections: [] }); } } return sections; } static extractTables(content) { const tables = []; const tableRegex = /\|(.+)\|\s*\n\|[-\s|:]+\|\s*\n((?:\|.+\|\s*\n?)*)/gm; let match; while ((match = tableRegex.exec(content)) !== null) { const headers = match[1].split('|').map(h => h.trim()).filter(h => h); const rowsText = match[2]; const rows = rowsText.split('\n') .filter(row => row.trim()) .map(row => row.split('|').map(cell => cell.trim()).filter(cell => cell)); if (headers.length > 0 && rows.length > 0) { tables.push({ headers, rows }); } } return tables; } static extractLinks(content) { const links = []; const linkRegex = /\[([^\]]+)\]\(([^)]+)(?:\s+"([^"]+)")?\)/g; let match; while ((match = linkRegex.exec(content)) !== null) { links.push({ text: match[1], url: match[2], title: match[3] }); } return links; } static extractImages(content) { const images = []; const imageRegex = /!\[([^\]]*)\]\(([^)]+)(?:\s+"([^"]+)")?\)/g; let match; while ((match = imageRegex.exec(content)) !== null) { images.push({ alt: match[1], url: match[2], title: match[3] }); } return images; } static extractCodeBlocks(content) { const codeBlocks = []; const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g; let match; while ((match = codeBlockRegex.exec(content)) !== null) { codeBlocks.push({ language: match[1], code: match[2] }); } return codeBlocks; } static generateSectionMarkdown(section) { let markdown = `${'#'.repeat(section.level)} ${section.title}\n\n`; if (section.content) { markdown += `${section.content}\n\n`; } if (section.subsections) { for (const subsection of section.subsections) { markdown += this.generateSectionMarkdown(subsection); } } return markdown; } static generateTableMarkdown(table) { let markdown = ''; if (table.caption) { markdown += `**${table.caption}**\n\n`; } // Headers markdown += `| ${table.headers.join(' | ')} |\n`; markdown += `| ${table.headers.map(() => '---').join(' | ')} |\n`; // Rows for (const row of table.rows) { markdown += `| ${row.join(' | ')} |\n`; } markdown += '\n'; return markdown; } static generateCodeBlockMarkdown(codeBlock) { let markdown = '```'; if (codeBlock.language) { markdown += codeBlock.language; } markdown += `\n${codeBlock.code}\n\`\`\`\n\n`; return markdown; } static countDefectsBySeverity(defects) { const severityCount = { 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Unknown': 0 }; defects.forEach(defect => { const severity = defect.severity || 'Unknown'; severityCount[severity] = (severityCount[severity] || 0) + 1; }); return severityCount; } static determineComplianceStatus(defects) { const criticalDefects = defects.filter(d => d.severity === 'Critical').length; const highDefects = defects.filter(d => d.severity === 'High').length; if (criticalDefects > 0) { return 'Non-Compliant (Critical Issues)'; } else if (highDefects > 0) { return 'Non-Compliant (High Priority Issues)'; } else if (defects.length > 0) { return 'Compliant with Minor Issues'; } else { return 'Fully Compliant'; } } static calculateComplianceStatistics(data) { const total = data.length; const compliant = data.filter(item => item.compliance_status === 'Compliant' || item.compliance_status === 'Fully Compliant').length; const nonCompliant = total - compliant; const complianceRate = total > 0 ? (compliant / total) * 100 : 0; return { total, compliant, nonCompliant, complianceRate }; } } MarkdownProcessor.DEFAULT_OPTIONS = { sanitize: true, maxLength: 100000, allowHtml: false, preserveLineBreaks: true, headingLevels: [1, 2, 3, 4, 5, 6] }; //# sourceMappingURL=markdown.js.map