devcompass 2.7.1 ā 2.8.0
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 +475 -129
- package/bin/devcompass.js +3 -1
- package/package.json +8 -3
- package/src/commands/fix.js +295 -213
- package/src/utils/backup-manager.js +113 -0
- package/src/utils/fix-report.js +129 -0
- package/src/utils/progress-tracker.js +79 -0
package/bin/devcompass.js
CHANGED
|
@@ -4,7 +4,7 @@ const { Command } = require('commander');
|
|
|
4
4
|
const chalk = require('chalk');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { analyze } = require('../src/commands/analyze');
|
|
7
|
-
const
|
|
7
|
+
const fix = require('../src/commands/fix');
|
|
8
8
|
const packageJson = require('../package.json');
|
|
9
9
|
|
|
10
10
|
// Check if running from local node_modules
|
|
@@ -40,6 +40,8 @@ program
|
|
|
40
40
|
.description('Fix issues automatically (remove unused, update safe packages)')
|
|
41
41
|
.option('-p, --path <path>', 'Project path', process.cwd())
|
|
42
42
|
.option('-y, --yes', 'Skip confirmation prompt', false)
|
|
43
|
+
.option('--dry-run', 'Show what would be fixed without making changes')
|
|
44
|
+
.option('--dry', 'Alias for --dry-run')
|
|
43
45
|
.action(fix);
|
|
44
46
|
|
|
45
47
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devcompass",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Dependency health checker with ecosystem intelligence, real-time GitHub issue tracking for 500+ popular npm packages, parallel processing, supply chain security analysis,
|
|
3
|
+
"version": "2.8.0",
|
|
4
|
+
"description": "Dependency health checker with ecosystem intelligence, real-time GitHub issue tracking for 500+ popular npm packages, parallel processing, supply chain security analysis, advanced license risk detection, and enhanced fix command with dry-run, progress tracking, and automatic backups.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"devcompass": "./bin/devcompass.js"
|
|
@@ -53,7 +53,12 @@
|
|
|
53
53
|
"license-risk",
|
|
54
54
|
"package-quality",
|
|
55
55
|
"security-recommendations",
|
|
56
|
-
"dependency-quality"
|
|
56
|
+
"dependency-quality",
|
|
57
|
+
"auto-fix",
|
|
58
|
+
"dry-run",
|
|
59
|
+
"backup-restore",
|
|
60
|
+
"fix-report",
|
|
61
|
+
"progress-tracking"
|
|
57
62
|
],
|
|
58
63
|
"author": "Ajay Thorat <ajaythorat988@gmail.com>",
|
|
59
64
|
"license": "MIT",
|
package/src/commands/fix.js
CHANGED
|
@@ -1,253 +1,335 @@
|
|
|
1
1
|
// src/commands/fix.js
|
|
2
|
-
const chalk = require('chalk');
|
|
3
|
-
const ora = require('ora');
|
|
4
2
|
const { execSync } = require('child_process');
|
|
5
|
-
const
|
|
3
|
+
const fs = require('fs');
|
|
6
4
|
const path = require('path');
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const ora = require('ora');
|
|
7
|
+
const ProgressTracker = require('../utils/progress-tracker');
|
|
8
|
+
const FixReport = require('../utils/fix-report');
|
|
9
|
+
const BackupManager = require('../utils/backup-manager');
|
|
12
10
|
const { clearCache } = require('../cache/manager');
|
|
13
11
|
|
|
14
|
-
async function fix(options) {
|
|
12
|
+
async function fix(options = {}) {
|
|
15
13
|
const projectPath = options.path || process.cwd();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
14
|
+
const autoApply = options.yes || options.y || false;
|
|
15
|
+
const dryRun = options.dryRun || options.dry || false;
|
|
16
|
+
|
|
17
|
+
console.log(chalk.bold.cyan('\nš§ DevCompass Fix\n'));
|
|
18
|
+
|
|
19
|
+
if (dryRun) {
|
|
20
|
+
console.log(chalk.yellow('š DRY RUN MODE - No changes will be made\n'));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check if package.json exists
|
|
24
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
25
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
26
|
+
console.error(chalk.red('ā No package.json found in this directory'));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Initialize report and backup
|
|
31
|
+
const report = new FixReport();
|
|
32
|
+
const backupManager = new BackupManager(projectPath);
|
|
33
|
+
|
|
25
34
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
// Step 1: Analyze what needs fixing
|
|
36
|
+
console.log(chalk.bold('Step 1: Analyzing issues...\n'));
|
|
37
|
+
const spinner = ora('Scanning project...').start();
|
|
38
|
+
|
|
39
|
+
const { alerts, unused, outdated, security } = await analyzeProject(projectPath);
|
|
40
|
+
|
|
41
|
+
spinner.succeed('Analysis complete');
|
|
42
|
+
|
|
43
|
+
// Calculate total fixes needed
|
|
44
|
+
const totalFixes = calculateTotalFixes(alerts, unused, outdated, security);
|
|
45
|
+
|
|
46
|
+
if (totalFixes === 0) {
|
|
47
|
+
console.log(chalk.green('\n⨠No issues to fix! Your project is healthy.\n'));
|
|
48
|
+
return;
|
|
32
49
|
}
|
|
50
|
+
|
|
51
|
+
// Step 2: Show what will be fixed
|
|
52
|
+
console.log(chalk.bold('\nStep 2: Planned fixes\n'));
|
|
53
|
+
displayPlannedFixes(alerts, unused, outdated, security, dryRun);
|
|
54
|
+
|
|
55
|
+
// Step 3: Get confirmation (unless auto-apply or dry-run)
|
|
56
|
+
if (!dryRun && !autoApply) {
|
|
57
|
+
console.log(chalk.bold('\n' + '='.repeat(70)));
|
|
58
|
+
const readline = require('readline').createInterface({
|
|
59
|
+
input: process.stdin,
|
|
60
|
+
output: process.stdout
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const answer = await new Promise(resolve => {
|
|
64
|
+
readline.question(chalk.yellow('ā ļø Apply these fixes? (y/N): '), resolve);
|
|
65
|
+
});
|
|
66
|
+
readline.close();
|
|
67
|
+
|
|
68
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
69
|
+
console.log(chalk.gray('\nFix cancelled by user.\n'));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (dryRun) {
|
|
75
|
+
console.log(chalk.cyan('\nā Dry run complete. No changes were made.\n'));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Step 4: Create backup
|
|
80
|
+
console.log(chalk.bold('\nStep 4: Creating backup...\n'));
|
|
81
|
+
const backupPath = await backupManager.createBackup();
|
|
82
|
+
if (backupPath) {
|
|
83
|
+
console.log(chalk.green(`ā Backup created: ${path.basename(backupPath)}\n`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Step 5: Apply fixes with progress tracking
|
|
87
|
+
console.log(chalk.bold('Step 5: Applying fixes...\n'));
|
|
33
88
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
89
|
+
const progress = new ProgressTracker(totalFixes);
|
|
90
|
+
progress.start('Starting fixes...');
|
|
91
|
+
|
|
92
|
+
// Fix critical security issues first
|
|
93
|
+
if (security.metadata.critical > 0 || security.metadata.high > 0) {
|
|
94
|
+
progress.update('Fixing security vulnerabilities...');
|
|
95
|
+
await fixSecurityIssues(projectPath, report, progress);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Fix ecosystem alerts
|
|
99
|
+
if (alerts.length > 0) {
|
|
100
|
+
for (const alert of alerts) {
|
|
101
|
+
if (alert.severity === 'critical' || alert.severity === 'high') {
|
|
102
|
+
progress.update(`Fixing ${alert.package}...`);
|
|
103
|
+
await fixAlert(alert, projectPath, report, progress);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Remove unused dependencies
|
|
109
|
+
if (unused.length > 0) {
|
|
110
|
+
for (const dep of unused) {
|
|
111
|
+
progress.update(`Removing ${dep}...`);
|
|
112
|
+
await removeUnusedDependency(dep, projectPath, report, progress);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Update outdated packages (only patch/minor)
|
|
117
|
+
if (outdated.length > 0) {
|
|
118
|
+
for (const pkg of outdated) {
|
|
119
|
+
if (pkg.versionsBehind !== 'major') {
|
|
120
|
+
progress.update(`Updating ${pkg.name}...`);
|
|
121
|
+
await updatePackage(pkg, projectPath, report, progress);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
progress.succeed('All fixes applied!');
|
|
127
|
+
|
|
128
|
+
// Step 6: Clear cache
|
|
129
|
+
console.log(chalk.bold('\nStep 6: Clearing cache...\n'));
|
|
130
|
+
clearCache(projectPath);
|
|
131
|
+
console.log(chalk.green('ā Cache cleared\n'));
|
|
132
|
+
|
|
133
|
+
// Step 7: Generate and display report
|
|
134
|
+
report.finalize();
|
|
135
|
+
report.display();
|
|
136
|
+
|
|
137
|
+
// Save report to file
|
|
138
|
+
const reportPath = await report.save(projectPath);
|
|
139
|
+
if (reportPath) {
|
|
140
|
+
console.log(chalk.cyan(`š Full report saved to: ${path.basename(reportPath)}\n`));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Final summary
|
|
144
|
+
const summary = report.getSummary();
|
|
145
|
+
if (summary.totalFixes > 0) {
|
|
146
|
+
console.log(chalk.green.bold(`ā Successfully applied ${summary.totalFixes} fix(es)!\n`));
|
|
147
|
+
console.log(chalk.gray('š” TIP: Run'), chalk.cyan('devcompass analyze'), chalk.gray('to verify improvements\n'));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (summary.totalErrors > 0) {
|
|
151
|
+
console.log(chalk.yellow(`ā ļø ${summary.totalErrors} error(s) occurred during fix\n`));
|
|
152
|
+
}
|
|
153
|
+
|
|
58
154
|
} catch (error) {
|
|
59
|
-
|
|
60
|
-
console.log(chalk.
|
|
155
|
+
console.error(chalk.red('\nā Fix failed:'), error.message);
|
|
156
|
+
console.log(chalk.yellow('\nš” TIP: Your backup is available in .devcompass-backups/\n'));
|
|
61
157
|
process.exit(1);
|
|
62
158
|
}
|
|
63
159
|
}
|
|
64
160
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
161
|
+
// Helper functions
|
|
162
|
+
|
|
163
|
+
async function analyzeProject(projectPath) {
|
|
164
|
+
// Load existing analyzers
|
|
165
|
+
const alerts = require('../alerts');
|
|
166
|
+
const unusedDeps = require('../analyzers/unused-deps');
|
|
167
|
+
const outdated = require('../analyzers/outdated');
|
|
168
|
+
const security = require('../analyzers/security');
|
|
169
|
+
|
|
170
|
+
const packageJson = JSON.parse(
|
|
171
|
+
fs.readFileSync(path.join(projectPath, 'package.json'), 'utf8')
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const dependencies = {
|
|
175
|
+
...packageJson.dependencies,
|
|
176
|
+
...packageJson.devDependencies
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Run analyses
|
|
180
|
+
const alertsList = await alerts.checkEcosystemAlerts(projectPath, dependencies);
|
|
181
|
+
const unusedList = await unusedDeps.findUnusedDeps(projectPath, dependencies);
|
|
182
|
+
const outdatedList = await outdated.findOutdatedDeps(projectPath, dependencies);
|
|
183
|
+
const securityData = await security.checkSecurity(projectPath);
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
alerts: alertsList,
|
|
187
|
+
unused: unusedList,
|
|
188
|
+
outdated: outdatedList,
|
|
189
|
+
security: securityData
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function calculateTotalFixes(alerts, unused, outdated, security) {
|
|
194
|
+
let total = 0;
|
|
195
|
+
|
|
196
|
+
// Count security fixes
|
|
197
|
+
if (security.metadata.critical > 0 || security.metadata.high > 0) {
|
|
198
|
+
total += 1; // npm audit fix counts as one operation
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Count critical/high alerts
|
|
202
|
+
total += alerts.filter(a => a.severity === 'critical' || a.severity === 'high').length;
|
|
203
|
+
|
|
204
|
+
// Count unused deps
|
|
205
|
+
total += unused.length;
|
|
206
|
+
|
|
207
|
+
// Count safe updates (patch/minor only)
|
|
208
|
+
total += outdated.filter(pkg => pkg.versionsBehind !== 'major').length;
|
|
209
|
+
|
|
210
|
+
return total;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function displayPlannedFixes(alerts, unused, outdated, security, dryRun) {
|
|
214
|
+
let fixCount = 0;
|
|
215
|
+
|
|
216
|
+
// Security fixes
|
|
217
|
+
if (security.metadata.critical > 0 || security.metadata.high > 0) {
|
|
218
|
+
console.log(chalk.red.bold('š“ CRITICAL SECURITY FIXES'));
|
|
219
|
+
console.log(` ${chalk.cyan('ā')} Run npm audit fix to resolve ${security.metadata.critical + security.metadata.high} vulnerabilities`);
|
|
220
|
+
fixCount++;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Ecosystem alerts
|
|
224
|
+
const criticalAlerts = alerts.filter(a => a.severity === 'critical' || a.severity === 'high');
|
|
69
225
|
if (criticalAlerts.length > 0) {
|
|
70
|
-
console.log(chalk.red.bold('š“ CRITICAL ISSUES
|
|
71
|
-
|
|
226
|
+
console.log(chalk.red.bold('\nš“ CRITICAL PACKAGE ISSUES'));
|
|
72
227
|
criticalAlerts.forEach(alert => {
|
|
73
|
-
|
|
74
|
-
console.log(
|
|
75
|
-
console.log(`
|
|
76
|
-
|
|
77
|
-
if (alert.fix && /^\d+\.\d+/.test(alert.fix)) {
|
|
78
|
-
console.log(` ${chalk.green('Fix:')} Upgrade to ${alert.fix}\n`);
|
|
79
|
-
actions.push({
|
|
80
|
-
type: 'upgrade',
|
|
81
|
-
package: alert.package,
|
|
82
|
-
version: alert.fix,
|
|
83
|
-
reason: 'Critical security/stability issue'
|
|
84
|
-
});
|
|
85
|
-
} else {
|
|
86
|
-
console.log(` ${chalk.yellow('Fix:')} ${alert.fix}\n`);
|
|
87
|
-
}
|
|
228
|
+
console.log(` ${chalk.cyan(alert.package)}`);
|
|
229
|
+
console.log(` ${chalk.gray('ā')} ${alert.title}`);
|
|
230
|
+
console.log(` ${chalk.gray('Fix:')} ${alert.fix}`);
|
|
231
|
+
fixCount++;
|
|
88
232
|
});
|
|
89
|
-
|
|
90
|
-
console.log('ā'.repeat(70) + '\n');
|
|
91
233
|
}
|
|
92
|
-
|
|
234
|
+
|
|
93
235
|
// Unused dependencies
|
|
94
|
-
if (
|
|
95
|
-
console.log(chalk.yellow.bold('
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
console.log(`
|
|
99
|
-
|
|
100
|
-
type: 'uninstall',
|
|
101
|
-
package: dep.name,
|
|
102
|
-
reason: 'Not used in project'
|
|
103
|
-
});
|
|
236
|
+
if (unused.length > 0) {
|
|
237
|
+
console.log(chalk.yellow.bold('\nš” UNUSED DEPENDENCIES'));
|
|
238
|
+
unused.forEach(dep => {
|
|
239
|
+
console.log(` ${chalk.cyan(dep.name)}`);
|
|
240
|
+
console.log(` ${chalk.gray('ā')} Will be removed`);
|
|
241
|
+
fixCount++;
|
|
104
242
|
});
|
|
105
|
-
|
|
106
|
-
console.log('\n' + 'ā'.repeat(70) + '\n');
|
|
107
243
|
}
|
|
108
|
-
|
|
109
|
-
// Safe updates
|
|
110
|
-
const safeUpdates =
|
|
111
|
-
dep.versionsBehind === 'patch update' || dep.versionsBehind === 'minor update'
|
|
112
|
-
);
|
|
113
|
-
|
|
244
|
+
|
|
245
|
+
// Safe updates
|
|
246
|
+
const safeUpdates = outdated.filter(pkg => pkg.versionsBehind !== 'major');
|
|
114
247
|
if (safeUpdates.length > 0) {
|
|
115
|
-
console.log(chalk.cyan.bold('
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
console.log(`
|
|
119
|
-
|
|
120
|
-
type: 'update',
|
|
121
|
-
package: dep.name,
|
|
122
|
-
version: dep.latest,
|
|
123
|
-
reason: dep.versionsBehind
|
|
124
|
-
});
|
|
248
|
+
console.log(chalk.cyan.bold('\nšµ SAFE UPDATES (patch/minor)'));
|
|
249
|
+
safeUpdates.forEach(pkg => {
|
|
250
|
+
console.log(` ${chalk.cyan(pkg.name)}`);
|
|
251
|
+
console.log(` ${chalk.gray('ā')} ${pkg.current} ā ${pkg.latest}`);
|
|
252
|
+
fixCount++;
|
|
125
253
|
});
|
|
126
|
-
|
|
127
|
-
console.log('\n' + 'ā'.repeat(70) + '\n');
|
|
128
254
|
}
|
|
129
|
-
|
|
130
|
-
// Major updates (
|
|
131
|
-
const majorUpdates =
|
|
132
|
-
|
|
255
|
+
|
|
256
|
+
// Major updates (will be skipped)
|
|
257
|
+
const majorUpdates = outdated.filter(pkg => pkg.versionsBehind === 'major');
|
|
133
258
|
if (majorUpdates.length > 0) {
|
|
134
|
-
console.log(chalk.gray.bold('
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
console.log(`
|
|
259
|
+
console.log(chalk.gray.bold('\nāŖ SKIPPED (major updates - manual review required)'));
|
|
260
|
+
majorUpdates.forEach(pkg => {
|
|
261
|
+
console.log(` ${chalk.gray(pkg.name)}`);
|
|
262
|
+
console.log(` ${chalk.gray('ā')} ${pkg.current} ā ${pkg.latest} (breaking changes possible)`);
|
|
138
263
|
});
|
|
139
|
-
|
|
140
|
-
console.log(chalk.gray('\n Run these manually after reviewing changelog:\n'));
|
|
141
|
-
majorUpdates.forEach(dep => {
|
|
142
|
-
console.log(chalk.gray(` npm install ${dep.name}@${dep.latest}`));
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
console.log('\n' + 'ā'.repeat(70) + '\n');
|
|
146
264
|
}
|
|
265
|
+
|
|
266
|
+
console.log(chalk.bold('\n' + '='.repeat(70)));
|
|
267
|
+
console.log(chalk.bold(`Total fixes to apply: ${chalk.cyan(fixCount)}`));
|
|
147
268
|
|
|
148
|
-
if (
|
|
149
|
-
console.log(chalk.
|
|
150
|
-
return;
|
|
269
|
+
if (dryRun) {
|
|
270
|
+
console.log(chalk.yellow('(Dry run - no changes will be made)'));
|
|
151
271
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
await applyFixes(actions, projectPath);
|
|
165
|
-
} else {
|
|
166
|
-
const confirmed = await askConfirmation('\nā Apply these fixes?');
|
|
167
|
-
|
|
168
|
-
if (confirmed) {
|
|
169
|
-
await applyFixes(actions, projectPath);
|
|
170
|
-
} else {
|
|
171
|
-
console.log(chalk.yellow('\nā ļø Fix cancelled. No changes made.\n'));
|
|
172
|
-
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function fixSecurityIssues(projectPath, report, progress) {
|
|
275
|
+
try {
|
|
276
|
+
execSync('npm audit fix', {
|
|
277
|
+
cwd: projectPath,
|
|
278
|
+
stdio: 'pipe'
|
|
279
|
+
});
|
|
280
|
+
report.addFix('security', 'npm audit', 'Fixed security vulnerabilities');
|
|
281
|
+
} catch (error) {
|
|
282
|
+
report.addError('npm audit', error);
|
|
283
|
+
progress.warn('Some security issues could not be auto-fixed');
|
|
173
284
|
}
|
|
174
285
|
}
|
|
175
286
|
|
|
176
|
-
async function
|
|
177
|
-
console.log(chalk.cyan.bold('\nš§ Applying fixes...\n'));
|
|
178
|
-
|
|
179
|
-
const spinner = ora('Processing...').start();
|
|
180
|
-
|
|
287
|
+
async function fixAlert(alert, projectPath, report, progress) {
|
|
181
288
|
try {
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
spinner.succeed(chalk.green(`ā
Removed ${toUninstall.length} unused packages`));
|
|
195
|
-
spinner.start();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Upgrade critical packages
|
|
199
|
-
for (const action of toUpgrade) {
|
|
200
|
-
spinner.text = `Fixing ${action.package}@${action.version}...`;
|
|
201
|
-
|
|
202
|
-
const cmd = `npm install ${action.package}@${action.version}`;
|
|
203
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
204
|
-
|
|
205
|
-
spinner.succeed(chalk.green(`ā
Fixed ${action.package}@${action.version}`));
|
|
206
|
-
spinner.start();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Update safe packages
|
|
210
|
-
if (toUpdate.length > 0) {
|
|
211
|
-
spinner.text = `Updating ${toUpdate.length} packages...`;
|
|
212
|
-
|
|
213
|
-
for (const action of toUpdate) {
|
|
214
|
-
const cmd = `npm install ${action.package}@${action.version}`;
|
|
215
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
spinner.succeed(chalk.green(`ā
Updated ${toUpdate.length} packages`));
|
|
219
|
-
} else {
|
|
220
|
-
spinner.stop();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
console.log(chalk.green.bold('\n⨠All fixes applied successfully!\n'));
|
|
224
|
-
console.log(chalk.cyan('š” Run') + chalk.bold(' devcompass analyze ') + chalk.cyan('to see the new health score.\n'));
|
|
225
|
-
|
|
226
|
-
// Clear cache after fixes - ADDED
|
|
227
|
-
spinner.text = 'Clearing cache...';
|
|
228
|
-
clearCache(projectPath);
|
|
229
|
-
spinner.succeed(chalk.gray('Cache cleared'));
|
|
230
|
-
|
|
289
|
+
const pkg = alert.package.split('@')[0];
|
|
290
|
+
const version = alert.fix;
|
|
291
|
+
|
|
292
|
+
execSync(`npm install ${pkg}@${version}`, {
|
|
293
|
+
cwd: projectPath,
|
|
294
|
+
stdio: 'pipe'
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
report.addFix('alert', pkg, `Updated to ${version}`, {
|
|
298
|
+
from: alert.package.split('@')[1],
|
|
299
|
+
to: version
|
|
300
|
+
});
|
|
231
301
|
} catch (error) {
|
|
232
|
-
|
|
233
|
-
console.log(chalk.red(`\nā Error: ${error.message}\n`));
|
|
234
|
-
console.log(chalk.yellow('š” You may need to fix this manually.\n'));
|
|
235
|
-
process.exit(1);
|
|
302
|
+
report.addError(alert.package, error);
|
|
236
303
|
}
|
|
237
304
|
}
|
|
238
305
|
|
|
239
|
-
function
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
306
|
+
async function removeUnusedDependency(dep, projectPath, report, progress) {
|
|
307
|
+
try {
|
|
308
|
+
execSync(`npm uninstall ${dep.name}`, {
|
|
309
|
+
cwd: projectPath,
|
|
310
|
+
stdio: 'pipe'
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
report.addFix('unused', dep.name, 'Removed unused dependency');
|
|
314
|
+
} catch (error) {
|
|
315
|
+
report.addError(dep.name, error);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function updatePackage(pkg, projectPath, report, progress) {
|
|
320
|
+
try {
|
|
321
|
+
execSync(`npm install ${pkg.name}@${pkg.latest}`, {
|
|
322
|
+
cwd: projectPath,
|
|
323
|
+
stdio: 'pipe'
|
|
249
324
|
});
|
|
250
|
-
|
|
325
|
+
|
|
326
|
+
report.addFix('update', pkg.name, `Updated to ${pkg.latest}`, {
|
|
327
|
+
from: pkg.current,
|
|
328
|
+
to: pkg.latest
|
|
329
|
+
});
|
|
330
|
+
} catch (error) {
|
|
331
|
+
report.addError(pkg.name, error);
|
|
332
|
+
}
|
|
251
333
|
}
|
|
252
334
|
|
|
253
|
-
module.exports =
|
|
335
|
+
module.exports = fix;
|