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.
- package/README.md +66 -10
- package/cli/collaboration-manager.js +3 -1
- package/cli/dev-tools-integration.js +9 -7
- package/cli/enhanced-setup.js +3 -1
- package/cli/file-watcher-manager.js +216 -0
- package/cli/interactive.js +1527 -85
- package/cli/logger.js +181 -0
- package/cli/mcp-client.js +32 -9
- package/cli/ml-training-manager.js +3 -1
- package/cli/natural-language-processor.js +3 -1
- package/cli/project-manager.js +3 -1
- package/cli/rules-engine.js +9 -4
- package/cli/run.js +90 -13
- package/cli/setup-wizard.js +3 -1
- package/cli/slash-commands.js +132 -5
- package/cli/task-manager.js +13 -5
- package/cli/team-collaboration.js +3 -1
- package/cli/todo-manager.js +391 -0
- package/cli/unified-error-handler.js +260 -0
- package/cli/user-experience.js +3 -1
- package/cli/user-onboarding.js +251 -0
- package/cli/vision-analyzer.js +3 -1
- package/index.js +88 -13
- package/package.json +7 -1
- package/plugins/enhanced-plugin-manager.js +31 -11
- package/scripts/performance-benchmark.js +3 -1
- package/scripts/security-audit.js +3 -1
- package/setup.js +3 -1
package/cli/interactive.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
41
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
'
|
|
478
|
-
'
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
console.log(
|
|
1197
|
-
|
|
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
|
-
//
|
|
1202
|
-
|
|
1258
|
+
// Dynamic status information
|
|
1259
|
+
this.displayDynamicStatus();
|
|
1203
1260
|
console.log('');
|
|
1204
1261
|
|
|
1205
|
-
//
|
|
1206
|
-
this.
|
|
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
|
|
1486
|
+
console.log(chalk.magenta('│') + chalk.white.bold(' 🚀 Available Commands ') + chalk.magenta('│'));
|
|
1339
1487
|
console.log(chalk.magenta('╰─────────────────────────────────────────╯'));
|
|
1340
1488
|
console.log('');
|
|
1341
|
-
|
|
1342
|
-
console.log(chalk.
|
|
1343
|
-
console.log(chalk.gray('/
|
|
1344
|
-
console.log(chalk.gray('/
|
|
1345
|
-
console.log(chalk.gray('/
|
|
1346
|
-
console.log(chalk.gray('/
|
|
1347
|
-
console.log(
|
|
1348
|
-
|
|
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
|
-
|
|
4096
|
-
|
|
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
|
-
|
|
4099
|
-
this.stopProgressiveLoading();
|
|
4100
|
-
this.stopStreamingDisplay();
|
|
4308
|
+
const analysis = this.analyzeCurrentProject();
|
|
4101
4309
|
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
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
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
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
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
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
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
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
|
-
//
|
|
4127
|
-
if (
|
|
4128
|
-
|
|
4129
|
-
|
|
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() {
|