codecrucible-synth
Version:
Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability
1,243 lines (1,102 loc) • 34.4 kB
text/typescript
/**
* Project Intelligence System - Enhanced Context Awareness
* Iteration 3: Add enhanced context awareness and project intelligence
*/
import { EventEmitter } from 'events';
import { readdir, readFile, stat, access } from 'fs/promises';
import { join, relative, extname, dirname, basename } from 'path';
import { Logger } from '../logger.js';
import { unifiedCache } from '../cache/unified-cache-system.js';
import { ProjectContext } from '../types.js';
export interface ProjectIntelligence {
structure: ProjectStructure;
insights: ProjectInsights;
dependencies: DependencyGraph;
patterns: ArchitecturePatterns;
metadata: ProjectMetadata;
recommendations: IntelligentRecommendations;
}
export interface ProjectStructure {
rootPath: string;
directories: DirectoryNode[];
files: FileNode[];
packageFiles: PackageFile[];
configFiles: ConfigFile[];
documentationFiles: DocumentationFile[];
testFiles: TestFile[];
buildFiles: BuildFile[];
totalFiles: number;
totalDirectories: number;
codebaseSize: number;
}
export interface DirectoryNode {
path: string;
name: string;
depth: number;
fileCount: number;
childDirectories: string[];
purpose: DirectoryPurpose;
importance: 'high' | 'medium' | 'low';
}
export interface FileNode {
path: string;
name: string;
extension: string;
language: string;
size: number;
linesOfCode: number;
complexity: CodeComplexity;
dependencies: string[];
exports: string[];
imports: string[];
functions: FunctionSignature[];
classes: ClassSignature[];
interfaces: InterfaceSignature[];
purpose: FilePurpose;
lastModified: Date;
importance: 'critical' | 'high' | 'medium' | 'low';
}
export interface ProjectInsights {
primaryLanguage: string;
languageDistribution: Record<string, number>;
frameworksDetected: FrameworkInfo[];
architecturePattern: ArchitecturePattern;
projectType: ProjectType;
maturityLevel: 'prototype' | 'development' | 'production' | 'legacy';
codeQuality: CodeQualityMetrics;
technicalDebt: TechnicalDebtAnalysis;
securityConcerns: SecurityConcern[];
performanceIndicators: PerformanceIndicator[];
}
export interface DependencyGraph {
nodes: DependencyNode[];
edges: DependencyEdge[];
cycles: CircularDependency[];
criticalPath: string[];
modularity: ModularityMetrics;
externalDependencies: ExternalDependency[];
internalDependencies: InternalDependency[];
}
export interface ArchitecturePatterns {
primaryPattern: string;
secondaryPatterns: string[];
designPrinciples: string[];
antiPatterns: AntiPattern[];
refactoringOpportunities: RefactoringOpportunity[];
}
export interface IntelligentRecommendations {
codeImprovement: CodeRecommendation[];
architecture: ArchitectureRecommendation[];
performance: PerformanceRecommendation[];
security: SecurityRecommendation[];
testing: TestingRecommendation[];
documentation: DocumentationRecommendation[];
maintenance: MaintenanceRecommendation[];
}
// Supporting interfaces
export type DirectoryPurpose =
| 'source'
| 'tests'
| 'build'
| 'config'
| 'docs'
| 'assets'
| 'dependencies'
| 'other';
export type FilePurpose =
| 'core'
| 'utility'
| 'test'
| 'config'
| 'documentation'
| 'build'
| 'assets'
| 'entry';
export type ProjectType = 'library' | 'application' | 'service' | 'tool' | 'framework' | 'unknown';
export type ArchitecturePattern =
| 'mvc'
| 'microservices'
| 'layered'
| 'hexagonal'
| 'modular'
| 'monolithic'
| 'unknown';
export interface FrameworkInfo {
name: string;
version?: string;
confidence: number;
evidence: string[];
}
export interface CodeComplexity {
cyclomaticComplexity: number;
cognitiveComplexity: number;
nestingDepth: number;
functionCount: number;
classCount: number;
}
export interface FunctionSignature {
name: string;
parameters: string[];
returnType?: string;
complexity: number;
lineNumber: number;
}
export interface ClassSignature {
name: string;
methods: string[];
properties: string[];
inheritance: string[];
lineNumber: number;
}
export interface InterfaceSignature {
name: string;
methods: string[];
properties: string[];
lineNumber: number;
}
export interface CodeQualityMetrics {
maintainabilityIndex: number;
duplication: number;
testCoverage: number;
commentDensity: number;
naming: QualityScore;
structure: QualityScore;
consistency: QualityScore;
}
export interface TechnicalDebtAnalysis {
totalDebt: number;
debtItems: DebtItem[];
debtRatio: number;
prioritizedFixes: PrioritizedFix[];
}
export interface SecurityConcern {
type: string;
severity: 'critical' | 'high' | 'medium' | 'low';
description: string;
file: string;
lineNumber?: number;
recommendation: string;
}
export interface PerformanceIndicator {
metric: string;
value: number;
target: number;
status: 'good' | 'warning' | 'critical';
recommendation: string;
}
export interface PackageFile {
path: string;
type: 'package.json' | 'requirements.txt' | 'Cargo.toml' | 'pom.xml' | 'other';
dependencies: string[];
devDependencies: string[];
scripts: Record<string, string>;
}
export interface ConfigFile {
path: string;
type: string;
purpose: string;
settings: Record<string, any>;
}
export interface DocumentationFile {
path: string;
type: 'readme' | 'api' | 'tutorial' | 'changelog' | 'other';
quality: 'excellent' | 'good' | 'fair' | 'poor';
coverage: string[];
}
export interface TestFile {
path: string;
type: 'unit' | 'integration' | 'e2e' | 'other';
framework: string;
coverage: string[];
}
export interface BuildFile {
path: string;
type: string;
commands: string[];
targets: string[];
}
export interface QualityScore {
score: number;
issues: string[];
suggestions: string[];
}
export interface DebtItem {
type: string;
severity: number;
effort: number;
description: string;
location: string;
}
export interface PrioritizedFix {
priority: number;
impact: 'high' | 'medium' | 'low';
effort: 'small' | 'medium' | 'large';
description: string;
files: string[];
}
export interface DependencyNode {
id: string;
name: string;
type: 'internal' | 'external';
version?: string;
importance: number;
}
export interface DependencyEdge {
from: string;
to: string;
type: 'import' | 'require' | 'dependency';
strength: number;
}
export interface CircularDependency {
cycle: string[];
severity: 'high' | 'medium' | 'low';
recommendation: string;
}
export interface ModularityMetrics {
cohesion: number;
coupling: number;
modularity: number;
instability: number;
}
export interface ExternalDependency {
name: string;
version: string;
type: 'production' | 'development' | 'optional';
usage: string[];
risk: 'high' | 'medium' | 'low';
}
export interface InternalDependency {
from: string;
to: string;
relationship: 'depends-on' | 'extends' | 'implements' | 'uses';
strength: number;
}
export interface AntiPattern {
name: string;
description: string;
locations: string[];
severity: 'high' | 'medium' | 'low';
solution: string;
}
export interface RefactoringOpportunity {
type: string;
description: string;
files: string[];
effort: 'small' | 'medium' | 'large';
benefit: 'high' | 'medium' | 'low';
priority: number;
}
export interface CodeRecommendation {
category: 'refactoring' | 'optimization' | 'modernization' | 'cleanup';
priority: 'high' | 'medium' | 'low';
description: string;
files: string[];
effort: string;
benefit: string;
}
export interface ArchitectureRecommendation {
type: 'structural' | 'pattern' | 'design';
description: string;
rationale: string;
impact: 'high' | 'medium' | 'low';
effort: 'small' | 'medium' | 'large';
}
export interface PerformanceRecommendation {
metric: string;
current: number;
target: number;
improvement: string;
implementation: string;
}
export interface SecurityRecommendation {
category: string;
priority: 'critical' | 'high' | 'medium' | 'low';
description: string;
solution: string;
resources: string[];
}
export interface TestingRecommendation {
type: 'coverage' | 'strategy' | 'framework';
current: string;
recommended: string;
rationale: string;
implementation: string;
}
export interface DocumentationRecommendation {
type: 'api' | 'user' | 'developer' | 'architecture';
priority: 'high' | 'medium' | 'low';
description: string;
template?: string;
}
export interface MaintenanceRecommendation {
category: 'updates' | 'monitoring' | 'automation' | 'tooling';
description: string;
frequency: string;
automation: boolean;
tools: string[];
}
export interface ProjectMetadata {
name: string;
version?: string;
description?: string;
author?: string;
license?: string;
repository?: string;
homepage?: string;
keywords?: string[];
createdDate?: Date;
lastModified: Date;
contributors?: string[];
stats: ProjectStats;
}
export interface ProjectStats {
totalFiles: number;
totalLines: number;
codeLines: number;
commentLines: number;
blankLines: number;
testFiles: number;
configFiles: number;
documentFiles: number;
}
export class ProjectIntelligenceSystem extends EventEmitter {
private logger: Logger;
private analysisInProgress: Set<string> = new Set();
constructor() {
super();
this.logger = new Logger('ProjectIntelligenceSystem');
}
/**
* Analyze project and generate comprehensive intelligence
*/
async analyzeProject(
rootPath: string,
options: AnalysisOptions = {}
): Promise<ProjectIntelligence> {
const normalizedPath = join(rootPath);
// Check if analysis is already in progress
if (this.analysisInProgress.has(normalizedPath)) {
throw new Error(`Analysis already in progress for ${normalizedPath}`);
}
// Check cache first
const cacheKey = `project-intel:${normalizedPath}`;
if (!options.force) {
const cacheResult = await unifiedCache.get<ProjectIntelligence>(cacheKey);
if (cacheResult?.hit) {
this.logger.info(`Using cached analysis for ${normalizedPath}`);
return cacheResult.value;
}
}
this.analysisInProgress.add(normalizedPath);
this.logger.info(`Starting comprehensive project analysis for ${normalizedPath}`);
try {
const startTime = Date.now();
// Phase 1: Structural Analysis
this.emit('analysis:phase', { phase: 'structure', progress: 0 });
const structure = await this.analyzeProjectStructure(rootPath, options);
// Phase 2: Code Analysis
this.emit('analysis:phase', { phase: 'code', progress: 20 });
const insights = await this.generateProjectInsights(structure, options);
// Phase 3: Dependency Analysis
this.emit('analysis:phase', { phase: 'dependencies', progress: 40 });
const dependencies = await this.analyzeDependencies(structure, options);
// Phase 4: Architecture Analysis
this.emit('analysis:phase', { phase: 'architecture', progress: 60 });
const patterns = await this.identifyArchitecturePatterns(structure, insights, dependencies);
// Phase 5: Metadata Extraction
this.emit('analysis:phase', { phase: 'metadata', progress: 80 });
const metadata = await this.extractProjectMetadata(structure, options);
// Phase 6: Generate Recommendations
this.emit('analysis:phase', { phase: 'recommendations', progress: 90 });
const recommendations = await this.generateRecommendations(
structure,
insights,
dependencies,
patterns,
metadata
);
const intelligence: ProjectIntelligence = {
structure,
insights,
dependencies,
patterns,
metadata,
recommendations,
};
// Cache the results with 1 hour TTL and project intelligence tags
await unifiedCache.set(cacheKey, intelligence, {
ttl: 3600000, // 1 hour
tags: ['project-intelligence', 'analysis'],
metadata: { path: normalizedPath, analysisTime: Date.now() - startTime },
});
const analysisTime = Date.now() - startTime;
this.logger.info(`Project analysis completed in ${analysisTime}ms`);
this.emit('analysis:complete', { path: normalizedPath, intelligence, time: analysisTime });
return intelligence;
} finally {
this.analysisInProgress.delete(normalizedPath);
}
}
/**
* Analyze project structure and file organization
*/
private async analyzeProjectStructure(
rootPath: string,
options: AnalysisOptions
): Promise<ProjectStructure> {
const files: FileNode[] = [];
const directories: DirectoryNode[] = [];
const packageFiles: PackageFile[] = [];
const configFiles: ConfigFile[] = [];
const documentationFiles: DocumentationFile[] = [];
const testFiles: TestFile[] = [];
const buildFiles: BuildFile[] = [];
let totalSize = 0;
const scanDirectory = async (dirPath: string, depth = 0): Promise<void> => {
try {
const entries = await readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = join(dirPath, entry.name);
const relativePath = relative(rootPath, fullPath);
// Skip common ignore patterns
if (this.shouldIgnoreFile(relativePath)) continue;
if (entry.isDirectory()) {
const dirNode: DirectoryNode = {
path: relativePath,
name: entry.name,
depth,
fileCount: 0,
childDirectories: [],
purpose: this.determineDirectoryPurpose(entry.name, relativePath),
importance: this.assessDirectoryImportance(entry.name, relativePath),
};
directories.push(dirNode);
// Recursively scan subdirectories
if (depth < (options.maxDepth || 10)) {
await scanDirectory(fullPath, depth + 1);
}
} else if (entry.isFile()) {
const stats = await stat(fullPath);
const fileNode = await this.analyzeFile(fullPath, relativePath, stats);
files.push(fileNode);
totalSize += stats.size;
// Categorize special files
this.categorizeSpecialFile(
fileNode,
packageFiles,
configFiles,
documentationFiles,
testFiles,
buildFiles
);
}
}
} catch (error) {
this.logger.warn(`Error scanning directory ${dirPath}:`, error);
}
};
await scanDirectory(rootPath);
// Update directory file counts
this.updateDirectoryFileCounts(directories, files);
return {
rootPath,
directories,
files,
packageFiles,
configFiles,
documentationFiles,
testFiles,
buildFiles,
totalFiles: files.length,
totalDirectories: directories.length,
codebaseSize: totalSize,
};
}
/**
* Generate comprehensive project insights
*/
private async generateProjectInsights(
structure: ProjectStructure,
options: AnalysisOptions
): Promise<ProjectInsights> {
// Analyze languages
const languageStats = this.analyzeLanguageDistribution(structure.files);
const primaryLanguage = Object.keys(languageStats).reduce(
(a, b) => (languageStats[a] > languageStats[b] ? a : b),
''
);
// Detect frameworks
const frameworksDetected = await this.detectFrameworks(structure);
// Determine project type and architecture
const projectType = this.determineProjectType(structure, frameworksDetected);
const architecturePattern = this.identifyPrimaryArchitecture(structure, frameworksDetected);
// Assess maturity and quality
const maturityLevel = this.assessProjectMaturity(structure);
const codeQuality = await this.assessCodeQuality(structure);
const technicalDebt = await this.analyzeTechnicalDebt(structure);
// Security and performance analysis
const securityConcerns = await this.identifySecurityConcerns(structure);
const performanceIndicators = await this.analyzePerformanceIndicators(structure);
return {
primaryLanguage,
languageDistribution: languageStats,
frameworksDetected,
architecturePattern,
projectType,
maturityLevel,
codeQuality,
technicalDebt,
securityConcerns,
performanceIndicators,
};
}
/**
* Analyze project dependencies and relationships
*/
private async analyzeDependencies(
structure: ProjectStructure,
options: AnalysisOptions
): Promise<DependencyGraph> {
// This is a simplified implementation - in practice, this would involve
// parsing import statements, package files, etc.
const nodes: DependencyNode[] = [];
const edges: DependencyEdge[] = [];
const externalDependencies: ExternalDependency[] = [];
const internalDependencies: InternalDependency[] = [];
// Analyze package files for external dependencies
for (const pkg of structure.packageFiles) {
for (const dep of pkg.dependencies) {
externalDependencies.push({
name: dep,
version: 'unknown',
type: 'production',
usage: [],
risk: 'low',
});
}
}
// Analyze internal file dependencies (simplified)
for (const file of structure.files) {
nodes.push({
id: file.path,
name: file.name,
type: 'internal',
importance: file.importance === 'critical' ? 1 : file.importance === 'high' ? 0.8 : 0.5,
});
}
return {
nodes,
edges,
cycles: [],
criticalPath: [],
modularity: {
cohesion: 0.7,
coupling: 0.3,
modularity: 0.8,
instability: 0.4,
},
externalDependencies,
internalDependencies,
};
}
/**
* Identify architecture patterns and design principles
*/
private async identifyArchitecturePatterns(
structure: ProjectStructure,
insights: ProjectInsights,
dependencies: DependencyGraph
): Promise<ArchitecturePatterns> {
// Simplified pattern detection
const primaryPattern = insights.architecturePattern || 'modular';
return {
primaryPattern,
secondaryPatterns: ['layered'],
designPrinciples: ['separation of concerns', 'single responsibility'],
antiPatterns: [],
refactoringOpportunities: [],
};
}
/**
* Extract project metadata
*/
private async extractProjectMetadata(
structure: ProjectStructure,
options: AnalysisOptions
): Promise<ProjectMetadata> {
let metadata: Partial<ProjectMetadata> = {
name: basename(structure.rootPath),
lastModified: new Date(),
};
// Try to extract from package.json or similar
for (const pkg of structure.packageFiles) {
if (pkg.path.endsWith('package.json')) {
try {
const content = await readFile(join(structure.rootPath, pkg.path), 'utf8');
const packageInfo = JSON.parse(content);
metadata = {
...metadata,
name: packageInfo.name || metadata.name,
version: packageInfo.version,
description: packageInfo.description,
author:
typeof packageInfo.author === 'string'
? packageInfo.author
: packageInfo.author?.name,
license: packageInfo.license,
repository:
typeof packageInfo.repository === 'string'
? packageInfo.repository
: packageInfo.repository?.url,
homepage: packageInfo.homepage,
keywords: packageInfo.keywords,
};
break;
} catch (error) {
this.logger.warn(`Error parsing ${pkg.path}:`, error);
}
}
}
// Calculate project statistics
const stats = this.calculateProjectStats(structure);
return {
name: metadata.name || 'Unknown Project',
version: metadata.version,
description: metadata.description,
author: metadata.author,
license: metadata.license,
repository: metadata.repository,
homepage: metadata.homepage,
keywords: metadata.keywords,
lastModified: metadata.lastModified!,
stats,
};
}
/**
* Generate intelligent recommendations
*/
private async generateRecommendations(
structure: ProjectStructure,
insights: ProjectInsights,
dependencies: DependencyGraph,
patterns: ArchitecturePatterns,
metadata: ProjectMetadata
): Promise<IntelligentRecommendations> {
return {
codeImprovement: [],
architecture: [],
performance: [],
security: [],
testing: [],
documentation: [],
maintenance: [],
};
}
// Helper methods (simplified implementations)
private shouldIgnoreFile(path: string): boolean {
const ignorePatterns = [
'node_modules',
'.git',
'.vscode',
'.idea',
'dist',
'build',
'coverage',
'.nyc_output',
'.DS_Store',
'Thumbs.db',
'*.log',
];
return ignorePatterns.some(pattern => path.includes(pattern));
}
private determineDirectoryPurpose(name: string, path: string): DirectoryPurpose {
const purposeMap: Record<string, DirectoryPurpose> = {
src: 'source',
source: 'source',
lib: 'source',
test: 'tests',
tests: 'tests',
__tests__: 'tests',
spec: 'tests',
build: 'build',
dist: 'build',
config: 'config',
docs: 'docs',
doc: 'docs',
assets: 'assets',
static: 'assets',
node_modules: 'dependencies',
};
return purposeMap[name.toLowerCase()] || 'other';
}
private assessDirectoryImportance(name: string, path: string): 'high' | 'medium' | 'low' {
if (['src', 'source', 'lib'].includes(name.toLowerCase())) return 'high';
if (['test', 'tests', 'config', 'docs'].includes(name.toLowerCase())) return 'medium';
return 'low';
}
private async analyzeFile(fullPath: string, relativePath: string, stats: any): Promise<FileNode> {
const ext = extname(relativePath);
const name = basename(relativePath);
const language = this.detectLanguage(ext);
let linesOfCode = 0;
let complexity: CodeComplexity = {
cyclomaticComplexity: 0,
cognitiveComplexity: 0,
nestingDepth: 0,
functionCount: 0,
classCount: 0,
};
// Read and analyze file content for code files
if (this.isCodeFile(ext)) {
try {
const content = await readFile(fullPath, 'utf8');
linesOfCode = content.split('\n').length;
complexity = this.analyzeCodeComplexity(content, language);
} catch (error) {
this.logger.warn(`Error reading file ${fullPath}:`, error);
}
}
return {
path: relativePath,
name,
extension: ext,
language,
size: stats.size,
linesOfCode,
complexity,
dependencies: [],
exports: [],
imports: [],
functions: [],
classes: [],
interfaces: [],
purpose: this.determineFilePurpose(name, relativePath),
lastModified: stats.mtime,
importance: this.assessFileImportance(name, relativePath),
};
}
private detectLanguage(extension: string): string {
const languageMap: Record<string, string> = {
'.js': 'JavaScript',
'.ts': 'TypeScript',
'.jsx': 'JavaScript',
'.tsx': 'TypeScript',
'.py': 'Python',
'.java': 'Java',
'.cs': 'C#',
'.cpp': 'C++',
'.c': 'C',
'.go': 'Go',
'.rs': 'Rust',
'.php': 'PHP',
'.rb': 'Ruby',
'.swift': 'Swift',
'.kt': 'Kotlin',
};
return languageMap[extension.toLowerCase()] || 'Unknown';
}
private isCodeFile(extension: string): boolean {
const codeExtensions = [
'.js',
'.ts',
'.jsx',
'.tsx',
'.py',
'.java',
'.cs',
'.cpp',
'.c',
'.go',
'.rs',
'.php',
'.rb',
'.swift',
'.kt',
'.scala',
'.r',
'.m',
];
return codeExtensions.includes(extension.toLowerCase());
}
private determineFilePurpose(name: string, path: string): FilePurpose {
if (
name.toLowerCase().includes('test') ||
path.includes('/test/') ||
path.includes('/__tests__/')
)
return 'test';
if (name.toLowerCase().includes('config') || name.includes('.config.')) return 'config';
if (
['index.js', 'index.ts', 'main.js', 'main.ts', 'app.js', 'app.ts'].includes(
name.toLowerCase()
)
)
return 'entry';
if (name.toLowerCase().includes('util') || name.toLowerCase().includes('helper'))
return 'utility';
if (['readme.md', 'readme.txt', 'changelog.md'].includes(name.toLowerCase()))
return 'documentation';
return 'core';
}
private assessFileImportance(name: string, path: string): 'critical' | 'high' | 'medium' | 'low' {
if (
['index.js', 'index.ts', 'main.js', 'main.ts', 'app.js', 'app.ts'].includes(
name.toLowerCase()
)
)
return 'critical';
if (path.startsWith('src/') && !path.includes('/test/')) return 'high';
if (name.toLowerCase().includes('test')) return 'medium';
return 'low';
}
private analyzeCodeComplexity(content: string, language: string): CodeComplexity {
// Simplified complexity analysis
const lines = content.split('\n');
const functionMatches = content.match(/function\s+\w+|def\s+\w+|class\s+\w+/gi) || [];
const classMatches = content.match(/class\s+\w+/gi) || [];
return {
cyclomaticComplexity: Math.min(functionMatches.length * 2, 50),
cognitiveComplexity: Math.min(functionMatches.length * 1.5, 40),
nestingDepth: Math.min(
lines.filter(line => line.trim().startsWith('if') || line.trim().startsWith('for')).length,
10
),
functionCount: functionMatches.length,
classCount: classMatches.length,
};
}
private categorizeSpecialFile(
file: FileNode,
packageFiles: PackageFile[],
configFiles: ConfigFile[],
documentationFiles: DocumentationFile[],
testFiles: TestFile[],
buildFiles: BuildFile[]
): void {
const name = file.name.toLowerCase();
if (
name === 'package.json' ||
name === 'requirements.txt' ||
name === 'cargo.toml' ||
name === 'pom.xml'
) {
packageFiles.push({
path: file.path,
type: name.includes('.json') ? 'package.json' : 'other',
dependencies: [],
devDependencies: [],
scripts: {},
} as PackageFile);
}
if (name.includes('config') || name.includes('.config.') || name.includes('.env')) {
configFiles.push({
path: file.path,
type: file.extension,
purpose: 'configuration',
settings: {},
});
}
if (name.includes('readme') || name.includes('doc') || file.extension === '.md') {
documentationFiles.push({
path: file.path,
type: name.includes('readme') ? 'readme' : 'other',
quality: 'fair',
coverage: [],
});
}
if (file.purpose === 'test') {
testFiles.push({
path: file.path,
type: 'unit',
framework: 'unknown',
coverage: [],
});
}
if (
name.includes('build') ||
name.includes('webpack') ||
name.includes('rollup') ||
name.includes('gulp')
) {
buildFiles.push({
path: file.path,
type: file.extension,
commands: [],
targets: [],
});
}
}
private updateDirectoryFileCounts(directories: DirectoryNode[], files: FileNode[]): void {
for (const dir of directories) {
dir.fileCount = files.filter(file => file.path.startsWith(dir.path + '/')).length;
dir.childDirectories = directories
.filter(d => d.path.startsWith(dir.path + '/') && d.depth === dir.depth + 1)
.map(d => d.path);
}
}
private analyzeLanguageDistribution(files: FileNode[]): Record<string, number> {
const distribution: Record<string, number> = {};
for (const file of files) {
if (this.isCodeFile(file.extension)) {
distribution[file.language] = (distribution[file.language] || 0) + file.linesOfCode;
}
}
return distribution;
}
private async detectFrameworks(structure: ProjectStructure): Promise<FrameworkInfo[]> {
const frameworks: FrameworkInfo[] = [];
// Check package files for framework dependencies
for (const pkg of structure.packageFiles) {
if (pkg.dependencies.includes('react')) {
frameworks.push({ name: 'React', confidence: 0.9, evidence: ['package dependency'] });
}
if (pkg.dependencies.includes('vue')) {
frameworks.push({ name: 'Vue', confidence: 0.9, evidence: ['package dependency'] });
}
if (pkg.dependencies.includes('angular')) {
frameworks.push({ name: 'Angular', confidence: 0.9, evidence: ['package dependency'] });
}
if (pkg.dependencies.includes('express')) {
frameworks.push({ name: 'Express', confidence: 0.9, evidence: ['package dependency'] });
}
}
return frameworks;
}
private determineProjectType(
structure: ProjectStructure,
frameworks: FrameworkInfo[]
): ProjectType {
// Check for library indicators
if (structure.packageFiles.some(pkg => pkg.path.includes('package.json'))) {
return 'library';
}
// Check for application indicators
if (frameworks.some(f => ['React', 'Vue', 'Angular'].includes(f.name))) {
return 'application';
}
// Check for service indicators
if (frameworks.some(f => f.name === 'Express')) {
return 'service';
}
return 'unknown';
}
private identifyPrimaryArchitecture(
structure: ProjectStructure,
frameworks: FrameworkInfo[]
): ArchitecturePattern {
// Simple architecture detection based on directory structure
const hasControllers = structure.directories.some(d =>
d.name.toLowerCase().includes('controller')
);
const hasModels = structure.directories.some(d => d.name.toLowerCase().includes('model'));
const hasViews = structure.directories.some(d => d.name.toLowerCase().includes('view'));
if (hasControllers && hasModels && hasViews) {
return 'mvc';
}
if (structure.directories.some(d => d.name.toLowerCase().includes('service'))) {
return 'microservices';
}
return 'modular';
}
private assessProjectMaturity(
structure: ProjectStructure
): 'prototype' | 'development' | 'production' | 'legacy' {
const hasTests = structure.testFiles.length > 0;
const hasDocumentation = structure.documentationFiles.length > 0;
const hasConfig = structure.configFiles.length > 0;
const hasBuildSystem = structure.buildFiles.length > 0;
const maturityScore = [hasTests, hasDocumentation, hasConfig, hasBuildSystem].filter(
Boolean
).length;
if (maturityScore >= 3) return 'production';
if (maturityScore >= 2) return 'development';
return 'prototype';
}
private async assessCodeQuality(structure: ProjectStructure): Promise<CodeQualityMetrics> {
// Simplified quality assessment
const totalFiles = structure.files.filter(f => this.isCodeFile(f.extension)).length;
const testFiles = structure.testFiles.length;
return {
maintainabilityIndex: 75,
duplication: 0.1,
testCoverage: totalFiles > 0 ? (testFiles / totalFiles) * 100 : 0,
commentDensity: 0.15,
naming: { score: 0.8, issues: [], suggestions: [] },
structure: { score: 0.75, issues: [], suggestions: [] },
consistency: { score: 0.85, issues: [], suggestions: [] },
};
}
private async analyzeTechnicalDebt(structure: ProjectStructure): Promise<TechnicalDebtAnalysis> {
// Simplified debt analysis
return {
totalDebt: 5,
debtItems: [],
debtRatio: 0.1,
prioritizedFixes: [],
};
}
private async identifySecurityConcerns(structure: ProjectStructure): Promise<SecurityConcern[]> {
// Simplified security analysis
return [];
}
private async analyzePerformanceIndicators(
structure: ProjectStructure
): Promise<PerformanceIndicator[]> {
// Simplified performance analysis
return [];
}
private calculateProjectStats(structure: ProjectStructure): ProjectStats {
const codeFiles = structure.files.filter(f => this.isCodeFile(f.extension));
const totalLines = codeFiles.reduce((sum, file) => sum + file.linesOfCode, 0);
return {
totalFiles: structure.files.length,
totalLines,
codeLines: Math.floor(totalLines * 0.8), // Estimate
commentLines: Math.floor(totalLines * 0.15), // Estimate
blankLines: Math.floor(totalLines * 0.05), // Estimate
testFiles: structure.testFiles.length,
configFiles: structure.configFiles.length,
documentFiles: structure.documentationFiles.length,
};
}
/**
* Get cached analysis if available
*/
async getCachedAnalysis(path: string): Promise<ProjectIntelligence | null> {
const cacheKey = `project-intel:${join(path)}`;
const cacheResult = await unifiedCache.get<ProjectIntelligence>(cacheKey);
return cacheResult?.value || null;
}
/**
* Clear analysis cache
*/
async clearCache(path?: string): Promise<void> {
if (path) {
const cacheKey = `project-intel:${join(path)}`;
await unifiedCache.delete(cacheKey);
} else {
await unifiedCache.clearByTags(['project-intelligence']);
}
}
/**
* Get system metrics
*/
async getSystemMetrics(): Promise<any> {
const cacheStats = await unifiedCache.getStats();
return {
cachedAnalyses: cacheStats.size || 0,
activeAnalyses: this.analysisInProgress.size,
memoryUsage: process.memoryUsage(),
};
}
}
export interface AnalysisOptions {
force?: boolean;
maxDepth?: number;
includeTests?: boolean;
includeNodeModules?: boolean;
languages?: string[];
skipLargeFiles?: boolean;
maxFileSize?: number;
}
export default ProjectIntelligenceSystem;