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