const fs = require('fs');
const path = require('path');
// Configuration
const ROOT_DIR = path.join(__dirname, '..');
const DIST_DIR = path.join(__dirname, 'dist');
const FILES_DIR = path.join(DIST_DIR, 'files');
const METADATA_DIR = path.join(ROOT_DIR, 'metadata');
// Directories to exclude from scanning
const EXCLUDED_DIRS = ['.git', 'node_modules', 'site', 'assets'];
// File extensions to include
const INCLUDED_EXTENSIONS = ['.txt', '.json', '.md'];
// Utility function to escape HTML
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
// Load metadata files
function loadMetadata() {
const metadata = [];
if (!fs.existsSync(METADATA_DIR)) {
return metadata;
}
const files = fs.readdirSync(METADATA_DIR);
for (const file of files) {
if (file.endsWith('.json') && file !== 'README.md') {
try {
const content = fs.readFileSync(path.join(METADATA_DIR, file), 'utf-8');
metadata.push(JSON.parse(content));
} catch (error) {
console.warn(`Warning: Could not load metadata from ${file}`);
}
}
}
return metadata;
}
// Generate enhanced HTML for individual file pages
function generateFileHTML(filePath, content, fileInfo, metadata) {
const relativePath = path.relative(ROOT_DIR, filePath);
const extension = path.extname(filePath);
const language = extension === '.json' ? 'json' : extension === '.md' ? 'markdown' : 'text';
const lines = content.split('\n');
return `
${escapeHtml(relativePath)} - System Prompts
Path: ${escapeHtml(relativePath)}
Size: ${fileInfo.size.toLocaleString()} bytes
Lines: ${lines.length.toLocaleString()}
Type: ${language}
`;
}
// Generate enhanced index HTML with search and filters
function generateIndexHTML(fileTree, stats, metadata) {
const metadataJson = JSON.stringify(metadata, null, 2);
return `
System Prompts and Models of AI Tools
Tool Type
All Types
IDE Plugins
CLI Tools
Web Platforms
Autonomous Agents
Pricing
All Pricing
Free
Freemium
Paid
Features
All Features
Agent Mode
Parallel Execution
TODO Tracking
Memory System
${stats.totalFiles}
Total Files
${stats.totalDirectories}
Tool Directories
${Math.round(stats.totalSize / 1024)}KB
Total Size
${metadata.length}
Tools Documented
š Files
š ļø Tools
š Comparison
${generateFileTreeHTML(fileTree)}
${generateToolCardsHTML(metadata)}
${generateComparisonTableHTML(metadata)}
`;
}
// Generate file tree HTML
function generateFileTreeHTML(tree) {
let html = '';
const sortedDirs = Object.keys(tree).sort();
for (const dir of sortedDirs) {
const files = tree[dir];
if (files.length === 0) continue;
html += `
š ${escapeHtml(dir)}
ā¼
`;
const sortedFiles = files.sort((a, b) => a.name.localeCompare(b.name));
for (const file of sortedFiles) {
const icon = file.name.endsWith('.json') ? 'š' : file.name.endsWith('.md') ? 'š' : 'š';
html += `
${icon}
${escapeHtml(file.name)}
`;
}
html += ` `;
}
return html || 'No files found
';
}
// Generate tool cards HTML
function generateToolCardsHTML(metadata) {
if (metadata.length === 0) {
return 'No tools found
';
}
let html = '';
for (const tool of metadata) {
const tags = tool.tags || [];
const tagsHTML = tags.slice(0, 3).map(tag => `${escapeHtml(tag)} `).join('');
html += `
`;
}
return html;
}
// Generate comparison table HTML
function generateComparisonTableHTML(metadata) {
if (metadata.length === 0) {
return 'No tools available for comparison
';
}
let html = `
Tool
Type
Pricing
Agent Mode
Parallel
TODO System
Memory
`;
for (const tool of metadata) {
html += `
${escapeHtml(tool.name)}
${escapeHtml(tool.type)}
${escapeHtml(tool.pricing?.model || 'Unknown')}
${tool.features?.agentMode ? 'ā
' : 'ā'}
${tool.features?.parallelExecution ? 'ā
' : 'ā'}
${tool.features?.todoTracking ? 'ā
' : 'ā'}
${tool.features?.memorySystem ? 'ā
' : 'ā'}
`;
}
html += `
`;
return html;
}
// Scan directory recursively
function scanDirectory(dir, baseDir = dir, fileTree = {}, stats = { totalFiles: 0, totalDirectories: 0, totalSize: 0 }) {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const relativePath = path.relative(baseDir, fullPath);
// Skip excluded directories
if (EXCLUDED_DIRS.some(excluded => relativePath.startsWith(excluded))) {
continue;
}
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
stats.totalDirectories++;
scanDirectory(fullPath, baseDir, fileTree, stats);
} else if (stat.isFile()) {
const ext = path.extname(fullPath);
if (INCLUDED_EXTENSIONS.includes(ext)) {
const dirName = path.dirname(relativePath);
const displayDir = dirName === '.' ? 'Root' : dirName;
if (!fileTree[displayDir]) {
fileTree[displayDir] = [];
}
stats.totalFiles++;
stats.totalSize += stat.size;
fileTree[displayDir].push({
name: path.basename(fullPath),
path: fullPath,
relativePath: relativePath,
id: Buffer.from(relativePath).toString('base64').replace(/[^a-zA-Z0-9]/g, '_'),
size: stat.size
});
}
}
}
return { fileTree, stats };
}
// Main build function
function build() {
console.log('š Starting enhanced build process...\n');
// Clean and create dist directories
if (fs.existsSync(DIST_DIR)) {
fs.rmSync(DIST_DIR, { recursive: true });
}
fs.mkdirSync(DIST_DIR, { recursive: true });
fs.mkdirSync(FILES_DIR, { recursive: true });
console.log('š Scanning repository...');
const { fileTree, stats } = scanDirectory(ROOT_DIR);
console.log('š Loading metadata...');
const metadata = loadMetadata();
console.log(`\nš Statistics:`);
console.log(` - Total files: ${stats.totalFiles}`);
console.log(` - Total directories: ${stats.totalDirectories}`);
console.log(` - Total size: ${Math.round(stats.totalSize / 1024)}KB`);
console.log(` - Tools with metadata: ${metadata.length}\n`);
// Generate individual file pages
console.log('š Generating file pages...');
let generatedPages = 0;
for (const dir in fileTree) {
for (const file of fileTree[dir]) {
try {
const content = fs.readFileSync(file.path, 'utf-8');
const html = generateFileHTML(file.path, content, { size: file.size }, metadata);
const outputPath = path.join(FILES_DIR, `${file.id}.html`);
fs.writeFileSync(outputPath, html);
generatedPages++;
} catch (error) {
console.error(` ā ļø Error processing ${file.relativePath}: ${error.message}`);
}
}
}
console.log(` ā Generated ${generatedPages} file pages`);
// Generate index page
console.log('\nš Generating enhanced index page...');
const indexHTML = generateIndexHTML(fileTree, stats, metadata);
fs.writeFileSync(path.join(DIST_DIR, 'index.html'), indexHTML);
console.log(' ā Index page generated with search, filters, and comparison');
console.log('\n⨠Enhanced build completed successfully!');
console.log(`\nš Output directory: ${DIST_DIR}`);
console.log('š Open dist/index.html to view the site\n');
console.log('⨠New features:');
console.log(' ⢠š Search across all files and tools');
console.log(' ⢠šØ Dark/Light theme toggle');
console.log(' ⢠š·ļø Filter by type, pricing, and features');
console.log(' ⢠š Copy code with one click');
console.log(' ⢠š Comparison table view');
console.log(' ⢠š± Mobile-responsive design\n');
}
// Run build
try {
build();
} catch (error) {
console.error('ā Build failed:', error);
process.exit(1);
}