devcompass 2.2.0 → 2.3.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 CHANGED
@@ -6,22 +6,24 @@
6
6
  [![npm downloads](https://img.shields.io/npm/dm/devcompass.svg)](https://www.npmjs.com/package/devcompass)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
- Analyze your JavaScript projects to find unused dependencies, outdated packages, **detect known security issues**, and **automatically fix them** 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**, **check bundle sizes**, **verify licenses**, and **automatically fix issues** with a single command. Perfect for **CI/CD pipelines** with JSON output and exit codes.
10
10
 
11
+ > **NEW in v2.3:** Security scanning, bundle analysis & license checker! 🔐
11
12
  > **NEW in v2.2:** CI/CD integration with JSON output & smart caching! 🚀
12
13
  > **NEW in v2.1:** Auto-fix command! 🔧 Fix critical issues automatically!
13
14
  > **NEW in v2.0:** Real-time ecosystem alerts for known issues! 🚨
14
15
 
15
16
  ## ✨ Features
16
17
 
17
- - 🚀 **CI/CD Integration** (NEW in v2.2!) - JSON output, exit codes, and silent mode
18
- - **Smart Caching** (NEW in v2.2!) - 70% faster on repeated runs
19
- - 🎛️ **Advanced Filtering** (NEW in v2.2!) - Control alerts by severity level
18
+ - 🔐 **Security Scanning** (NEW in v2.3!) - npm audit integration with severity breakdown
19
+ - 📦 **Bundle Size Analysis** (NEW in v2.3!) - Identify heavy packages (> 1MB)
20
+ - ⚖️ **License Checker** (NEW in v2.3!) - Detect restrictive licenses (GPL, AGPL)
21
+ - 🚀 **CI/CD Integration** (v2.2) - JSON output, exit codes, and silent mode
22
+ - ⚡ **Smart Caching** (v2.2) - 70% faster on repeated runs
23
+ - 🎛️ **Advanced Filtering** (v2.2) - Control alerts by severity level
20
24
  - 🔧 **Auto-Fix Command** (v2.1) - Fix issues automatically with one command
21
25
  - 🚨 **Ecosystem Intelligence** (v2.0) - Detect known issues before they break production
22
26
  - 🔍 **Detect unused dependencies** - Find packages you're not actually using
23
- - 📦 **Check for outdated packages** - See what needs updating
24
- - 🔐 **Security alerts** - Critical vulnerabilities and deprecated packages
25
27
  - 📊 **Project health score** - Get a 0-10 rating for your dependencies
26
28
  - 🎨 **Beautiful terminal UI** - Colored output with severity indicators
27
29
  - 🔧 **Framework-aware** - Handles React, Next.js, Angular, NestJS, PostCSS, Tailwind
@@ -63,7 +65,155 @@ devcompass analyze --ci
63
65
  devcompass analyze --silent
64
66
  ```
65
67
 
66
- ## 🚀 NEW in v2.2: CI/CD Integration
68
+ ## 🔐 NEW in v2.3: Security & Compliance Features
69
+
70
+ ### Security Vulnerability Scanning
71
+
72
+ DevCompass now integrates with **npm audit** to detect security vulnerabilities automatically!
73
+
74
+ **Example Output:**
75
+ ```
76
+ 🔐 SECURITY VULNERABILITIES (12)
77
+
78
+ 🔴 CRITICAL: 2
79
+ 🟠 HIGH: 4
80
+ 🟡 MODERATE: 5
81
+ ⚪ LOW: 1
82
+
83
+ Run npm audit fix to fix vulnerabilities
84
+ ```
85
+
86
+ **How it works:**
87
+ 1. Runs `npm audit` in the background
88
+ 2. Parses vulnerability data
89
+ 3. Shows severity breakdown
90
+ 4. Impacts health score (-2.5 per critical issue)
91
+ 5. Suggests fix commands
92
+
93
+ **Health Score Impact:**
94
+ - Critical: −2.5 points each
95
+ - High: −1.5 points each
96
+ - Moderate: −0.5 points each
97
+ - Low: −0.2 points each
98
+
99
+ ### Bundle Size Analysis
100
+
101
+ Identify large dependencies that bloat your `node_modules`!
102
+
103
+ **Example Output:**
104
+ ```
105
+ 📦 HEAVY PACKAGES (3)
106
+
107
+ Packages larger than 1MB:
108
+
109
+ webpack 2.3 MB
110
+ typescript 8.1 MB
111
+ @tensorflow/tfjs 12.4 MB
112
+ ```
113
+
114
+ **Perfect for:**
115
+ - Frontend developers optimizing bundle size
116
+ - Identifying unnecessary large dependencies
117
+ - Web performance optimization
118
+ - Docker image size reduction
119
+
120
+ ### License Compliance Checker
121
+
122
+ Detect restrictive licenses that may require legal review!
123
+
124
+ **Example Output:**
125
+ ```
126
+ ⚖️ LICENSE WARNINGS (2)
127
+
128
+ sharp - Restrictive (LGPL-3.0)
129
+ custom-lib - Unknown (UNLICENSED)
130
+
131
+ Note: Restrictive licenses may require legal review
132
+ ```
133
+
134
+ **What gets flagged:**
135
+ - **Restrictive licenses:** GPL, AGPL, LGPL (may require source code disclosure)
136
+ - **Unknown licenses:** Packages without license information
137
+ - **Unlicensed packages:** Legal risk for commercial use
138
+
139
+ **Supported licenses:**
140
+ - ✅ **Safe:** MIT, Apache-2.0, BSD, ISC, CC0
141
+ - ⚠️ **Restrictive:** GPL, AGPL, LGPL
142
+ - ❓ **Unknown:** Missing or custom licenses
143
+
144
+ ### Combined Analysis Example (v2.3)
145
+
146
+ **Full Output:**
147
+ ```
148
+ 🔍 DevCompass v2.3.0 - Analyzing your project...
149
+ ✔ Scanned 25 dependencies in project
150
+
151
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
152
+
153
+ 🔐 SECURITY VULNERABILITIES (5)
154
+
155
+ 🔴 CRITICAL: 1
156
+ 🟠 HIGH: 2
157
+ 🟡 MODERATE: 2
158
+
159
+ Run npm audit fix to fix vulnerabilities
160
+
161
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
162
+
163
+ 🚨 ECOSYSTEM ALERTS (1)
164
+
165
+ 🟠 HIGH
166
+ axios@1.6.0
167
+ Issue: Memory leak in request interceptors
168
+ Fix: 1.6.2
169
+
170
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
171
+
172
+ 📦 HEAVY PACKAGES (2)
173
+
174
+ Packages larger than 1MB:
175
+
176
+ typescript 8.1 MB
177
+ webpack 2.3 MB
178
+
179
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
180
+
181
+ ⚖️ LICENSE WARNINGS (1)
182
+
183
+ sharp - Restrictive (LGPL-3.0)
184
+
185
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
186
+
187
+ 📊 PROJECT HEALTH
188
+
189
+ Overall Score: 6.2/10
190
+ Total Dependencies: 25
191
+ Security Vulnerabilities: 5
192
+ Ecosystem Alerts: 1
193
+ Unused: 0
194
+ Outdated: 3
195
+
196
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
197
+
198
+ 💡 QUICK WINS
199
+
200
+ 🔐 Fix security vulnerabilities:
201
+
202
+ npm audit fix
203
+
204
+ 🔴 Fix critical issues:
205
+
206
+ npm install axios@1.6.2
207
+
208
+ Expected impact:
209
+ ✓ Resolve security vulnerabilities
210
+ ✓ Resolve critical stability issues
211
+ ✓ Improve health score → 8.7/10
212
+
213
+ 💡 TIP: Run 'devcompass fix' to apply these fixes automatically!
214
+ ```
215
+
216
+ ## 🚀 CI/CD Integration (v2.2)
67
217
 
68
218
  ### JSON Output
69
219
  Perfect for parsing in CI/CD pipelines:
@@ -71,26 +221,43 @@ Perfect for parsing in CI/CD pipelines:
71
221
  devcompass analyze --json
72
222
  ```
73
223
 
74
- **Output:**
224
+ **Output (v2.3):**
75
225
  ```json
76
226
  {
77
- "version": "2.2.0",
78
- "timestamp": "2026-04-01T15:51:10.395Z",
227
+ "version": "2.3.0",
228
+ "timestamp": "2026-04-02T10:30:00.000Z",
79
229
  "summary": {
80
- "healthScore": 7.5,
81
- "totalDependencies": 15,
82
- "ecosystemAlerts": 2,
83
- "unusedDependencies": 3,
84
- "outdatedPackages": 5
230
+ "healthScore": 6.2,
231
+ "totalDependencies": 25,
232
+ "securityVulnerabilities": 5,
233
+ "ecosystemAlerts": 1,
234
+ "unusedDependencies": 0,
235
+ "outdatedPackages": 3,
236
+ "heavyPackages": 2,
237
+ "licenseWarnings": 1
238
+ },
239
+ "security": {
240
+ "total": 5,
241
+ "critical": 1,
242
+ "high": 2,
243
+ "moderate": 2,
244
+ "low": 0,
245
+ "vulnerabilities": [...]
246
+ },
247
+ "bundleAnalysis": {
248
+ "heavyPackages": [
249
+ { "name": "typescript", "size": "8.1 MB" },
250
+ { "name": "webpack", "size": "2.3 MB" }
251
+ ]
252
+ },
253
+ "licenses": {
254
+ "warnings": [
255
+ { "package": "sharp", "license": "LGPL-3.0", "type": "restrictive" }
256
+ ]
85
257
  },
86
258
  "ecosystemAlerts": [...],
87
259
  "unusedDependencies": [...],
88
- "outdatedPackages": [...],
89
- "scoreBreakdown": {
90
- "unusedPenalty": 0.8,
91
- "outdatedPenalty": 1.7,
92
- "alertsPenalty": 3.5
93
- }
260
+ "outdatedPackages": [...]
94
261
  }
95
262
  ```
96
263
 
@@ -115,8 +282,8 @@ jobs:
115
282
  steps:
116
283
  - uses: actions/checkout@v3
117
284
  - uses: actions/setup-node@v3
118
- - run: npm install -g devcompass
119
- - run: devcompass analyze --ci
285
+ - run: npm install
286
+ - run: npx devcompass analyze --ci
120
287
  ```
121
288
 
122
289
  ### Silent Mode
@@ -126,15 +293,23 @@ devcompass analyze --silent
126
293
  echo $? # Check exit code
127
294
  ```
128
295
 
129
- ## ⚡ NEW in v2.2: Smart Caching
296
+ ## ⚡ Smart Caching (v2.2)
130
297
 
131
- DevCompass now caches results to improve performance:
298
+ DevCompass caches results to improve performance:
132
299
 
133
300
  - **First run:** Normal speed (fetches all data)
134
301
  - **Cached runs:** ~70% faster
135
302
  - **Cache duration:** 1 hour
136
303
  - **Cache file:** `.devcompass-cache.json` (auto-gitignored)
137
304
 
305
+ **What gets cached:**
306
+ - Security vulnerabilities
307
+ - Ecosystem alerts
308
+ - Unused dependencies
309
+ - Outdated packages
310
+ - Bundle sizes
311
+ - License information
312
+
138
313
  **Disable caching:**
139
314
  ```json
140
315
  // devcompass.config.json
@@ -143,7 +318,7 @@ DevCompass now caches results to improve performance:
143
318
  }
144
319
  ```
145
320
 
146
- ## 🎛️ NEW in v2.2: Advanced Configuration
321
+ ## 🎛️ Advanced Configuration (v2.2)
147
322
 
148
323
  Create `devcompass.config.json` in your project root:
149
324
  ```json
@@ -174,32 +349,33 @@ Create `devcompass.config.json` in your project root:
174
349
 
175
350
  ### Example Configurations
176
351
 
177
- **Only show critical security issues:**
352
+ **Security-focused (strict):**
178
353
  ```json
179
354
  {
180
355
  "minSeverity": "critical",
181
- "minScore": 8
356
+ "minScore": 9
182
357
  }
183
358
  ```
184
359
 
185
- **Ignore low-priority alerts:**
360
+ **Balanced (recommended):**
186
361
  ```json
187
362
  {
188
- "ignoreSeverity": ["low"]
363
+ "ignoreSeverity": ["low"],
364
+ "minScore": 7
189
365
  }
190
366
  ```
191
367
 
192
- **Strict CI mode:**
368
+ **Relaxed (development):**
193
369
  ```json
194
370
  {
195
- "minScore": 9,
196
- "minSeverity": "high"
371
+ "ignoreSeverity": ["low", "medium"],
372
+ "minScore": 5
197
373
  }
198
374
  ```
199
375
 
200
- ## 🔧 Auto-Fix Command
376
+ ## 🔧 Auto-Fix Command (v2.1)
201
377
 
202
- DevCompass can now **automatically fix issues** in your project!
378
+ DevCompass can **automatically fix issues** in your project!
203
379
 
204
380
  ### What it does:
205
381
  - 🔴 **Fixes critical security issues** - Upgrades packages with known vulnerabilities
@@ -220,67 +396,6 @@ devcompass fix -y
220
396
  devcompass fix --path /path/to/project
221
397
  ```
222
398
 
223
- ### Example Output
224
- ```
225
- 🔧 DevCompass Fix - Analyzing and fixing your project...
226
-
227
- 🔴 CRITICAL ISSUES TO FIX:
228
-
229
- 🔴 lodash@4.17.19
230
- Issue: Prototype pollution vulnerability
231
- Fix: Upgrade to 4.17.21
232
-
233
- 🟠 axios@1.6.0
234
- Issue: Memory leak in request interceptors
235
- Fix: Upgrade to 1.6.2
236
-
237
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
238
-
239
- 🧹 UNUSED DEPENDENCIES TO REMOVE:
240
-
241
- ● moment
242
- ● express
243
-
244
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
245
-
246
- ⬆️ SAFE UPDATES (patch/minor):
247
-
248
- react-dom: 18.2.0 → 18.2.1 (patch update)
249
-
250
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
251
-
252
- ⚠️ MAJOR UPDATES (skipped - may have breaking changes):
253
-
254
- express: 4.18.0 → 5.2.1
255
-
256
- Run these manually after reviewing changelog:
257
- npm install express@5.2.1
258
-
259
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
260
-
261
- 📊 FIX SUMMARY:
262
-
263
- Critical fixes: 2
264
- Remove unused: 2
265
- Safe updates: 1
266
- Skipped major: 1
267
-
268
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
269
-
270
- ❓ Apply these fixes? (y/N): y
271
-
272
- 🔧 Applying fixes...
273
-
274
- ✔ ✅ Removed 2 unused packages
275
- ✔ ✅ Fixed lodash@4.17.21
276
- ✔ ✅ Fixed axios@1.6.2
277
- ✔ ✅ Updated 1 packages
278
-
279
- ✨ All fixes applied successfully!
280
-
281
- 💡 Run devcompass analyze to see the new health score.
282
- ```
283
-
284
399
  ### Safety Features
285
400
  - ✅ Shows what will be changed before applying
286
401
  - ✅ Requires confirmation (unless `--yes` flag used)
@@ -300,74 +415,7 @@ devcompass fix
300
415
  devcompass analyze
301
416
  ```
302
417
 
303
- ## 📊 Analyze Command
304
-
305
- ### Example Output (v2.2)
306
- ```
307
- 🔍 DevCompass v2.2.0 - Analyzing your project...
308
- ✔ Scanned 15 dependencies in project
309
-
310
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
311
-
312
- 🚨 ECOSYSTEM ALERTS (2)
313
-
314
- 🔴 CRITICAL
315
- lodash@4.17.19
316
- Issue: Prototype pollution vulnerability
317
- Affected: <4.17.21
318
- Fix: 4.17.21
319
- Source: npm advisory 1523
320
-
321
- 🟠 HIGH
322
- axios@1.6.0
323
- Issue: Memory leak in request interceptors
324
- Affected: >=1.5.0 <1.6.2
325
- Fix: 1.6.2
326
- Source: GitHub Issue #5456
327
-
328
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
329
-
330
- 🔴 UNUSED DEPENDENCIES (2)
331
- ● moment
332
- ● request
333
-
334
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
335
-
336
- 🟡 OUTDATED PACKAGES (3)
337
- react 18.2.0 → ^19.0.0 (major update)
338
- express 4.18.0 → ^4.19.0 (patch update)
339
-
340
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
341
-
342
- 📊 PROJECT HEALTH
343
- Overall Score: 5.5/10
344
- Total Dependencies: 15
345
- Ecosystem Alerts: 2
346
- Unused: 2
347
- Outdated: 3
348
-
349
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
350
-
351
- 💡 QUICK WINS
352
- 🔴 Fix critical issues:
353
-
354
- npm install lodash@4.17.21
355
- npm install axios@1.6.2
356
-
357
- 🧹 Clean up unused dependencies:
358
-
359
- npm uninstall moment request
360
-
361
- Expected impact:
362
- ✓ Resolve critical security/stability issues
363
- ✓ Remove 2 unused packages
364
- ✓ Reduce node_modules size
365
- ✓ Improve health score → 8.5/10
366
-
367
- 💡 TIP: Run 'devcompass fix' to apply these fixes automatically!
368
- ```
369
-
370
- ## 🚨 Ecosystem Intelligence
418
+ ## 🚨 Ecosystem Intelligence (v2.0)
371
419
 
372
420
  DevCompass tracks **real-world issues** in popular packages and warns you before they break production!
373
421
 
@@ -420,11 +468,12 @@ DevCompass won't flag these as unused (they're typically used in config files):
420
468
  - Shows current vs latest versions
421
469
  - Indicates update type (major/minor/patch)
422
470
 
423
- ### Health Score (Enhanced in v2.0)
471
+ ### Health Score (Enhanced in v2.3)
424
472
  Calculated from 0-10 based on:
425
473
  - Percentage of unused dependencies (−4 points per 100%)
426
474
  - Percentage of outdated packages (−3 points per 100%)
427
475
  - Ecosystem alerts by severity (−0.2 to −2.0 per issue)
476
+ - Security vulnerabilities by severity (−0.2 to −2.5 per issue)
428
477
  - Higher score = healthier project
429
478
 
430
479
  ## ⚙️ Commands & Options
@@ -511,6 +560,21 @@ if [ $? -ne 0 ]; then
511
560
  fi
512
561
  ```
513
562
 
563
+ ### Security-Focused Workflow
564
+ ```bash
565
+ # 1. Run security scan
566
+ devcompass analyze
567
+
568
+ # 2. Check for critical vulnerabilities
569
+ devcompass analyze --json | jq '.security.critical'
570
+
571
+ # 3. Auto-fix if possible
572
+ npm audit fix
573
+
574
+ # 4. Verify fixes
575
+ devcompass analyze
576
+ ```
577
+
514
578
  ## ⚠️ Known Issues & Best Practices
515
579
 
516
580
  ### Installation
@@ -543,12 +607,14 @@ If you encounter a false positive, please [report it](https://github.com/AjayBTh
543
607
 
544
608
  1. **Run regularly** - Add to your CI/CD pipeline or git hooks
545
609
  2. **Use fix command** - Let DevCompass handle routine maintenance
546
- 3. **Configure severity levels** - Filter out noise with `minSeverity`
547
- 4. **Enable CI mode** - Catch issues before they reach production
548
- 5. **Use JSON output** - Integrate with your monitoring tools
549
- 6. **Fix critical alerts first** - Prioritize security and stability
550
- 7. **Review major updates** - Always check changelogs before major version bumps
551
- 8. **Verify before uninstalling** - DevCompass helps identify candidates, but always verify
610
+ 3. **Check security first** - Prioritize fixing critical vulnerabilities
611
+ 4. **Monitor bundle size** - Keep an eye on heavy packages
612
+ 5. **Review licenses** - Ensure compliance with your legal requirements
613
+ 6. **Configure severity levels** - Filter out noise with `minSeverity`
614
+ 7. **Enable CI mode** - Catch issues before they reach production
615
+ 8. **Use JSON output** - Integrate with your monitoring tools
616
+ 9. **Review major updates** - Always check changelogs before major version bumps
617
+ 10. **Verify before uninstalling** - DevCompass helps identify candidates, but always verify
552
618
 
553
619
  ## 🤝 Contributing
554
620
 
@@ -632,18 +698,21 @@ Check out DevCompass stats:
632
698
 
633
699
  ## 🌟 What's Next?
634
700
 
635
- ### Roadmap (v2.3+)
701
+ ### Roadmap (v2.4+)
636
702
  - [x] ~~Automatic fix command~~ ✅ **Added in v2.1!**
637
703
  - [x] ~~CI/CD integration with JSON output~~ ✅ **Added in v2.2!**
638
704
  - [x] ~~Smart caching system~~ ✅ **Added in v2.2!**
639
705
  - [x] ~~Custom ignore rules via config file~~ ✅ **Added in v2.2!**
640
- - [ ] Integration with `npm audit` for automated security scanning
641
- - [ ] GitHub Issues API for real-time issue tracking
642
- - [ ] Web dashboard for team health monitoring
643
- - [ ] More tracked packages (React, Next.js, Vue, Angular)
644
- - [ ] Bundle size analysis
645
- - [ ] Automated security patch suggestions
646
- - [ ] Team collaboration features
706
+ - [x] ~~npm audit integration~~ **Added in v2.3!**
707
+ - [x] ~~Bundle size analysis~~ **Added in v2.3!**
708
+ - [x] ~~License compliance checker~~ **Added in v2.3!**
709
+ - [ ] GitHub Issues API for real-time issue tracking (v2.4.0)
710
+ - [ ] Automated security patch suggestions (v2.4.0)
711
+ - [ ] Dependency graph visualization (v2.5.0)
712
+ - [ ] Web dashboard for team health monitoring (v2.5.0)
713
+ - [ ] More tracked packages (React, Next.js, Vue, Angular) (v2.5.0)
714
+ - [ ] Team collaboration features (v2.6.0)
715
+ - [ ] Slack/Discord notifications (v2.6.0)
647
716
 
648
717
  Want to contribute? Pick an item and open an issue! 🚀
649
718
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devcompass",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Dependency health checker with ecosystem intelligence for JavaScript/TypeScript projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -33,7 +33,10 @@
33
33
  "ci-cd",
34
34
  "automation",
35
35
  "caching",
36
- "json-output"
36
+ "json-output",
37
+ "npm-audit",
38
+ "bundle-size",
39
+ "license-checker"
37
40
  ],
38
41
  "author": "Ajay Thorat <ajaythorat988@gmail.com>",
39
42
  "license": "MIT",
@@ -56,4 +59,4 @@
56
59
  "url": "https://github.com/AjayBThorat-20/devcompass/issues"
57
60
  },
58
61
  "homepage": "https://github.com/AjayBThorat-20/devcompass#readme"
59
- }
62
+ }
@@ -0,0 +1,54 @@
1
+ // src/alerts/predictive.js
2
+
3
+ /**
4
+ * Analyze package health trends
5
+ * NOTE: This is a simplified version without GitHub API
6
+ * For production, integrate with GitHub Issues API
7
+ */
8
+ async function analyzeTrends(packageName) {
9
+ // Placeholder for future GitHub API integration
10
+ // For now, return basic analysis
11
+
12
+ return {
13
+ package: packageName,
14
+ recentIssues: 0,
15
+ trend: 'stable',
16
+ recommendation: null
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Calculate risk score based on trends
22
+ */
23
+ function calculateRiskScore(trends) {
24
+ let risk = 0;
25
+
26
+ // High issue activity = higher risk
27
+ if (trends.recentIssues > 20) {
28
+ risk += 3;
29
+ } else if (trends.recentIssues > 10) {
30
+ risk += 2;
31
+ } else if (trends.recentIssues > 5) {
32
+ risk += 1;
33
+ }
34
+
35
+ return risk;
36
+ }
37
+
38
+ /**
39
+ * Generate predictive warnings
40
+ */
41
+ function generatePredictiveWarnings(packages) {
42
+ const warnings = [];
43
+
44
+ // This is a placeholder
45
+ // In production, this would analyze GitHub activity
46
+
47
+ return warnings;
48
+ }
49
+
50
+ module.exports = {
51
+ analyzeTrends,
52
+ calculateRiskScore,
53
+ generatePredictiveWarnings
54
+ };
@@ -0,0 +1,85 @@
1
+ // src/analyzers/bundle-size.js
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ /**
6
+ * Get package sizes from node_modules
7
+ */
8
+ async function analyzeBundleSizes(projectPath, dependencies) {
9
+ const sizes = [];
10
+
11
+ for (const packageName of Object.keys(dependencies)) {
12
+ try {
13
+ const packagePath = path.join(projectPath, 'node_modules', packageName);
14
+
15
+ if (!fs.existsSync(packagePath)) {
16
+ continue;
17
+ }
18
+
19
+ const size = await getDirectorySize(packagePath);
20
+ const sizeInKB = Math.round(size / 1024);
21
+
22
+ sizes.push({
23
+ name: packageName,
24
+ size: sizeInKB,
25
+ sizeFormatted: formatSize(sizeInKB)
26
+ });
27
+
28
+ } catch (error) {
29
+ // Skip packages we can't measure
30
+ continue;
31
+ }
32
+ }
33
+
34
+ // Sort by size (largest first)
35
+ sizes.sort((a, b) => b.size - a.size);
36
+
37
+ return sizes;
38
+ }
39
+
40
+ /**
41
+ * Get total size of directory recursively
42
+ */
43
+ function getDirectorySize(dirPath) {
44
+ let totalSize = 0;
45
+
46
+ const items = fs.readdirSync(dirPath);
47
+
48
+ for (const item of items) {
49
+ const itemPath = path.join(dirPath, item);
50
+ const stats = fs.statSync(itemPath);
51
+
52
+ if (stats.isFile()) {
53
+ totalSize += stats.size;
54
+ } else if (stats.isDirectory()) {
55
+ totalSize += getDirectorySize(itemPath);
56
+ }
57
+ }
58
+
59
+ return totalSize;
60
+ }
61
+
62
+ /**
63
+ * Format size in human-readable format
64
+ */
65
+ function formatSize(kb) {
66
+ if (kb < 1024) {
67
+ return `${kb} KB`;
68
+ } else {
69
+ const mb = (kb / 1024).toFixed(1);
70
+ return `${mb} MB`;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Identify heavy packages (> 1MB)
76
+ */
77
+ function findHeavyPackages(sizes) {
78
+ return sizes.filter(pkg => pkg.size > 1024); // > 1MB
79
+ }
80
+
81
+ module.exports = {
82
+ analyzeBundleSizes,
83
+ findHeavyPackages,
84
+ formatSize
85
+ };
@@ -0,0 +1,107 @@
1
+ // src/analyzers/licenses.js
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ // Restrictive licenses that might cause issues
6
+ const RESTRICTIVE_LICENSES = [
7
+ 'GPL',
8
+ 'GPL-2.0',
9
+ 'GPL-3.0',
10
+ 'AGPL',
11
+ 'AGPL-3.0',
12
+ 'LGPL',
13
+ 'LGPL-2.1',
14
+ 'LGPL-3.0'
15
+ ];
16
+
17
+ // Permissive licenses (usually safe)
18
+ const PERMISSIVE_LICENSES = [
19
+ 'MIT',
20
+ 'Apache-2.0',
21
+ 'BSD-2-Clause',
22
+ 'BSD-3-Clause',
23
+ 'ISC',
24
+ 'CC0-1.0',
25
+ 'Unlicense'
26
+ ];
27
+
28
+ /**
29
+ * Check licenses of all dependencies
30
+ */
31
+ async function checkLicenses(projectPath, dependencies) {
32
+ const licenses = [];
33
+
34
+ for (const [packageName, version] of Object.entries(dependencies)) {
35
+ try {
36
+ const packageJsonPath = path.join(
37
+ projectPath,
38
+ 'node_modules',
39
+ packageName,
40
+ 'package.json'
41
+ );
42
+
43
+ if (!fs.existsSync(packageJsonPath)) {
44
+ continue;
45
+ }
46
+
47
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
48
+ const license = packageJson.license || 'UNKNOWN';
49
+
50
+ licenses.push({
51
+ package: packageName,
52
+ license: license,
53
+ type: getLicenseType(license)
54
+ });
55
+
56
+ } catch (error) {
57
+ // Skip packages we can't read
58
+ continue;
59
+ }
60
+ }
61
+
62
+ return licenses;
63
+ }
64
+
65
+ /**
66
+ * Determine license type
67
+ */
68
+ function getLicenseType(license) {
69
+ const licenseStr = String(license).toUpperCase();
70
+
71
+ // Check for restrictive licenses
72
+ for (const restrictive of RESTRICTIVE_LICENSES) {
73
+ if (licenseStr.includes(restrictive)) {
74
+ return 'restrictive';
75
+ }
76
+ }
77
+
78
+ // Check for permissive licenses
79
+ for (const permissive of PERMISSIVE_LICENSES) {
80
+ if (licenseStr.includes(permissive)) {
81
+ return 'permissive';
82
+ }
83
+ }
84
+
85
+ // Unknown or custom license
86
+ if (licenseStr === 'UNKNOWN' || licenseStr === 'UNLICENSED') {
87
+ return 'unknown';
88
+ }
89
+
90
+ return 'other';
91
+ }
92
+
93
+ /**
94
+ * Find problematic licenses
95
+ */
96
+ function findProblematicLicenses(licenses) {
97
+ return licenses.filter(pkg =>
98
+ pkg.type === 'restrictive' || pkg.type === 'unknown'
99
+ );
100
+ }
101
+
102
+ module.exports = {
103
+ checkLicenses,
104
+ findProblematicLicenses,
105
+ RESTRICTIVE_LICENSES,
106
+ PERMISSIVE_LICENSES
107
+ };
@@ -1,5 +1,12 @@
1
1
  // src/analyzers/scoring.js
2
- function calculateScore(totalDeps, unusedCount, outdatedCount, alertsCount = 0, alertPenalty = 0) {
2
+ function calculateScore(
3
+ totalDeps,
4
+ unusedCount,
5
+ outdatedCount,
6
+ alertsCount = 0,
7
+ alertPenalty = 0,
8
+ securityPenalty = 0 // NEW
9
+ ) {
3
10
  let score = 10;
4
11
 
5
12
  if (totalDeps === 0) {
@@ -9,9 +16,11 @@ function calculateScore(totalDeps, unusedCount, outdatedCount, alertsCount = 0,
9
16
  unused: 0,
10
17
  outdated: 0,
11
18
  alerts: 0,
19
+ security: 0,
12
20
  unusedPenalty: 0,
13
21
  outdatedPenalty: 0,
14
- alertsPenalty: 0
22
+ alertsPenalty: 0,
23
+ securityPenalty: 0
15
24
  }
16
25
  };
17
26
  }
@@ -26,9 +35,12 @@ function calculateScore(totalDeps, unusedCount, outdatedCount, alertsCount = 0,
26
35
  const outdatedPenalty = outdatedRatio * 3;
27
36
  score -= outdatedPenalty;
28
37
 
29
- // Ecosystem alerts penalty (from formatter.calculateAlertPenalty)
38
+ // Ecosystem alerts penalty
30
39
  score -= alertPenalty;
31
40
 
41
+ // Security vulnerabilities penalty (NEW)
42
+ score -= securityPenalty;
43
+
32
44
  // Ensure score is between 0 and 10
33
45
  score = Math.max(0, Math.min(10, score));
34
46
 
@@ -38,9 +50,11 @@ function calculateScore(totalDeps, unusedCount, outdatedCount, alertsCount = 0,
38
50
  unused: unusedCount,
39
51
  outdated: outdatedCount,
40
52
  alerts: alertsCount,
53
+ security: securityPenalty > 0 ? 1 : 0, // Binary indicator
41
54
  unusedPenalty: parseFloat(unusedPenalty.toFixed(1)),
42
55
  outdatedPenalty: parseFloat(outdatedPenalty.toFixed(1)),
43
- alertsPenalty: parseFloat(alertPenalty.toFixed(1))
56
+ alertsPenalty: parseFloat(alertPenalty.toFixed(1)),
57
+ securityPenalty: parseFloat(securityPenalty.toFixed(1))
44
58
  }
45
59
  };
46
60
  }
@@ -0,0 +1,111 @@
1
+ // src/analyzers/security.js
2
+ const { execSync } = require('child_process');
3
+
4
+ /**
5
+ * Run npm audit and parse results
6
+ */
7
+ async function checkSecurity(projectPath) {
8
+ try {
9
+ // Run npm audit in JSON mode
10
+ const auditOutput = execSync('npm audit --json', {
11
+ cwd: projectPath,
12
+ encoding: 'utf8',
13
+ stdio: ['pipe', 'pipe', 'pipe']
14
+ });
15
+
16
+ const auditData = JSON.parse(auditOutput);
17
+
18
+ // Extract vulnerabilities
19
+ const vulnerabilities = [];
20
+
21
+ if (auditData.vulnerabilities) {
22
+ Object.entries(auditData.vulnerabilities).forEach(([packageName, vuln]) => {
23
+ vulnerabilities.push({
24
+ package: packageName,
25
+ severity: vuln.severity, // critical, high, moderate, low
26
+ title: vuln.via[0]?.title || 'Security vulnerability',
27
+ range: vuln.range,
28
+ fixAvailable: vuln.fixAvailable,
29
+ cve: vuln.via[0]?.cve || null,
30
+ url: vuln.via[0]?.url || null
31
+ });
32
+ });
33
+ }
34
+
35
+ return {
36
+ vulnerabilities,
37
+ metadata: {
38
+ total: auditData.metadata?.vulnerabilities?.total || 0,
39
+ critical: auditData.metadata?.vulnerabilities?.critical || 0,
40
+ high: auditData.metadata?.vulnerabilities?.high || 0,
41
+ moderate: auditData.metadata?.vulnerabilities?.moderate || 0,
42
+ low: auditData.metadata?.vulnerabilities?.low || 0
43
+ }
44
+ };
45
+
46
+ } catch (error) {
47
+ // npm audit returns non-zero exit code when vulnerabilities found
48
+ // Try to parse the error output
49
+ try {
50
+ const auditData = JSON.parse(error.stdout);
51
+
52
+ const vulnerabilities = [];
53
+
54
+ if (auditData.vulnerabilities) {
55
+ Object.entries(auditData.vulnerabilities).forEach(([packageName, vuln]) => {
56
+ vulnerabilities.push({
57
+ package: packageName,
58
+ severity: vuln.severity,
59
+ title: vuln.via[0]?.title || 'Security vulnerability',
60
+ range: vuln.range,
61
+ fixAvailable: vuln.fixAvailable,
62
+ cve: vuln.via[0]?.cve || null,
63
+ url: vuln.via[0]?.url || null
64
+ });
65
+ });
66
+ }
67
+
68
+ return {
69
+ vulnerabilities,
70
+ metadata: {
71
+ total: auditData.metadata?.vulnerabilities?.total || 0,
72
+ critical: auditData.metadata?.vulnerabilities?.critical || 0,
73
+ high: auditData.metadata?.vulnerabilities?.high || 0,
74
+ moderate: auditData.metadata?.vulnerabilities?.moderate || 0,
75
+ low: auditData.metadata?.vulnerabilities?.low || 0
76
+ }
77
+ };
78
+ } catch (parseError) {
79
+ // If we can't parse, return empty
80
+ return {
81
+ vulnerabilities: [],
82
+ metadata: {
83
+ total: 0,
84
+ critical: 0,
85
+ high: 0,
86
+ moderate: 0,
87
+ low: 0
88
+ }
89
+ };
90
+ }
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Calculate security penalty for health score
96
+ */
97
+ function calculateSecurityPenalty(metadata) {
98
+ let penalty = 0;
99
+
100
+ penalty += metadata.critical * 2.5; // Critical: -2.5 points each
101
+ penalty += metadata.high * 1.5; // High: -1.5 points each
102
+ penalty += metadata.moderate * 0.5; // Moderate: -0.5 points each
103
+ penalty += metadata.low * 0.2; // Low: -0.2 points each
104
+
105
+ return Math.min(penalty, 5.0); // Cap at 5 points
106
+ }
107
+
108
+ module.exports = {
109
+ checkSecurity,
110
+ calculateSecurityPenalty
111
+ };
@@ -8,6 +8,9 @@ const { findUnusedDeps } = require('../analyzers/unused-deps');
8
8
  const { findOutdatedDeps } = require('../analyzers/outdated');
9
9
  const { calculateScore } = require('../analyzers/scoring');
10
10
  const { checkEcosystemAlerts } = require('../alerts');
11
+ const { checkSecurity, calculateSecurityPenalty } = require('../analyzers/security');
12
+ const { analyzeBundleSizes, findHeavyPackages } = require('../analyzers/bundle-size');
13
+ const { checkLicenses, findProblematicLicenses } = require('../analyzers/licenses');
11
14
  const {
12
15
  formatAlerts,
13
16
  getSeverityDisplay,
@@ -34,15 +37,25 @@ async function analyze(options) {
34
37
  // Handle output modes
35
38
  const outputMode = options.json ? 'json' : (options.ci ? 'ci' : (options.silent ? 'silent' : 'normal'));
36
39
 
37
- if (outputMode !== 'silent') {
40
+ // Only show header for normal and CI modes
41
+ if (outputMode !== 'silent' && outputMode !== 'json') {
38
42
  console.log('\n');
39
43
  log(chalk.cyan.bold(`🔍 DevCompass v${packageJson.version}`) + ' - Analyzing your project...\n');
40
44
  }
41
45
 
42
- const spinner = ora({
43
- text: 'Loading project...',
44
- color: 'cyan'
45
- }).start();
46
+ // Create spinner (disabled for json/silent modes to prevent EPIPE errors)
47
+ const spinner = (outputMode === 'json' || outputMode === 'silent')
48
+ ? {
49
+ start: function() { return this; },
50
+ succeed: function() {},
51
+ fail: function(msg) { if (msg) console.error(msg); },
52
+ text: '',
53
+ set text(val) {}
54
+ }
55
+ : ora({
56
+ text: 'Loading project...',
57
+ color: 'cyan'
58
+ }).start();
46
59
 
47
60
  try {
48
61
  const packageJsonPath = path.join(projectPath, 'package.json');
@@ -148,28 +161,95 @@ async function analyze(options) {
148
161
  }
149
162
  }
150
163
 
164
+ // Check security vulnerabilities (NEW)
165
+ spinner.text = 'Checking security vulnerabilities...';
166
+ let securityData = { vulnerabilities: [], metadata: { total: 0, critical: 0, high: 0, moderate: 0, low: 0 } };
167
+
168
+ if (config.cache) {
169
+ const cached = getCached(projectPath, 'security');
170
+ if (cached) securityData = cached;
171
+ }
172
+
173
+ if (securityData.metadata.total === 0) {
174
+ try {
175
+ securityData = await checkSecurity(projectPath);
176
+ if (config.cache) {
177
+ setCache(projectPath, 'security', securityData);
178
+ }
179
+ } catch (error) {
180
+ if (outputMode !== 'silent') {
181
+ console.log(chalk.yellow('\n⚠️ Could not check security vulnerabilities'));
182
+ console.log(chalk.gray(` Error: ${error.message}\n`));
183
+ }
184
+ }
185
+ }
186
+
187
+ // Analyze bundle sizes (NEW)
188
+ spinner.text = 'Analyzing bundle sizes...';
189
+ let bundleSizes = [];
190
+
191
+ if (config.cache) {
192
+ const cached = getCached(projectPath, 'bundleSizes');
193
+ if (cached) bundleSizes = cached;
194
+ }
195
+
196
+ if (bundleSizes.length === 0) {
197
+ try {
198
+ bundleSizes = await analyzeBundleSizes(projectPath, dependencies);
199
+ if (config.cache && bundleSizes.length > 0) {
200
+ setCache(projectPath, 'bundleSizes', bundleSizes);
201
+ }
202
+ } catch (error) {
203
+ // Bundle size analysis is optional
204
+ }
205
+ }
206
+
207
+ // Check licenses (NEW)
208
+ spinner.text = 'Checking licenses...';
209
+ let licenses = [];
210
+
211
+ if (config.cache) {
212
+ const cached = getCached(projectPath, 'licenses');
213
+ if (cached) licenses = cached;
214
+ }
215
+
216
+ if (licenses.length === 0) {
217
+ try {
218
+ licenses = await checkLicenses(projectPath, dependencies);
219
+ if (config.cache && licenses.length > 0) {
220
+ setCache(projectPath, 'licenses', licenses);
221
+ }
222
+ } catch (error) {
223
+ // License checking is optional
224
+ }
225
+ }
226
+
227
+ // Calculate score (UPDATED)
151
228
  const alertPenalty = calculateAlertPenalty(alerts);
229
+ const securityPenalty = calculateSecurityPenalty(securityData.metadata);
230
+
152
231
  const score = calculateScore(
153
232
  totalDeps,
154
233
  unusedDeps.length,
155
234
  outdatedDeps.length,
156
235
  alerts.length,
157
- alertPenalty
236
+ alertPenalty,
237
+ securityPenalty
158
238
  );
159
239
 
160
240
  spinner.succeed(chalk.green(`Scanned ${totalDeps} dependencies in project`));
161
241
 
162
242
  // Handle different output modes
163
243
  if (outputMode === 'json') {
164
- const jsonOutput = formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps);
244
+ const jsonOutput = formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses);
165
245
  console.log(jsonOutput);
166
246
  } else if (outputMode === 'ci') {
167
- displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps);
247
+ displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses);
168
248
  handleCiMode(score, config, alerts, unusedDeps);
169
249
  } else if (outputMode === 'silent') {
170
250
  // Silent mode - no output
171
251
  } else {
172
- displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps);
252
+ displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses);
173
253
  }
174
254
 
175
255
  } catch (error) {
@@ -182,10 +262,40 @@ async function analyze(options) {
182
262
  }
183
263
  }
184
264
 
185
- function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
265
+ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses) {
186
266
  logDivider();
187
267
 
188
- // ECOSYSTEM ALERTS (NEW SECTION)
268
+ // SECURITY VULNERABILITIES (NEW SECTION)
269
+ if (securityData.metadata.total > 0) {
270
+ const criticalCount = securityData.metadata.critical;
271
+ const highCount = securityData.metadata.high;
272
+ const moderateCount = securityData.metadata.moderate;
273
+ const lowCount = securityData.metadata.low;
274
+
275
+ logSection('🔐 SECURITY VULNERABILITIES', securityData.metadata.total);
276
+
277
+ if (criticalCount > 0) {
278
+ log(chalk.red.bold(`\n 🔴 CRITICAL: ${criticalCount}`));
279
+ }
280
+ if (highCount > 0) {
281
+ log(chalk.red(` 🟠 HIGH: ${highCount}`));
282
+ }
283
+ if (moderateCount > 0) {
284
+ log(chalk.yellow(` 🟡 MODERATE: ${moderateCount}`));
285
+ }
286
+ if (lowCount > 0) {
287
+ log(chalk.gray(` ⚪ LOW: ${lowCount}`));
288
+ }
289
+
290
+ log(chalk.cyan('\n Run') + chalk.bold(' npm audit fix ') + chalk.cyan('to fix vulnerabilities\n'));
291
+ } else {
292
+ logSection('✅ SECURITY VULNERABILITIES');
293
+ log(chalk.green(' No vulnerabilities detected!\n'));
294
+ }
295
+
296
+ logDivider();
297
+
298
+ // ECOSYSTEM ALERTS
189
299
  if (alerts.length > 0) {
190
300
  logSection('🚨 ECOSYSTEM ALERTS', alerts.length);
191
301
 
@@ -266,6 +376,46 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
266
376
 
267
377
  logDivider();
268
378
 
379
+ // BUNDLE SIZE (NEW SECTION)
380
+ const heavyPackages = findHeavyPackages(bundleSizes);
381
+ if (heavyPackages.length > 0) {
382
+ logSection('📦 HEAVY PACKAGES', heavyPackages.length);
383
+
384
+ log(chalk.gray(' Packages larger than 1MB:\n'));
385
+
386
+ heavyPackages.slice(0, 10).forEach(pkg => {
387
+ const nameCol = pkg.name.padEnd(25);
388
+ const size = pkg.size > 5120
389
+ ? chalk.red(pkg.sizeFormatted)
390
+ : chalk.yellow(pkg.sizeFormatted);
391
+
392
+ log(` ${nameCol} ${size}`);
393
+ });
394
+
395
+ log('');
396
+ logDivider();
397
+ }
398
+
399
+ // LICENSE WARNINGS (NEW SECTION - ALWAYS SHOW)
400
+ const problematicLicenses = findProblematicLicenses(licenses);
401
+ if (problematicLicenses.length > 0) {
402
+ logSection('⚖️ LICENSE WARNINGS', problematicLicenses.length);
403
+
404
+ problematicLicenses.forEach(pkg => {
405
+ const type = pkg.type === 'restrictive'
406
+ ? chalk.red('Restrictive')
407
+ : chalk.yellow('Unknown');
408
+ log(` ${chalk.bold(pkg.package)} - ${type} (${pkg.license})`);
409
+ });
410
+
411
+ log(chalk.gray('\n Note: Restrictive licenses may require legal review\n'));
412
+ } else {
413
+ logSection('✅ LICENSE COMPLIANCE');
414
+ log(chalk.green(' All licenses are permissive!\n'));
415
+ }
416
+
417
+ logDivider();
418
+
269
419
  // PROJECT HEALTH
270
420
  logSection('📊 PROJECT HEALTH');
271
421
 
@@ -273,6 +423,10 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
273
423
  log(` Overall Score: ${scoreColor(score.total + '/10')}`);
274
424
  log(` Total Dependencies: ${chalk.cyan(totalDeps)}`);
275
425
 
426
+ if (securityData.metadata.total > 0) {
427
+ log(` Security Vulnerabilities: ${chalk.red(securityData.metadata.total)}`);
428
+ }
429
+
276
430
  if (alerts.length > 0) {
277
431
  log(` Ecosystem Alerts: ${chalk.red(alerts.length)}`);
278
432
  }
@@ -283,16 +437,23 @@ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
283
437
  logDivider();
284
438
 
285
439
  // QUICK WINS
286
- displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps);
440
+ displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData);
287
441
  }
