devcompass 2.2.0 → 2.3.1

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
@@ -1,3 +1,5 @@
1
+ cd ~/devCampuss
2
+ cat > README.md << 'EOF'
1
3
  # 🧭 DevCompass
2
4
 
3
5
  **Dependency health checker with ecosystem intelligence for JavaScript/TypeScript projects**
@@ -6,22 +8,37 @@
6
8
  [![npm downloads](https://img.shields.io/npm/dm/devcompass.svg)](https://www.npmjs.com/package/devcompass)
7
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
10
 
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.
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.
10
12
 
13
+ > **NEW in v2.3.1:** Fixed all security vulnerabilities! Health score: 2.5/10 → 8/10 🔒
14
+ > **NEW in v2.3:** Security scanning, bundle analysis & license checker! 🔐
11
15
  > **NEW in v2.2:** CI/CD integration with JSON output & smart caching! 🚀
12
16
  > **NEW in v2.1:** Auto-fix command! 🔧 Fix critical issues automatically!
13
17
  > **NEW in v2.0:** Real-time ecosystem alerts for known issues! 🚨
14
18
 
19
+ ## 🎉 Latest Update: v2.3.1
20
+
21
+ **We practice what we preach!** After releasing v2.3.0 with security scanning, we ran DevCompass on itself and found 14 vulnerabilities. We fixed them all:
22
+
23
+ - ✅ **Health score improved:** 2.5/10 → 8/10
24
+ - ✅ **Security vulnerabilities:** 14 → 0
25
+ - ✅ **Bundle size reduced:** 9.1 MB → 6.2 MB (32% smaller)
26
+ - ✅ **Dependencies upgraded:** npm-check-updates v16 → v20
27
+ - ✅ **Removed 315 vulnerable packages**
28
+
29
+ This is what "eating your own dog food" looks like. DevCompass helps you catch and fix security issues before they reach production.
30
+
15
31
  ## ✨ Features
16
32
 
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
33
+ - 🔐 **Security Scanning** (v2.3) - npm audit integration with severity breakdown
34
+ - 📦 **Bundle Size Analysis** (v2.3) - Identify heavy packages (> 1MB)
35
+ - ⚖️ **License Checker** (v2.3) - Detect restrictive licenses (GPL, AGPL)
36
+ - 🚀 **CI/CD Integration** (v2.2) - JSON output, exit codes, and silent mode
37
+ - ⚡ **Smart Caching** (v2.2) - 70% faster on repeated runs
38
+ - 🎛️ **Advanced Filtering** (v2.2) - Control alerts by severity level
20
39
  - 🔧 **Auto-Fix Command** (v2.1) - Fix issues automatically with one command
21
40
  - 🚨 **Ecosystem Intelligence** (v2.0) - Detect known issues before they break production
22
41
  - 🔍 **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
42
  - 📊 **Project health score** - Get a 0-10 rating for your dependencies
26
43
  - 🎨 **Beautiful terminal UI** - Colored output with severity indicators
27
44
  - 🔧 **Framework-aware** - Handles React, Next.js, Angular, NestJS, PostCSS, Tailwind
@@ -63,7 +80,145 @@ devcompass analyze --ci
63
80
  devcompass analyze --silent
64
81
  ```
65
82
 
66
- ## 🚀 NEW in v2.2: CI/CD Integration
83
+ ## 🔐 Security & Compliance Features
84
+
85
+ ### Security Vulnerability Scanning
86
+
87
+ DevCompass integrates with **npm audit** to detect security vulnerabilities automatically!
88
+
89
+ **Example Output:**
90
+ ```
91
+ 🔐 SECURITY VULNERABILITIES (12)
92
+
93
+ 🔴 CRITICAL: 2
94
+ 🟠 HIGH: 4
95
+ 🟡 MODERATE: 5
96
+ ⚪ LOW: 1
97
+
98
+ Run npm audit fix to fix vulnerabilities
99
+ ```
100
+
101
+ **How it works:**
102
+ 1. Runs `npm audit` in the background
103
+ 2. Parses vulnerability data
104
+ 3. Shows severity breakdown
105
+ 4. Impacts health score (-2.5 per critical issue)
106
+ 5. Suggests fix commands
107
+
108
+ **Health Score Impact:**
109
+ - Critical: −2.5 points each
110
+ - High: −1.5 points each
111
+ - Moderate: −0.5 points each
112
+ - Low: −0.2 points each
113
+
114
+ ### Bundle Size Analysis
115
+
116
+ Identify large dependencies that bloat your `node_modules`!
117
+
118
+ **Example Output:**
119
+ ```
120
+ 📦 HEAVY PACKAGES (3)
121
+
122
+ Packages larger than 1MB:
123
+
124
+ webpack 2.3 MB
125
+ typescript 8.1 MB
126
+ @tensorflow/tfjs 12.4 MB
127
+ ```
128
+
129
+ **Perfect for:**
130
+ - Frontend developers optimizing bundle size
131
+ - Identifying unnecessary large dependencies
132
+ - Web performance optimization
133
+ - Docker image size reduction
134
+
135
+ ### License Compliance Checker
136
+
137
+ Detect restrictive licenses that may require legal review!
138
+
139
+ **Example Output:**
140
+ ```
141
+ ⚖️ LICENSE WARNINGS (2)
142
+
143
+ sharp - Restrictive (LGPL-3.0)
144
+ custom-lib - Unknown (UNLICENSED)
145
+
146
+ Note: Restrictive licenses may require legal review
147
+ ```
148
+
149
+ **What gets flagged:**
150
+ - **Restrictive licenses:** GPL, AGPL, LGPL (may require source code disclosure)
151
+ - **Unknown licenses:** Packages without license information
152
+ - **Unlicensed packages:** Legal risk for commercial use
153
+
154
+ **Supported licenses:**
155
+ - ✅ **Safe:** MIT, Apache-2.0, BSD, ISC, CC0
156
+ - ⚠️ **Restrictive:** GPL, AGPL, LGPL
157
+ - ❓ **Unknown:** Missing or custom licenses
158
+
159
+ ### Combined Analysis Example
160
+
161
+ **Full Output:**
162
+ ```
163
+ 🔍 DevCompass v2.3.1 - Analyzing your project...
164
+ ✔ Scanned 25 dependencies in project
165
+
166
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
167
+
168
+ ✅ SECURITY VULNERABILITIES
169
+
170
+ No vulnerabilities detected!
171
+
172
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
173
+
174
+ 🚨 ECOSYSTEM ALERTS (1)
175
+
176
+ 🟠 HIGH
177
+ axios@1.6.0
178
+ Issue: Memory leak in request interceptors
179
+ Fix: 1.6.2
180
+
181
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
182
+
183
+ 📦 HEAVY PACKAGES (2)
184
+
185
+ Packages larger than 1MB:
186
+
187
+ typescript 8.1 MB
188
+ webpack 2.3 MB
189
+
190
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
191
+
192
+ ✅ LICENSE COMPLIANCE
193
+
194
+ All licenses are permissive!
195
+
196
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
197
+
198
+ 📊 PROJECT HEALTH
199
+
200
+ Overall Score: 8.5/10
201
+ Total Dependencies: 25
202
+ Ecosystem Alerts: 1
203
+ Unused: 0
204
+ Outdated: 2
205
+
206
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
207
+
208
+ 💡 QUICK WINS
209
+
210
+ 🔴 Fix critical issues:
211
+
212
+ npm install axios@1.6.2
213
+
214
+ Expected impact:
215
+ ✓ Resolve critical stability issues
216
+ ✓ Improve health score → 10/10
217
+
218
+ 💡 TIP: Run 'devcompass fix' to apply these fixes automatically!
219
+ ```
220
+
221
+ ## 🚀 CI/CD Integration
67
222
 
68
223
  ### JSON Output
69
224
  Perfect for parsing in CI/CD pipelines:
@@ -74,23 +229,38 @@ devcompass analyze --json
74
229
  **Output:**
75
230
  ```json
76
231
  {
77
- "version": "2.2.0",
78
- "timestamp": "2026-04-01T15:51:10.395Z",
232
+ "version": "2.3.1",
233
+ "timestamp": "2026-04-02T10:30:00.000Z",
79
234
  "summary": {
80
- "healthScore": 7.5,
81
- "totalDependencies": 15,
82
- "ecosystemAlerts": 2,
83
- "unusedDependencies": 3,
84
- "outdatedPackages": 5
235
+ "healthScore": 8.5,
236
+ "totalDependencies": 25,
237
+ "securityVulnerabilities": 0,
238
+ "ecosystemAlerts": 1,
239
+ "unusedDependencies": 0,
240
+ "outdatedPackages": 2,
241
+ "heavyPackages": 2,
242
+ "licenseWarnings": 0
243
+ },
244
+ "security": {
245
+ "total": 0,
246
+ "critical": 0,
247
+ "high": 0,
248
+ "moderate": 0,
249
+ "low": 0,
250
+ "vulnerabilities": []
251
+ },
252
+ "bundleAnalysis": {
253
+ "heavyPackages": [
254
+ { "name": "typescript", "size": "8.1 MB" },
255
+ { "name": "webpack", "size": "2.3 MB" }
256
+ ]
257
+ },
258
+ "licenses": {
259
+ "warnings": []
85
260
  },
86
261
  "ecosystemAlerts": [...],
87
- "unusedDependencies": [...],
88
- "outdatedPackages": [...],
89
- "scoreBreakdown": {
90
- "unusedPenalty": 0.8,
91
- "outdatedPenalty": 1.7,
92
- "alertsPenalty": 3.5
93
- }
262
+ "unusedDependencies": [],
263
+ "outdatedPackages": [...]
94
264
  }
95
265
  ```
96
266
 
@@ -115,8 +285,8 @@ jobs:
115
285
  steps:
116
286
  - uses: actions/checkout@v3
117
287
  - uses: actions/setup-node@v3
118
- - run: npm install -g devcompass
119
- - run: devcompass analyze --ci
288
+ - run: npm install
289
+ - run: npx devcompass analyze --ci
120
290
  ```
121
291
 
122
292
  ### Silent Mode
@@ -126,15 +296,23 @@ devcompass analyze --silent
126
296
  echo $? # Check exit code
127
297
  ```
128
298
 
129
- ## ⚡ NEW in v2.2: Smart Caching
299
+ ## ⚡ Smart Caching
130
300
 
131
- DevCompass now caches results to improve performance:
301
+ DevCompass caches results to improve performance:
132
302
 
133
303
  - **First run:** Normal speed (fetches all data)
134
304
  - **Cached runs:** ~70% faster
135
305
  - **Cache duration:** 1 hour
136
306
  - **Cache file:** `.devcompass-cache.json` (auto-gitignored)
137
307
 
308
+ **What gets cached:**
309
+ - Security vulnerabilities
310
+ - Ecosystem alerts
311
+ - Unused dependencies
312
+ - Outdated packages
313
+ - Bundle sizes
314
+ - License information
315
+
138
316
  **Disable caching:**
139
317
  ```json
140
318
  // devcompass.config.json
@@ -143,7 +321,7 @@ DevCompass now caches results to improve performance:
143
321
  }
144
322
  ```
145
323
 
146
- ## 🎛️ NEW in v2.2: Advanced Configuration
324
+ ## 🎛️ Advanced Configuration
147
325
 
148
326
  Create `devcompass.config.json` in your project root:
149
327
  ```json
@@ -174,32 +352,33 @@ Create `devcompass.config.json` in your project root:
174
352
 
175
353
  ### Example Configurations
176
354
 
177
- **Only show critical security issues:**
355
+ **Security-focused (strict):**
178
356
  ```json
179
357
  {
180
358
  "minSeverity": "critical",
181
- "minScore": 8
359
+ "minScore": 9
182
360
  }
183
361
  ```
184
362
 
185
- **Ignore low-priority alerts:**
363
+ **Balanced (recommended):**
186
364
  ```json
187
365
  {
188
- "ignoreSeverity": ["low"]
366
+ "ignoreSeverity": ["low"],
367
+ "minScore": 7
189
368
  }
190
369
  ```
191
370
 
192
- **Strict CI mode:**
371
+ **Relaxed (development):**
193
372
  ```json
194
373
  {
195
- "minScore": 9,
196
- "minSeverity": "high"
374
+ "ignoreSeverity": ["low", "medium"],
375
+ "minScore": 5
197
376
  }
198
377
  ```
199
378
 
200
379
  ## 🔧 Auto-Fix Command
201
380
 
202
- DevCompass can now **automatically fix issues** in your project!
381
+ DevCompass can **automatically fix issues** in your project!
203
382
 
204
383
  ### What it does:
205
384
  - 🔴 **Fixes critical security issues** - Upgrades packages with known vulnerabilities
@@ -220,67 +399,6 @@ devcompass fix -y
220
399
  devcompass fix --path /path/to/project
221
400
  ```
222
401
 
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
402
  ### Safety Features
285
403
  - ✅ Shows what will be changed before applying
286
404
  - ✅ Requires confirmation (unless `--yes` flag used)
@@ -300,73 +418,6 @@ devcompass fix
300
418
  devcompass analyze
301
419
  ```
302
420
 
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
421
  ## 🚨 Ecosystem Intelligence
371
422
 
372
423
  DevCompass tracks **real-world issues** in popular packages and warns you before they break production!
@@ -420,11 +471,12 @@ DevCompass won't flag these as unused (they're typically used in config files):
420
471
  - Shows current vs latest versions
