UNPKG

csvlod-ai-mcp-server

Version:

CSVLOD-AI MCP Server v3.0 with Quantum Context Intelligence - Revolutionary Context Intelligence Engine and Multimodal Processor for sovereign AI development

313 lines (312 loc) 12 kB
import { z } from 'zod'; import { execSync } from 'child_process'; import * as fs from 'fs/promises'; export const patternDetectorTool = { name: 'sis_patterns', description: 'Detect patterns across workspace using quantum correlation', parameters: z.object({ type: z.enum(['structural', 'behavioral', 'evolutionary', 'all']).default('all'), threshold: z.number().min(0).max(1).default(0.7), depth: z.number().min(1).max(5).default(3), save: z.boolean().default(true) }), execute: async (args) => { const patterns = { structural: [], behavioral: [], evolutionary: [] }; // Structural patterns if (args.type === 'structural' || args.type === 'all') { patterns.structural = await detectStructuralPatterns(args.depth); } // Behavioral patterns if (args.type === 'behavioral' || args.type === 'all') { patterns.behavioral = await detectBehavioralPatterns(args.threshold); } // Evolutionary patterns if (args.type === 'evolutionary' || args.type === 'all') { patterns.evolutionary = await detectEvolutionaryPatterns(); } // Filter by threshold const filtered = filterPatternsByThreshold(patterns, args.threshold); // Save to SIS patterns directory if (args.save && Object.values(filtered).flat().length > 0) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const patternFile = `./.sis/patterns/detected-${timestamp}.json`; await fs.mkdir('./.sis/patterns', { recursive: true }); await fs.writeFile(patternFile, JSON.stringify(filtered, null, 2)); // Update PATTERNS.md if significant patterns found const significantPatterns = Object.values(filtered).flat() .filter((p) => p.confidence >= 0.9); if (significantPatterns.length > 0) { await updatePatternsDocument(significantPatterns); } } return { patterns: filtered, total_detected: Object.values(filtered).flat().length, high_confidence: Object.values(filtered).flat() .filter((p) => p.confidence >= 0.9).length, pattern_locations: args.save ? `./.sis/patterns/` : null }; } }; async function detectStructuralPatterns(depth) { const patterns = []; // Directory structure patterns const dirTree = execSync(`find . -type d -maxdepth ${depth} | grep -v -E '^\\./(\\.|node_modules|venv)'`, { encoding: 'utf-8' }).split('\n').filter(Boolean); // Analyze directory naming patterns const dirPatterns = new Map(); for (const dir of dirTree) { const parts = dir.split('/'); const lastPart = parts[parts.length - 1]; // Common patterns if (lastPart.match(/^(src|lib|test|tests|spec|docs|scripts|utils|helpers|models|views|controllers)$/i)) { dirPatterns.set('standard-structure', (dirPatterns.get('standard-structure') || 0) + 1); } if (lastPart.match(/^v\d+|version-?\d+/i)) { dirPatterns.set('versioned-directories', (dirPatterns.get('versioned-directories') || 0) + 1); } } // File naming patterns const files = execSync('find . -type f -name "*.md" -o -name "*.py" -o -name "*.ts" -o -name "*.js" | head -100', { encoding: 'utf-8' }).split('\n').filter(Boolean); const filePatterns = analyzeFilePatterns(files); // Convert to pattern objects for (const [pattern, count] of dirPatterns) { if (count >= 3) { patterns.push({ type: 'structural', pattern: pattern, occurrences: count, confidence: Math.min(count / 10, 1), description: `Directory structure pattern: ${pattern}`, locations: dirTree.filter(d => d.match(getPatternRegex(pattern))).slice(0, 5) }); } } patterns.push(...filePatterns); return patterns; } async function detectBehavioralPatterns(threshold) { const patterns = []; // Git commit patterns try { const commits = execSync('git log --format="%s" -100', { encoding: 'utf-8' }) .split('\n').filter(Boolean); const commitPatterns = new Map(); for (const commit of commits) { // Conventional commits const match = commit.match(/^(feat|fix|docs|style|refactor|test|chore|build|ci)(\(.+\))?:/); if (match) { commitPatterns.set('conventional-commits', (commitPatterns.get('conventional-commits') || 0) + 1); } // Version bumps if (commit.match(/^(v?\d+\.\d+\.\d+|bump version|release)/i)) { commitPatterns.set('version-releases', (commitPatterns.get('version-releases') || 0) + 1); } // Merge patterns if (commit.match(/^Merge/)) { commitPatterns.set('merge-commits', (commitPatterns.get('merge-commits') || 0) + 1); } } for (const [pattern, count] of commitPatterns) { const confidence = count / commits.length; if (confidence >= threshold) { patterns.push({ type: 'behavioral', pattern: pattern, occurrences: count, confidence: confidence, description: `Git commit pattern: ${pattern}`, recommendation: getPatternRecommendation(pattern) }); } } } catch { // Git not available } // File change patterns const streamData = await readLatestStreamData(); if (streamData.length > 10) { const changePatterns = analyzeChangePatterns(streamData); patterns.push(...changePatterns.filter(p => p.confidence >= threshold)); } return patterns; } async function detectEvolutionaryPatterns() { const patterns = []; // Growth patterns try { const fileCounts = execSync('git log --format="%at" --name-only --since="6 months ago" | grep -v "^$" | sort -u | wc -l', { encoding: 'utf-8' }); const currentFiles = execSync('find . -type f | wc -l', { encoding: 'utf-8' }); patterns.push({ type: 'evolutionary', pattern: 'repository-growth', current_size: parseInt(currentFiles), growth_rate: 'calculated', confidence: 0.8, description: 'Repository growth pattern detected' }); } catch { // Fallback for non-git repos } // Technology evolution const techEvolution = await analyzeTechnologyEvolution(); patterns.push(...techEvolution); return patterns; } function analyzeFilePatterns(files) { const patterns = []; const namingConventions = new Map(); for (const file of files) { const basename = file.split('/').pop() || ''; // snake_case if (basename.match(/^[a-z]+(_[a-z]+)+\./)) { namingConventions.set('snake_case', (namingConventions.get('snake_case') || 0) + 1); } // kebab-case if (basename.match(/^[a-z]+(-[a-z]+)+\./)) { namingConventions.set('kebab-case', (namingConventions.get('kebab-case') || 0) + 1); } // CamelCase if (basename.match(/^[A-Z][a-z]+([A-Z][a-z]+)+\./)) { namingConventions.set('CamelCase', (namingConventions.get('CamelCase') || 0) + 1); } } for (const [convention, count] of namingConventions) { if (count >= 5) { patterns.push({ type: 'structural', pattern: `naming-convention-${convention}`, occurrences: count, confidence: Math.min(count / files.length, 1), description: `File naming convention: ${convention}` }); } } return patterns; } function getPatternRegex(pattern) { switch (pattern) { case 'standard-structure': return /(src|lib|test|docs)/; case 'versioned-directories': return /v\d+|version-?\d+/; default: return new RegExp(pattern); } } function getPatternRecommendation(pattern) { switch (pattern) { case 'conventional-commits': return 'Continue using conventional commits for consistency'; case 'version-releases': return 'Consider semantic versioning for releases'; case 'merge-commits': return 'Consider squash merging for cleaner history'; default: return 'Pattern detected - maintain consistency'; } } async function readLatestStreamData() { try { const streamPath = './.sis/intelligence/stream.jsonl'; const content = await fs.readFile(streamPath, 'utf-8'); const lines = content.trim().split('\n').slice(-100); // Last 100 entries return lines.map(line => { try { return JSON.parse(line); } catch { return null; } }).filter(Boolean); } catch { return []; } } function analyzeChangePatterns(streamData) { const patterns = []; // Time-based patterns const hourlyActivity = new Map(); for (const entry of streamData) { const hour = new Date(entry.t * 1000).getHours(); hourlyActivity.set(hour, (hourlyActivity.get(hour) || 0) + 1); } // Find peak hours const peakHours = Array.from(hourlyActivity.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 3); if (peakHours.length > 0 && peakHours[0][1] > streamData.length * 0.2) { patterns.push({ type: 'behavioral', pattern: 'peak-activity-hours', peak_hours: peakHours.map(([h]) => h), confidence: peakHours[0][1] / streamData.length, description: `Peak development activity during hours: ${peakHours.map(([h]) => h).join(', ')}` }); } return patterns; } async function analyzeTechnologyEvolution() { const patterns = []; // Check for framework migrations try { const packageJson = await fs.readFile('./package.json', 'utf-8'); const packages = JSON.parse(packageJson); if (packages.dependencies || packages.devDependencies) { patterns.push({ type: 'evolutionary', pattern: 'technology-stack', stack: 'node.js', maturity: 'established', confidence: 0.9, description: 'Node.js ecosystem detected' }); } } catch { // Not a Node project } return patterns; } function filterPatternsByThreshold(patterns, threshold) { const filtered = {}; for (const [type, typePatterns] of Object.entries(patterns)) { filtered[type] = typePatterns.filter(p => p.confidence >= threshold); } return filtered; } async function updatePatternsDocument(patterns) { try { const patternsPath = './PATTERNS.md'; let content = await fs.readFile(patternsPath, 'utf-8'); // Add new patterns section const newSection = ` ## Automatically Detected Patterns (${new Date().toISOString().split('T')[0]}) ${patterns.map(p => `### ${p.pattern} - **Type**: ${p.type} - **Confidence**: ${(p.confidence * 100).toFixed(1)}% - **Description**: ${p.description} ${p.recommendation ? `- **Recommendation**: ${p.recommendation}` : ''} `).join('\n')} `; // Append to file content += newSection; await fs.writeFile(patternsPath, content); } catch { // PATTERNS.md doesn't exist or not writable } } //# sourceMappingURL=pattern-detector.js.map