288
442
 
289
- function displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
443
+ function displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData) {
290
444
  const hasCriticalAlerts = alerts.some(a => a.severity === 'critical' || a.severity === 'high');
445
+ const hasCriticalSecurity = securityData.metadata.critical > 0 || securityData.metadata.high > 0;
291
446
 
292
- if (hasCriticalAlerts || unusedDeps.length > 0) {
447
+ if (hasCriticalSecurity || hasCriticalAlerts || unusedDeps.length > 0) {
293
448
  logSection('💡 QUICK WINS');
294
449
 
295
- // Fix critical alerts first
450
+ // Fix security vulnerabilities first
451
+ if (hasCriticalSecurity) {
452
+ log(' 🔐 Fix security vulnerabilities:\n');
453
+ log(chalk.cyan(` npm audit fix\n`));
454
+ }
455
+
456
+ // Fix critical alerts
296
457
  if (hasCriticalAlerts) {
297
458
  const criticalAlerts = alerts.filter(a => a.severity === 'critical' || a.severity === 'high');
298
459
 
@@ -325,13 +486,18 @@ function displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
325
486
  0,
326
487
  outdatedDeps.length,
327
488
  alerts.length - alerts.filter(a => a.severity === 'critical' || a.severity === 'high').length,
328
- alertPenalty
489
+ alertPenalty,
490
+ 0 // Assume security issues fixed
329
491
  );
330
492
 
331
493
  log(' Expected impact:');
332
494
 
495
+ if (hasCriticalSecurity) {
496
+ log(` ${chalk.green('✓')} Resolve security vulnerabilities`);
497
+ }
498
+
333
499
  if (hasCriticalAlerts) {
334
- log(` ${chalk.green('✓')} Resolve critical security/stability issues`);
500
+ log(` ${chalk.green('✓')} Resolve critical stability issues`);
335
501
  }
336
502
 
337
503
  if (unusedDeps.length > 0) {
@@ -3,16 +3,36 @@
3
3
  /**
4
4
  * Format analysis results as JSON
5
5
  */
6
- function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
6
+ function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps, securityData, bundleSizes, licenses) {
7
+ const problematicLicenses = licenses.filter(l => l.type === 'restrictive' || l.type === 'unknown');
8
+ const heavyPackages = bundleSizes.filter(p => p.size > 1024);
9
+
7
10
  return JSON.stringify({
8
11
  version: require('../../package.json').version,
9
12
  timestamp: new Date().toISOString(),
10
13
  summary: {
11
14
  healthScore: score.total,
12
15
  totalDependencies: totalDeps,
16
+ securityVulnerabilities: securityData.metadata.total,
13
17
  ecosystemAlerts: alerts.length,
14
18
  unusedDependencies: unusedDeps.length,
15
- outdatedPackages: outdatedDeps.length
19
+ outdatedPackages: outdatedDeps.length,
20
+ heavyPackages: heavyPackages.length,
21
+ licenseWarnings: problematicLicenses.length
22
+ },
23
+ security: {
24
+ total: securityData.metadata.total,
25
+ critical: securityData.metadata.critical,
26
+ high: securityData.metadata.high,
27
+ moderate: securityData.metadata.moderate,
28
+ low: securityData.metadata.low,
29
+ vulnerabilities: securityData.vulnerabilities.map(v => ({
30
+ package: v.package,
31
+ severity: v.severity,
32
+ title: v.title,
33
+ cve: v.cve,
34
+ fixAvailable: v.fixAvailable
35
+ }))
16
36
  },
17
37
  ecosystemAlerts: alerts.map(alert => ({
18
38
  package: alert.package,
@@ -33,10 +53,24 @@ function formatAsJson(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
33
53
  latest: dep.latest,
34
54
  updateType: dep.versionsBehind
35
55
  })),
56
+ bundleAnalysis: {
57
+ heavyPackages: heavyPackages.map(pkg => ({
58
+ name: pkg.name,
59
+ size: pkg.sizeFormatted
60
+ }))
61
+ },
62
+ licenses: {
63
+ warnings: problematicLicenses.map(pkg => ({
64
+ package: pkg.package,
65
+ license: pkg.license,
66
+ type: pkg.type
67
+ }))
68
+ },
36
69
  scoreBreakdown: {
37
70
  unusedPenalty: score.breakdown.unusedPenalty,
38
71
  outdatedPenalty: score.breakdown.outdatedPenalty,
39
- alertsPenalty: score.breakdown.alertsPenalty
72
+ alertsPenalty: score.breakdown.alertsPenalty,
73
+ securityPenalty: score.breakdown.securityPenalty
40
74
  }
41
75
  }, null, 2);
42
76
  }