@vibe-dev-kit/cli
Version:
Advanced Command-line toolkit that analyzes your codebase and deploys project-aware rules, memories, commands and agents to any AI coding assistant - VDK is the world's first Vibe Development Kit
243 lines (208 loc) • 6.63 kB
JavaScript
/**
* Project Insights Generator
* Generates analytics and insights about projects using VDK
*/
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const colors = {
green: '\x1b[32m',
blue: '\x1b[36m',
yellow: '\x1b[33m',
red: '\x1b[31m',
reset: '\x1b[0m',
bright: '\x1b[1m',
}
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`)
}
/**
* Analyze project rules and generate insights
* @param {string} projectPath - Path to project directory
* @returns {Object} Project insights
*/
function generateProjectInsights(projectPath = process.cwd()) {
const rulesPath = path.join(projectPath, '.ai', 'rules')
if (!fs.existsSync(rulesPath)) {
return {
error: 'No VDK rules found. Run `vdk` to set up rules first.',
hasRules: false,
}
}
const insights = {
hasRules: true,
rulesCount: 0,
ruleTypes: {},
technologies: new Set(),
frameworks: new Set(),
languages: new Set(),
lastUpdated: null,
projectSize: 'unknown',
recommendations: [],
}
try {
// Analyze rule files
const ruleFiles = fs.readdirSync(rulesPath).filter((f) => f.endsWith('.mdc'))
insights.rulesCount = ruleFiles.length
let latestTime = 0
for (const file of ruleFiles) {
const filePath = path.join(rulesPath, file)
const stats = fs.statSync(filePath)
if (stats.mtime.getTime() > latestTime) {
latestTime = stats.mtime.getTime()
insights.lastUpdated = stats.mtime.toISOString()
}
// Categorize rule types
const content = fs.readFileSync(filePath, 'utf8')
if (file.includes('project-context')) {
insights.ruleTypes.context = true
}
if (
file.includes('framework') ||
content.includes('React') ||
content.includes('Vue') ||
content.includes('Angular')
) {
insights.ruleTypes.framework = true
// Extract framework info
if (content.includes('React')) {
insights.frameworks.add('React')
}
if (content.includes('Vue')) {
insights.frameworks.add('Vue')
}
if (content.includes('Angular')) {
insights.frameworks.add('Angular')
}
if (content.includes('Next.js')) {
insights.frameworks.add('Next.js')
}
if (content.includes('Django')) {
insights.frameworks.add('Django')
}
if (content.includes('Express')) {
insights.frameworks.add('Express')
}
}
if (
file.includes('language') ||
content.includes('TypeScript') ||
content.includes('Python')
) {
insights.ruleTypes.language = true
// Extract language info
if (content.includes('TypeScript')) {
insights.languages.add('TypeScript')
}
if (content.includes('JavaScript')) {
insights.languages.add('JavaScript')
}
if (content.includes('Python')) {
insights.languages.add('Python')
}
if (content.includes('Java')) {
insights.languages.add('Java')
}
if (content.includes('Go')) {
insights.languages.add('Go')
}
}
if (file.includes('common-errors')) {
insights.ruleTypes.errorHandling = true
}
if (file.includes('mcp-configuration')) {
insights.ruleTypes.mcpConfig = true
}
}
// Convert sets to arrays for JSON serialization
insights.technologies = Array.from(insights.technologies)
insights.frameworks = Array.from(insights.frameworks)
insights.languages = Array.from(insights.languages)
// Generate recommendations
if (insights.rulesCount < 3) {
insights.recommendations.push(
'Consider running the setup wizard again to generate more comprehensive rules'
)
}
if (!insights.ruleTypes.errorHandling) {
insights.recommendations.push('Add common error handling patterns to improve AI suggestions')
}
if (!insights.ruleTypes.mcpConfig && insights.frameworks.length > 0) {
insights.recommendations.push('Configure MCP settings for better IDE integration')
}
// Estimate project size based on rule complexity
if (insights.rulesCount >= 5 && insights.frameworks.length >= 2) {
insights.projectSize = 'large'
} else if (insights.rulesCount >= 3 && insights.frameworks.length > 0) {
insights.projectSize = 'medium'
} else {
insights.projectSize = 'small'
}
} catch (error) {
insights.error = `Failed to analyze rules: ${error.message}`
}
return insights
}
/**
* Display insights in a formatted way
* @param {Object} insights - Project insights object
*/
function displayInsights(insights) {
if (!insights.hasRules) {
log('❌ No VDK rules found', 'red')
log(insights.error, 'yellow')
return
}
log('📊 Project Insights', 'blue')
log('==================', 'blue')
log('')
log(`Rules Count: ${insights.rulesCount}`, 'green')
log(`Project Size: ${insights.projectSize}`, 'green')
log(
`Last Updated: ${insights.lastUpdated ? new Date(insights.lastUpdated).toLocaleDateString() : 'Unknown'}`,
'green'
)
if (insights.languages.length > 0) {
log(`Languages: ${insights.languages.join(', ')}`, 'green')
}
if (insights.frameworks.length > 0) {
log(`Frameworks: ${insights.frameworks.join(', ')}`, 'green')
}
log('')
log('Rule Types:', 'yellow')
if (insights.ruleTypes.context) {
log(' ✅ Project Context', 'green')
}
if (insights.ruleTypes.framework) {
log(' ✅ Framework Rules', 'green')
}
if (insights.ruleTypes.language) {
log(' ✅ Language Rules', 'green')
}
if (insights.ruleTypes.errorHandling) {
log(' ✅ Error Handling', 'green')
}
if (insights.ruleTypes.mcpConfig) {
log(' ✅ MCP Configuration', 'green')
}
if (insights.recommendations.length > 0) {
log('')
log('💡 Recommendations:', 'yellow')
for (const rec of insights.recommendations) {
log(` • ${rec}`, 'yellow')
}
}
}
// CLI usage
if (import.meta.url === `file://${process.argv[1]}`) {
const projectPath = process.argv[2] || process.cwd()
const insights = generateProjectInsights(projectPath)
if (process.argv.includes('--json')) {
console.log(JSON.stringify(insights, null, 2))
} else {
displayInsights(insights)
}
}
export { displayInsights, generateProjectInsights }