UNPKG

@boundless-oss/atlas

Version:

Atlas - MCP Server for comprehensive startup project management

236 lines 7.69 kB
export function getNygardTemplate() { return { name: 'nygard', description: 'Michael Nygard\'s template - simple and effective for most decisions', fields: [ 'title', 'status', 'date', 'deciders', 'context', 'decision', 'consequences', 'tags', 'relatedTo', 'supersedes', 'supersededBy' ], requiredFields: [ 'title', 'deciders', 'context', 'decision', 'consequences' ], optionalFields: [ 'tags', 'relatedTo', 'supersedes', 'supersededBy' ] }; } export function getMADRTemplate() { return { name: 'madr', description: 'Markdown Architectural Decision Records - comprehensive template with structured options', fields: [ 'title', 'status', 'date', 'deciders', 'context', 'decisionDrivers', 'consideredOptions', 'decision', 'consequences', 'prosAndCons', 'links', 'tags', 'relatedTo', 'supersedes', 'supersededBy' ], requiredFields: [ 'title', 'deciders', 'context', 'decisionDrivers', 'decision', 'consequences' ], optionalFields: [ 'consideredOptions', 'prosAndCons', 'links', 'tags', 'relatedTo', 'supersedes', 'supersededBy' ] }; } export function getYStatementTemplate() { return { name: 'y-statement', description: 'Y-statement - simple format focusing on context, decision, and consequences', fields: [ 'title', 'status', 'date', 'deciders', 'context', 'decision', 'consequences', 'tags' ], requiredFields: [ 'title', 'deciders', 'context', 'decision', 'consequences' ], optionalFields: [ 'tags' ] }; } export function renderADRTemplate(adr) { let markdown = `# ${adr.id}: ${adr.title}\n\n`; // Status if (adr.template === 'y-statement') { markdown += `## Status: ${adr.status.charAt(0).toUpperCase() + adr.status.slice(1)}\n\n`; } else { markdown += `## Status\n\n`; markdown += `${adr.status.charAt(0).toUpperCase() + adr.status.slice(1)}\n\n`; } // Metadata markdown += `**Date**: ${adr.date.toISOString().split('T')[0]}\n`; markdown += `**Deciders**: ${adr.deciders.join(', ')}\n`; if (adr.tags && adr.tags.length > 0) { markdown += `**Tags**: ${adr.tags.join(', ')}\n`; } markdown += '\n'; // Context markdown += `## Context\n\n${adr.context}\n\n`; // Decision Drivers (MADR only) if (adr.template === 'madr' && adr.decisionDrivers && adr.decisionDrivers.length > 0) { markdown += `## Decision Drivers\n\n`; adr.decisionDrivers.forEach(driver => { markdown += `* ${driver}\n`; }); markdown += '\n'; } // Considered Options (MADR only) if (adr.template === 'madr' && adr.consideredOptions && adr.consideredOptions.length > 0) { markdown += `## Considered Options\n\n`; adr.consideredOptions.forEach(option => { markdown += `* ${option.title} - ${option.description}\n`; }); markdown += '\n'; } // Decision markdown += `## Decision\n\n${adr.decision}\n\n`; // Consequences markdown += `## Consequences\n\n${adr.consequences}\n\n`; // Pros and Cons per option (MADR) if (adr.template === 'madr' && adr.consideredOptions && adr.consideredOptions.length > 0) { adr.consideredOptions.forEach(option => { markdown += `### ${option.title}\n\n`; if (option.description) { markdown += `${option.description}\n\n`; } option.pros.forEach(pro => { markdown += `* Good, because ${pro}\n`; }); option.cons.forEach(con => { markdown += `* Bad, because ${con}\n`; }); markdown += '\n'; }); } // Links/Relationships const hasLinks = adr.supersedes?.length || adr.supersededBy || adr.relatedTo?.length; if (hasLinks) { markdown += `## Links\n\n`; if (adr.supersedes && adr.supersedes.length > 0) { markdown += `* Supersedes: ${adr.supersedes.join(', ')}\n`; } if (adr.supersededBy) { markdown += `* Superseded by: ${adr.supersededBy}\n`; } if (adr.relatedTo && adr.relatedTo.length > 0) { markdown += `* Related to: ${adr.relatedTo.join(', ')}\n`; } markdown += '\n'; } // Status History if (adr.statusHistory && adr.statusHistory.length > 0) { markdown += `## Status History\n\n`; adr.statusHistory.forEach(change => { markdown += `* ${change.from}${change.to} on ${change.date.toISOString().split('T')[0]}`; markdown += ` by ${change.changedBy}`; if (change.reason) { markdown += `: ${change.reason}`; } markdown += '\n'; }); } return markdown; } export function getTemplateFields(template) { switch (template) { case 'nygard': return { required: getNygardTemplate().requiredFields, optional: getNygardTemplate().optionalFields }; case 'madr': return { required: getMADRTemplate().requiredFields, optional: getMADRTemplate().optionalFields }; case 'y-statement': return { required: getYStatementTemplate().requiredFields, optional: getYStatementTemplate().optionalFields }; default: throw new Error(`Unknown template: ${template}`); } } export function validateTemplateData(template, data) { const errors = []; const fields = getTemplateFields(template); // Check required fields for (const field of fields.required) { if (!(field in data) || data[field] === undefined || data[field] === null) { errors.push(`Missing required field: ${field}`); } else if (Array.isArray(data[field]) && data[field].length === 0 && field === 'deciders') { errors.push(`Field "deciders" cannot be empty`); } } // Validate array fields const arrayFields = ['deciders', 'tags', 'decisionDrivers', 'consideredOptions', 'prosAndCons']; for (const field of arrayFields) { if (field in data && data[field] !== undefined && !Array.isArray(data[field])) { errors.push(`Field "${field}" must be an array`); } } // Validate consideredOptions structure if (data.consideredOptions && Array.isArray(data.consideredOptions)) { data.consideredOptions.forEach((option, index) => { if (!option.title || !option.description || !option.pros || !option.cons) { errors.push(`Option must have title, description, pros, and cons`); } }); } return { valid: errors.length === 0, errors }; } //# sourceMappingURL=templates.js.map