recoder-code 2.2.1 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ const fs = require('fs');
8
8
  const path = require('path');
9
9
  const crypto = require('crypto');
10
10
  const OpenAI = require('openai');
11
- const chokidar = require('chokidar');
11
+ // Removed direct chokidar import - use FileWatcherManager instead
12
12
  const config = require('../config.js');
13
13
  const PluginManager = require('../plugins/enhanced-plugin-manager.js');
14
14
  const VoiceManager = require('./voice-manager.js');
@@ -25,6 +25,8 @@ const TaskManager = require('./task-manager.js');
25
25
  const DevToolsIntegration = require('./dev-tools-integration.js');
26
26
  const VisionAnalyzer = require('./vision-analyzer.js');
27
27
  const NaturalLanguageProcessor = require('./natural-language-processor.js');
28
+ const TodoManager = require('./todo-manager.js');
29
+ const FileWatcherManager = require('./file-watcher-manager.js');
28
30
 
29
31
  // Create logs and sessions directories
30
32
  const logsDir = path.join(process.cwd(), 'logs');
@@ -35,10 +37,17 @@ const sessionsDir = path.join(process.cwd(), 'sessions');
35
37
  }
36
38
  });
37
39
 
40
+ // Initialize unified error handling for interactive mode
41
+ const UnifiedErrorHandler = require('./unified-error-handler.js');
42
+ const errorHandler = UnifiedErrorHandler.instance;
43
+ errorHandler.initialize();
44
+
38
45
  class InteractiveRecoderChat {
39
46
  constructor() {
40
- this.apiKey = config.apiKey;
41
- this.model = config.model;
47
+ // Load user configuration
48
+ this.userConfig = this.loadUserConfig();
49
+ this.apiKey = this.userConfig.apiKey || config.apiKey;
50
+ this.model = this.userConfig.model || config.model;
42
51
  this.maxTokens = config.maxTokens;
43
52
  this.temperature = config.temperature;
44
53
 
@@ -58,7 +67,11 @@ class InteractiveRecoderChat {
58
67
  this.historyIndex = -1;
59
68
  this.keyboardShortcutsEnabled = true;
60
69
  this.watchedFiles = new Set();
61
- this.fileWatchEnabled = true;
70
+ // Disable file watching by default to prevent EMFILE errors in production
71
+ this.fileWatchEnabled = process.env.RECODER_ENABLE_FILE_WATCH === 'true' || false;
72
+
73
+ // Simple mode disables heavy systems to prevent resource exhaustion
74
+ this.simpleMode = process.env.RECODER_SIMPLE_MODE !== 'false'; // Default to simple mode
62
75
  this.projectContext = {
63
76
  packageJson: null,
64
77
  gitInfo: null,
@@ -106,6 +119,12 @@ class InteractiveRecoderChat {
106
119
  sessionId: this.sessionId
107
120
  });
108
121
 
122
+ // Initialize todo manager for production-ready task tracking
123
+ this.todoManager = new TodoManager({ user: process.env.USER || 'developer' });
124
+
125
+ // Add comprehensive promise rejection handling
126
+ this.setupGlobalErrorHandlers();
127
+
109
128
  // Initialize advanced systems
110
129
  this.contextEngine = null;
111
130
  this.slashCommands = null;
@@ -147,12 +166,22 @@ class InteractiveRecoderChat {
147
166
  * Initialize advanced systems (Context Engine, MCP, etc.)
148
167
  */
149
168
  async initializeAdvancedSystems() {
169
+ // Skip advanced systems in simple mode to prevent resource exhaustion
170
+ if (this.simpleMode) {
171
+ console.log(chalk.gray('📱 Simple mode enabled - advanced features disabled for stability'));
172
+ return;
173
+ }
174
+
150
175
  try {
151
176
  // Silently initialize advanced features (no console.log for clean startup)
152
177
 
153
178
  // Initialize context engine for codebase understanding
154
179
  this.contextEngine = new ContextEngine();
155
- await this.contextEngine.initialize();
180
+ try {
181
+ await this.contextEngine.initialize();
182
+ } catch (contextError) {
183
+ console.log(chalk.yellow(`⚠️ Context engine initialization failed: ${contextError.message}`));
184
+ }
156
185
 
157
186
  // Initialize MCP client for model communication
158
187
  this.mcpClient = new MCPClient();
@@ -162,30 +191,46 @@ class InteractiveRecoderChat {
162
191
 
163
192
  // Initialize rules engine with project context
164
193
  this.rulesEngine = new RulesEngine(this.projectManager);
165
- await this.rulesEngine.autoDiscoverProjectRules();
194
+ try {
195
+ await this.rulesEngine.autoDiscoverProjectRules();
196
+ } catch (rulesError) {
197
+ console.log(chalk.yellow(`⚠️ Rules engine initialization failed: ${rulesError.message}`));
198
+ }
166
199
 
167
200
  // Initialize task manager with full integration
168
201
  this.taskManager = new TaskManager(this.projectManager, this.contextEngine, this.rulesEngine);
169
- this.taskManager.setupSmartAutomationTriggers();
202
+ try {
203
+ this.taskManager.setupSmartAutomationTriggers();
204
+ } catch (automationError) {
205
+ console.log(chalk.yellow(`⚠️ Automation setup failed: ${automationError.message}`));
206
+ }
170
207
 
171
208
  // Initialize development tools integration
172
209
  this.devTools = new DevToolsIntegration(this.contextEngine, this.projectManager, this.taskManager);
173
- await this.devTools.setupIDEIntegration();
174
- await this.devTools.setupGitIntegration();
175
- await this.devTools.setupDatabaseIntegration();
176
- await this.devTools.setupPerformanceMonitoring();
210
+ try {
211
+ await this.devTools.setupIDEIntegration();
212
+ await this.devTools.setupGitIntegration();
213
+ await this.devTools.setupDatabaseIntegration();
214
+ await this.devTools.setupPerformanceMonitoring();
215
+ } catch (devToolsError) {
216
+ console.log(chalk.yellow(`⚠️ Dev tools setup failed: ${devToolsError.message}`));
217
+ }
177
218
 
178
219
  // Initialize vision analyzer with model manager and context engine
179
220
  this.visionAnalyzer = new VisionAnalyzer(this.modelManager, this.contextEngine);
180
221
 
181
- // Initialize slash commands system with all dependencies including vision analyzer
182
- this.slashCommands = new SlashCommandsEngine(this.contextEngine, this.projectManager, this.visionAnalyzer);
222
+ // Initialize slash commands system with all dependencies including vision analyzer and todo manager
223
+ this.slashCommands = new SlashCommandsEngine(this.contextEngine, this.projectManager, this.visionAnalyzer, this.todoManager);
183
224
 
184
225
  // Initialize natural language processor with access to all systems
185
226
  this.nlProcessor = new NaturalLanguageProcessor(this);
186
227
 
187
228
  // Set up system integrations
188
- await this.setupSystemIntegrations();
229
+ try {
230
+ await this.setupSystemIntegrations();
231
+ } catch (integrationError) {
232
+ console.log(chalk.yellow(`⚠️ System integrations setup failed: ${integrationError.message}`));
233
+ }
189
234
 
190
235
  // Enable auto model switching based on context
191
236
  this.enableIntelligentModelSwitching();
@@ -204,7 +249,7 @@ class InteractiveRecoderChat {
204
249
  async setupSystemIntegrations() {
205
250
  try {
206
251
  // Connect rules engine to context for AI prompts
207
- if (this.rulesEngine && this.contextEngine) {
252
+ if (this.rulesEngine && this.contextEngine && typeof this.contextEngine.addContextProvider === 'function') {
208
253
  this.contextEngine.addContextProvider('rules', () => {
209
254
  return this.rulesEngine.generateAIPromptContext();
210
255
  });
@@ -469,27 +514,44 @@ class InteractiveRecoderChat {
469
514
  }
470
515
 
471
516
  initializeFileWatcher() {
472
- if (!this.fileWatchEnabled) return;
473
-
474
- // Watch current directory and subdirectories, excluding node_modules, .git, etc.
475
- this.fileWatcher = chokidar.watch('.', {
476
- ignored: [
477
- '**/node_modules/**',
478
- '**/.git/**',
479
- '**/logs/**',
480
- '**/sessions/**',
481
- '**/.env',
482
- '**/.recoderrc',
483
- '**/.*'
484
- ],
485
- ignoreInitial: true,
486
- depth: 3
487
- });
517
+ if (!this.fileWatchEnabled || this.fileWatcher) return; // Prevent multiple initializations
518
+
519
+ try {
520
+ // Use FileWatcherManager to prevent EMFILE errors
521
+ this.fileWatcher = FileWatcherManager.instance.createWatcher(
522
+ 'interactive-chat',
523
+ '.',
524
+ {
525
+ ignored: [
526
+ '**/node_modules/**',
527
+ '**/.git/**',
528
+ '**/logs/**',
529
+ '**/sessions/**',
530
+ '**/.env',
531
+ '**/.recoderrc',
532
+ '**/.*'
533
+ ],
534
+ ignoreInitial: true,
535
+ depth: 2 // Reduced depth to prevent too many watchers
536
+ },
537
+ {
538
+ onChange: (filePath) => this.onFileChanged(filePath),
539
+ onAdd: (filePath) => this.onFileAdded(filePath),
540
+ onUnlink: (filePath) => this.onFileDeleted(filePath)
541
+ }
542
+ );
488
543
 
489
- this.fileWatcher
490
- .on('change', (filePath) => this.onFileChanged(filePath))
491
- .on('add', (filePath) => this.onFileAdded(filePath))
492
- .on('unlink', (filePath) => this.onFileDeleted(filePath));
544
+ if (this.fileWatcher) {
545
+ this.fileWatcher
546
+ .on('change', (filePath) => this.onFileChanged(filePath))
547
+ .on('add', (filePath) => this.onFileAdded(filePath))
548
+ .on('unlink', (filePath) => this.onFileDeleted(filePath));
549
+ }
550
+ } catch (error) {
551
+ // Silently fail file watcher initialization to prevent crashes
552
+ this.logger?.warn('File watcher initialization failed, continuing without file watching');
553
+ this.fileWatchEnabled = false;
554
+ }
493
555
  }
494
556
 
495
557
  onFileChanged(filePath) {
@@ -1182,32 +1244,100 @@ class InteractiveRecoderChat {
1182
1244
  displayWelcome() {
1183
1245
  console.clear();
1184
1246
 
1185
- // Beautiful welcome screen with neon purple/white/gray theme
1186
- console.log('');
1187
- console.log(chalk.magenta('╭─────────────────────────────────────────────────────────────╮'));
1188
- console.log(chalk.magenta('│') + chalk.white.bold(' ✨ Welcome to Recoder Code ') + chalk.magenta('│'));
1189
- console.log(chalk.magenta('╰─────────────────────────────────────────────────────────────╯'));
1247
+ // Enhanced welcome screen with gradient effects and animations
1190
1248
  console.log('');
1191
1249
 
1192
- // Stylized ASCII art in neon purple
1193
- console.log(chalk.magenta.bold('██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗'));
1194
- console.log(chalk.magenta.bold('██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗'));
1195
- console.log(chalk.magenta.bold('██████╔╝█████╗ ██║ ██║ ██║██║ ██║█████╗ ██████╔╝'));
1196
- console.log(chalk.white('██╔══██╗██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗'));
1197
- console.log(chalk.white('██║ ██║███████╗╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║'));
1198
- console.log(chalk.gray('╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'));
1250
+ // Animated gradient border
1251
+ this.displayAnimatedBorder();
1252
+
1253
+ // Beautiful gradient ASCII art
1254
+ console.log('');
1255
+ this.displayGradientLogo();
1199
1256
  console.log('');
1200
1257
 
1201
- // Status line
1202
- console.log(chalk.gray('Press Enter to continue'));
1258
+ // Dynamic status information
1259
+ this.displayDynamicStatus();
1203
1260
  console.log('');
1204
1261
 
1205
- // Add bottom status hints like Claude Code
1206
- this.showStatusHints();
1262
+ // Enhanced status hints with themes
1263
+ this.showEnhancedStatusHints();
1207
1264
 
1208
1265
  this.rl.prompt();
1209
1266
  }
1210
1267
 
1268
+ displayAnimatedBorder() {
1269
+ const colors = ['magenta', 'cyan', 'blue', 'magenta'];
1270
+ const border = '╭─────────────────────────────────────────────────────────────╮';
1271
+ const title = '│ ✨ Welcome to Recoder Code - AI Terminal │';
1272
+ const bottom = '╰─────────────────────────────────────────────────────────────╯';
1273
+
1274
+ console.log(chalk[colors[0]](border));
1275
+ console.log(chalk[colors[1]](title));
1276
+ console.log(chalk[colors[2]](bottom));
1277
+ }
1278
+
1279
+ displayGradientLogo() {
1280
+ // Beautiful gradient ASCII art with purple to cyan transition
1281
+ const lines = [
1282
+ '██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗',
1283
+ '██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗',
1284
+ '██████╔╝█████╗ ██║ ██║ ██║██║ ██║█████╗ ██████╔╝',
1285
+ '██╔══██╗██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗',
1286
+ '██║ ██║███████╗╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║',
1287
+ '╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝'
1288
+ ];
1289
+
1290
+ const gradientColors = ['magenta', 'magenta', 'cyan', 'blue', 'blue', 'gray'];
1291
+
1292
+ lines.forEach((line, index) => {
1293
+ console.log(chalk[gradientColors[index]].bold(line));
1294
+ });
1295
+ }
1296
+
1297
+ displayDynamicStatus() {
1298
+ const currentTime = new Date().toLocaleTimeString();
1299
+ const projectContext = this.getCurrentProjectContext();
1300
+
1301
+ console.log(chalk.gray('┌─ Session Info ─────────────────────────────────────────────┐'));
1302
+ console.log(chalk.gray('│') + chalk.white(` 🕐 Started: ${currentTime}`) +
1303
+ chalk.gray(' │'));
1304
+ console.log(chalk.gray('│') + chalk.cyan(` 📁 Project: ${projectContext.name || 'recoder-code'}`) +
1305
+ chalk.gray(' │'));
1306
+ console.log(chalk.gray('│') + chalk.green(` 🤖 Model: ${this.model || 'claude-sonnet-4'}`) +
1307
+ chalk.gray(' │'));
1308
+ console.log(chalk.gray('└────────────────────────────────────────────────────────────┘'));
1309
+ }
1310
+
1311
+ getCurrentProjectContext() {
1312
+ try {
1313
+ const packageJson = require(process.cwd() + '/package.json');
1314
+ return {
1315
+ name: packageJson.name || 'Unknown Project',
1316
+ version: packageJson.version || '1.0.0'
1317
+ };
1318
+ } catch (error) {
1319
+ return { name: 'recoder-code', version: '2.0.0' };
1320
+ }
1321
+ }
1322
+
1323
+ showEnhancedStatusHints() {
1324
+ console.log(chalk.gray('┌─ Quick Commands ───────────────────────────────────────────┐'));
1325
+ console.log(chalk.gray('│') + chalk.yellow(' ! ') + chalk.white('bash mode') +
1326
+ chalk.gray(' • ') + chalk.yellow('/ ') + chalk.white('commands') +
1327
+ chalk.gray(' • ') + chalk.yellow('tab ') + chalk.white('autocomplete') +
1328
+ chalk.gray(' ') + chalk.red('ESC ') + chalk.white('exit') +
1329
+ chalk.gray(' │'));
1330
+ console.log(chalk.gray('└────────────────────────────────────────────────────────────┘'));
1331
+
1332
+ console.log(chalk.gray('┌─ Features ─────────────────────────────────────────────────┐'));
1333
+ console.log(chalk.gray('│') + chalk.magenta(' 📁 ') + chalk.white(this.getCurrentProjectContext().name) +
1334
+ chalk.gray(' • ') + chalk.green('✨ ') + chalk.white('AI Ready') +
1335
+ chalk.gray(' • ') + chalk.cyan('Ctrl+S ') + chalk.white('save') +
1336
+ chalk.gray(' • ') + chalk.blue('Ctrl+H ') + chalk.white('help') +
1337
+ chalk.gray(' │'));
1338
+ console.log(chalk.gray('└────────────────────────────────────────────────────────────┘'));
1339
+ }
1340
+
1211
1341
  showError(error) {
1212
1342
  // Beautiful error display like Claude Code
1213
1343
  console.log(chalk.red('╭─────────────────────────────────────────╮'));
@@ -1324,6 +1454,24 @@ class InteractiveRecoderChat {
1324
1454
  case 'save':
1325
1455
  this.saveCurrentSession();
1326
1456
  break;
1457
+ case 'analyze':
1458
+ this.performCodeAnalysis();
1459
+ break;
1460
+ case 'git':
1461
+ this.showGitStatus();
1462
+ break;
1463
+ case 'review':
1464
+ this.performCodeReview();
1465
+ break;
1466
+ case 'optimize':
1467
+ this.performOptimizationAnalysis();
1468
+ break;
1469
+ case 'security':
1470
+ this.performSecurityAnalysis();
1471
+ break;
1472
+ case 'theme':
1473
+ this.cycleTheme();
1474
+ break;
1327
1475
  default:
1328
1476
  console.log(chalk.red(`Unknown command: ${input}`));
1329
1477
  console.log(chalk.gray('Type /help for available commands'));
@@ -1335,17 +1483,37 @@ class InteractiveRecoderChat {
1335
1483
  showHelp() {
1336
1484
  console.log('');
1337
1485
  console.log(chalk.magenta('╭─────────────────────────────────────────╮'));
1338
- console.log(chalk.magenta('│') + chalk.white.bold(' Available Commands ') + chalk.magenta('│'));
1486
+ console.log(chalk.magenta('│') + chalk.white.bold(' 🚀 Available Commands ') + chalk.magenta('│'));
1339
1487
  console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
1340
1488
  console.log('');
1341
- console.log(chalk.gray('/help ') + chalk.white('Show this help message'));
1342
- console.log(chalk.gray('/clear ') + chalk.white('Clear the screen'));
1343
- console.log(chalk.gray('/status ') + chalk.white('Show system status'));
1344
- console.log(chalk.gray('/history ') + chalk.white('Show conversation history'));
1345
- console.log(chalk.gray('/session ') + chalk.white('Show current session info'));
1346
- console.log(chalk.gray('/watch ') + chalk.white('Show watched files'));
1347
- console.log(chalk.gray('/save ') + chalk.white('Save current session'));
1348
- console.log(chalk.gray('/exit ') + chalk.white('Exit Recoder Code'));
1489
+
1490
+ console.log(chalk.cyan('📋 Basic Commands:'));
1491
+ console.log(chalk.gray(' /help ') + chalk.white('Show this help message'));
1492
+ console.log(chalk.gray(' /clear ') + chalk.white('Clear the screen'));
1493
+ console.log(chalk.gray(' /status ') + chalk.white('Show system status'));
1494
+ console.log(chalk.gray(' /exit ') + chalk.white('Exit the terminal'));
1495
+ console.log('');
1496
+
1497
+ console.log(chalk.green('🔍 Analysis Commands:'));
1498
+ console.log(chalk.gray(' /analyze ') + chalk.white('Perform intelligent code analysis'));
1499
+ console.log(chalk.gray(' /review ') + chalk.white('AI-powered code review'));
1500
+ console.log(chalk.gray(' /security') + chalk.white('Security vulnerability analysis'));
1501
+ console.log(chalk.gray(' /optimize') + chalk.white('Performance optimization suggestions'));
1502
+ console.log('');
1503
+
1504
+ console.log(chalk.blue('🌿 Git Commands:'));
1505
+ console.log(chalk.gray(' /git ') + chalk.white('Show git repository status'));
1506
+ console.log('');
1507
+
1508
+ console.log(chalk.magenta('🎨 Customization:'));
1509
+ console.log(chalk.gray(' /theme ') + chalk.white('Cycle through visual themes'));
1510
+ console.log('');
1511
+
1512
+ console.log(chalk.yellow('💾 Session Management:'));
1513
+ console.log(chalk.gray(' /history ') + chalk.white('Show conversation history'));
1514
+ console.log(chalk.gray(' /session ') + chalk.white('Show current session info'));
1515
+ console.log(chalk.gray(' /save ') + chalk.white('Save current session'));
1516
+ console.log(chalk.gray(' /watch ') + chalk.white('Show watched files'));
1349
1517
  console.log('');
1350
1518
  }
1351
1519
 
@@ -4092,42 +4260,1316 @@ ${projectInfo}`
4092
4260
  }
4093
4261
  }
4094
4262
 
4095
- async cleanup() {
4096
- this.logger.info('Starting cleanup process');
4263
+ setupGlobalErrorHandlers() {
4264
+ // Register domain-specific handlers with unified error handler
4265
+ errorHandler.registerHandler('interactive', (error) => {
4266
+ if (this.logger) {
4267
+ this.logger.error('Interactive mode error', {
4268
+ error: error?.toString(),
4269
+ stack: error?.stack
4270
+ });
4271
+ }
4272
+
4273
+ // In debug mode, show detailed error for interactive context
4274
+ if (process.env.RECODER_DEBUG === 'true') {
4275
+ console.log(chalk.blue('\n🔍 Interactive Context Error:'));
4276
+ console.log(chalk.gray(error?.toString()));
4277
+ if (error?.stack) {
4278
+ console.log(chalk.gray(error.stack.split('\n').slice(0, 5).join('\n')));
4279
+ }
4280
+ }
4281
+ });
4282
+
4283
+ // Register MCP error handler for graceful degradation
4284
+ errorHandler.registerHandler('mcp', (error) => {
4285
+ // MCP errors are non-critical, just log for debugging
4286
+ if (process.env.RECODER_DEBUG === 'true') {
4287
+ console.log(chalk.gray('🔌 MCP connection issue (non-critical):'), error?.message);
4288
+ }
4289
+ });
4290
+
4291
+ // Handle warnings specifically
4292
+ process.on('warning', (warning) => {
4293
+ if (warning.name === 'PromiseRejectionHandledWarning' ||
4294
+ warning.name === 'UnhandledPromiseRejectionWarning') {
4295
+ if (this.logger) {
4296
+ this.logger.warn('Promise warning', { name: warning.name, message: warning.message });
4297
+ }
4298
+ }
4299
+ });
4300
+ }
4301
+
4302
+ // ========== INTELLIGENT FEATURES ==========
4303
+
4304
+ performCodeAnalysis() {
4305
+ console.log(chalk.cyan('🔍 Analyzing Codebase...'));
4306
+ console.log('');
4097
4307
 
4098
- // Clean up streaming and loading animations
4099
- this.stopProgressiveLoading();
4100
- this.stopStreamingDisplay();
4308
+ const analysis = this.analyzeCurrentProject();
4101
4309
 
4102
- if (this.fileWatcher) {
4103
- this.fileWatcher.close();
4104
- this.fileWatcher = null;
4105
- this.logger.debug('File watcher closed');
4310
+ console.log(chalk.magenta('╭─────────────────────────────────────────╮'));
4311
+ console.log(chalk.magenta('│') + chalk.white.bold(' 📊 Code Analysis Results ') + chalk.magenta('│'));
4312
+ console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
4313
+ console.log('');
4314
+
4315
+ console.log(chalk.cyan('📁 Project Structure:'));
4316
+ console.log(chalk.white(` • Files: ${analysis.fileCount}`));
4317
+ console.log(chalk.white(` • Languages: ${analysis.languages.join(', ')}`));
4318
+ console.log(chalk.white(` • Main Language: ${analysis.mainLanguage}`));
4319
+ console.log('');
4320
+
4321
+ console.log(chalk.green('✅ Strengths:'));
4322
+ analysis.strengths.forEach(strength => {
4323
+ console.log(chalk.white(` • ${strength}`));
4324
+ });
4325
+ console.log('');
4326
+
4327
+ console.log(chalk.yellow('💡 Suggestions:'));
4328
+ analysis.suggestions.forEach(suggestion => {
4329
+ console.log(chalk.white(` • ${suggestion}`));
4330
+ });
4331
+ console.log('');
4332
+ }
4333
+
4334
+ analyzeCurrentProject() {
4335
+ const fs = require('fs');
4336
+ const path = require('path');
4337
+
4338
+ try {
4339
+ const analysis = {
4340
+ fileCount: 0,
4341
+ languages: new Set(),
4342
+ fileTypes: {},
4343
+ dependencies: [],
4344
+ devDependencies: [],
4345
+ strengths: [],
4346
+ issues: [],
4347
+ suggestions: []
4348
+ };
4349
+
4350
+ // Scan actual files in project
4351
+ const scanDirectory = (dir, depth = 0) => {
4352
+ if (depth > 3) return; // Limit depth
4353
+
4354
+ try {
4355
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
4356
+
4357
+ for (const entry of entries) {
4358
+ const fullPath = path.join(dir, entry.name);
4359
+
4360
+ // Skip node_modules, .git, etc.
4361
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
4362
+
4363
+ if (entry.isFile()) {
4364
+ analysis.fileCount++;
4365
+ const ext = path.extname(entry.name).toLowerCase();
4366
+
4367
+ // Count file types
4368
+ analysis.fileTypes[ext] = (analysis.fileTypes[ext] || 0) + 1;
4369
+
4370
+ // Detect languages
4371
+ const languageMap = {
4372
+ '.js': 'JavaScript',
4373
+ '.ts': 'TypeScript',
4374
+ '.py': 'Python',
4375
+ '.java': 'Java',
4376
+ '.cpp': 'C++',
4377
+ '.c': 'C',
4378
+ '.cs': 'C#',
4379
+ '.go': 'Go',
4380
+ '.rs': 'Rust',
4381
+ '.php': 'PHP',
4382
+ '.rb': 'Ruby',
4383
+ '.json': 'JSON',
4384
+ '.md': 'Markdown',
4385
+ '.html': 'HTML',
4386
+ '.css': 'CSS',
4387
+ '.scss': 'SCSS',
4388
+ '.yaml': 'YAML',
4389
+ '.yml': 'YAML'
4390
+ };
4391
+
4392
+ if (languageMap[ext]) {
4393
+ analysis.languages.add(languageMap[ext]);
4394
+ }
4395
+ } else if (entry.isDirectory()) {
4396
+ scanDirectory(fullPath, depth + 1);
4397
+ }
4398
+ }
4399
+ } catch (error) {
4400
+ // Skip directories we can't read
4401
+ }
4402
+ };
4403
+
4404
+ // Scan from current directory
4405
+ scanDirectory(process.cwd());
4406
+
4407
+ // Analyze package.json if it exists
4408
+ try {
4409
+ const packagePath = path.join(process.cwd(), 'package.json');
4410
+ if (fs.existsSync(packagePath)) {
4411
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
4412
+ analysis.dependencies = Object.keys(packageJson.dependencies || {});
4413
+ analysis.devDependencies = Object.keys(packageJson.devDependencies || {});
4414
+
4415
+ // Analyze dependencies for insights
4416
+ if (analysis.dependencies.includes('express')) analysis.strengths.push('Express.js web framework detected');
4417
+ if (analysis.dependencies.includes('react')) analysis.strengths.push('React frontend framework detected');
4418
+ if (analysis.dependencies.includes('chalk')) analysis.strengths.push('Terminal styling with chalk');
4419
+ if (analysis.devDependencies.includes('jest')) analysis.strengths.push('Jest testing framework configured');
4420
+ if (analysis.devDependencies.includes('eslint')) analysis.strengths.push('ESLint code linting configured');
4421
+ }
4422
+ } catch (error) {
4423
+ analysis.issues.push('Could not read package.json');
4424
+ }
4425
+
4426
+ // Generate insights based on actual analysis
4427
+ const languageArray = Array.from(analysis.languages);
4428
+ const mainLanguage = this.determineMainLanguage(analysis.fileTypes);
4429
+
4430
+ if (analysis.fileCount === 0) {
4431
+ analysis.issues.push('No files found in project');
4432
+ } else if (analysis.fileCount > 1000) {
4433
+ analysis.issues.push('Large project detected - consider optimization');
4434
+ }
4435
+
4436
+ if (!languageArray.includes('TypeScript') && languageArray.includes('JavaScript')) {
4437
+ analysis.suggestions.push('Consider migrating to TypeScript for better type safety');
4438
+ }
4439
+
4440
+ if (!analysis.fileTypes['.md']) {
4441
+ analysis.suggestions.push('Add README.md and documentation');
4442
+ }
4443
+
4444
+ if (analysis.dependencies.length === 0) {
4445
+ analysis.suggestions.push('Consider using npm/yarn for dependency management');
4446
+ }
4447
+
4448
+ if (!analysis.devDependencies.includes('jest') && !analysis.devDependencies.includes('mocha')) {
4449
+ analysis.suggestions.push('Add testing framework (Jest/Mocha)');
4450
+ }
4451
+
4452
+ return {
4453
+ fileCount: analysis.fileCount,
4454
+ languages: languageArray,
4455
+ mainLanguage: mainLanguage,
4456
+ fileTypes: analysis.fileTypes,
4457
+ dependencies: analysis.dependencies,
4458
+ devDependencies: analysis.devDependencies,
4459
+ strengths: analysis.strengths.length > 0 ? analysis.strengths : ['Project structure analyzed'],
4460
+ issues: analysis.issues,
4461
+ suggestions: analysis.suggestions.length > 0 ? analysis.suggestions : ['Project appears well-structured']
4462
+ };
4463
+
4464
+ } catch (error) {
4465
+ return {
4466
+ fileCount: 0,
4467
+ languages: ['Unknown'],
4468
+ mainLanguage: 'Unknown',
4469
+ fileTypes: {},
4470
+ dependencies: [],
4471
+ devDependencies: [],
4472
+ strengths: ['Basic analysis attempted'],
4473
+ issues: [`Analysis error: ${error.message}`],
4474
+ suggestions: ['Ensure proper file permissions']
4475
+ };
4106
4476
  }
4477
+ }
4478
+
4479
+ determineMainLanguage(fileTypes) {
4480
+ let maxCount = 0;
4481
+ let mainExt = '';
4107
4482
 
4108
- // Cleanup voice manager
4109
- if (this.voiceManager) {
4110
- this.voiceManager.cleanup();
4111
- this.logger.debug('Voice manager cleaned up');
4483
+ for (const [ext, count] of Object.entries(fileTypes)) {
4484
+ if (count > maxCount && ext !== '.md' && ext !== '.json') {
4485
+ maxCount = count;
4486
+ mainExt = ext;
4487
+ }
4112
4488
  }
4113
4489
 
4114
- // Cleanup collaboration manager
4115
- if (this.collaborationManager) {
4116
- this.collaborationManager.cleanup();
4117
- this.logger.debug('Collaboration manager cleaned up');
4490
+ const languageMap = {
4491
+ '.js': 'JavaScript',
4492
+ '.ts': 'TypeScript',
4493
+ '.py': 'Python',
4494
+ '.java': 'Java',
4495
+ '.cpp': 'C++',
4496
+ '.go': 'Go',
4497
+ '.rs': 'Rust'
4498
+ };
4499
+
4500
+ return languageMap[mainExt] || 'Mixed';
4501
+ }
4502
+
4503
+ showGitStatus() {
4504
+ console.log(chalk.cyan('📊 Git Repository Status'));
4505
+ console.log('');
4506
+
4507
+ const { execSync } = require('child_process');
4508
+
4509
+ try {
4510
+ // Check if git is available
4511
+ execSync('git --version', { stdio: 'ignore' });
4512
+
4513
+ // Check if we're in a git repository
4514
+ execSync('git rev-parse --git-dir', { stdio: 'ignore' });
4515
+
4516
+ console.log(chalk.magenta('╭─────────────────────────────────────────╮'));
4517
+ console.log(chalk.magenta('│') + chalk.white.bold(' 🌿 Git Repository Analysis ') + chalk.magenta('│'));
4518
+ console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
4519
+ console.log('');
4520
+
4521
+ // Get comprehensive git information
4522
+ const gitInfo = this.getGitInformation();
4523
+
4524
+ // Display branch information
4525
+ console.log(chalk.green(`🌿 Current Branch: ${gitInfo.currentBranch}`));
4526
+ if (gitInfo.upstreamBranch) {
4527
+ console.log(chalk.blue(`🔗 Upstream: ${gitInfo.upstreamBranch}`));
4528
+ }
4529
+
4530
+ // Show commits ahead/behind
4531
+ if (gitInfo.aheadBehind.ahead > 0 || gitInfo.aheadBehind.behind > 0) {
4532
+ console.log(chalk.yellow(`📊 Sync Status: ${gitInfo.aheadBehind.ahead} ahead, ${gitInfo.aheadBehind.behind} behind`));
4533
+ }
4534
+ console.log('');
4535
+
4536
+ // Show working directory status
4537
+ if (gitInfo.statusFiles.length > 0) {
4538
+ console.log(chalk.yellow('📝 Working Directory Changes:'));
4539
+
4540
+ const statusCounts = { modified: 0, added: 0, deleted: 0, untracked: 0 };
4541
+
4542
+ gitInfo.statusFiles.forEach(file => {
4543
+ let statusIcon = '❓';
4544
+ let statusColor = 'white';
4545
+
4546
+ if (file.status.includes('M')) {
4547
+ statusIcon = '📝';
4548
+ statusColor = 'yellow';
4549
+ statusCounts.modified++;
4550
+ } else if (file.status.includes('A')) {
4551
+ statusIcon = '➕';
4552
+ statusColor = 'green';
4553
+ statusCounts.added++;
4554
+ } else if (file.status.includes('D')) {
4555
+ statusIcon = '🗑️';
4556
+ statusColor = 'red';
4557
+ statusCounts.deleted++;
4558
+ } else if (file.status.includes('??')) {
4559
+ statusIcon = '❔';
4560
+ statusColor = 'gray';
4561
+ statusCounts.untracked++;
4562
+ }
4563
+
4564
+ console.log(chalk[statusColor](` ${statusIcon} ${file.file}`));
4565
+ });
4566
+
4567
+ console.log('');
4568
+ console.log(chalk.cyan('📊 Summary:'));
4569
+ if (statusCounts.modified > 0) console.log(chalk.yellow(` 📝 ${statusCounts.modified} modified`));
4570
+ if (statusCounts.added > 0) console.log(chalk.green(` ➕ ${statusCounts.added} added`));
4571
+ if (statusCounts.deleted > 0) console.log(chalk.red(` 🗑️ ${statusCounts.deleted} deleted`));
4572
+ if (statusCounts.untracked > 0) console.log(chalk.gray(` ❔ ${statusCounts.untracked} untracked`));
4573
+
4574
+ } else {
4575
+ console.log(chalk.green('✅ Working directory clean'));
4576
+ }
4577
+
4578
+ console.log('');
4579
+
4580
+ // Show recent commits with more detail
4581
+ console.log(chalk.blue('📚 Recent Commits:'));
4582
+ gitInfo.recentCommits.forEach((commit, index) => {
4583
+ const timeAgo = this.getTimeAgo(commit.date);
4584
+ console.log(chalk.gray(` ${index + 1}. ${commit.hash} ${commit.message}`));
4585
+ console.log(chalk.gray(` by ${commit.author} ${timeAgo}`));
4586
+ });
4587
+
4588
+ console.log('');
4589
+
4590
+ // Show repository statistics
4591
+ console.log(chalk.cyan('📈 Repository Stats:'));
4592
+ console.log(chalk.white(` 🏷️ Total Tags: ${gitInfo.stats.totalTags}`));
4593
+ console.log(chalk.white(` 🌿 Total Branches: ${gitInfo.stats.totalBranches}`));
4594
+ console.log(chalk.white(` 📝 Total Commits: ${gitInfo.stats.totalCommits}`));
4595
+ console.log(chalk.white(` 👥 Contributors: ${gitInfo.stats.contributors}`));
4596
+
4597
+ } catch (error) {
4598
+ if (error.message.includes('not a git repository')) {
4599
+ console.log(chalk.red('❌ Not a git repository'));
4600
+ console.log(chalk.gray('Initialize with: git init'));
4601
+ } else if (error.message.includes('git --version')) {
4602
+ console.log(chalk.red('❌ Git not installed or not in PATH'));
4603
+ } else {
4604
+ console.log(chalk.red(`❌ Git error: ${error.message}`));
4605
+ }
4118
4606
  }
4607
+ console.log('');
4608
+ }
4609
+
4610
+ getGitInformation() {
4611
+ const { execSync } = require('child_process');
4119
4612
 
4120
- // Cleanup plugins
4121
- if (this.pluginManager) {
4122
- await this.pluginManager.cleanup();
4123
- this.logger.debug('Plugins cleaned up');
4613
+ try {
4614
+ // Get current branch
4615
+ const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();
4616
+
4617
+ // Get upstream branch
4618
+ let upstreamBranch = null;
4619
+ try {
4620
+ upstreamBranch = execSync('git rev-parse --abbrev-ref @{upstream}', { encoding: 'utf8' }).trim();
4621
+ } catch (e) {
4622
+ // No upstream branch
4623
+ }
4624
+
4625
+ // Get ahead/behind count
4626
+ let aheadBehind = { ahead: 0, behind: 0 };
4627
+ if (upstreamBranch) {
4628
+ try {
4629
+ const aheadBehindOutput = execSync(`git rev-list --count --left-right ${upstreamBranch}...HEAD`, { encoding: 'utf8' }).trim();
4630
+ const [behind, ahead] = aheadBehindOutput.split('\t').map(Number);
4631
+ aheadBehind = { ahead, behind };
4632
+ } catch (e) {
4633
+ // Can't determine ahead/behind
4634
+ }
4635
+ }
4636
+
4637
+ // Get status files
4638
+ const statusOutput = execSync('git status --porcelain', { encoding: 'utf8' });
4639
+ const statusFiles = statusOutput.split('\n')
4640
+ .filter(line => line.trim())
4641
+ .map(line => ({
4642
+ status: line.substring(0, 2),
4643
+ file: line.substring(3)
4644
+ }));
4645
+
4646
+ // Get recent commits with detailed info
4647
+ const commitOutput = execSync('git log --oneline --format="%H|%s|%an|%ad" --date=iso -10', { encoding: 'utf8' });
4648
+ const recentCommits = commitOutput.split('\n')
4649
+ .filter(line => line.trim())
4650
+ .map(line => {
4651
+ const [hash, message, author, date] = line.split('|');
4652
+ return {
4653
+ hash: hash.substring(0, 8),
4654
+ message,
4655
+ author,
4656
+ date: new Date(date)
4657
+ };
4658
+ });
4659
+
4660
+ // Get repository statistics
4661
+ const totalTags = execSync('git tag --list | wc -l', { encoding: 'utf8' }).trim();
4662
+ const totalBranches = execSync('git branch -a | wc -l', { encoding: 'utf8' }).trim();
4663
+ const totalCommits = execSync('git rev-list --count HEAD', { encoding: 'utf8' }).trim();
4664
+ const contributors = execSync('git shortlog -sn | wc -l', { encoding: 'utf8' }).trim();
4665
+
4666
+ return {
4667
+ currentBranch,
4668
+ upstreamBranch,
4669
+ aheadBehind,
4670
+ statusFiles,
4671
+ recentCommits,
4672
+ stats: {
4673
+ totalTags: parseInt(totalTags) || 0,
4674
+ totalBranches: parseInt(totalBranches) || 0,
4675
+ totalCommits: parseInt(totalCommits) || 0,
4676
+ contributors: parseInt(contributors) || 0
4677
+ }
4678
+ };
4679
+
4680
+ } catch (error) {
4681
+ throw error;
4682
+ }
4683
+ }
4684
+
4685
+ getTimeAgo(date) {
4686
+ const now = new Date();
4687
+ const diffMs = now - date;
4688
+ const diffMins = Math.floor(diffMs / 60000);
4689
+ const diffHours = Math.floor(diffMs / 3600000);
4690
+ const diffDays = Math.floor(diffMs / 86400000);
4691
+
4692
+ if (diffMins < 60) return `${diffMins} minutes ago`;
4693
+ if (diffHours < 24) return `${diffHours} hours ago`;
4694
+ if (diffDays < 30) return `${diffDays} days ago`;
4695
+ return date.toLocaleDateString();
4696
+ }
4697
+
4698
+ performCodeReview() {
4699
+ console.log(chalk.cyan('🔍 Performing AI Code Review...'));
4700
+ console.log('');
4701
+
4702
+ console.log(chalk.magenta('╭─────────────────────────────────────────╮'));
4703
+ console.log(chalk.magenta('│') + chalk.white.bold(' 🤖 AI Code Review ') + chalk.magenta('│'));
4704
+ console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
4705
+ console.log('');
4706
+
4707
+ const review = this.generateRealCodeReview();
4708
+
4709
+ // Display scores with color coding
4710
+ const getScoreColor = (score) => {
4711
+ if (score >= 90) return 'green';
4712
+ if (score >= 75) return 'yellow';
4713
+ return 'red';
4714
+ };
4715
+
4716
+ console.log(chalk[getScoreColor(review.scores.quality)](`✅ Code Quality: ${review.scores.quality}/100`));
4717
+ console.log(chalk[getScoreColor(review.scores.maintainability)](`📊 Maintainability: ${review.scores.maintainability}/100`));
4718
+ console.log(chalk[getScoreColor(review.scores.security)](`🛡️ Security: ${review.scores.security}/100`));
4719
+ console.log(chalk[getScoreColor(review.scores.testCoverage)](`🧪 Test Coverage: ${review.scores.testCoverage}/100`));
4720
+ console.log('');
4721
+
4722
+ // Display architecture analysis
4723
+ if (review.architecture.length > 0) {
4724
+ console.log(chalk.blue('🏗️ Architecture Analysis:'));
4725
+ review.architecture.forEach(item => {
4726
+ console.log(chalk.white(` • ${item.type}: ${item.description}`));
4727
+ if (item.file) {
4728
+ console.log(chalk.gray(` File: ${item.file}`));
4729
+ }
4730
+ });
4731
+ console.log('');
4124
4732
  }
4125
4733
 
4126
- // End session logging
4127
- if (this.logger) {
4128
- this.logger.endSession();
4129
- this.logger.info('Session cleanup completed');
4734
+ // Display code quality issues
4735
+ if (review.qualityIssues.length > 0) {
4736
+ console.log(chalk.yellow('⚠️ Code Quality Issues:'));
4737
+ review.qualityIssues.forEach(issue => {
4738
+ console.log(chalk.white(` • ${issue.type}: ${issue.description}`));
4739
+ console.log(chalk.gray(` File: ${issue.file}:${issue.line}`));
4740
+ });
4741
+ console.log('');
4742
+ }
4743
+
4744
+ // Display maintainability metrics
4745
+ if (review.maintainabilityMetrics.length > 0) {
4746
+ console.log(chalk.cyan('📈 Maintainability Metrics:'));
4747
+ review.maintainabilityMetrics.forEach(metric => {
4748
+ console.log(chalk.white(` • ${metric.metric}: ${metric.value} (${metric.assessment})`));
4749
+ if (metric.suggestion) {
4750
+ console.log(chalk.gray(` Suggestion: ${metric.suggestion}`));
4751
+ }
4752
+ });
4753
+ console.log('');
4130
4754
  }
4755
+
4756
+ // Display AI recommendations
4757
+ if (review.recommendations.length > 0) {
4758
+ console.log(chalk.cyan('💡 AI-Powered Recommendations:'));
4759
+ review.recommendations.forEach(rec => {
4760
+ console.log(chalk.white(` • ${rec.category}: ${rec.suggestion}`));
4761
+ if (rec.priority) {
4762
+ console.log(chalk.gray(` Priority: ${rec.priority}`));
4763
+ }
4764
+ });
4765
+ console.log('');
4766
+ }
4767
+
4768
+ // Display overall assessment
4769
+ const overallScore = Math.round((review.scores.quality + review.scores.maintainability + review.scores.security + review.scores.testCoverage) / 4);
4770
+ console.log(chalk[getScoreColor(overallScore)](`🎯 Overall Code Health: ${overallScore}/100`));
4771
+ }
4772
+
4773
+ generateRealCodeReview() {
4774
+ const fs = require('fs');
4775
+ const path = require('path');
4776
+
4777
+ const review = {
4778
+ scores: {
4779
+ quality: 100,
4780
+ maintainability: 100,
4781
+ security: 100,
4782
+ testCoverage: 50
4783
+ },
4784
+ architecture: [],
4785
+ qualityIssues: [],
4786
+ maintainabilityMetrics: [],
4787
+ recommendations: []
4788
+ };
4789
+
4790
+ // Code quality patterns to analyze
4791
+ const qualityPatterns = [
4792
+ { pattern: /function\s+\w+\s*\([^)]*\)\s*\{[\s\S]{500,}?\}/, type: 'Long Function', description: 'Function exceeds recommended length' },
4793
+ { pattern: /if\s*\([^)]+\)\s*\{[\s\S]*?if\s*\([^)]+\)\s*\{[\s\S]*?if\s*\([^)]+\)/, type: 'Deep Nesting', description: 'Excessive nesting depth detected' },
4794
+ { pattern: /var\s+\w+/, type: 'Var Usage', description: 'Use const/let instead of var' },
4795
+ { pattern: /==\s*(?!null)/, type: 'Loose Equality', description: 'Use strict equality (===) instead' },
4796
+ { pattern: /console\.log/, type: 'Debug Code', description: 'Remove console.log from production code' },
4797
+ { pattern: /\.catch\s*\(\s*\(\s*\)\s*=>\s*\{\s*\}\s*\)/, type: 'Empty Catch', description: 'Empty catch block - handle errors properly' }
4798
+ ];
4799
+
4800
+ // Maintainability patterns
4801
+ const maintainabilityPatterns = [
4802
+ { pattern: /\/\*[\s\S]*?\*\/|\/\/.*$/gm, type: 'Comments', description: 'Code documentation' },
4803
+ { pattern: /class\s+\w+/, type: 'Classes', description: 'Object-oriented structure' },
4804
+ { pattern: /export\s+/, type: 'Modules', description: 'Modular architecture' },
4805
+ { pattern: /import\s+.*from/, type: 'Dependencies', description: 'Dependency management' }
4806
+ ];
4807
+
4808
+ // Architecture patterns
4809
+ const architecturePatterns = [
4810
+ { pattern: /class\s+\w+Manager/, type: 'Manager Pattern', description: 'Centralized management logic' },
4811
+ { pattern: /\.on\(|\.emit\(/, type: 'Event-Driven', description: 'Event-driven architecture' },
4812
+ { pattern: /async\s+function|await\s+/, type: 'Async Pattern', description: 'Asynchronous programming patterns' },
4813
+ { pattern: /module\.exports\s*=/, type: 'Module System', description: 'CommonJS module pattern' }
4814
+ ];
4815
+
4816
+ let totalLines = 0;
4817
+ let totalFunctions = 0;
4818
+ let totalClasses = 0;
4819
+ let commentLines = 0;
4820
+ let testFiles = 0;
4821
+
4822
+ // Analyze codebase
4823
+ const analyzeDirectory = (dir, depth = 0) => {
4824
+ if (depth > 3) return;
4825
+
4826
+ try {
4827
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
4828
+
4829
+ for (const entry of entries) {
4830
+ const fullPath = path.join(dir, entry.name);
4831
+
4832
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
4833
+
4834
+ if (entry.isFile() && this.isCodeFile(entry.name)) {
4835
+ this.analyzeCodeFile(fullPath, qualityPatterns, maintainabilityPatterns, architecturePatterns, review);
4836
+
4837
+ // Count metrics
4838
+ const content = fs.readFileSync(fullPath, 'utf8');
4839
+ const lines = content.split('\n');
4840
+ totalLines += lines.length;
4841
+
4842
+ // Count functions and classes
4843
+ totalFunctions += (content.match(/function\s+\w+|=>\s*\{|\w+\s*:\s*function/g) || []).length;
4844
+ totalClasses += (content.match(/class\s+\w+/g) || []).length;
4845
+
4846
+ // Count comments
4847
+ commentLines += (content.match(/\/\*[\s\S]*?\*\/|\/\/.*$/gm) || []).length;
4848
+
4849
+ // Check if it's a test file
4850
+ if (entry.name.includes('test') || entry.name.includes('spec')) {
4851
+ testFiles++;
4852
+ }
4853
+
4854
+ } else if (entry.isDirectory()) {
4855
+ analyzeDirectory(fullPath, depth + 1);
4856
+ }
4857
+ }
4858
+ } catch (error) {
4859
+ // Skip directories we can't read
4860
+ }
4861
+ };
4862
+
4863
+ analyzeDirectory(process.cwd());
4864
+
4865
+ // Calculate scores based on findings
4866
+ const qualityIssueCount = review.qualityIssues.length;
4867
+ review.scores.quality = Math.max(0, 100 - (qualityIssueCount * 5));
4868
+
4869
+ // Maintainability score based on structure and documentation
4870
+ const commentRatio = totalLines > 0 ? (commentLines / totalLines) * 100 : 0;
4871
+ const avgFunctionsPerFile = totalFunctions > 0 ? totalFunctions / (totalLines / 50) : 0;
4872
+
4873
+ review.scores.maintainability = Math.max(0, 100 -
4874
+ (avgFunctionsPerFile > 10 ? 20 : 0) -
4875
+ (commentRatio < 10 ? 15 : 0) -
4876
+ (totalClasses === 0 ? 10 : 0));
4877
+
4878
+ // Test coverage estimation
4879
+ review.scores.testCoverage = Math.min(100, testFiles * 20);
4880
+
4881
+ // Add maintainability metrics
4882
+ review.maintainabilityMetrics.push({
4883
+ metric: 'Comment Ratio',
4884
+ value: `${commentRatio.toFixed(1)}%`,
4885
+ assessment: commentRatio > 15 ? 'Good' : commentRatio > 5 ? 'Fair' : 'Poor',
4886
+ suggestion: commentRatio < 10 ? 'Add more documentation' : null
4887
+ });
4888
+
4889
+ review.maintainabilityMetrics.push({
4890
+ metric: 'Total Lines of Code',
4891
+ value: totalLines.toString(),
4892
+ assessment: totalLines < 5000 ? 'Manageable' : totalLines < 15000 ? 'Large' : 'Very Large'
4893
+ });
4894
+
4895
+ review.maintainabilityMetrics.push({
4896
+ metric: 'Functions Count',
4897
+ value: totalFunctions.toString(),
4898
+ assessment: 'Active'
4899
+ });
4900
+
4901
+ review.maintainabilityMetrics.push({
4902
+ metric: 'Classes Count',
4903
+ value: totalClasses.toString(),
4904
+ assessment: totalClasses > 0 ? 'Object-oriented' : 'Functional'
4905
+ });
4906
+
4907
+ // Generate AI-powered recommendations
4908
+ if (qualityIssueCount > 0) {
4909
+ review.recommendations.push({
4910
+ category: 'Code Quality',
4911
+ suggestion: 'Address code quality issues to improve maintainability',
4912
+ priority: 'High'
4913
+ });
4914
+ }
4915
+
4916
+ if (review.scores.testCoverage < 70) {
4917
+ review.recommendations.push({
4918
+ category: 'Testing',
4919
+ suggestion: 'Increase test coverage with unit and integration tests',
4920
+ priority: 'High'
4921
+ });
4922
+ }
4923
+
4924
+ if (commentRatio < 10) {
4925
+ review.recommendations.push({
4926
+ category: 'Documentation',
4927
+ suggestion: 'Add more inline documentation and comments',
4928
+ priority: 'Medium'
4929
+ });
4930
+ }
4931
+
4932
+ review.recommendations.push({
4933
+ category: 'Architecture',
4934
+ suggestion: 'Consider implementing design patterns for better code organization',
4935
+ priority: 'Medium'
4936
+ });
4937
+
4938
+ review.recommendations.push({
4939
+ category: 'Performance',
4940
+ suggestion: 'Profile critical code paths and optimize bottlenecks',
4941
+ priority: 'Low'
4942
+ });
4943
+
4944
+ review.recommendations.push({
4945
+ category: 'Security',
4946
+ suggestion: 'Implement input validation and security best practices',
4947
+ priority: 'High'
4948
+ });
4949
+
4950
+ return review;
4951
+ }
4952
+
4953
+ analyzeCodeFile(filePath, qualityPatterns, maintainabilityPatterns, architecturePatterns, review) {
4954
+ const fs = require('fs');
4955
+
4956
+ try {
4957
+ const content = fs.readFileSync(filePath, 'utf8');
4958
+ const lines = content.split('\n');
4959
+
4960
+ // Check for quality issues
4961
+ for (const patternInfo of qualityPatterns) {
4962
+ if (patternInfo.pattern.test(content)) {
4963
+ review.qualityIssues.push({
4964
+ type: patternInfo.type,
4965
+ description: patternInfo.description,
4966
+ file: filePath.replace(process.cwd(), '.'),
4967
+ line: this.findPatternLine(lines, patternInfo.pattern)
4968
+ });
4969
+ }
4970
+ }
4971
+
4972
+ // Check architecture patterns
4973
+ for (const patternInfo of architecturePatterns) {
4974
+ if (patternInfo.pattern.test(content)) {
4975
+ review.architecture.push({
4976
+ type: patternInfo.type,
4977
+ description: patternInfo.description,
4978
+ file: filePath.replace(process.cwd(), '.')
4979
+ });
4980
+ }
4981
+ }
4982
+
4983
+ } catch (error) {
4984
+ // Skip files we can't read
4985
+ }
4986
+ }
4987
+
4988
+ findPatternLine(lines, pattern) {
4989
+ for (let i = 0; i < lines.length; i++) {
4990
+ if (pattern.test(lines[i])) {
4991
+ return i + 1;
4992
+ }
4993
+ }
4994
+ return 1;
4995
+ }
4996
+
4997
+ performSecurityAnalysis() {
4998
+ console.log(chalk.cyan('🛡️ Performing Security Analysis...'));
4999
+ console.log('');
5000
+
5001
+ console.log(chalk.magenta('╭─────────────────────────────────────────╮'));
5002
+ console.log(chalk.magenta('│') + chalk.white.bold(' 🛡️ Security Vulnerability Scan ') + chalk.magenta('│'));
5003
+ console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
5004
+ console.log('');
5005
+
5006
+ const securityReport = this.performRealSecurityScan();
5007
+
5008
+ // Display security score
5009
+ let scoreColor = 'green';
5010
+ if (securityReport.score < 70) scoreColor = 'red';
5011
+ else if (securityReport.score < 85) scoreColor = 'yellow';
5012
+
5013
+ console.log(chalk[scoreColor](`🛡️ Security Score: ${securityReport.score}/100`));
5014
+ console.log('');
5015
+
5016
+ // Display vulnerabilities by severity
5017
+ if (securityReport.vulnerabilities.critical.length > 0) {
5018
+ console.log(chalk.red('🚨 Critical Vulnerabilities:'));
5019
+ securityReport.vulnerabilities.critical.forEach(vuln => {
5020
+ console.log(chalk.red(` • ${vuln.type}: ${vuln.description}`));
5021
+ console.log(chalk.gray(` File: ${vuln.file}:${vuln.line}`));
5022
+ });
5023
+ console.log('');
5024
+ }
5025
+
5026
+ if (securityReport.vulnerabilities.high.length > 0) {
5027
+ console.log(chalk.red('⚠️ High Risk Issues:'));
5028
+ securityReport.vulnerabilities.high.forEach(vuln => {
5029
+ console.log(chalk.yellow(` • ${vuln.type}: ${vuln.description}`));
5030
+ console.log(chalk.gray(` File: ${vuln.file}:${vuln.line}`));
5031
+ });
5032
+ console.log('');
5033
+ }
5034
+
5035
+ if (securityReport.vulnerabilities.medium.length > 0) {
5036
+ console.log(chalk.yellow('⚠️ Medium Risk Issues:'));
5037
+ securityReport.vulnerabilities.medium.forEach(vuln => {
5038
+ console.log(chalk.yellow(` • ${vuln.type}: ${vuln.description}`));
5039
+ console.log(chalk.gray(` File: ${vuln.file}:${vuln.line}`));
5040
+ });
5041
+ console.log('');
5042
+ }
5043
+
5044
+ if (securityReport.vulnerabilities.low.length > 0) {
5045
+ console.log(chalk.cyan('ℹ️ Low Risk Issues:'));
5046
+ securityReport.vulnerabilities.low.forEach(vuln => {
5047
+ console.log(chalk.cyan(` • ${vuln.type}: ${vuln.description}`));
5048
+ console.log(chalk.gray(` File: ${vuln.file}:${vuln.line}`));
5049
+ });
5050
+ console.log('');
5051
+ }
5052
+
5053
+ // Show dependency vulnerabilities
5054
+ if (securityReport.dependencyIssues.length > 0) {
5055
+ console.log(chalk.yellow('📦 Dependency Vulnerabilities:'));
5056
+ securityReport.dependencyIssues.forEach(dep => {
5057
+ console.log(chalk.yellow(` • ${dep.name}@${dep.version}: ${dep.issue}`));
5058
+ console.log(chalk.gray(` Severity: ${dep.severity}, Fix: ${dep.fix}`));
5059
+ });
5060
+ console.log('');
5061
+ }
5062
+
5063
+ // Show recommendations
5064
+ if (securityReport.recommendations.length > 0) {
5065
+ console.log(chalk.cyan('💡 Security Recommendations:'));
5066
+ securityReport.recommendations.forEach(rec => {
5067
+ console.log(chalk.white(` • ${rec}`));
5068
+ });
5069
+ console.log('');
5070
+ }
5071
+
5072
+ // Summary
5073
+ const totalIssues = securityReport.vulnerabilities.critical.length +
5074
+ securityReport.vulnerabilities.high.length +
5075
+ securityReport.vulnerabilities.medium.length +
5076
+ securityReport.vulnerabilities.low.length;
5077
+
5078
+ if (totalIssues === 0) {
5079
+ console.log(chalk.green('✅ No security vulnerabilities detected in code scan'));
5080
+ } else {
5081
+ console.log(chalk.yellow(`📊 Total Issues Found: ${totalIssues}`));
5082
+ }
5083
+ }
5084
+
5085
+ performRealSecurityScan() {
5086
+ const fs = require('fs');
5087
+ const path = require('path');
5088
+
5089
+ const securityReport = {
5090
+ score: 100,
5091
+ vulnerabilities: {
5092
+ critical: [],
5093
+ high: [],
5094
+ medium: [],
5095
+ low: []
5096
+ },
5097
+ dependencyIssues: [],
5098
+ recommendations: []
5099
+ };
5100
+
5101
+ // Security patterns to detect
5102
+ const securityPatterns = {
5103
+ critical: [
5104
+ { pattern: /password\s*=\s*['"][^'"]+['"]/, type: 'Hardcoded Password', description: 'Hardcoded password detected' },
5105
+ { pattern: /api[_-]?key\s*=\s*['"][^'"]+['"]/, type: 'Hardcoded API Key', description: 'Hardcoded API key detected' },
5106
+ { pattern: /secret\s*=\s*['"][^'"]+['"]/, type: 'Hardcoded Secret', description: 'Hardcoded secret detected' },
5107
+ { pattern: /eval\s*\(/, type: 'Code Injection', description: 'Use of eval() detected - potential code injection risk' }
5108
+ ],
5109
+ high: [
5110
+ { pattern: /exec\s*\(.*\$/, type: 'Command Injection', description: 'Potential command injection vulnerability' },
5111
+ { pattern: /innerHTML\s*=/, type: 'XSS Risk', description: 'Use of innerHTML - potential XSS vulnerability' },
5112
+ { pattern: /document\.write\s*\(/, type: 'XSS Risk', description: 'Use of document.write - potential XSS vulnerability' },
5113
+ { pattern: /sql\s*=.*\+/, type: 'SQL Injection', description: 'Potential SQL injection vulnerability' }
5114
+ ],
5115
+ medium: [
5116
+ { pattern: /console\.log\s*\(.*password/, type: 'Information Disclosure', description: 'Password logged to console' },
5117
+ { pattern: /console\.log\s*\(.*token/, type: 'Information Disclosure', description: 'Token logged to console' },
5118
+ { pattern: /http:\/\//, type: 'Insecure Protocol', description: 'Use of insecure HTTP protocol' },
5119
+ { pattern: /Math\.random\s*\(\)/, type: 'Weak Cryptography', description: 'Use of Math.random() for security purposes' }
5120
+ ],
5121
+ low: [
5122
+ { pattern: /TODO.*security/, type: 'Security TODO', description: 'Security-related TODO comment' },
5123
+ { pattern: /FIXME.*security/, type: 'Security FIXME', description: 'Security-related FIXME comment' },
5124
+ { pattern: /\.trim\s*\(\)\.length/, type: 'Input Validation', description: 'Consider more robust input validation' }
5125
+ ]
5126
+ };
5127
+
5128
+ // Scan files for security issues
5129
+ const scanDirectory = (dir, depth = 0) => {
5130
+ if (depth > 3) return;
5131
+
5132
+ try {
5133
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
5134
+
5135
+ for (const entry of entries) {
5136
+ const fullPath = path.join(dir, entry.name);
5137
+
5138
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
5139
+
5140
+ if (entry.isFile() && this.isCodeFile(entry.name)) {
5141
+ this.scanFileForSecurity(fullPath, securityPatterns, securityReport);
5142
+ } else if (entry.isDirectory()) {
5143
+ scanDirectory(fullPath, depth + 1);
5144
+ }
5145
+ }
5146
+ } catch (error) {
5147
+ // Skip directories we can't read
5148
+ }
5149
+ };
5150
+
5151
+ scanDirectory(process.cwd());
5152
+
5153
+ // Check dependencies for known vulnerabilities
5154
+ this.checkDependencyVulnerabilities(securityReport);
5155
+
5156
+ // Calculate final score
5157
+ const criticalCount = securityReport.vulnerabilities.critical.length;
5158
+ const highCount = securityReport.vulnerabilities.high.length;
5159
+ const mediumCount = securityReport.vulnerabilities.medium.length;
5160
+ const lowCount = securityReport.vulnerabilities.low.length;
5161
+
5162
+ securityReport.score = Math.max(0, 100 - (criticalCount * 25) - (highCount * 15) - (mediumCount * 10) - (lowCount * 5));
5163
+
5164
+ // Generate recommendations based on findings
5165
+ if (criticalCount > 0) {
5166
+ securityReport.recommendations.push('🚨 Address critical vulnerabilities immediately');
5167
+ }
5168
+ if (highCount > 0) {
5169
+ securityReport.recommendations.push('⚠️ Review and fix high-risk security issues');
5170
+ }
5171
+
5172
+ securityReport.recommendations.push('🔒 Use environment variables for sensitive data');
5173
+ securityReport.recommendations.push('🛡️ Implement input validation and sanitization');
5174
+ securityReport.recommendations.push('📦 Keep dependencies updated regularly');
5175
+ securityReport.recommendations.push('🔍 Consider using a security linter (ESLint security plugin)');
5176
+
5177
+ return securityReport;
5178
+ }
5179
+
5180
+ isCodeFile(filename) {
5181
+ const codeExtensions = ['.js', '.ts', '.py', '.java', '.cpp', '.c', '.cs', '.go', '.rs', '.php', '.rb'];
5182
+ return codeExtensions.some(ext => filename.toLowerCase().endsWith(ext));
5183
+ }
5184
+
5185
+ scanFileForSecurity(filePath, patterns, report) {
5186
+ const fs = require('fs');
5187
+
5188
+ try {
5189
+ const content = fs.readFileSync(filePath, 'utf8');
5190
+ const lines = content.split('\n');
5191
+
5192
+ for (const [severity, patternList] of Object.entries(patterns)) {
5193
+ for (const patternInfo of patternList) {
5194
+ for (let i = 0; i < lines.length; i++) {
5195
+ if (patternInfo.pattern.test(lines[i])) {
5196
+ report.vulnerabilities[severity].push({
5197
+ type: patternInfo.type,
5198
+ description: patternInfo.description,
5199
+ file: filePath.replace(process.cwd(), '.'),
5200
+ line: i + 1,
5201
+ code: lines[i].trim()
5202
+ });
5203
+ }
5204
+ }
5205
+ }
5206
+ }
5207
+ } catch (error) {
5208
+ // Skip files we can't read
5209
+ }
5210
+ }
5211
+
5212
+ checkDependencyVulnerabilities(report) {
5213
+ const fs = require('fs');
5214
+ const path = require('path');
5215
+
5216
+ try {
5217
+ const packagePath = path.join(process.cwd(), 'package.json');
5218
+ if (!fs.existsSync(packagePath)) return;
5219
+
5220
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
5221
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
5222
+
5223
+ // Check for known vulnerable packages (simplified check)
5224
+ const knownVulnerablePackages = {
5225
+ 'lodash': { versions: ['< 4.17.21'], issue: 'Prototype pollution vulnerability', severity: 'High', fix: 'Update to latest version' },
5226
+ 'node-forge': { versions: ['< 1.0.0'], issue: 'RSA PKCS#1 signature verification issue', severity: 'High', fix: 'Update to 1.0.0+' },
5227
+ 'axios': { versions: ['< 0.21.2'], issue: 'Server-side request forgery', severity: 'Medium', fix: 'Update to 0.21.2+' }
5228
+ };
5229
+
5230
+ for (const [depName, version] of Object.entries(dependencies)) {
5231
+ if (knownVulnerablePackages[depName]) {
5232
+ const vuln = knownVulnerablePackages[depName];
5233
+ report.dependencyIssues.push({
5234
+ name: depName,
5235
+ version: version,
5236
+ issue: vuln.issue,
5237
+ severity: vuln.severity,
5238
+ fix: vuln.fix
5239
+ });
5240
+ }
5241
+ }
5242
+ } catch (error) {
5243
+ // Could not check dependencies
5244
+ }
5245
+ }
5246
+
5247
+ performOptimizationAnalysis() {
5248
+ console.log(chalk.cyan('⚡ Analyzing Performance...'));
5249
+ console.log('');
5250
+
5251
+ console.log(chalk.magenta('╭─────────────────────────────────────────╮'));
5252
+ console.log(chalk.magenta('│') + chalk.white.bold(' ⚡ Performance Analysis ') + chalk.magenta('│'));
5253
+ console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
5254
+ console.log('');
5255
+
5256
+ const perfReport = this.performRealPerformanceAnalysis();
5257
+
5258
+ // Display performance score
5259
+ let scoreColor = 'green';
5260
+ if (perfReport.score < 60) scoreColor = 'red';
5261
+ else if (perfReport.score < 80) scoreColor = 'yellow';
5262
+
5263
+ console.log(chalk[scoreColor](`⚡ Performance Score: ${perfReport.score}/100`));
5264
+ console.log('');
5265
+
5266
+ // Display bottlenecks
5267
+ if (perfReport.bottlenecks.length > 0) {
5268
+ console.log(chalk.yellow('🐌 Performance Bottlenecks Detected:'));
5269
+ perfReport.bottlenecks.forEach(bottleneck => {
5270
+ console.log(chalk.white(` • ${bottleneck.type}: ${bottleneck.description}`));
5271
+ console.log(chalk.gray(` File: ${bottleneck.file}:${bottleneck.line}`));
5272
+ });
5273
+ console.log('');
5274
+ }
5275
+
5276
+ // Display file size issues
5277
+ if (perfReport.fileSizeIssues.length > 0) {
5278
+ console.log(chalk.yellow('📁 Large File Issues:'));
5279
+ perfReport.fileSizeIssues.forEach(issue => {
5280
+ console.log(chalk.white(` • ${issue.file}: ${issue.sizeKB}KB (${issue.description})`));
5281
+ });
5282
+ console.log('');
5283
+ }
5284
+
5285
+ // Display dependency analysis
5286
+ if (perfReport.dependencyImpact.heavyDependencies.length > 0) {
5287
+ console.log(chalk.yellow('📦 Heavy Dependencies:'));
5288
+ perfReport.dependencyImpact.heavyDependencies.forEach(dep => {
5289
+ console.log(chalk.white(` • ${dep}: Large bundle size impact`));
5290
+ });
5291
+ console.log('');
5292
+ }
5293
+
5294
+ // Display optimization suggestions
5295
+ if (perfReport.optimizations.length > 0) {
5296
+ console.log(chalk.cyan('🚀 Optimization Suggestions:'));
5297
+ perfReport.optimizations.forEach(opt => {
5298
+ console.log(chalk.white(` • ${opt}`));
5299
+ });
5300
+ console.log('');
5301
+ }
5302
+
5303
+ // Show memory usage patterns
5304
+ if (perfReport.memoryPatterns.length > 0) {
5305
+ console.log(chalk.blue('🧠 Memory Usage Patterns:'));
5306
+ perfReport.memoryPatterns.forEach(pattern => {
5307
+ console.log(chalk.white(` • ${pattern.type}: ${pattern.description}`));
5308
+ if (pattern.file) {
5309
+ console.log(chalk.gray(` File: ${pattern.file}:${pattern.line}`));
5310
+ }
5311
+ });
5312
+ console.log('');
5313
+ }
5314
+
5315
+ // Summary
5316
+ const totalIssues = perfReport.bottlenecks.length + perfReport.fileSizeIssues.length;
5317
+ if (totalIssues === 0) {
5318
+ console.log(chalk.green('✅ No major performance issues detected'));
5319
+ } else {
5320
+ console.log(chalk.yellow(`📊 Total Performance Issues: ${totalIssues}`));
5321
+ }
5322
+ }
5323
+
5324
+ performRealPerformanceAnalysis() {
5325
+ const fs = require('fs');
5326
+ const path = require('path');
5327
+
5328
+ const perfReport = {
5329
+ score: 100,
5330
+ bottlenecks: [],
5331
+ fileSizeIssues: [],
5332
+ dependencyImpact: {
5333
+ heavyDependencies: [],
5334
+ totalDependencies: 0
5335
+ },
5336
+ memoryPatterns: [],
5337
+ optimizations: []
5338
+ };
5339
+
5340
+ // Performance anti-patterns to detect
5341
+ const performancePatterns = [
5342
+ { pattern: /for\s*\(.*\.length.*\)/, type: 'Loop Optimization', description: 'Loop with .length in condition - cache length outside loop' },
5343
+ { pattern: /document\.getElementById.*\(/, type: 'DOM Query', description: 'Repeated DOM queries - consider caching elements' },
5344
+ { pattern: /\$\(.*\)\..*\$\(.*\)/, type: 'jQuery Chaining', description: 'Multiple jQuery selectors - consider chaining or caching' },
5345
+ { pattern: /setInterval\s*\(.*1\)/, type: 'High Frequency Timer', description: 'Very high frequency interval detected' },
5346
+ { pattern: /JSON\.parse\s*\(.*JSON\.stringify/, type: 'Deep Clone', description: 'Inefficient deep cloning - consider structured clone or lodash' },
5347
+ { pattern: /new\s+Array\s*\(/, type: 'Array Constructor', description: 'Use array literal [] instead of new Array()' },
5348
+ { pattern: /\.innerHTML\s*\+=/, type: 'DOM Manipulation', description: 'Inefficient DOM updates - consider batch operations' },
5349
+ { pattern: /require\s*\(.*\).*require\s*\(.*\)/, type: 'Module Loading', description: 'Multiple requires in same scope - consider combining imports' }
5350
+ ];
5351
+
5352
+ // Memory leak patterns
5353
+ const memoryPatterns = [
5354
+ { pattern: /addEventListener.*(?!removeEventListener)/, type: 'Event Listener Leak', description: 'Event listener without cleanup' },
5355
+ { pattern: /setInterval.*(?!clearInterval)/, type: 'Timer Leak', description: 'setInterval without clearInterval' },
5356
+ { pattern: /setTimeout.*(?!clearTimeout)/, type: 'Timer Leak', description: 'setTimeout pattern that might not clear' },
5357
+ { pattern: /closure.*function.*closure/, type: 'Closure Chain', description: 'Potential closure memory retention' }
5358
+ ];
5359
+
5360
+ // Scan files for performance issues
5361
+ const scanDirectory = (dir, depth = 0) => {
5362
+ if (depth > 3) return;
5363
+
5364
+ try {
5365
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
5366
+
5367
+ for (const entry of entries) {
5368
+ const fullPath = path.join(dir, entry.name);
5369
+
5370
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;
5371
+
5372
+ if (entry.isFile()) {
5373
+ // Check file size
5374
+ const stats = fs.statSync(fullPath);
5375
+ const sizeKB = Math.round(stats.size / 1024);
5376
+
5377
+ if (sizeKB > 500 && this.isCodeFile(entry.name)) {
5378
+ perfReport.fileSizeIssues.push({
5379
+ file: fullPath.replace(process.cwd(), '.'),
5380
+ sizeKB: sizeKB,
5381
+ description: sizeKB > 1000 ? 'Very large file - consider splitting' : 'Large file - review for optimization'
5382
+ });
5383
+ }
5384
+
5385
+ // Scan code files for performance patterns
5386
+ if (this.isCodeFile(entry.name)) {
5387
+ this.scanFileForPerformance(fullPath, performancePatterns, memoryPatterns, perfReport);
5388
+ }
5389
+ } else if (entry.isDirectory()) {
5390
+ scanDirectory(fullPath, depth + 1);
5391
+ }
5392
+ }
5393
+ } catch (error) {
5394
+ // Skip directories we can't read
5395
+ }
5396
+ };
5397
+
5398
+ scanDirectory(process.cwd());
5399
+
5400
+ // Analyze dependencies
5401
+ this.analyzeDependencyPerformance(perfReport);
5402
+
5403
+ // Calculate score based on findings
5404
+ const bottleneckCount = perfReport.bottlenecks.length;
5405
+ const fileSizeIssueCount = perfReport.fileSizeIssues.length;
5406
+ const memoryIssueCount = perfReport.memoryPatterns.length;
5407
+
5408
+ perfReport.score = Math.max(0, 100 - (bottleneckCount * 10) - (fileSizeIssueCount * 5) - (memoryIssueCount * 8));
5409
+
5410
+ // Generate optimization recommendations
5411
+ if (bottleneckCount > 0) {
5412
+ perfReport.optimizations.push('🔧 Address performance bottlenecks in critical code paths');
5413
+ }
5414
+ if (fileSizeIssueCount > 0) {
5415
+ perfReport.optimizations.push('📦 Consider code splitting for large files');
5416
+ }
5417
+ if (memoryIssueCount > 0) {
5418
+ perfReport.optimizations.push('🧠 Implement proper memory management and cleanup');
5419
+ }
5420
+
5421
+ perfReport.optimizations.push('⚡ Use Web Workers for CPU-intensive tasks');
5422
+ perfReport.optimizations.push('🗂️ Implement lazy loading for non-critical resources');
5423
+ perfReport.optimizations.push('📊 Add performance monitoring and profiling');
5424
+ perfReport.optimizations.push('🔄 Consider using virtual scrolling for large lists');
5425
+
5426
+ return perfReport;
5427
+ }
5428
+
5429
+ scanFileForPerformance(filePath, performancePatterns, memoryPatterns, report) {
5430
+ const fs = require('fs');
5431
+
5432
+ try {
5433
+ const content = fs.readFileSync(filePath, 'utf8');
5434
+ const lines = content.split('\n');
5435
+
5436
+ // Check for performance bottlenecks
5437
+ for (const patternInfo of performancePatterns) {
5438
+ for (let i = 0; i < lines.length; i++) {
5439
+ if (patternInfo.pattern.test(lines[i])) {
5440
+ report.bottlenecks.push({
5441
+ type: patternInfo.type,
5442
+ description: patternInfo.description,
5443
+ file: filePath.replace(process.cwd(), '.'),
5444
+ line: i + 1,
5445
+ code: lines[i].trim()
5446
+ });
5447
+ }
5448
+ }
5449
+ }
5450
+
5451
+ // Check for memory patterns
5452
+ for (const patternInfo of memoryPatterns) {
5453
+ for (let i = 0; i < lines.length; i++) {
5454
+ if (patternInfo.pattern.test(lines[i])) {
5455
+ report.memoryPatterns.push({
5456
+ type: patternInfo.type,
5457
+ description: patternInfo.description,
5458
+ file: filePath.replace(process.cwd(), '.'),
5459
+ line: i + 1,
5460
+ code: lines[i].trim()
5461
+ });
5462
+ }
5463
+ }
5464
+ }
5465
+ } catch (error) {
5466
+ // Skip files we can't read
5467
+ }
5468
+ }
5469
+
5470
+ analyzeDependencyPerformance(report) {
5471
+ const fs = require('fs');
5472
+ const path = require('path');
5473
+
5474
+ try {
5475
+ const packagePath = path.join(process.cwd(), 'package.json');
5476
+ if (!fs.existsSync(packagePath)) return;
5477
+
5478
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
5479
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
5480
+
5481
+ report.dependencyImpact.totalDependencies = Object.keys(dependencies).length;
5482
+
5483
+ // Known heavy dependencies that impact performance
5484
+ const heavyDependencies = ['lodash', 'moment', 'jquery', 'axios', 'react', 'vue', 'angular'];
5485
+
5486
+ for (const depName of Object.keys(dependencies)) {
5487
+ if (heavyDependencies.includes(depName)) {
5488
+ report.dependencyImpact.heavyDependencies.push(depName);
5489
+ }
5490
+ }
5491
+
5492
+ // Add recommendations based on dependency analysis
5493
+ if (dependencies['lodash']) {
5494
+ report.optimizations.push('Consider using native ES6 methods instead of lodash where possible');
5495
+ }
5496
+ if (dependencies['moment']) {
5497
+ report.optimizations.push('Consider using date-fns or dayjs instead of moment.js for smaller bundle size');
5498
+ }
5499
+
5500
+ } catch (error) {
5501
+ // Skip dependency analysis if package.json is not readable
5502
+ }
5503
+ }
5504
+
5505
+ cycleTheme() {
5506
+ if (!this.currentTheme) this.currentTheme = 'neon-purple';
5507
+
5508
+ const themes = ['neon-purple', 'matrix-green', 'ocean-blue', 'sunset-orange'];
5509
+ const currentIndex = themes.indexOf(this.currentTheme);
5510
+ const nextIndex = (currentIndex + 1) % themes.length;
5511
+ this.currentTheme = themes[nextIndex];
5512
+
5513
+ console.log(chalk.cyan(`🎨 Theme switched to: ${this.currentTheme}`));
5514
+ console.log(chalk.gray('New color scheme will apply to future messages'));
5515
+ console.log('');
5516
+ }
5517
+
5518
+ async cleanup() {
5519
+ this.logger.info('Starting cleanup process');
5520
+
5521
+ // Clean up streaming and loading animations
5522
+ this.stopProgressiveLoading();
5523
+ this.stopStreamingDisplay();
5524
+
5525
+ if (this.fileWatcher) {
5526
+ this.fileWatcher.close();
5527
+ this.fileWatcher = null;
5528
+ this.logger.debug('File watcher closed');
5529
+ }
5530
+
5531
+ // Cleanup voice manager
5532
+ if (this.voiceManager) {
5533
+ this.voiceManager.cleanup();
5534
+ this.logger.debug('Voice manager cleaned up');
5535
+ }
5536
+
5537
+ // Cleanup collaboration manager
5538
+ if (this.collaborationManager) {
5539
+ this.collaborationManager.cleanup();
5540
+ this.logger.debug('Collaboration manager cleaned up');
5541
+ }
5542
+
5543
+ // Cleanup plugins
5544
+ if (this.pluginManager) {
5545
+ await this.pluginManager.cleanup();
5546
+ this.logger.debug('Plugins cleaned up');
5547
+ }
5548
+
5549
+ // End session logging
5550
+ if (this.logger) {
5551
+ this.logger.endSession();
5552
+ this.logger.info('Session cleanup completed');
5553
+ }
5554
+ }
5555
+
5556
+ /**
5557
+ * Load user configuration from onboarding
5558
+ */
5559
+ loadUserConfig() {
5560
+ const path = require('path');
5561
+ const fs = require('fs');
5562
+ const configFile = path.join(require('os').homedir(), '.recoder-code', 'config.json');
5563
+
5564
+ try {
5565
+ if (fs.existsSync(configFile)) {
5566
+ return JSON.parse(fs.readFileSync(configFile, 'utf8'));
5567
+ }
5568
+ } catch (error) {
5569
+ // Return empty config if can't load
5570
+ }
5571
+
5572
+ return {};
4131
5573
  }
4132
5574
 
4133
5575
  start() {