sf-agent-framework
Version:
AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction
423 lines (363 loc) ⢠12.6 kB
JavaScript
/**
* Template Converter - Converts v1 templates to v2 enhanced format
* Part of SF-Agent Framework v4.0
*
* Features:
* - Automatic LLM instruction generation
* - Variable extraction and typing
* - Processor attachment
* - Validation rules creation
*/
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
class TemplateConverter {
constructor() {
this.stats = {
processed: 0,
converted: 0,
skipped: 0,
errors: 0,
};
}
/**
* Convert a v1 template to v2 enhanced format
*/
convertTemplate(inputPath, outputPath) {
try {
console.log(`Converting: ${path.basename(inputPath)}`);
// Read the v1 template
const content = fs.readFileSync(inputPath, 'utf8');
const isYaml = inputPath.endsWith('.yaml') || inputPath.endsWith('.yml');
let v1Template;
if (isYaml) {
v1Template = yaml.load(content);
} else {
// Parse markdown template
v1Template = this.parseMarkdownTemplate(content);
}
// Convert to v2 format
const v2Template = this.transformToV2(v1Template, inputPath);
// Write the v2 template
const outputContent = yaml.dump(v2Template, {
indent: 2,
lineWidth: 120,
noRefs: true,
});
fs.writeFileSync(outputPath, outputContent);
this.stats.converted++;
console.log(`ā
Converted successfully: ${path.basename(outputPath)}`);
return true;
} catch (error) {
console.error(`ā Error converting ${inputPath}: ${error.message}`);
this.stats.errors++;
return false;
}
}
/**
* Parse a markdown template into structured format
*/
parseMarkdownTemplate(content) {
const template = {
title: '',
description: '',
sections: [],
variables: [],
};
// Extract title
const titleMatch = content.match(/^#\s+(.+)$/m);
if (titleMatch) {
template.title = titleMatch[1].replace(' Template', '');
}
// Extract description
const descMatch = content.match(/^(.+?)(?=\n##)/s);
if (descMatch) {
template.description = descMatch[1].replace(/^#.+\n/, '').trim();
}
// Extract variables ({{variable}})
const varMatches = content.matchAll(/\{\{(\w+)\}\}/g);
const variables = new Set();
for (const match of varMatches) {
variables.add(match[1]);
}
template.variables = Array.from(variables);
// Extract sections
const sectionMatches = content.matchAll(/^##\s+(.+)$([\s\S]*?)(?=^##\s+|\Z)/gm);
for (const match of sectionMatches) {
template.sections.push({
title: match[1],
content: match[2].trim(),
});
}
return template;
}
/**
* Transform v1 template to v2 enhanced format
*/
transformToV2(v1Template, inputPath) {
const baseName = path.basename(inputPath, path.extname(inputPath));
const enhancedName = baseName.replace('-tmpl', '').replace('_tmpl', '') + '-enhanced';
const v2Template = {
title: `${v1Template.title} Enhanced`,
version: '2.0',
type: 'enhanced',
description: v1Template.description || `Enhanced version of ${v1Template.title}`,
// Generate LLM instructions based on template type
instruction: this.generateLLMInstruction(v1Template, baseName),
// Convert variables to typed format
variables: this.generateVariables(v1Template),
// Generate enhanced content
content: this.generateEnhancedContent(v1Template),
// Add processors
processors: this.generateProcessors(baseName),
// Output configuration
output: {
format: 'markdown',
filename: `{{projectName}}-${baseName}.md`,
additionalFiles: this.generateAdditionalFiles(baseName),
},
};
return v2Template;
}
/**
* Generate LLM instructions based on template type
*/
generateLLMInstruction(template, templateName) {
const domainMap = {
apex: 'Apex development and Salesforce programming',
lwc: 'Lightning Web Components and modern UI development',
flow: 'Salesforce Flow automation and process design',
integration: 'System integration and API design',
security: 'Security architecture and compliance',
data: 'Data modeling and migration',
test: 'Testing strategies and quality assurance',
deployment: 'Release management and deployment',
architecture: 'Solution architecture and technical design',
};
// Determine domain from template name
let domain = 'general Salesforce development';
for (const [key, value] of Object.entries(domainMap)) {
if (templateName.toLowerCase().includes(key)) {
domain = value;
break;
}
}
return `|
[[LLM: You are an expert in ${domain}. Your task is to:
1. Analyze the requirements and generate optimal solutions
2. Apply best practices and design patterns
3. Identify potential issues and provide recommendations
4. Create comprehensive documentation
5. Generate test scenarios and validation criteria
Focus on:
- Technical accuracy and completeness
- Performance optimization
- Security considerations
- Maintainability and scalability
- User experience and adoption]]`;
}
/**
* Generate typed variables from v1 template
*/
generateVariables(template) {
const variables = [];
const commonVars = {
projectName: { type: 'string', required: true, description: 'Project name' },
projectType: { type: 'enum', values: ['new', 'enhancement', 'migration'], default: 'new' },
environment: { type: 'enum', values: ['dev', 'test', 'uat', 'prod'], default: 'dev' },
complexity: { type: 'enum', values: ['simple', 'moderate', 'complex'], default: 'moderate' },
userName: { type: 'string', required: false, description: 'User full name' },
date: { type: 'date', required: false, default: 'today' },
};
// Process template variables
if (template.variables && Array.isArray(template.variables)) {
template.variables.forEach((varName) => {
if (commonVars[varName]) {
variables.push({
name: varName,
...commonVars[varName],
});
} else {
// Generate default variable definition
variables.push({
name: varName,
type: 'string',
required: false,
description: `${varName.replace(/([A-Z])/g, ' $1').toLowerCase()}`,
});
}
});
}
// Ensure projectName is always included
if (!variables.find((v) => v.name === 'projectName')) {
variables.unshift({
name: 'projectName',
type: 'string',
required: true,
description: 'Project name',
});
}
return variables;
}
/**
* Generate enhanced content with LLM directives
*/
generateEnhancedContent(template) {
let content = '|';
// Add title
content += '\n # {{projectName}}';
content += '\n ';
content += '\n [[LLM: Generate an executive summary based on the project context]]';
content += '\n ';
// Process sections
if (template.sections && Array.isArray(template.sections)) {
template.sections.forEach((section) => {
content += `\n ## ${section.title}`;
content += '\n ';
// Add LLM enhancement for specific sections
if (section.title.toLowerCase().includes('requirement')) {
content += '\n [[LLM: Analyze requirements and identify gaps, risks, and dependencies]]';
} else if (section.title.toLowerCase().includes('design')) {
content += '\n [[LLM: Generate design recommendations based on best practices]]';
} else if (section.title.toLowerCase().includes('test')) {
content += '\n [[LLM: Create comprehensive test scenarios with expected results]]';
} else if (section.title.toLowerCase().includes('security')) {
content += '\n [[LLM: Perform security analysis and provide recommendations]]';
} else {
content += `\n [[LLM: Enhance this section with relevant insights and recommendations]]`;
}
content += '\n ';
// Include original content if exists
if (section.content) {
content += '\n ' + section.content.replace(/\n/g, '\n ');
}
content += '\n ';
});
}
// Add recommendations section
content += '\n ## Recommendations';
content += '\n ';
content += '\n [[LLM: Based on the analysis, provide:';
content += '\n 1. Immediate action items';
content += '\n 2. Best practices to implement';
content += '\n 3. Potential risks to mitigate';
content += '\n 4. Future enhancements to consider]]';
return content;
}
/**
* Generate processors based on template type
*/
generateProcessors(templateName) {
const processors = [];
// Add validation processor
processors.push({
type: 'validation',
function: `validate${this.toPascalCase(templateName)}`,
});
// Add specific processors based on type
if (templateName.includes('test')) {
processors.push({
type: 'generation',
function: 'generateTestCases',
});
} else if (templateName.includes('security')) {
processors.push({
type: 'analysis',
function: 'performSecurityAnalysis',
});
} else if (templateName.includes('integration')) {
processors.push({
type: 'generation',
function: 'generateAPISpec',
});
}
return processors;
}
/**
* Generate additional output files
*/
generateAdditionalFiles(templateName) {
const files = [];
if (templateName.includes('test')) {
files.push({ testCases: '{{projectName}}-test-cases.xlsx' });
}
if (templateName.includes('deployment')) {
files.push({ checklist: '{{projectName}}-deployment-checklist.pdf' });
}
if (templateName.includes('architecture')) {
files.push({ diagram: '{{projectName}}-architecture.svg' });
}
return files;
}
/**
* Convert string to PascalCase
*/
toPascalCase(str) {
return str
.replace(/[-_]/g, ' ')
.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase())
.replace(/\s/g, '');
}
/**
* Convert all templates in a directory
*/
convertDirectory(inputDir, outputDir) {
console.log('š Starting template conversion...\n');
// Create output directory if it doesn't exist
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Get all template files
const files = fs
.readdirSync(inputDir)
.filter(
(file) =>
(file.endsWith('.yaml') || file.endsWith('.yml') || file.endsWith('.md')) &&
!file.includes('-enhanced')
);
// Process each file
files.forEach((file) => {
this.stats.processed++;
const inputPath = path.join(inputDir, file);
const baseName = path.basename(file, path.extname(file));
const outputName = baseName.replace('-tmpl', '').replace('_tmpl', '') + '-enhanced.yaml';
const outputPath = path.join(outputDir, outputName);
// Skip if already exists
if (fs.existsSync(outputPath)) {
console.log(`āļø Skipping ${file} (already exists)`);
this.stats.skipped++;
} else {
this.convertTemplate(inputPath, outputPath);
}
});
// Print summary
console.log('\nš Conversion Summary:');
console.log(` Processed: ${this.stats.processed}`);
console.log(` Converted: ${this.stats.converted}`);
console.log(` Skipped: ${this.stats.skipped}`);
console.log(` Errors: ${this.stats.errors}`);
console.log(
` Success Rate: ${Math.round((this.stats.converted / this.stats.processed) * 100)}%`
);
}
}
// CLI interface
if (require.main === module) {
const args = process.argv.slice(2);
if (args.length < 2) {
console.log('Usage: node template-converter.js <input> <output>');
console.log(' input: Template file or directory');
console.log(' output: Output file or directory');
process.exit(1);
}
const converter = new TemplateConverter();
const inputPath = path.resolve(args[0]);
const outputPath = path.resolve(args[1]);
if (fs.statSync(inputPath).isDirectory()) {
converter.convertDirectory(inputPath, outputPath);
} else {
converter.convertTemplate(inputPath, outputPath);
}
}
module.exports = TemplateConverter;