devcompass 2.3.1 ā 2.4.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 +123 -27
- package/package.json +9 -4
- package/src/alerts/github-tracker.js +177 -0
- package/src/alerts/predictive.js +68 -38
- package/src/commands/analyze.js +67 -11
- package/src/commands/fix.js +13 -7
- package/src/utils/json-formatter.js +10 -1
package/README.md
CHANGED
|
@@ -1,40 +1,50 @@
|
|
|
1
|
-
cd ~/devCampuss
|
|
2
|
-
cat > README.md << 'EOF'
|
|
3
1
|
# š§ DevCompass
|
|
4
2
|
|
|
5
|
-
**Dependency health checker with ecosystem intelligence for JavaScript/TypeScript projects**
|
|
3
|
+
**Dependency health checker with ecosystem intelligence and real-time GitHub issue tracking for JavaScript/TypeScript projects**
|
|
6
4
|
|
|
7
5
|
[](https://www.npmjs.com/package/devcompass)
|
|
8
6
|
[](https://www.npmjs.com/package/devcompass)
|
|
9
7
|
[](https://opensource.org/licenses/MIT)
|
|
10
8
|
|
|
11
|
-
Analyze your JavaScript projects to find unused dependencies, outdated packages, **detect security vulnerabilities**, **check bundle sizes**, **verify licenses**, and **automatically fix issues** with a single command. Perfect for **CI/CD pipelines** with JSON output and exit codes.
|
|
9
|
+
Analyze your JavaScript projects to find unused dependencies, outdated packages, **detect security vulnerabilities**, **monitor GitHub issues in real-time**, **check bundle sizes**, **verify licenses**, and **automatically fix issues** with a single command. Perfect for **CI/CD pipelines** with JSON output and exit codes.
|
|
12
10
|
|
|
11
|
+
> **NEW in v2.4.0:** Real-time GitHub issue tracking & predictive warnings! š®
|
|
13
12
|
> **NEW in v2.3.1:** Fixed all security vulnerabilities! Health score: 2.5/10 ā 8/10 š
|
|
14
13
|
> **NEW in v2.3:** Security scanning, bundle analysis & license checker! š
|
|
15
14
|
> **NEW in v2.2:** CI/CD integration with JSON output & smart caching! š
|
|
16
15
|
> **NEW in v2.1:** Auto-fix command! š§ Fix critical issues automatically!
|
|
17
16
|
> **NEW in v2.0:** Real-time ecosystem alerts for known issues! šØ
|
|
18
17
|
|
|
19
|
-
## š Latest Update: v2.
|
|
18
|
+
## š Latest Update: v2.4.0
|
|
20
19
|
|
|
21
|
-
**
|
|
20
|
+
**Real-time GitHub issue tracking is here!** DevCompass now monitors live GitHub activity for 14+ popular packages:
|
|
22
21
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
22
|
+
- š® **Predictive warnings** based on recent bug activity
|
|
23
|
+
- š **Risk scoring** (high/medium/low severity)
|
|
24
|
+
- š **Trend analysis** (increasing/stable/decreasing)
|
|
25
|
+
- ā” **93% faster** with smart caching (8s ā 0.5s)
|
|
26
|
+
- š **Direct links** to GitHub repositories
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
**Example warning:**
|
|
29
|
+
```
|
|
30
|
+
š® PREDICTIVE WARNINGS (1)
|
|
31
|
+
|
|
32
|
+
š” express
|
|
33
|
+
Increased issue activity
|
|
34
|
+
15 new issues in last 7 days
|
|
35
|
+
ā Monitor for stability
|
|
36
|
+
GitHub: https://github.com/expressjs/express
|
|
37
|
+
```
|
|
30
38
|
|
|
31
39
|
## ⨠Features
|
|
32
40
|
|
|
41
|
+
- š® **GitHub Issue Tracking** (v2.4) - Real-time monitoring of package health
|
|
42
|
+
- š **Predictive Warnings** (v2.4) - Detect issues before they're announced
|
|
33
43
|
- š **Security Scanning** (v2.3) - npm audit integration with severity breakdown
|
|
34
44
|
- š¦ **Bundle Size Analysis** (v2.3) - Identify heavy packages (> 1MB)
|
|
35
45
|
- āļø **License Checker** (v2.3) - Detect restrictive licenses (GPL, AGPL)
|
|
36
46
|
- š **CI/CD Integration** (v2.2) - JSON output, exit codes, and silent mode
|
|
37
|
-
- ā” **Smart Caching** (v2.2) -
|
|
47
|
+
- ā” **Smart Caching** (v2.2) - 93% faster on repeated runs
|
|
38
48
|
- šļø **Advanced Filtering** (v2.2) - Control alerts by severity level
|
|
39
49
|
- š§ **Auto-Fix Command** (v2.1) - Fix issues automatically with one command
|
|
40
50
|
- šØ **Ecosystem Intelligence** (v2.0) - Detect known issues before they break production
|
|
@@ -80,6 +90,55 @@ devcompass analyze --ci
|
|
|
80
90
|
devcompass analyze --silent
|
|
81
91
|
```
|
|
82
92
|
|
|
93
|
+
## š® Predictive Warnings (v2.4.0)
|
|
94
|
+
|
|
95
|
+
DevCompass now monitors **real-time GitHub activity** to detect potential issues before they're officially reported!
|
|
96
|
+
|
|
97
|
+
### What it tracks:
|
|
98
|
+
- š **Open bug reports** in the last 7/30 days
|
|
99
|
+
- š„ **High-activity packages** with unusual issue spikes
|
|
100
|
+
- š **Trend analysis** (increasing/stable/decreasing)
|
|
101
|
+
- ā ļø **Critical issues** flagged by maintainers
|
|
102
|
+
|
|
103
|
+
### Currently tracked packages (14+):
|
|
104
|
+
- **axios**, **lodash**, **moment**, **express**
|
|
105
|
+
- **react**, **vue**, **next**, **webpack**
|
|
106
|
+
- **typescript**, **eslint**, **jest**, **prettier**
|
|
107
|
+
- **node-fetch**, **chalk**
|
|
108
|
+
|
|
109
|
+
### Example Output:
|
|
110
|
+
```
|
|
111
|
+
š® PREDICTIVE WARNINGS (2)
|
|
112
|
+
|
|
113
|
+
Based on recent GitHub activity:
|
|
114
|
+
|
|
115
|
+
š axios
|
|
116
|
+
High bug activity detected
|
|
117
|
+
15 new issues in last 7 days
|
|
118
|
+
ā Consider delaying upgrade or monitoring closely
|
|
119
|
+
GitHub: https://github.com/axios/axios
|
|
120
|
+
|
|
121
|
+
š” webpack
|
|
122
|
+
Increased issue activity
|
|
123
|
+
8 issues opened recently
|
|
124
|
+
ā Monitor for stability
|
|
125
|
+
GitHub: https://github.com/webpack/webpack
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### How it works:
|
|
129
|
+
1. Fetches live issue data from GitHub API
|
|
130
|
+
2. Analyzes issue frequency (last 7/30 days)
|
|
131
|
+
3. Detects critical issues via labels
|
|
132
|
+
4. Calculates risk scores
|
|
133
|
+
5. Provides actionable recommendations
|
|
134
|
+
|
|
135
|
+
### Performance:
|
|
136
|
+
- **First run:** ~8 seconds (fetches GitHub data for 14 packages)
|
|
137
|
+
- **Cached runs:** ~0.5 seconds (93% faster!)
|
|
138
|
+
- **Cache duration:** 1 hour
|
|
139
|
+
|
|
140
|
+
> More packages being added in v2.5.0 (expanding to top 500)!
|
|
141
|
+
|
|
83
142
|
## š Security & Compliance Features
|
|
84
143
|
|
|
85
144
|
### Security Vulnerability Scanning
|
|
@@ -160,7 +219,7 @@ Detect restrictive licenses that may require legal review!
|
|
|
160
219
|
|
|
161
220
|
**Full Output:**
|
|
162
221
|
```
|
|
163
|
-
š DevCompass v2.
|
|
222
|
+
š DevCompass v2.4.0 - Analyzing your project...
|
|
164
223
|
ā Scanned 25 dependencies in project
|
|
165
224
|
|
|
166
225
|
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
@@ -180,6 +239,18 @@ Detect restrictive licenses that may require legal review!
|
|
|
180
239
|
|
|
181
240
|
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
182
241
|
|
|
242
|
+
š® PREDICTIVE WARNINGS (1)
|
|
243
|
+
|
|
244
|
+
Based on recent GitHub activity:
|
|
245
|
+
|
|
246
|
+
š” express
|
|
247
|
+
Increased issue activity
|
|
248
|
+
8 issues opened recently
|
|
249
|
+
ā Monitor for stability
|
|
250
|
+
GitHub: https://github.com/expressjs/express
|
|
251
|
+
|
|
252
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
253
|
+
|
|
183
254
|
š¦ HEAVY PACKAGES (2)
|
|
184
255
|
|
|
185
256
|
Packages larger than 1MB:
|
|
@@ -200,6 +271,7 @@ Detect restrictive licenses that may require legal review!
|
|
|
200
271
|
Overall Score: 8.5/10
|
|
201
272
|
Total Dependencies: 25
|
|
202
273
|
Ecosystem Alerts: 1
|
|
274
|
+
Predictive Warnings: 1
|
|
203
275
|
Unused: 0
|
|
204
276
|
Outdated: 2
|
|
205
277
|
|
|
@@ -229,13 +301,14 @@ devcompass analyze --json
|
|
|
229
301
|
**Output:**
|
|
230
302
|
```json
|
|
231
303
|
{
|
|
232
|
-
"version": "2.
|
|
233
|
-
"timestamp": "2026-04-
|
|
304
|
+
"version": "2.4.0",
|
|
305
|
+
"timestamp": "2026-04-04T10:30:00.000Z",
|
|
234
306
|
"summary": {
|
|
235
307
|
"healthScore": 8.5,
|
|
236
308
|
"totalDependencies": 25,
|
|
237
309
|
"securityVulnerabilities": 0,
|
|
238
310
|
"ecosystemAlerts": 1,
|
|
311
|
+
"predictiveWarnings": 1,
|
|
239
312
|
"unusedDependencies": 0,
|
|
240
313
|
"outdatedPackages": 2,
|
|
241
314
|
"heavyPackages": 2,
|
|
@@ -249,6 +322,21 @@ devcompass analyze --json
|
|
|
249
322
|
"low": 0,
|
|
250
323
|
"vulnerabilities": []
|
|
251
324
|
},
|
|
325
|
+
"predictiveWarnings": [
|
|
326
|
+
{
|
|
327
|
+
"package": "express",
|
|
328
|
+
"severity": "medium",
|
|
329
|
+
"title": "Increased issue activity",
|
|
330
|
+
"description": "8 issues opened recently",
|
|
331
|
+
"recommendation": "Monitor for stability",
|
|
332
|
+
"githubData": {
|
|
333
|
+
"totalIssues": 234,
|
|
334
|
+
"recentIssues": 8,
|
|
335
|
+
"trend": "increasing",
|
|
336
|
+
"repoUrl": "https://github.com/expressjs/express"
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
],
|
|
252
340
|
"bundleAnalysis": {
|
|
253
341
|
"heavyPackages": [
|
|
254
342
|
{ "name": "typescript", "size": "8.1 MB" },
|
|
@@ -300,12 +388,14 @@ echo $? # Check exit code
|
|
|
300
388
|
|
|
301
389
|
DevCompass caches results to improve performance:
|
|
302
390
|
|
|
303
|
-
- **First run:**
|
|
304
|
-
- **Cached runs:** ~
|
|
391
|
+
- **First run:** ~8 seconds (fetches GitHub + npm data)
|
|
392
|
+
- **Cached runs:** ~0.5 seconds (93% faster!)
|
|
305
393
|
- **Cache duration:** 1 hour
|
|
306
394
|
- **Cache file:** `.devcompass-cache.json` (auto-gitignored)
|
|
307
395
|
|
|
308
396
|
**What gets cached:**
|
|
397
|
+
- GitHub issue data (NEW in v2.4.0)
|
|
398
|
+
- Predictive warnings (NEW in v2.4.0)
|
|
309
399
|
- Security vulnerabilities
|
|
310
400
|
- Ecosystem alerts
|
|
311
401
|
- Unused dependencies
|
|
@@ -385,6 +475,7 @@ DevCompass can **automatically fix issues** in your project!
|
|
|
385
475
|
- š§¹ **Removes unused dependencies** - Cleans up packages you're not using
|
|
386
476
|
- ā¬ļø **Safe updates** - Applies patch and minor updates automatically
|
|
387
477
|
- ā ļø **Skips breaking changes** - Major updates require manual review
|
|
478
|
+
- š **Clears cache** - Ensures fresh analysis after fixes (NEW in v2.4.0)
|
|
388
479
|
|
|
389
480
|
### Usage
|
|
390
481
|
```bash
|
|
@@ -404,6 +495,7 @@ devcompass fix --path /path/to/project
|
|
|
404
495
|
- ā
Requires confirmation (unless `--yes` flag used)
|
|
405
496
|
- ā
Skips major updates (may have breaking changes)
|
|
406
497
|
- ā
Groups actions by priority (critical ā cleanup ā updates)
|
|
498
|
+
- ā
Clears cache after fixes (NEW in v2.4.0)
|
|
407
499
|
- ā
Provides clear summary of changes
|
|
408
500
|
|
|
409
501
|
### Workflow Example
|
|
@@ -618,6 +710,8 @@ If you encounter a false positive, please [report it](https://github.com/AjayBTh
|
|
|
618
710
|
8. **Use JSON output** - Integrate with your monitoring tools
|
|
619
711
|
9. **Review major updates** - Always check changelogs before major version bumps
|
|
620
712
|
10. **Verify before uninstalling** - DevCompass helps identify candidates, but always verify
|
|
713
|
+
11. **Watch predictive warnings** - Monitor packages with increasing issue activity (NEW)
|
|
714
|
+
12. **Cache for speed** - First run takes ~8s, cached runs ~0.5s (NEW)
|
|
621
715
|
|
|
622
716
|
## š¤ Contributing
|
|
623
717
|
|
|
@@ -710,13 +804,16 @@ Check out DevCompass stats:
|
|
|
710
804
|
- [x] ~~Bundle size analysis~~ ā
**Added in v2.3!**
|
|
711
805
|
- [x] ~~License compliance checker~~ ā
**Added in v2.3!**
|
|
712
806
|
- [x] ~~Fix all security vulnerabilities~~ ā
**Fixed in v2.3.1!**
|
|
713
|
-
- [
|
|
714
|
-
- [
|
|
715
|
-
- [ ]
|
|
716
|
-
- [ ]
|
|
717
|
-
- [ ]
|
|
718
|
-
- [ ]
|
|
719
|
-
- [ ]
|
|
807
|
+
- [x] ~~GitHub Issues API for real-time issue tracking~~ ā
**Added in v2.4.0!**
|
|
808
|
+
- [x] ~~Predictive warnings based on bug activity~~ ā
**Added in v2.4.0!**
|
|
809
|
+
- [ ] Expand to top 500 npm packages (v2.5.0)
|
|
810
|
+
- [ ] Performance optimizations (v2.6.0)
|
|
811
|
+
- [ ] Advanced security features with Snyk (v2.7.0)
|
|
812
|
+
- [ ] Enhanced fix command improvements (v2.8.0)
|
|
813
|
+
- [ ] Dependency graph visualization (v3.0.0)
|
|
814
|
+
- [ ] Web dashboard for team health monitoring (v3.0.0)
|
|
815
|
+
- [ ] Team collaboration features (v3.1.0)
|
|
816
|
+
- [ ] Slack/Discord notifications (v3.1.0)
|
|
720
817
|
|
|
721
818
|
Want to contribute? Pick an item and open an issue! š
|
|
722
819
|
|
|
@@ -726,5 +823,4 @@ Want to contribute? Pick an item and open an issue! š
|
|
|
726
823
|
|
|
727
824
|
*DevCompass - Keep your dependencies healthy!* š§
|
|
728
825
|
|
|
729
|
-
**Like Lighthouse for your dependencies** ā”
|
|
730
|
-
EOF
|
|
826
|
+
**Like Lighthouse for your dependencies** ā”
|
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 for JavaScript/TypeScript projects",
|
|
3
|
+
"version": "2.4.0",
|
|
4
|
+
"description": "Dependency health checker with ecosystem intelligence and real-time GitHub issue tracking for JavaScript/TypeScript projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"devcompass": "./bin/devcompass.js"
|
|
@@ -36,7 +36,12 @@
|
|
|
36
36
|
"json-output",
|
|
37
37
|
"npm-audit",
|
|
38
38
|
"bundle-size",
|
|
39
|
-
"license-checker"
|
|
39
|
+
"license-checker",
|
|
40
|
+
"github-issues",
|
|
41
|
+
"predictive-warnings",
|
|
42
|
+
"risk-detection",
|
|
43
|
+
"dependency-monitoring",
|
|
44
|
+
"issue-tracking"
|
|
40
45
|
],
|
|
41
46
|
"author": "Ajay Thorat <ajaythorat988@gmail.com>",
|
|
42
47
|
"license": "MIT",
|
|
@@ -59,4 +64,4 @@
|
|
|
59
64
|
"url": "https://github.com/AjayBThorat-20/devcompass/issues"
|
|
60
65
|
},
|
|
61
66
|
"homepage": "https://github.com/AjayBThorat-20/devcompass#readme"
|
|
62
|
-
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// src/alerts/github-tracker.js
|
|
2
|
+
const https = require('https');
|
|
3
|
+
|
|
4
|
+
// GitHub repos we track (you can expand this)
|
|
5
|
+
const TRACKED_REPOS = {
|
|
6
|
+
'axios': 'axios/axios',
|
|
7
|
+
'lodash': 'lodash/lodash',
|
|
8
|
+
'moment': 'moment/moment',
|
|
9
|
+
'express': 'expressjs/express',
|
|
10
|
+
'react': 'facebook/react',
|
|
11
|
+
'vue': 'vuejs/core',
|
|
12
|
+
'next': 'vercel/next.js',
|
|
13
|
+
'webpack': 'webpack/webpack',
|
|
14
|
+
'typescript': 'microsoft/TypeScript',
|
|
15
|
+
'eslint': 'eslint/eslint',
|
|
16
|
+
'jest': 'jestjs/jest',
|
|
17
|
+
'prettier': 'prettier/prettier',
|
|
18
|
+
'node-fetch': 'node-fetch/node-fetch',
|
|
19
|
+
'chalk': 'chalk/chalk'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fetch GitHub issues for a package
|
|
24
|
+
*/
|
|
25
|
+
async function fetchGitHubIssues(packageName) {
|
|
26
|
+
const repo = TRACKED_REPOS[packageName];
|
|
27
|
+
|
|
28
|
+
if (!repo) {
|
|
29
|
+
return null; // Not tracked
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const data = await makeGitHubRequest(`/repos/${repo}/issues`, {
|
|
34
|
+
state: 'open',
|
|
35
|
+
per_page: 100,
|
|
36
|
+
labels: 'bug'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return analyzeIssues(data, packageName);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(`GitHub API error for ${packageName}:`, error.message);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Make GitHub API request
|
|
48
|
+
*/
|
|
49
|
+
function makeGitHubRequest(path, params = {}) {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const queryString = Object.entries(params)
|
|
52
|
+
.map(([key, val]) => `${key}=${encodeURIComponent(val)}`)
|
|
53
|
+
.join('&');
|
|
54
|
+
|
|
55
|
+
const options = {
|
|
56
|
+
hostname: 'api.github.com',
|
|
57
|
+
path: `${path}?${queryString}`,
|
|
58
|
+
method: 'GET',
|
|
59
|
+
headers: {
|
|
60
|
+
'User-Agent': 'DevCompass',
|
|
61
|
+
'Accept': 'application/vnd.github.v3+json'
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const req = https.request(options, (res) => {
|
|
66
|
+
let data = '';
|
|
67
|
+
|
|
68
|
+
res.on('data', (chunk) => {
|
|
69
|
+
data += chunk;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
res.on('end', () => {
|
|
73
|
+
if (res.statusCode === 200) {
|
|
74
|
+
try {
|
|
75
|
+
resolve(JSON.parse(data));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
reject(new Error('Failed to parse GitHub response'));
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
reject(new Error(`GitHub API returned ${res.statusCode}`));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
req.on('error', reject);
|
|
86
|
+
req.end();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Analyze issues to detect trends
|
|
92
|
+
*/
|
|
93
|
+
function analyzeIssues(issues, packageName) {
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
const day = 24 * 60 * 60 * 1000;
|
|
96
|
+
|
|
97
|
+
// Count issues by recency
|
|
98
|
+
const last7Days = issues.filter(i =>
|
|
99
|
+
(now - new Date(i.created_at).getTime()) < 7 * day
|
|
100
|
+
).length;
|
|
101
|
+
|
|
102
|
+
const last30Days = issues.filter(i =>
|
|
103
|
+
(now - new Date(i.created_at).getTime()) < 30 * day
|
|
104
|
+
).length;
|
|
105
|
+
|
|
106
|
+
// Detect critical issues (high priority labels)
|
|
107
|
+
const criticalLabels = ['critical', 'security', 'regression', 'breaking'];
|
|
108
|
+
const criticalIssues = issues.filter(issue =>
|
|
109
|
+
issue.labels.some(label =>
|
|
110
|
+
criticalLabels.some(critical =>
|
|
111
|
+
label.name.toLowerCase().includes(critical)
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// Calculate risk score
|
|
117
|
+
let riskScore = 0;
|
|
118
|
+
if (last7Days > 15) riskScore += 3;
|
|
119
|
+
else if (last7Days > 10) riskScore += 2;
|
|
120
|
+
else if (last7Days > 5) riskScore += 1;
|
|
121
|
+
|
|
122
|
+
if (criticalIssues.length > 5) riskScore += 2;
|
|
123
|
+
else if (criticalIssues.length > 2) riskScore += 1;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
package: packageName,
|
|
127
|
+
totalIssues: issues.length,
|
|
128
|
+
last7Days,
|
|
129
|
+
last30Days,
|
|
130
|
+
criticalIssues: criticalIssues.length,
|
|
131
|
+
riskScore,
|
|
132
|
+
trend: determineTrend(last7Days, last30Days),
|
|
133
|
+
repoUrl: `https://github.com/${TRACKED_REPOS[packageName]}`
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Determine trend (increasing/stable/decreasing)
|
|
139
|
+
*/
|
|
140
|
+
function determineTrend(last7Days, last30Days) {
|
|
141
|
+
const weeklyAverage = last30Days / 4;
|
|
142
|
+
|
|
143
|
+
if (last7Days > weeklyAverage * 1.5) {
|
|
144
|
+
return 'increasing';
|
|
145
|
+
} else if (last7Days < weeklyAverage * 0.5) {
|
|
146
|
+
return 'decreasing';
|
|
147
|
+
} else {
|
|
148
|
+
return 'stable';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Check GitHub issues for multiple packages
|
|
154
|
+
*/
|
|
155
|
+
async function checkGitHubIssues(packages) {
|
|
156
|
+
const results = [];
|
|
157
|
+
|
|
158
|
+
// Process in batches to avoid rate limits
|
|
159
|
+
for (const packageName of packages) {
|
|
160
|
+
const result = await fetchGitHubIssues(packageName);
|
|
161
|
+
|
|
162
|
+
if (result) {
|
|
163
|
+
results.push(result);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Rate limit: wait 1 second between requests
|
|
167
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
checkGitHubIssues,
|
|
175
|
+
fetchGitHubIssues,
|
|
176
|
+
TRACKED_REPOS
|
|
177
|
+
};
|
package/src/alerts/predictive.js
CHANGED
|
@@ -1,54 +1,84 @@
|
|
|
1
1
|
// src/alerts/predictive.js
|
|
2
|
+
const { checkGitHubIssues } = require('./github-tracker');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
* NOTE: This is a simplified version without GitHub API
|
|
6
|
-
* For production, integrate with GitHub Issues API
|
|
5
|
+
* Generate predictive warnings based on GitHub activity
|
|
7
6
|
*/
|
|
8
|
-
async function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
async function generatePredictiveWarnings(packages) {
|
|
8
|
+
try {
|
|
9
|
+
const packageNames = Object.keys(packages);
|
|
10
|
+
const githubData = await checkGitHubIssues(packageNames);
|
|
11
|
+
|
|
12
|
+
const warnings = [];
|
|
13
|
+
|
|
14
|
+
for (const data of githubData) {
|
|
15
|
+
// High risk: many recent issues
|
|
16
|
+
if (data.riskScore >= 3) {
|
|
17
|
+
warnings.push({
|
|
18
|
+
package: data.package,
|
|
19
|
+
severity: 'high',
|
|
20
|
+
type: 'predictive',
|
|
21
|
+
title: 'High bug activity detected',
|
|
22
|
+
description: `${data.last7Days} new issues in last 7 days`,
|
|
23
|
+
recommendation: 'Consider delaying upgrade or monitoring closely',
|
|
24
|
+
data: {
|
|
25
|
+
totalIssues: data.totalIssues,
|
|
26
|
+
recentIssues: data.last7Days,
|
|
27
|
+
criticalIssues: data.criticalIssues,
|
|
28
|
+
trend: data.trend,
|
|
29
|
+
repoUrl: data.repoUrl
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Medium risk: increasing trend
|
|
35
|
+
else if (data.riskScore >= 2 || data.trend === 'increasing') {
|
|
36
|
+
warnings.push({
|
|
37
|
+
package: data.package,
|
|
38
|
+
severity: 'medium',
|
|
39
|
+
type: 'predictive',
|
|
40
|
+
title: 'Increased issue activity',
|
|
41
|
+
description: `${data.last7Days} issues opened recently`,
|
|
42
|
+
recommendation: 'Monitor for stability',
|
|
43
|
+
data: {
|
|
44
|
+
totalIssues: data.totalIssues,
|
|
45
|
+
recentIssues: data.last7Days,
|
|
46
|
+
trend: data.trend,
|
|
47
|
+
repoUrl: data.repoUrl
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return warnings;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Error generating predictive warnings:', error.message);
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
18
58
|
}
|
|
19
59
|
|
|
20
60
|
/**
|
|
21
|
-
* Calculate risk score
|
|
61
|
+
* Calculate risk score for a package
|
|
22
62
|
*/
|
|
23
|
-
function calculateRiskScore(
|
|
24
|
-
let
|
|
63
|
+
function calculateRiskScore(githubData) {
|
|
64
|
+
let score = 0;
|
|
25
65
|
|
|
26
|
-
// High
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
risk += 2;
|
|
31
|
-
} else if (trends.recentIssues > 5) {
|
|
32
|
-
risk += 1;
|
|
33
|
-
}
|
|
66
|
+
// High recent activity
|
|
67
|
+
if (githubData.last7Days > 20) score += 3;
|
|
68
|
+
else if (githubData.last7Days > 10) score += 2;
|
|
69
|
+
else if (githubData.last7Days > 5) score += 1;
|
|
34
70
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Generate predictive warnings
|
|
40
|
-
*/
|
|
41
|
-
function generatePredictiveWarnings(packages) {
|
|
42
|
-
const warnings = [];
|
|
71
|
+
// Critical issues
|
|
72
|
+
if (githubData.criticalIssues > 5) score += 2;
|
|
73
|
+
else if (githubData.criticalIssues > 2) score += 1;
|
|
43
74
|
|
|
44
|
-
//
|
|
45
|
-
|
|
75
|
+
// Trend
|
|
76
|
+
if (githubData.trend === 'increasing') score += 1;
|
|
46
77
|
|
|
47
|
-
return
|
|
78
|
+
return score;
|
|
48
79
|
}
|
|
49
80
|
|
|
50
81
|
module.exports = {
|
|
51
|
-
|
|
52
|
-
calculateRiskScore
|
|
53
|
-
generatePredictiveWarnings
|
|
82
|
+
generatePredictiveWarnings,
|
|
83
|
+
calculateRiskScore
|
|
54
84
|
};
|
package/src/commands/analyze.js
CHANGED
|
@@ -161,7 +161,7 @@ async function analyze(options) {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// Check security vulnerabilities
|
|
164
|
+
// Check security vulnerabilities
|
|
165
165
|
spinner.text = 'Checking security vulnerabilities...';
|
|
166
166
|
let securityData = { vulnerabilities: [], metadata: { total: 0, critical: 0, high: 0, moderate: 0, low: 0 } };
|
|
167
167
|
|
|
@@ -184,7 +184,32 @@ async function analyze(options) {
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
//
|
|
187
|
+
// Check for predictive warnings (GitHub Issues) - NEW
|
|
188
|
+
spinner.text = 'Checking GitHub activity...';
|
|
189
|
+
let predictiveWarnings = [];
|
|
190
|
+
|
|
191
|
+
if (config.cache) {
|
|
192
|
+
predictiveWarnings = getCached(projectPath, 'predictive');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!predictiveWarnings) {
|
|
196
|
+
try {
|
|
197
|
+
const { generatePredictiveWarnings } = require('../alerts/predictive');
|
|
198
|
+
predictiveWarnings = await generatePredictiveWarnings(dependencies);
|
|
199
|
+
|
|
200
|
+
if (config.cache && predictiveWarnings.length > 0) {
|
|
201
|
+
setCache(projectPath, 'predictive', predictiveWarnings);
|
|
202
|
+
}
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (outputMode !== 'silent') {
|
|
205
|
+
console.log(chalk.yellow('\nā ļø Could not check GitHub activity'));
|
|
206
|
+
console.log(chalk.gray(` Error: ${error.message}\n`));
|
|
207
|
+
}
|
|
208
|
+
predictiveWarnings = [];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Analyze bundle sizes
|
|
188
213
|
spinner.text = 'Analyzing bundle sizes...';
|
|
189
214
|
let bundleSizes = [];
|
|
190
215
|
|
|
@@ -204,7 +229,7 @@ async function analyze(options) {
|
|
|
204
229
|
}
|
|
205
230
|
}
|
|
206
231
|
|
|
207
|
-
// Check licenses
|
|
232
|
+
// Check licenses
|
|
208
233
|
spinner.text = 'Checking licenses...';
|
|
209
234
|
let licenses = [];
|
|
210
235
|
|
|
@@ -224,7 +249,7 @@ async function analyze(options) {
|
|
|
224
249
|
}
|
|
225
250
|
}
|
|
226
251
|
|
|
227
|
-
// Calculate score
|
|
252
|
+
// Calculate score
|
|
228
253
|
const alertPenalty = calculateAlertPenalty(alerts);
|
|
229
254
|
const securityPenalty = calculateSecurityPenalty(securityData.metadata);
|
|
230
255
|
|
|
@@ -241,15 +266,15 @@ async function analyze(options) {
|
|
|
241
266
|
|
|
242
267
|
// Handle different output modes
|
|
243
268
|
if (outputMode === 'json') {
|
|
244
|
-
const jsonOutput = formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses);
|
|
269
|
+
const jsonOutput = formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses, predictiveWarnings);
|
|
245
270
|
console.log(jsonOutput);
|
|
246
271
|
} else if (outputMode === 'ci') {
|
|
247
|
-
displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses);
|
|
272
|
+
displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses, predictiveWarnings);
|
|
248
273
|
handleCiMode(score, config, alerts, unusedDeps);
|
|
249
274
|
} else if (outputMode === 'silent') {
|
|
250
275
|
// Silent mode - no output
|
|
251
276
|
} else {
|
|
252
|
-
displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses);
|
|
277
|
+
displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses, predictiveWarnings);
|
|
253
278
|
}
|
|
254
279
|
|
|
255
280
|
} catch (error) {
|
|
@@ -262,10 +287,10 @@ async function analyze(options) {
|
|
|
262
287
|
}
|
|
263
288
|
}
|
|
264
289
|
|
|
265
|
-
function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses) {
|
|
290
|
+
function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses, predictiveWarnings) {
|
|
266
291
|
logDivider();
|
|
267
292
|
|
|
268
|
-
// SECURITY VULNERABILITIES
|
|
293
|
+
// SECURITY VULNERABILITIES
|
|
269
294
|
if (securityData.metadata.total > 0) {
|
|
270
295
|
const criticalCount = securityData.metadata.critical;
|
|
271
296
|
const highCount = securityData.metadata.high;
|
|
@@ -335,6 +360,33 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, secu
|
|
|
335
360
|
|
|
336
361
|
logDivider();
|
|
337
362
|
|
|
363
|
+
// PREDICTIVE WARNINGS (NEW SECTION)
|
|
364
|
+
if (predictiveWarnings.length > 0) {
|
|
365
|
+
logSection('š® PREDICTIVE WARNINGS', predictiveWarnings.length);
|
|
366
|
+
|
|
367
|
+
log(chalk.gray(' Based on recent GitHub activity:\n'));
|
|
368
|
+
|
|
369
|
+
predictiveWarnings.forEach(warning => {
|
|
370
|
+
const display = getSeverityDisplay(warning.severity);
|
|
371
|
+
|
|
372
|
+
log(`${display.emoji} ${display.color(warning.package)}`);
|
|
373
|
+
log(` ${chalk.yellow(warning.title)}`);
|
|
374
|
+
log(` ${warning.description}`);
|
|
375
|
+
log(` ${chalk.cyan('ā')} ${warning.recommendation}`);
|
|
376
|
+
|
|
377
|
+
if (warning.data && warning.data.repoUrl) {
|
|
378
|
+
log(chalk.gray(` GitHub: ${warning.data.repoUrl}`));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
log('');
|
|
382
|
+
});
|
|
383
|
+
} else {
|
|
384
|
+
logSection('ā
PREDICTIVE ANALYSIS');
|
|
385
|
+
log(chalk.green(' No unusual activity detected!\n'));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
logDivider();
|
|
389
|
+
|
|
338
390
|
// UNUSED DEPENDENCIES
|
|
339
391
|
if (unusedDeps.length > 0) {
|
|
340
392
|
logSection('š“ UNUSED DEPENDENCIES', unusedDeps.length);
|
|
@@ -376,7 +428,7 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, secu
|
|
|
376
428
|
|
|
377
429
|
logDivider();
|
|
378
430
|
|
|
379
|
-
// BUNDLE SIZE
|
|
431
|
+
// BUNDLE SIZE
|
|
380
432
|
const heavyPackages = findHeavyPackages(bundleSizes);
|
|
381
433
|
if (heavyPackages.length > 0) {
|
|
382
434
|
logSection('š¦ HEAVY PACKAGES', heavyPackages.length);
|
|
@@ -396,7 +448,7 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, secu
|
|
|
396
448
|
logDivider();
|
|
397
449
|
}
|
|
398
450
|
|
|
399
|
-
// LICENSE WARNINGS
|
|
451
|
+
// LICENSE WARNINGS
|
|
400
452
|
const problematicLicenses = findProblematicLicenses(licenses);
|
|
401
453
|
if (problematicLicenses.length > 0) {
|
|
402
454
|
logSection('āļø LICENSE WARNINGS', problematicLicenses.length);
|
|
@@ -431,6 +483,10 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, secu
|
|
|
431
483
|
log(` Ecosystem Alerts: ${chalk.red(alerts.length)}`);
|
|
432
484
|
}
|
|
433
485
|
|
|
486
|
+
if (predictiveWarnings.length > 0) {
|
|
487
|
+
log(` Predictive Warnings: ${chalk.yellow(predictiveWarnings.length)}`);
|
|
488
|
+
}
|
|
489
|
+
|
|
434
490
|
log(` Unused: ${chalk.red(unusedDeps.length)}`);
|
|
435
491
|
log(` Outdated: ${chalk.yellow(outdatedDeps.length)}\n`);
|
|
436
492
|
|
package/src/commands/fix.js
CHANGED
|
@@ -3,11 +3,13 @@ const chalk = require('chalk');
|
|
|
3
3
|
const ora = require('ora');
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
5
|
const readline = require('readline');
|
|
6
|
+
const path = require('path');
|
|
6
7
|
|
|
7
8
|
const { findUnusedDeps } = require('../analyzers/unused-deps');
|
|
8
9
|
const { findOutdatedDeps } = require('../analyzers/outdated');
|
|
9
10
|
const { checkEcosystemAlerts } = require('../alerts');
|
|
10
11
|
const { getSeverityDisplay } = require('../alerts/formatter');
|
|
12
|
+
const { clearCache } = require('../cache/manager');
|
|
11
13
|
|
|
12
14
|
async function fix(options) {
|
|
13
15
|
const projectPath = options.path || process.cwd();
|
|
@@ -22,7 +24,6 @@ async function fix(options) {
|
|
|
22
24
|
|
|
23
25
|
try {
|
|
24
26
|
const fs = require('fs');
|
|
25
|
-
const path = require('path');
|
|
26
27
|
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
27
28
|
|
|
28
29
|
if (!fs.existsSync(packageJsonPath)) {
|
|
@@ -52,7 +53,7 @@ async function fix(options) {
|
|
|
52
53
|
spinner.succeed(chalk.green('Analysis complete!\n'));
|
|
53
54
|
|
|
54
55
|
// Show what will be fixed
|
|
55
|
-
await showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options);
|
|
56
|
+
await showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options, projectPath);
|
|
56
57
|
|
|
57
58
|
} catch (error) {
|
|
58
59
|
spinner.fail(chalk.red('Analysis failed'));
|
|
@@ -61,7 +62,7 @@ async function fix(options) {
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
async function showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options) {
|
|
65
|
+
async function showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options, projectPath) {
|
|
65
66
|
const actions = [];
|
|
66
67
|
|
|
67
68
|
// Critical alerts
|
|
@@ -160,19 +161,19 @@ async function showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options) {
|
|
|
160
161
|
|
|
161
162
|
// Confirm
|
|
162
163
|
if (options.yes) {
|
|
163
|
-
await applyFixes(actions);
|
|
164
|
+
await applyFixes(actions, projectPath);
|
|
164
165
|
} else {
|
|
165
166
|
const confirmed = await askConfirmation('\nā Apply these fixes?');
|
|
166
167
|
|
|
167
168
|
if (confirmed) {
|
|
168
|
-
await applyFixes(actions);
|
|
169
|
+
await applyFixes(actions, projectPath);
|
|
169
170
|
} else {
|
|
170
171
|
console.log(chalk.yellow('\nā ļø Fix cancelled. No changes made.\n'));
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
async function applyFixes(actions) {
|
|
176
|
+
async function applyFixes(actions, projectPath) {
|
|
176
177
|
console.log(chalk.cyan.bold('\nš§ Applying fixes...\n'));
|
|
177
178
|
|
|
178
179
|
const spinner = ora('Processing...').start();
|
|
@@ -222,6 +223,11 @@ async function applyFixes(actions) {
|
|
|
222
223
|
console.log(chalk.green.bold('\n⨠All fixes applied successfully!\n'));
|
|
223
224
|
console.log(chalk.cyan('š” Run') + chalk.bold(' devcompass analyze ') + chalk.cyan('to see the new health score.\n'));
|
|
224
225
|
|
|
226
|
+
// Clear cache after fixes - ADDED
|
|
227
|
+
spinner.text = 'Clearing cache...';
|
|
228
|
+
clearCache(projectPath);
|
|
229
|
+
spinner.succeed(chalk.gray('Cache cleared'));
|
|
230
|
+
|
|
225
231
|
} catch (error) {
|
|
226
232
|
spinner.fail(chalk.red('Fix failed'));
|
|
227
233
|
console.log(chalk.red(`\nā Error: ${error.message}\n`));
|
|
@@ -244,4 +250,4 @@ function askConfirmation(question) {
|
|
|
244
250
|
});
|
|
245
251
|
}
|
|
246
252
|
|
|
247
|
-
module.exports = { fix };
|
|
253
|
+
module.exports = { fix };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Format analysis results as JSON
|
|
5
5
|
*/
|
|
6
|
-
function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses) {
|
|
6
|
+
function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses, predictiveWarnings = []) {
|
|
7
7
|
const problematicLicenses = licenses.filter(l => l.type === 'restrictive' || l.type === 'unknown');
|
|
8
8
|
const heavyPackages = bundleSizes.filter(p => p.size > 1024);
|
|
9
9
|
|
|
@@ -15,6 +15,7 @@ function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securi
|
|
|
15
15
|
totalDependencies: totalDeps,
|
|
16
16
|
securityVulnerabilities: securityData.metadata.total,
|
|
17
17
|
ecosystemAlerts: alerts.length,
|
|
18
|
+
predictiveWarnings: predictiveWarnings.length,
|
|
18
19
|
unusedDependencies: unusedDeps.length,
|
|
19
20
|
outdatedPackages: outdatedDeps.length,
|
|
20
21
|
heavyPackages: heavyPackages.length,
|
|
@@ -44,6 +45,14 @@ function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securi
|
|
|
44
45
|
source: alert.source,
|
|
45
46
|
reported: alert.reported
|
|
46
47
|
})),
|
|
48
|
+
predictiveWarnings: predictiveWarnings.map(warning => ({
|
|
49
|
+
package: warning.package,
|
|
50
|
+
severity: warning.severity,
|
|
51
|
+
title: warning.title,
|
|
52
|
+
description: warning.description,
|
|
53
|
+
recommendation: warning.recommendation,
|
|
54
|
+
githubData: warning.data
|
|
55
|
+
})),
|
|
47
56
|
unusedDependencies: unusedDeps.map(dep => ({
|
|
48
57
|
name: dep.name
|
|
49
58
|
})),
|