 d96c931a29
			
		
	
	d96c931a29
	
	
	
		
			
			This comprehensive refactoring addresses critical architectural issues: IMPORT CYCLE RESOLUTION: • pkg/crypto ↔ pkg/slurp/roles: Created pkg/security/access_levels.go • pkg/ucxl → pkg/dht: Created pkg/storage/interfaces.go • pkg/slurp/leader → pkg/election → pkg/slurp/storage: Moved types to pkg/election/interfaces.go MODULE PATH MIGRATION: • Changed from github.com/anthonyrawlins/bzzz to chorus.services/bzzz • Updated all import statements across 115+ files • Maintains compatibility while removing personal GitHub account dependency TYPE SYSTEM IMPROVEMENTS: • Resolved duplicate type declarations in crypto package • Added missing type definitions (RoleStatus, TimeRestrictions, KeyStatus, KeyRotationResult) • Proper interface segregation to prevent future cycles ARCHITECTURAL BENEFITS: • Build now progresses past structural issues to normal dependency resolution • Cleaner separation of concerns between packages • Eliminates circular dependencies that prevented compilation • Establishes foundation for scalable codebase growth 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			650 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			650 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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{},
 | |
| 	}
 | |
| } |