package intelligence import ( "context" "fmt" "io/ioutil" "os" "path/filepath" "strings" "sync" "time" "chorus.services/bzzz/pkg/ucxl" slurpContext "chorus.services/bzzz/pkg/slurp/context" ) // AnalyzeFile analyzes a single file and generates contextual understanding func (e *DefaultIntelligenceEngine) AnalyzeFile(ctx context.Context, filePath string, role string) (*slurpContext.ContextNode, error) { start := time.Now() defer func() { e.updateStats("file_analysis", time.Since(start), true) }() // Check cache first cacheKey := fmt.Sprintf("file:%s:%s", filePath, role) if cached, ok := e.cache.Load(cacheKey); ok { if entry, ok := cached.(*CacheEntry); ok && time.Now().Before(entry.ExpiresAt) { e.mu.Lock() e.stats.CacheHitRate = (e.stats.CacheHitRate*float64(e.stats.TotalAnalyses) + 1) / float64(e.stats.TotalAnalyses+1) e.mu.Unlock() return entry.ContextNode, nil } } // Read file content content, err := e.readFileContent(filePath) if err != nil { e.updateStats("file_analysis", time.Since(start), false) return nil, fmt.Errorf("failed to read file %s: %w", filePath, err) } // Skip files that are too large if int64(len(content)) > e.config.MaxFileSize { e.updateStats("file_analysis", time.Since(start), false) return nil, fmt.Errorf("file %s too large (%d bytes > %d bytes)", filePath, len(content), e.config.MaxFileSize) } // Perform file analysis analysis, err := e.fileAnalyzer.AnalyzeContent(ctx, filePath, content) if err != nil { e.updateStats("file_analysis", time.Since(start), false) return nil, fmt.Errorf("failed to analyze file content: %w", err) } // Generate UCXL address for the file ucxlAddr, err := e.generateUCXLAddress(filePath) if err != nil { e.updateStats("file_analysis", time.Since(start), false) return nil, fmt.Errorf("failed to generate UCXL address: %w", err) } // Extract purpose and summary purpose, purposeConf, err := e.fileAnalyzer.IdentifyPurpose(ctx, analysis) if err != nil { purpose = "Unknown purpose" purposeConf = 0.0 } summary, err := e.fileAnalyzer.GenerateSummary(ctx, analysis) if err != nil { summary = "File analysis summary unavailable" } // Extract technologies technologies, err := e.fileAnalyzer.ExtractTechnologies(ctx, analysis) if err != nil { technologies = []string{} } // Generate basic tags tags := e.generateFileTags(analysis, filePath) // Generate role-specific insights insights, err := e.GenerateRoleInsights(ctx, nil, role) if err != nil { insights = []string{} } // Enhance with RAG if enabled ragConfidence := 0.0 if e.config.RAGEnabled { // This would be enhanced in a real implementation ragConfidence = 0.7 } // Create context node contextNode := &slurpContext.ContextNode{ Path: filePath, UCXLAddress: *ucxlAddr, Summary: summary, Purpose: purpose, Technologies: technologies, Tags: tags, Insights: insights, OverridesParent: false, ContextSpecificity: e.calculateSpecificity(analysis), AppliesToChildren: false, GeneratedAt: time.Now(), RAGConfidence: ragConfidence, EncryptedFor: e.determineEncryptionRoles(role, purposeConf), AccessLevel: e.determineAccessLevel(analysis, role), Metadata: make(map[string]interface{}), } // Add analysis metadata contextNode.Metadata["analysis"] = analysis contextNode.Metadata["purpose_confidence"] = purposeConf contextNode.Metadata["role"] = role // Cache the result cacheEntry := &CacheEntry{ ContextNode: contextNode, CreatedAt: time.Now(), ExpiresAt: time.Now().Add(e.config.CacheTTL), } e.cache.Store(cacheKey, cacheEntry) return contextNode, nil } // AnalyzeDirectory analyzes directory structure for hierarchical patterns func (e *DefaultIntelligenceEngine) AnalyzeDirectory(ctx context.Context, dirPath string) ([]*slurpContext.ContextNode, error) { start := time.Now() defer func() { e.updateStats("directory_analysis", time.Since(start), true) }() // Analyze directory structure structure, err := e.directoryAnalyzer.AnalyzeStructure(ctx, dirPath) if err != nil { e.updateStats("directory_analysis", time.Since(start), false) return nil, fmt.Errorf("failed to analyze directory structure: %w", err) } // Generate hierarchy with bounded depth hierarchy, err := e.directoryAnalyzer.GenerateHierarchy(ctx, dirPath, 5) // Max 5 levels deep if err != nil { e.updateStats("directory_analysis", time.Since(start), false) return nil, fmt.Errorf("failed to generate hierarchy: %w", err) } return hierarchy, nil } // GenerateRoleInsights generates role-specific insights for existing context func (e *DefaultIntelligenceEngine) GenerateRoleInsights(ctx context.Context, baseContext *slurpContext.ContextNode, role string) ([]string, error) { insights := []string{} // Get role profile profile, exists := e.roleProfiles[role] if !exists { // Generate generic insights insights = append(insights, "Generic insight: Consider code quality and maintainability") return insights, nil } // Generate role-specific insights based on profile for _, insightType := range profile.InsightTypes { switch insightType { case "security": insights = append(insights, "Security: Review for potential vulnerabilities and secure coding practices") case "performance": insights = append(insights, "Performance: Analyze for optimization opportunities and bottlenecks") case "architecture": insights = append(insights, "Architecture: Ensure alignment with system design patterns") case "testing": insights = append(insights, "Testing: Consider test coverage and quality assurance requirements") case "ui_ux": insights = append(insights, "UI/UX: Focus on user experience and interface design principles") case "api_design": insights = append(insights, "API Design: Ensure RESTful principles and proper error handling") case "database": insights = append(insights, "Database: Consider data modeling and query optimization") case "deployment": insights = append(insights, "Deployment: Plan for scalability and infrastructure requirements") } } // Add context-specific insights if baseContext is provided if baseContext != nil { contextInsights := e.generateContextSpecificInsights(baseContext, role) insights = append(insights, contextInsights...) } return insights, nil } // AssessGoalAlignment assesses how well context aligns with project goals func (e *DefaultIntelligenceEngine) AssessGoalAlignment(ctx context.Context, node *slurpContext.ContextNode) (float64, error) { if len(e.projectGoals) == 0 { return 0.5, nil // Default alignment score when no goals defined } totalAlignment := 0.0 totalWeight := 0.0 for _, goal := range e.projectGoals { alignment := e.calculateGoalAlignment(node, goal) weight := float64(10 - goal.Priority) // Higher priority = higher weight totalAlignment += alignment * weight totalWeight += weight } if totalWeight == 0 { return 0.5, nil } return totalAlignment / totalWeight, nil } // AnalyzeBatch processes multiple files efficiently in parallel func (e *DefaultIntelligenceEngine) AnalyzeBatch(ctx context.Context, filePaths []string, role string) (map[string]*slurpContext.ContextNode, error) { results := make(map[string]*slurpContext.ContextNode) mu := sync.Mutex{} wg := sync.WaitGroup{} errorCh := make(chan error, len(filePaths)) // Limit concurrency semaphore := make(chan struct{}, e.config.MaxConcurrentAnalysis) for _, filePath := range filePaths { wg.Add(1) go func(path string) { defer wg.Done() semaphore <- struct{}{} // Acquire semaphore defer func() { <-semaphore }() // Release semaphore ctxNode, err := e.AnalyzeFile(ctx, path, role) if err != nil { errorCh <- fmt.Errorf("failed to analyze %s: %w", path, err) return } mu.Lock() results[path] = ctxNode mu.Unlock() }(filePath) } wg.Wait() close(errorCh) // Collect any errors var errs []error for err := range errorCh { errs = append(errs, err) } if len(errs) > 0 { return results, fmt.Errorf("batch analysis errors: %v", errs) } return results, nil } // DetectPatterns identifies recurring patterns across multiple contexts func (e *DefaultIntelligenceEngine) DetectPatterns(ctx context.Context, contexts []*slurpContext.ContextNode) ([]*Pattern, error) { patterns := []*Pattern{} // Use pattern detector to find code patterns for _, context := range contexts { if context.Metadata["analysis"] != nil { if analysis, ok := context.Metadata["analysis"].(*FileAnalysis); ok { codePatterns, err := e.patternDetector.DetectCodePatterns(ctx, context.Path, []byte(analysis.FilePath)) if err == nil { for _, cp := range codePatterns { patterns = append(patterns, &cp.Pattern) } } } } } // Detect naming patterns namingPatterns, err := e.patternDetector.DetectNamingPatterns(ctx, contexts) if err == nil { for _, np := range namingPatterns { patterns = append(patterns, &np.Pattern) } } return patterns, nil } // EnhanceWithRAG enhances context using RAG system knowledge func (e *DefaultIntelligenceEngine) EnhanceWithRAG(ctx context.Context, node *slurpContext.ContextNode) (*slurpContext.ContextNode, error) { if !e.config.RAGEnabled { return node, nil // Return unchanged if RAG is disabled } // Create query for RAG system query := fmt.Sprintf("Provide insights for %s: %s", node.Purpose, node.Summary) queryContext := map[string]interface{}{ "file_path": node.Path, "technologies": node.Technologies, "tags": node.Tags, } // Query RAG system ragResponse, err := e.ragIntegration.Query(ctx, query, queryContext) if err != nil { return node, fmt.Errorf("RAG query failed: %w", err) } // Enhance context with RAG insights enhanced := node.Clone() if ragResponse.Confidence >= e.config.MinConfidenceThreshold { enhanced.Insights = append(enhanced.Insights, fmt.Sprintf("RAG: %s", ragResponse.Answer)) enhanced.RAGConfidence = ragResponse.Confidence // Add source information to metadata if len(ragResponse.Sources) > 0 { sources := make([]string, len(ragResponse.Sources)) for i, source := range ragResponse.Sources { sources[i] = source.Title } enhanced.Metadata["rag_sources"] = sources } } return enhanced, nil } // ValidateContext validates generated context quality and consistency func (e *DefaultIntelligenceEngine) ValidateContext(ctx context.Context, node *slurpContext.ContextNode) (*ValidationResult, error) { result := &ValidationResult{ Valid: true, ConfidenceScore: 1.0, QualityScore: 1.0, Issues: []*ValidationIssue{}, Suggestions: []*Suggestion{}, ValidatedAt: time.Now(), } // Validate basic structure if err := node.Validate(); err != nil { result.Valid = false result.Issues = append(result.Issues, &ValidationIssue{ Type: "structure", Severity: "error", Message: err.Error(), Field: "context_node", Suggestion: "Fix validation errors in context structure", Impact: 0.8, }) } // Check quality thresholds if node.RAGConfidence < e.config.MinConfidenceThreshold { result.QualityScore *= 0.8 result.Suggestions = append(result.Suggestions, &Suggestion{ Type: "quality", Title: "Low RAG confidence", Description: "Consider enhancing context with additional analysis", Confidence: 0.7, Priority: 2, Action: "re_analyze", Impact: "medium", }) } // Validate content quality if len(node.Summary) < 10 { result.QualityScore *= 0.9 result.Issues = append(result.Issues, &ValidationIssue{ Type: "content", Severity: "warning", Message: "Summary too short", Field: "summary", Suggestion: "Provide more detailed summary", Impact: 0.1, }) } return result, nil } // GetEngineStats returns engine performance and operational statistics func (e *DefaultIntelligenceEngine) GetEngineStats() (*EngineStatistics, error) { e.mu.RLock() defer e.mu.RUnlock() // Calculate cache hit rate cacheSize := 0 e.cache.Range(func(key, value interface{}) bool { cacheSize++ return true }) stats := *e.stats // Copy current stats stats.CacheHitRate = e.calculateCacheHitRate() return &stats, nil } // SetConfiguration updates engine configuration func (e *DefaultIntelligenceEngine) SetConfiguration(config *EngineConfig) error { e.mu.Lock() defer e.mu.Unlock() if config == nil { return fmt.Errorf("configuration cannot be nil") } e.config = config e.projectGoals = config.ProjectGoals e.roleProfiles = config.RoleProfiles return nil } // Helper methods // readFileContent reads and returns file content func (e *DefaultIntelligenceEngine) readFileContent(filePath string) ([]byte, error) { return ioutil.ReadFile(filePath) } // generateUCXLAddress generates a UCXL address for a file path func (e *DefaultIntelligenceEngine) generateUCXLAddress(filePath string) (*ucxl.Address, error) { // Simple implementation - in reality this would be more sophisticated cleanPath := filepath.Clean(filePath) addr, err := ucxl.ParseAddress(fmt.Sprintf("file://%s", cleanPath)) if err != nil { return nil, fmt.Errorf("failed to generate UCXL address: %w", err) } return addr, nil } // generateFileTags generates tags based on file analysis and path func (e *DefaultIntelligenceEngine) generateFileTags(analysis *FileAnalysis, filePath string) []string { tags := []string{} // Add language tag if analysis.Language != "" { tags = append(tags, analysis.Language) } // Add file type tag if analysis.FileType != "" { tags = append(tags, analysis.FileType) } // Add directory-based tags dir := filepath.Dir(filePath) dirName := filepath.Base(dir) if dirName != "." && dirName != "/" { tags = append(tags, "dir:"+dirName) } // Add complexity tag if analysis.Complexity > 10 { tags = append(tags, "high-complexity") } else if analysis.Complexity > 5 { tags = append(tags, "medium-complexity") } else { tags = append(tags, "low-complexity") } return tags } // calculateSpecificity calculates context specificity based on analysis func (e *DefaultIntelligenceEngine) calculateSpecificity(analysis *FileAnalysis) int { specificity := 1 // More specific if it has many functions/classes if len(analysis.Functions) > 5 || len(analysis.Classes) > 3 { specificity += 2 } // More specific if it has dependencies if len(analysis.Dependencies) > 0 { specificity += 1 } // More specific if it's complex if analysis.Complexity > 10 { specificity += 1 } return specificity } // determineEncryptionRoles determines which roles can access this context func (e *DefaultIntelligenceEngine) determineEncryptionRoles(role string, confidence float64) []string { roles := []string{role} // Add senior roles that can access everything seniorRoles := []string{"senior_architect", "project_manager"} for _, senior := range seniorRoles { if senior != role { roles = append(roles, senior) } } // If high confidence, allow broader access if confidence > 0.8 { roles = append(roles, "*") } return roles } // determineAccessLevel determines the required access level for context func (e *DefaultIntelligenceEngine) determineAccessLevel(analysis *FileAnalysis, role string) slurpContext.RoleAccessLevel { // Default to low access level := slurpContext.AccessLow // Increase level based on content sensitivity sensitive := false for _, comment := range analysis.Comments { if strings.Contains(strings.ToLower(comment), "password") || strings.Contains(strings.ToLower(comment), "secret") || strings.Contains(strings.ToLower(comment), "private") { sensitive = true break } } if sensitive { level = slurpContext.AccessHigh } else if len(analysis.Dependencies) > 5 { level = slurpContext.AccessMedium } return level } // generateContextSpecificInsights generates insights specific to the provided context func (e *DefaultIntelligenceEngine) generateContextSpecificInsights(context *slurpContext.ContextNode, role string) []string { insights := []string{} // Technology-specific insights for _, tech := range context.Technologies { switch strings.ToLower(tech) { case "react", "vue", "angular": insights = append(insights, fmt.Sprintf("Frontend: %s component requires testing for accessibility and responsiveness", tech)) case "go", "python", "java": insights = append(insights, fmt.Sprintf("Backend: %s code should follow language-specific best practices", tech)) case "docker", "kubernetes": insights = append(insights, fmt.Sprintf("Infrastructure: %s configuration needs security review", tech)) } } // Purpose-specific insights if strings.Contains(strings.ToLower(context.Purpose), "api") { insights = append(insights, "API: Consider rate limiting, authentication, and proper error responses") } if strings.Contains(strings.ToLower(context.Purpose), "database") { insights = append(insights, "Database: Review for proper indexing and query optimization") } return insights } // calculateGoalAlignment calculates alignment score between context and goal func (e *DefaultIntelligenceEngine) calculateGoalAlignment(node *slurpContext.ContextNode, goal *ProjectGoal) float64 { score := 0.0 checks := 0.0 // Check keyword overlap nodeText := strings.ToLower(node.Summary + " " + node.Purpose + " " + strings.Join(node.Technologies, " ")) for _, keyword := range goal.Keywords { checks += 1.0 if strings.Contains(nodeText, strings.ToLower(keyword)) { score += 1.0 } } // Check tag overlap for _, tag := range node.Tags { checks += 1.0 for _, keyword := range goal.Keywords { if strings.Contains(strings.ToLower(tag), strings.ToLower(keyword)) { score += 0.5 break } } } if checks == 0 { return 0.5 // Default score when no keywords to check } return score / checks } // updateStats updates engine statistics func (e *DefaultIntelligenceEngine) updateStats(operation string, duration time.Duration, success bool) { e.mu.Lock() defer e.mu.Unlock() e.stats.TotalAnalyses++ if success { e.stats.SuccessfulAnalyses++ } else { e.stats.FailedAnalyses++ } // Update average analysis time if e.stats.TotalAnalyses == 1 { e.stats.AverageAnalysisTime = duration } else { e.stats.AverageAnalysisTime = time.Duration( (int64(e.stats.AverageAnalysisTime)*(e.stats.TotalAnalyses-1) + int64(duration)) / e.stats.TotalAnalyses, ) } // Update operation-specific stats switch operation { case "file_analysis": e.stats.FilesAnalyzed++ case "directory_analysis": e.stats.DirectoriesAnalyzed++ } } // calculateCacheHitRate calculates the current cache hit rate func (e *DefaultIntelligenceEngine) calculateCacheHitRate() float64 { return e.stats.CacheHitRate // This would be calculated from cache access stats in a real implementation } // DefaultEngineConfig returns default configuration for the intelligence engine func DefaultEngineConfig() *EngineConfig { return &EngineConfig{ MaxConcurrentAnalysis: 4, AnalysisTimeout: 30 * time.Second, MaxFileSize: 10 * 1024 * 1024, // 10MB RAGEndpoint: "", RAGTimeout: 10 * time.Second, RAGEnabled: false, MinConfidenceThreshold: 0.6, RequireValidation: true, CacheEnabled: true, CacheTTL: 1 * time.Hour, RoleProfiles: make(map[string]*RoleProfile), ProjectGoals: []*ProjectGoal{}, } }