UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

877 lines (704 loc) 24.7 kB
--- ## Execution Modes **Choose your execution mode:** ### 1. YOLO Mode - Fast, Autonomous (0-1 prompts) - Autonomous decision making with logging - Minimal user interaction - **Best for:** Simple, deterministic tasks ### 2. Interactive Mode - Balanced, Educational (5-10 prompts) **[DEFAULT]** - Explicit decision checkpoints - Educational explanations - **Best for:** Learning, complex decisions ### 3. Pre-Flight Planning - Comprehensive Upfront Planning - Task analysis phase (identify all ambiguities) - Zero ambiguity execution - **Best for:** Ambiguous requirements, critical work **Parameter:** `mode` (optional, default: `interactive`) --- ## Task Definition (AIOS Task Format V1.0) ```yaml task: devSuggestRefactoring() responsável: Dex (Builder) responsavel_type: Agente atomic_layer: Strategy **Entrada:** - campo: task tipo: string origem: User Input obrigatório: true validação: Must be registered task - campo: parameters tipo: object origem: User Input obrigatório: false validação: Valid task parameters - campo: mode tipo: string origem: User Input obrigatório: false validação: yolo|interactive|pre-flight **Saída:** - campo: execution_result tipo: object destino: Memory persistido: false - campo: logs tipo: array destino: File (.ai/logs/*) persistido: true - campo: state tipo: object destino: State management persistido: true ``` --- ## Pre-Conditions **Purpose:** Validate prerequisites BEFORE task execution (blocking) **Checklist:** ```yaml pre-conditions: - [ ] Task is registered; required parameters provided; dependencies met tipo: pre-condition blocker: true validação: | Check task is registered; required parameters provided; dependencies met error_message: "Pre-condition failed: Task is registered; required parameters provided; dependencies met" ``` --- ## Post-Conditions **Purpose:** Validate execution success AFTER task completes **Checklist:** ```yaml post-conditions: - [ ] Task completed; exit code 0; expected outputs created tipo: post-condition blocker: true validação: | Verify task completed; exit code 0; expected outputs created error_message: "Post-condition failed: Task completed; exit code 0; expected outputs created" ``` --- ## Acceptance Criteria **Purpose:** Definitive pass/fail criteria for task completion **Checklist:** ```yaml acceptance-criteria: - [ ] Task completed as expected; side effects documented tipo: acceptance-criterion blocker: true validação: | Assert task completed as expected; side effects documented error_message: "Acceptance criterion not met: Task completed as expected; side effects documented" ``` --- ## Tools **External/shared resources used by this task:** - **Tool:** task-runner - **Purpose:** Task execution and orchestration - **Source:** .aios-core/core/task-runner.js - **Tool:** logger - **Purpose:** Execution logging and error tracking - **Source:** .aios-core/utils/logger.js --- ## Scripts **Agent-specific code for this task:** - **Script:** execute-task.js - **Purpose:** Generic task execution wrapper - **Language:** JavaScript - **Location:** .aios-core/scripts/execute-task.js --- ## Error Handling **Strategy:** retry **Common Errors:** 1. **Error:** Task Not Found - **Cause:** Specified task not registered in system - **Resolution:** Verify task name and registration - **Recovery:** List available tasks, suggest similar 2. **Error:** Invalid Parameters - **Cause:** Task parameters do not match expected schema - **Resolution:** Validate parameters against task definition - **Recovery:** Provide parameter template, reject execution 3. **Error:** Execution Timeout - **Cause:** Task exceeds maximum execution time - **Resolution:** Optimize task or increase timeout - **Recovery:** Kill task, cleanup resources, log state --- ## Performance **Expected Metrics:** ```yaml duration_expected: 5-20 min (estimated) cost_estimated: $0.003-0.015 token_usage: ~2,000-8,000 tokens ``` **Optimization Notes:** - Iterative analysis with depth limits; cache intermediate results; batch similar operations --- ## Metadata ```yaml story: N/A version: 1.0.0 dependencies: - N/A tags: - development - code updated_at: 2025-11-17 ``` --- checklists: - dev-master-checklist.md --- # Suggest Refactoring - AIOS Developer Task ## Purpose Analyze code and suggest automated refactoring opportunities to improve code quality, maintainability, and performance. ## Command Pattern ``` *suggest-refactoring <path> [options] ``` ## Parameters - `path`: File or directory path to analyze - `options`: Refactoring analysis configuration ### Options - `--patterns <types>`: Comma-separated refactoring patterns to check - `--threshold <level>`: Minimum impact threshold (1-10, default: 3) - `--limit <count>`: Maximum suggestions per file (default: 10) - `--apply <id>`: Apply specific suggestion by ID - `--apply-all`: Apply all suggestions with confirmation - `--export <file>`: Export suggestions to file - `--recursive`: Analyze directories recursively - `--exclude <patterns>`: Exclude file patterns (e.g., "*.test.js") - `--dry-run`: Show what would be changed without applying ## Refactoring Patterns - `extract_method`: Extract long methods into smaller ones - `extract_variable`: Extract complex expressions - `introduce_parameter_object`: Group related parameters - `replace_conditional`: Replace conditionals with polymorphism - `inline_temp`: Inline single-use variables - `remove_dead_code`: Remove unreachable code - `consolidate_duplicates`: Extract duplicate code - `simplify_conditionals`: Flatten nested conditionals - `replace_magic_numbers`: Extract constants - `decompose_class`: Split large classes ## Examples ```bash # Analyze single file *suggest-refactoring aios-core/scripts/complex-utility.js # Analyze directory with specific patterns *suggest-refactoring aios-core/agents --patterns extract_method,decompose_class --recursive # Apply high-impact suggestions *suggest-refactoring aios-core/utils --threshold 7 --apply-all # Export suggestions for review *suggest-refactoring . --recursive --export refactoring-report.json # Dry run to see changes *suggest-refactoring aios-core/agents/developer.md --apply ref-001 --dry-run ``` ## Implementation ```javascript const fs = require('fs').promises; const path = require('path'); const chalk = require('chalk'); const inquirer = require('inquirer'); const glob = require('glob').promises; class SuggestRefactoringTask { constructor() { this.taskName = 'suggest-refactoring'; this.description = 'Suggest automated refactoring opportunities'; this.rootPath = process.cwd(); this.refactoringSuggester = null; this.suggestions = []; this.appliedRefactorings = []; } async execute(params) { try { console.log(chalk.blue('🔧 AIOS Refactoring Analysis')); console.log(chalk.gray('Analyzing code for refactoring opportunities\n')); // Parse parameters const config = await this.parseParameters(params); // Initialize dependencies await this.initializeDependencies(); // Get files to analyze const files = await this.getFilesToAnalyze(config); if (files.length === 0) { console.log(chalk.yellow('No files found to analyze')); return { success: true, suggestions: [] }; } console.log(chalk.gray(`Found ${files.length} files to analyze\n`)); // Execute based on mode if (config.apply) { // Apply specific suggestion await this.applySuggestion(config.apply, config); } else if (config.applyAll) { // Analyze and apply all suggestions await this.analyzeFiles(files, config); await this.applyAllSuggestions(config); } else { // Just analyze and show suggestions await this.analyzeFiles(files, config); await this.displaySuggestions(config); } // Export if requested if (config.export) { await this.exportSuggestions(config.export); } return { success: true, filesAnalyzed: files.length, totalSuggestions: this.suggestions.length, appliedRefactorings: this.appliedRefactorings.length }; } catch (error) { console.error(chalk.red(`\n❌ Refactoring analysis failed: ${error.message}`)); throw error; } } async parseParameters(params) { if (params.length < 1) { throw new Error('Usage: *suggest-refactoring <path> [options]'); } const config = { targetPath: params[0], patterns: null, threshold: 3, limit: 10, apply: null, applyAll: false, export: null, recursive: false, exclude: [], dryRun: false }; // Parse options for (let i = 1; i < params.length; i++) { const param = params[i]; if (param === '--recursive') { config.recursive = true; } else if (param === '--apply-all') { config.applyAll = true; } else if (param === '--dry-run') { config.dryRun = true; } else if (param.startsWith('--patterns') && params[i + 1]) { config.patterns = params[++i].split(',').map(p => p.trim()); } else if (param.startsWith('--threshold') && params[i + 1]) { config.threshold = parseInt(params[++i]); } else if (param.startsWith('--limit') && params[i + 1]) { config.limit = parseInt(params[++i]); } else if (param.startsWith('--apply') && params[i + 1]) { config.apply = params[++i]; } else if (param.startsWith('--export') && params[i + 1]) { config.export = params[++i]; } else if (param.startsWith('--exclude') && params[i + 1]) { config.exclude = params[++i].split(',').map(e => e.trim()); } } // Validate threshold if (config.threshold < 1 || config.threshold > 10) { throw new Error('Threshold must be between 1 and 10'); } return config; } async initializeDependencies() { try { const RefactoringSuggester = require('../scripts/refactoring-suggester'); this.refactoringSuggester = new RefactoringSuggester({ rootPath: this.rootPath }); } catch (error) { throw new Error(`Failed to initialize dependencies: ${error.message}`); } } async getFilesToAnalyze(config) { const targetPath = path.resolve(this.rootPath, config.targetPath); const files = []; try { const stats = await fs.stat(targetPath); if (stats.isFile()) { // Single file if (this.shouldAnalyzeFile(targetPath, config)) { files.push(targetPath); } } else if (stats.isDirectory()) { // Directory const pattern = config.recursive ? '**/*.{js,jsx,ts,tsx}' : '*.{js,jsx,ts,tsx}'; const globPattern = path.join(targetPath, pattern); const matches = await glob(globPattern, { ignore: config.exclude.map(e => path.join(targetPath, '**', e)), nodir: true }); for (const match of matches) { if (this.shouldAnalyzeFile(match, config)) { files.push(match); } } } } catch (error) { console.warn(chalk.yellow(`Cannot access ${targetPath}: ${error.message}`)); } return files; } shouldAnalyzeFile(filePath, config) { // Skip test files unless explicitly included if (filePath.includes('.test.') || filePath.includes('.spec.')) { return false; } // Skip minified files if (filePath.includes('.min.')) { return false; } // Skip node_modules if (filePath.includes('node_modules')) { return false; } // Check file extension const ext = path.extname(filePath); return ['.js', '.jsx', '.ts', '.tsx'].includes(ext); } async analyzeFiles(files, config) { console.log(chalk.blue('🔍 Analyzing files...')); const progressInterval = Math.max(1, Math.floor(files.length / 20)); for (let i = 0; i < files.length; i++) { const file = files[i]; try { const result = await this.refactoringSuggester.analyzeCode(file, { patterns: config.patterns }); if (result.suggestions && result.suggestions.length > 0) { // Filter by threshold and limit const filteredSuggestions = result.suggestions .filter(s => s.impact >= config.threshold) .slice(0, config.limit); // Add to global suggestions with unique IDs for (const suggestion of filteredSuggestions) { suggestion.id = `ref-${this.suggestions.length + 1}`; suggestion.file = path.relative(this.rootPath, file); this.suggestions.push(suggestion); } } // Show progress if (i % progressInterval === 0) { const progress = Math.floor((i / files.length) * 100); process.stdout.write(`\rProgress: ${progress}%`); } } catch (error) { console.warn(chalk.yellow(`\nFailed to analyze ${file}: ${error.message}`)); } } console.log('\rProgress: 100%\n'); } async displaySuggestions(config) { if (this.suggestions.length === 0) { console.log(chalk.yellow('No refactoring suggestions found above threshold')); return; } console.log(chalk.blue(`\n📋 Found ${this.suggestions.length} refactoring suggestions:\n`)); // Group by file const byFile = {}; for (const suggestion of this.suggestions) { if (!byFile[suggestion.file]) { byFile[suggestion.file] = []; } byFile[suggestion.file].push(suggestion); } // Display suggestions for (const [file, suggestions] of Object.entries(byFile)) { console.log(chalk.blue(`\n📄 ${file}`)); console.log(chalk.gray('─'.repeat(50))); for (const suggestion of suggestions) { this.displaySuggestion(suggestion); } } // Show statistics this.displayStatistics(); // Show next steps console.log(chalk.blue('\n📌 Next Steps:')); console.log('1. Review suggestions carefully'); console.log(`2. Apply specific suggestion: *suggest-refactoring ${config.targetPath} --apply <id>`); console.log(`3. Apply all suggestions: *suggest-refactoring ${config.targetPath} --apply-all`); console.log(`4. Export for team review: *suggest-refactoring ${config.targetPath} --export report.json`); } displaySuggestion(suggestion) { const priorityColors = { high: chalk.red, medium: chalk.yellow, low: chalk.gray }; const priorityColor = priorityColors[suggestion.priority] || chalk.gray; console.log(`\n${chalk.gray(suggestion.id)} ${priorityColor(`[${suggestion.priority.toUpperCase()}]`)} ${suggestion.description}`); console.log(` ${chalk.gray('Location:')} Lines ${suggestion.location.start}-${suggestion.location.end}`); console.log(` ${chalk.gray('Impact:')} ${this.formatImpact(suggestion.impact)}`); console.log(` ${chalk.gray('Type:')} ${suggestion.pattern}`); console.log(` ${chalk.gray('Details:')} ${suggestion.details}`); if (suggestion.suggestedRefactoring && suggestion.suggestedRefactoring.action) { console.log(` ${chalk.gray('Action:')} ${suggestion.suggestedRefactoring.action}`); } } formatImpact(impact) { const bar = '█'.repeat(impact) + '░'.repeat(10 - impact); if (impact >= 8) { return chalk.red(bar) + ` (${impact}/10)`; } else if (impact >= 5) { return chalk.yellow(bar) + ` (${impact}/10)`; } else { return chalk.gray(bar) + ` (${impact}/10)`; } } async applySuggestion(suggestionId, config) { const suggestion = this.suggestions.find(s => s.id === suggestionId); if (!suggestion) { // Try to load from previous analysis const loaded = await this.loadSuggestion(suggestionId); if (!loaded) { throw new Error(`Suggestion not found: ${suggestionId}`); } suggestion = loaded; } console.log(chalk.blue('\n🔧 Applying Refactoring')); console.log(chalk.gray('─'.repeat(50))); this.displaySuggestion(suggestion); if (config.dryRun) { console.log(chalk.yellow('\n⚠️ DRY RUN - No changes will be made')); await this.showRefactoringPreview(suggestion); return; } // Confirm application const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: 'Apply this refactoring?', default: true }]); if (!confirm) { console.log(chalk.gray('Refactoring cancelled')); return; } // Apply the refactoring try { const result = await this.refactoringSuggester.applySuggestion(suggestion); if (result.success) { console.log(chalk.green('✅ Refactoring applied successfully')); this.appliedRefactorings.push({ suggestion, result, timestamp: new Date().toISOString() }); // Show changes for (const change of result.changes) { console.log(chalk.gray(` - ${change.description}`)); } } else { console.error(chalk.red(`Failed to apply refactoring: ${result.error}`)); } } catch (error) { console.error(chalk.red(`Error applying refactoring: ${error.message}`)); } } async applyAllSuggestions(config) { if (this.suggestions.length === 0) { console.log(chalk.yellow('No suggestions to apply')); return; } console.log(chalk.blue(`\n🔧 Applying ${this.suggestions.length} refactorings`)); // Group by type for better user experience const byType = {}; for (const suggestion of this.suggestions) { if (!byType[suggestion.type]) { byType[suggestion.type] = []; } byType[suggestion.type].push(suggestion); } // Show summary console.log(chalk.gray('\nRefactorings by type:')); for (const [type, suggestions] of Object.entries(byType)) { console.log(` ${type}: ${suggestions.length}`); } if (config.dryRun) { console.log(chalk.yellow('\n⚠️ DRY RUN - No changes will be made')); return; } // Confirm batch application const { confirmAll } = await inquirer.prompt([{ type: 'confirm', name: 'confirmAll', message: `Apply all ${this.suggestions.length} refactorings?`, default: false }]); if (!confirmAll) { // Ask for individual confirmation await this.applySelectiveSuggestions(config); return; } // Apply all suggestions let applied = 0; let failed = 0; for (const suggestion of this.suggestions) { try { console.log(chalk.gray(`\nApplying ${suggestion.id}: ${suggestion.description}`)); const result = await this.refactoringSuggester.applySuggestion(suggestion); if (result.success) { applied++; this.appliedRefactorings.push({ suggestion, result, timestamp: new Date().toISOString() }); } else { failed++; console.error(chalk.red(` Failed: ${result.error}`)); } } catch (error) { failed++; console.error(chalk.red(` Error: ${error.message}`)); } } console.log(chalk.blue('\n📊 Application Summary:')); console.log(chalk.green(` Applied: ${applied}`)); if (failed > 0) { console.log(chalk.red(` Failed: ${failed}`)); } } async applySelectiveSuggestions(config) { const choices = this.suggestions.map(s => ({ name: `${s.id} - ${s.description} (${s.file})`, value: s.id, checked: s.impact >= 7 // Pre-check high impact })); const { selected } = await inquirer.prompt([{ type: 'checkbox', name: 'selected', message: 'Select refactorings to apply:', choices, pageSize: 15 }]); if (selected.length === 0) { console.log(chalk.gray('No refactorings selected')); return; } // Apply selected suggestions for (const id of selected) { const suggestion = this.suggestions.find(s => s.id === id); await this.applySuggestion(id, config); } } async showRefactoringPreview(suggestion) { console.log(chalk.blue('\n📝 Refactoring Preview:')); // This would show actual code changes // For now, show the refactoring plan if (suggestion.suggestedRefactoring) { console.log(chalk.gray(JSON.stringify(suggestion.suggestedRefactoring, null, 2))); } } async loadSuggestion(suggestionId) { // Try to load from cache or previous export const cacheFile = path.join(this.rootPath, '.aios', 'refactoring', `${suggestionId}.json`); try { const content = await fs.readFile(cacheFile, 'utf-8'); return JSON.parse(content); } catch (error) { return null; } } async exportSuggestions(exportPath) { console.log(chalk.blue('\n📤 Exporting suggestions...')); const exportData = { version: 1, exportDate: new Date().toISOString(), analysisPath: this.rootPath, totalSuggestions: this.suggestions.length, statistics: this.refactoringSuggester.getStatistics(), suggestions: this.suggestions.map(s => ({ ...s, file: s.file || s.filePath })) }; await fs.writeFile(exportPath, JSON.stringify(exportData, null, 2)); console.log(chalk.green(`✅ Exported ${this.suggestions.length} suggestions to: ${exportPath}`)); } displayStatistics() { const stats = this.refactoringSuggester.getStatistics(); console.log(chalk.blue('\n📊 Refactoring Statistics:')); console.log(chalk.gray('─'.repeat(50))); console.log(`Total suggestions: ${stats.totalSuggestions}`); console.log(`Average impact: ${stats.averageImpact}/10`); console.log('\nBy priority:'); for (const [priority, count] of Object.entries(stats.byPriority)) { console.log(` ${priority}: ${count}`); } console.log('\nBy type:'); const sortedTypes = Object.entries(stats.byType) .sort(([,a], [,b]) => b - a) .slice(0, 5); for (const [type, count] of sortedTypes) { console.log(` ${type}: ${count}`); } } } module.exports = SuggestRefactoringTask; ``` ## Integration Points ### Refactoring Suggester - Core analysis engine - Pattern detection - Suggestion generation - Refactoring application ### AST Processing - Code parsing - Pattern matching - Code transformation - Generation ### Pattern Library - Refactoring patterns - Detection algorithms - Application strategies - Success metrics ### Code Metrics - Complexity analysis - Code quality metrics - Impact calculation - Priority assignment ## Refactoring Workflow ### Analysis Phase 1. Parse code into AST 2. Calculate code metrics 3. Run pattern detectors 4. Generate suggestions 5. Prioritize by impact 6. **Code Intelligence Blast Radius** (if available): - Call `assessRefactoringImpact(candidateFiles)` from `.aios-core/core/code-intel/helpers/dev-helper` - If result is not null, enrich each suggestion with: - `blastRadius`: number of affected references - `riskLevel`: LOW (<5 refs) | MEDIUM (5-15) | HIGH (>15) - If code intelligence not available: suggestions work as before (no blast radius shown) ### Review Phase 1. Display suggestions 2. Group by file/type 3. Show impact analysis (including blast radius and risk level when available) 4. Provide preview 5. Export for review ### Application Phase 1. Confirm changes 2. Create backup 3. Apply transformation 4. Validate result 5. Update metrics ## Best Practices ### Safe Refactoring - Always backup before changes - Validate syntax after refactoring - Run tests after changes - Use dry-run for preview - Apply incrementally ### Pattern Selection - Start with high-impact patterns - Focus on code hotspots - Consider team preferences - Respect coding standards - Monitor effectiveness ### Continuous Improvement - Track refactoring success - Learn from applied patterns - Update pattern library - Share successful refactorings - Measure code quality trends ## Security Considerations - Validate refactoring safety - Preserve functionality - Maintain security patterns - Audit changes - Test thoroughly