devcompass 2.7.0 → 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 +9 -4
- package/src/analyzers/supply-chain.js +37 -31
- 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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/utils/fix-report.js
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
|
|
6
|
+
class FixReport {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.fixes = [];
|
|
9
|
+
this.errors = [];
|
|
10
|
+
this.skipped = [];
|
|
11
|
+
this.startTime = Date.now();
|
|
12
|
+
this.endTime = null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
addFix(type, packageName, action, details = {}) {
|
|
16
|
+
this.fixes.push({
|
|
17
|
+
type,
|
|
18
|
+
package: packageName,
|
|
19
|
+
action,
|
|
20
|
+
details,
|
|
21
|
+
timestamp: new Date().toISOString()
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
addError(packageName, error, details = {}) {
|
|
26
|
+
this.errors.push({
|
|
27
|
+
package: packageName,
|
|
28
|
+
error: error.message || error,
|
|
29
|
+
details,
|
|
30
|
+
timestamp: new Date().toISOString()
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
addSkipped(packageName, reason, details = {}) {
|
|
35
|
+
this.skipped.push({
|
|
36
|
+
package: packageName,
|
|
37
|
+
reason,
|
|
38
|
+
details,
|
|
39
|
+
timestamp: new Date().toISOString()
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
finalize() {
|
|
44
|
+
this.endTime = Date.now();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getSummary() {
|
|
48
|
+
const duration = ((this.endTime || Date.now()) - this.startTime) / 1000;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
totalFixes: this.fixes.length,
|
|
52
|
+
totalErrors: this.errors.length,
|
|
53
|
+
totalSkipped: this.skipped.length,
|
|
54
|
+
duration: `${duration.toFixed(2)}s`,
|
|
55
|
+
timestamp: new Date().toISOString()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async save(projectPath) {
|
|
60
|
+
try {
|
|
61
|
+
const reportPath = path.join(projectPath, 'devcompass-fix-report.json');
|
|
62
|
+
const report = {
|
|
63
|
+
summary: this.getSummary(),
|
|
64
|
+
fixes: this.fixes,
|
|
65
|
+
errors: this.errors,
|
|
66
|
+
skipped: this.skipped
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
70
|
+
return reportPath;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(chalk.red('Failed to save fix report:'), error.message);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
display() {
|
|
78
|
+
console.log('\n' + chalk.bold('━'.repeat(70)));
|
|
79
|
+
console.log(chalk.bold.cyan('📊 FIX REPORT'));
|
|
80
|
+
console.log(chalk.bold('━'.repeat(70)) + '\n');
|
|
81
|
+
|
|
82
|
+
const summary = this.getSummary();
|
|
83
|
+
|
|
84
|
+
// Summary
|
|
85
|
+
console.log(chalk.bold('Summary:'));
|
|
86
|
+
console.log(` ${chalk.green('✓')} Fixes Applied: ${chalk.cyan(summary.totalFixes)}`);
|
|
87
|
+
if (summary.totalErrors > 0) {
|
|
88
|
+
console.log(` ${chalk.red('✗')} Errors: ${chalk.red(summary.totalErrors)}`);
|
|
89
|
+
}
|
|
90
|
+
if (summary.totalSkipped > 0) {
|
|
91
|
+
console.log(` ${chalk.yellow('⊘')} Skipped: ${chalk.yellow(summary.totalSkipped)}`);
|
|
92
|
+
}
|
|
93
|
+
console.log(` ${chalk.gray('⏱')} Duration: ${chalk.cyan(summary.duration)}`);
|
|
94
|
+
|
|
95
|
+
// Fixes
|
|
96
|
+
if (this.fixes.length > 0) {
|
|
97
|
+
console.log('\n' + chalk.bold('Fixes Applied:'));
|
|
98
|
+
this.fixes.forEach((fix, index) => {
|
|
99
|
+
console.log(` ${index + 1}. ${chalk.cyan(fix.package)}`);
|
|
100
|
+
console.log(` ${chalk.gray('→')} ${fix.action}`);
|
|
101
|
+
if (fix.details.from && fix.details.to) {
|
|
102
|
+
console.log(` ${chalk.gray('Version:')} ${fix.details.from} → ${chalk.green(fix.details.to)}`);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Errors
|
|
108
|
+
if (this.errors.length > 0) {
|
|
109
|
+
console.log('\n' + chalk.bold.red('Errors:'));
|
|
110
|
+
this.errors.forEach((error, index) => {
|
|
111
|
+
console.log(` ${index + 1}. ${chalk.red(error.package)}`);
|
|
112
|
+
console.log(` ${chalk.gray('→')} ${error.error}`);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Skipped
|
|
117
|
+
if (this.skipped.length > 0) {
|
|
118
|
+
console.log('\n' + chalk.bold.yellow('Skipped:'));
|
|
119
|
+
this.skipped.forEach((skip, index) => {
|
|
120
|
+
console.log(` ${index + 1}. ${chalk.yellow(skip.package)}`);
|
|
121
|
+
console.log(` ${chalk.gray('→')} ${skip.reason}`);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log('\n' + chalk.bold('━'.repeat(70)) + '\n');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = FixReport;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/utils/progress-tracker.js
|
|
2
|
+
const ora = require('ora');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
class ProgressTracker {
|
|
6
|
+
constructor(totalSteps) {
|
|
7
|
+
this.totalSteps = totalSteps;
|
|
8
|
+
this.currentStep = 0;
|
|
9
|
+
this.spinner = null;
|
|
10
|
+
this.startTime = Date.now();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
start(message) {
|
|
14
|
+
this.spinner = ora({
|
|
15
|
+
text: this.formatMessage(message),
|
|
16
|
+
spinner: 'dots'
|
|
17
|
+
}).start();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
update(message) {
|
|
21
|
+
this.currentStep++;
|
|
22
|
+
if (this.spinner) {
|
|
23
|
+
this.spinner.text = this.formatMessage(message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
succeed(message) {
|
|
28
|
+
if (this.spinner) {
|
|
29
|
+
this.spinner.succeed(this.formatMessage(message || 'Complete'));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fail(message) {
|
|
34
|
+
if (this.spinner) {
|
|
35
|
+
this.spinner.fail(chalk.red(message));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
warn(message) {
|
|
40
|
+
if (this.spinner) {
|
|
41
|
+
this.spinner.warn(chalk.yellow(message));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
info(message) {
|
|
46
|
+
if (this.spinner) {
|
|
47
|
+
this.spinner.info(chalk.cyan(message));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
formatMessage(message) {
|
|
52
|
+
const percentage = Math.round((this.currentStep / this.totalSteps) * 100);
|
|
53
|
+
const elapsed = this.getElapsedTime();
|
|
54
|
+
const eta = this.getETA();
|
|
55
|
+
|
|
56
|
+
return `${message} ${chalk.gray(`[${this.currentStep}/${this.totalSteps}]`)} ${chalk.cyan(`${percentage}%`)} ${chalk.gray(`• ${elapsed}s elapsed`)}${eta ? chalk.gray(` • ETA: ${eta}s`) : ''}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getElapsedTime() {
|
|
60
|
+
return ((Date.now() - this.startTime) / 1000).toFixed(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getETA() {
|
|
64
|
+
if (this.currentStep === 0) return null;
|
|
65
|
+
const elapsed = Date.now() - this.startTime;
|
|
66
|
+
const avgTimePerStep = elapsed / this.currentStep;
|
|
67
|
+
const remainingSteps = this.totalSteps - this.currentStep;
|
|
68
|
+
const eta = (avgTimePerStep * remainingSteps) / 1000;
|
|
69
|
+
return eta > 0 ? eta.toFixed(1) : null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
stop() {
|
|
73
|
+
if (this.spinner) {
|
|
74
|
+
this.spinner.stop();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = ProgressTracker;
|