Skip to main content
Glama
summarize.ts9.91 kB
import fs from 'fs'; import path from 'path'; import chalk from 'chalk'; import { MCPClient } from '../client.js'; import { readProjectContext } from '../utils/projectContext.js'; interface ProjectSummaryOptions { output?: string; budget?: number; model?: string; verbose?: boolean; endpoint?: string; apiKey?: string; username?: string; password?: string; } /** * Generate a comprehensive project summary by analyzing all project files and history */ export async function summarizeProject(options: ProjectSummaryOptions = {}) { const client = new MCPClient(options.endpoint, options.apiKey, options.username, options.password); try { console.log(chalk.blue('📊 Analyzing project for summary generation...')); // Read all project context const projectContext = readProjectContext(); // Read coding history if it exists const historyPath = 'project-coding-history.md'; let history = ''; if (fs.existsSync(historyPath)) { history = fs.readFileSync(historyPath, 'utf-8'); } // Get project structure const projectStructure = getProjectStructure('.'); // Count lines of code const codeStats = getCodeStatistics('.'); // Build comprehensive summary prompt const summaryPrompt = buildSummaryPrompt(projectContext, history, projectStructure, codeStats); if (options.verbose) { console.log(chalk.gray('Context loaded:')); if (projectContext.sketch) console.log(chalk.gray('- SKETCH.md')); if (projectContext.roadmap) console.log(chalk.gray('- ROADMAP.md')); if (projectContext.instructor) console.log(chalk.gray('- mcp-instructor.md')); if (history) console.log(chalk.gray('- project-coding-history.md')); console.log(chalk.gray(`- ${projectStructure.fileCount} files analyzed`)); console.log(chalk.gray(`- ${codeStats.totalLines} total lines of code`)); } console.log(chalk.yellow('🤖 Generating comprehensive project summary...')); // Request summary from AI const response = await client.send({ mode: 'chat', message: summaryPrompt, budget: options.budget ?? 0, // Use provided budget or default to free tier }); // Format the summary const timestamp = new Date().toISOString().split('T')[0]; const summaryContent = `# Project Summary - ${timestamp} Generated on: ${new Date().toLocaleString()} ${response.message || 'No summary generated'} --- ## Project Statistics - **Total Files**: ${projectStructure.fileCount} - **Total Lines of Code**: ${codeStats.totalLines} - **Primary Languages**: ${codeStats.languages.slice(0, 3).map(l => `${l.name} (${l.lines} lines)`).join(', ')} - **Directories**: ${projectStructure.dirCount} ## Files Analyzed ${projectStructure.files.slice(0, 10).map(f => `- ${f}`).join('\n')} ${projectStructure.files.length > 10 ? `\n... and ${projectStructure.files.length - 10} more files` : ''} --- *Generated by ai-mcp-gateway CLI* `; // Save summary to file const outputFile = options.output || `PROJECT-SUMMARY-${timestamp}.md`; fs.writeFileSync(outputFile, summaryContent); console.log(chalk.green(`✅ Project summary generated successfully!`)); console.log(chalk.cyan(`📄 Summary saved to: ${outputFile}`)); console.log(chalk.gray(`💰 Cost: $${response.cost?.toFixed(4) || '0.0000'}`)); } catch (error: any) { console.error(chalk.red('❌ Error generating project summary:'), error.message); process.exit(1); } } /** * Build comprehensive prompt for project summarization */ function buildSummaryPrompt( context: any, history: string, structure: any, stats: any ): string { let prompt = `Please analyze this project and generate a comprehensive summary. Include: 1. **Project Overview** - What is this project about? 2. **Architecture & Technology Stack** - Key technologies, frameworks, patterns used 3. **Current Status** - What's implemented vs. what's planned 4. **Key Features** - Main functionality and capabilities 5. **Development Progress** - Based on coding history if available 6. **Code Quality & Structure** - Analysis of codebase organization 7. **Next Steps** - Recommendations for future development ## Project Context `; // Add project documentation context if (context.sketch) { prompt += `### Project Sketch\n${context.sketch}\n\n`; } if (context.roadmap) { prompt += `### Project Roadmap\n${context.roadmap}\n\n`; } if (context.instructor) { prompt += `### Instructions/Requirements\n${context.instructor}\n\n`; } if (context.readme) { prompt += `### README\n${context.readme}\n\n`; } // Add project structure prompt += `## Project Structure (${structure.fileCount} files)\n\n`; prompt += '```\n'; prompt += structure.tree; prompt += '\n```\n\n'; // Add code statistics prompt += `## Code Statistics\n\n`; prompt += `- Total lines: ${stats.totalLines}\n`; prompt += `- Languages: ${stats.languages.map((l: any) => `${l.name} (${l.lines} lines)`).join(', ')}\n\n`; // Add coding history if available if (history) { prompt += `## Development History\n\n${history}\n\n`; } prompt += `Please provide a detailed, well-structured analysis in markdown format.`; return prompt; } /** * Get project directory structure */ function getProjectStructure(dir: string): { files: string[], fileCount: number, dirCount: number, tree: string } { const files: string[] = []; let fileCount = 0; let dirCount = 0; function walkDir(currentPath: string, prefix: string = ''): string { let tree = ''; try { const items = fs.readdirSync(currentPath) .filter(item => !item.startsWith('.') && item !== 'node_modules') .sort(); for (let i = 0; i < items.length; i++) { const item = items[i]; const itemPath = path.join(currentPath, item); const isLast = i === items.length - 1; const connector = isLast ? '└── ' : '├── '; try { const stat = fs.statSync(itemPath); if (stat.isDirectory()) { tree += `${prefix}${connector}${item}/\n`; dirCount++; const newPrefix = prefix + (isLast ? ' ' : '│ '); tree += walkDir(itemPath, newPrefix); } else { tree += `${prefix}${connector}${item}\n`; files.push(path.relative(dir, itemPath)); fileCount++; } } catch (err) { // Skip inaccessible files/directories } } } catch (err) { // Skip inaccessible directories } return tree; } const tree = walkDir(dir); return { files, fileCount, dirCount, tree }; } /** * Get code statistics by language */ function getCodeStatistics(dir: string): { totalLines: number, languages: Array<{ name: string, lines: number }> } { const languageMap: { [key: string]: number } = {}; let totalLines = 0; const extensions = { '.js': 'JavaScript', '.ts': 'TypeScript', '.jsx': 'JavaScript React', '.tsx': 'TypeScript React', '.py': 'Python', '.java': 'Java', '.cpp': 'C++', '.c': 'C', '.cs': 'C#', '.php': 'PHP', '.rb': 'Ruby', '.go': 'Go', '.rs': 'Rust', '.swift': 'Swift', '.kt': 'Kotlin', '.scala': 'Scala', '.html': 'HTML', '.css': 'CSS', '.scss': 'SCSS', '.sass': 'SASS', '.less': 'LESS', '.vue': 'Vue', '.sql': 'SQL', '.sh': 'Shell', '.bash': 'Bash', '.ps1': 'PowerShell', '.md': 'Markdown', '.json': 'JSON', '.xml': 'XML', '.yaml': 'YAML', '.yml': 'YAML' }; function countLinesInFile(filePath: string): number { try { const content = fs.readFileSync(filePath, 'utf-8'); return content.split('\n').length; } catch { return 0; } } function processDirectory(currentPath: string) { try { const items = fs.readdirSync(currentPath); for (const item of items) { if (item.startsWith('.') || item === 'node_modules') continue; const itemPath = path.join(currentPath, item); try { const stat = fs.statSync(itemPath); if (stat.isDirectory()) { processDirectory(itemPath); } else { const ext = path.extname(item).toLowerCase(); const language = extensions[ext as keyof typeof extensions]; if (language) { const lines = countLinesInFile(itemPath); languageMap[language] = (languageMap[language] || 0) + lines; totalLines += lines; } } } catch { // Skip inaccessible files } } } catch { // Skip inaccessible directories } } processDirectory(dir); const languages = Object.entries(languageMap) .map(([name, lines]) => ({ name, lines })) .sort((a, b) => b.lines - a.lines); return { totalLines, languages }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babasida246/ai-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server