421
472
  - Indicates update type (major/minor/patch)
422
473
 
423
- ### Health Score (Enhanced in v2.0)
474
+ ### Health Score
424
475
  Calculated from 0-10 based on:
425
476
  - Percentage of unused dependencies (−4 points per 100%)
426
477
  - Percentage of outdated packages (−3 points per 100%)
427
478
  - Ecosystem alerts by severity (−0.2 to −2.0 per issue)
479
+ - Security vulnerabilities by severity (−0.2 to −2.5 per issue)
428
480
  - Higher score = healthier project
429
481
 
430
482
  ## ⚙️ Commands & Options
@@ -511,6 +563,21 @@ if [ $? -ne 0 ]; then
511
563
  fi
512
564
  ```
513
565
 
566
+ ### Security-Focused Workflow
567
+ ```bash
568
+ # 1. Run security scan
569
+ devcompass analyze
570
+
571
+ # 2. Check for critical vulnerabilities
572
+ devcompass analyze --json | jq '.security.critical'
573
+
574
+ # 3. Auto-fix if possible
575
+ npm audit fix
576
+
577
+ # 4. Verify fixes
578
+ devcompass analyze
579
+ ```
580
+
514
581
  ## ⚠️ Known Issues & Best Practices
515
582
 
516
583
  ### Installation
@@ -543,12 +610,14 @@ If you encounter a false positive, please [report it](https://github.com/AjayBTh
543
610
 
544
611
  1. **Run regularly** - Add to your CI/CD pipeline or git hooks
545
612
  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
613
+ 3. **Check security first** - Prioritize fixing critical vulnerabilities
614
+ 4. **Monitor bundle size** - Keep an eye on heavy packages
615
+ 5. **Review licenses** - Ensure compliance with your legal requirements
616
+ 6. **Configure severity levels** - Filter out noise with `minSeverity`
617
+ 7. **Enable CI mode** - Catch issues before they reach production
618
+ 8. **Use JSON output** - Integrate with your monitoring tools
619
+ 9. **Review major updates** - Always check changelogs before major version bumps
620
+ 10. **Verify before uninstalling** - DevCompass helps identify candidates, but always verify
552
621
 
553
622
  ## 🤝 Contributing
554
623
 
@@ -632,18 +701,22 @@ Check out DevCompass stats:
632
701
 
633
702
  ## 🌟 What's Next?
634
703
 
635
- ### Roadmap (v2.3+)
704
+ ### Roadmap
636
705
  - [x] ~~Automatic fix command~~ ✅ **Added in v2.1!**
637
706
  - [x] ~~CI/CD integration with JSON output~~ ✅ **Added in v2.2!**
638
707
  - [x] ~~Smart caching system~~ ✅ **Added in v2.2!**
639
708
  - [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
709
+ - [x] ~~npm audit integration~~ **Added in v2.3!**
710
+ - [x] ~~Bundle size analysis~~ **Added in v2.3!**
711
+ - [x] ~~License compliance checker~~ **Added in v2.3!**
712
+ - [x] ~~Fix all security vulnerabilities~~ **Fixed in v2.3.1!**
713
+ - [ ] GitHub Issues API for real-time issue tracking (v2.4.0)
714
+ - [ ] Automated security patch suggestions (v2.4.0)
715
+ - [ ] Dependency graph visualization (v2.5.0)
716
+ - [ ] Web dashboard for team health monitoring (v2.5.0)
717
+ - [ ] More tracked packages (React, Next.js, Vue, Angular) (v2.5.0)
718
+ - [ ] Team collaboration features (v2.6.0)
719
+ - [ ] Slack/Discord notifications (v2.6.0)
647
720
 
648
721
  Want to contribute? Pick an item and open an issue! 🚀
649
722
 
@@ -653,4 +726,5 @@ Want to contribute? Pick an item and open an issue! 🚀
653
726
 
654
727
  *DevCompass - Keep your dependencies healthy!* 🧭
655
728
 
656
- **Like Lighthouse for your dependencies** ⚡
729
+ **Like Lighthouse for your dependencies** ⚡
730
+ EOF
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devcompass",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
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",
@@ -41,7 +44,7 @@
41
44
  "chalk": "^4.1.2",
42
45
  "commander": "^11.1.0",
43
46
  "depcheck": "^1.4.7",
44
- "npm-check-updates": "^16.14.12",
47
+ "npm-check-updates": "^20.0.0",
45
48
  "ora": "^5.4.1",
46
49
  "semver": "^7.6.0"
47
50
  },
@@ -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
  }