devcompass 1.0.5 โ†’ 2.1.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
@@ -1,19 +1,25 @@
1
1
  # ๐Ÿงญ DevCompass
2
2
 
3
- **Dependency health checker for JavaScript/TypeScript projects**
3
+ **Dependency health checker with ecosystem intelligence for JavaScript/TypeScript projects**
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/devcompass.svg)](https://www.npmjs.com/package/devcompass)
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, and get a health score.
9
+ Analyze your JavaScript projects to find unused dependencies, outdated packages, **detect known security issues**, and **automatically fix them** with a single command.
10
+
11
+ > **NEW in v2.1:** Auto-fix command! ๐Ÿ”ง Fix critical issues automatically!
12
+ > **NEW in v2.0:** Real-time ecosystem alerts for known issues! ๐Ÿšจ
10
13
 
11
14
  ## โœจ Features
12
15
 
16
+ - ๐Ÿ”ง **Auto-Fix Command** (NEW in v2.1!) - Fix issues automatically with one command
17
+ - ๐Ÿšจ **Ecosystem Intelligence** - Detect known issues before they break production
13
18
  - ๐Ÿ” **Detect unused dependencies** - Find packages you're not actually using
14
19
  - ๐Ÿ“ฆ **Check for outdated packages** - See what needs updating
20
+ - ๐Ÿ” **Security alerts** - Critical vulnerabilities and deprecated packages
15
21
  - ๐Ÿ“Š **Project health score** - Get a 0-10 rating for your dependencies
16
- - ๐ŸŽจ **Beautiful terminal UI** - Colored output with clear sections
22
+ - ๐ŸŽจ **Beautiful terminal UI** - Colored output with severity indicators
17
23
  - โšก **Fast analysis** - Scans projects in seconds
18
24
  - ๐Ÿ”ง **Framework-aware** - Handles React, Next.js, Angular, NestJS, PostCSS, Tailwind
19
25
 
@@ -36,48 +42,219 @@ npx devcompass analyze
36
42
 
37
43
  ## ๐Ÿ“– Usage
38
44
 
45
+ ### Analyze Your Project
39
46
  Navigate to your project directory and run:
40
47
  ```bash
41
48
  devcompass analyze
42
49
  ```
43
50
 
51
+ ### Auto-Fix Issues (NEW in v2.1!)
52
+ Automatically fix detected issues:
53
+ ```bash
54
+ devcompass fix
55
+ ```
56
+
57
+ ## ๐Ÿ”ง Auto-Fix Command (NEW in v2.1!)
58
+
59
+ DevCompass can now **automatically fix issues** in your project!
60
+
61
+ ### What it does:
62
+ - ๐Ÿ”ด **Fixes critical security issues** - Upgrades packages with known vulnerabilities
63
+ - ๐Ÿงน **Removes unused dependencies** - Cleans up packages you're not using
64
+ - โฌ†๏ธ **Safe updates** - Applies patch and minor updates automatically
65
+ - โš ๏ธ **Skips breaking changes** - Major updates require manual review
66
+
67
+ ### Usage
68
+ ```bash
69
+ # Interactive mode (asks for confirmation)
70
+ devcompass fix
71
+
72
+ # Auto-apply without confirmation
73
+ devcompass fix --yes
74
+ devcompass fix -y
75
+
76
+ # Fix specific directory
77
+ devcompass fix --path /path/to/project
78
+ ```
79
+
44
80
  ### Example Output
45
81
  ```
46
- ๐Ÿ” DevCompass v1.0.1 - Analyzing your project...
82
+ ๐Ÿ”ง DevCompass Fix - Analyzing and fixing your project...
83
+
84
+ ๐Ÿ”ด CRITICAL ISSUES TO FIX:
85
+
86
+ ๐Ÿ”ด lodash@4.17.19
87
+ Issue: Prototype pollution vulnerability
88
+ Fix: Upgrade to 4.17.21
89
+
90
+ ๐ŸŸ  axios@1.6.0
91
+ Issue: Memory leak in request interceptors
92
+ Fix: Upgrade to 1.6.2
93
+
94
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
95
+
96
+ ๐Ÿงน UNUSED DEPENDENCIES TO REMOVE:
97
+
98
+ โ— moment
99
+ โ— express
100
+
101
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
102
+
103
+ โฌ†๏ธ SAFE UPDATES (patch/minor):
104
+
105
+ react-dom: 18.2.0 โ†’ 18.2.1 (patch update)
106
+
107
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
108
+
109
+ โš ๏ธ MAJOR UPDATES (skipped - may have breaking changes):
110
+
111
+ express: 4.18.0 โ†’ 5.2.1
112
+
113
+ Run these manually after reviewing changelog:
114
+ npm install express@5.2.1
115
+
116
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
117
+
118
+ ๐Ÿ“Š FIX SUMMARY:
119
+
120
+ Critical fixes: 2
121
+ Remove unused: 2
122
+ Safe updates: 1
123
+ Skipped major: 1
124
+
125
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
126
+
127
+ โ“ Apply these fixes? (y/N): y
128
+
129
+ ๐Ÿ”ง Applying fixes...
130
+
131
+ โœ” โœ… Removed 2 unused packages
132
+ โœ” โœ… Fixed lodash@4.17.21
133
+ โœ” โœ… Fixed axios@1.6.2
134
+ โœ” โœ… Updated 1 packages
135
+
136
+ โœจ All fixes applied successfully!
137
+
138
+ ๐Ÿ’ก Run devcompass analyze to see the new health score.
139
+ ```
140
+
141
+ ### Safety Features
142
+ - โœ… Shows what will be changed before applying
143
+ - โœ… Requires confirmation (unless `--yes` flag used)
144
+ - โœ… Skips major updates (may have breaking changes)
145
+ - โœ… Groups actions by priority (critical โ†’ cleanup โ†’ updates)
146
+ - โœ… Provides clear summary of changes
147
+
148
+ ### Workflow Example
149
+ ```bash
150
+ # 1. Analyze your project
151
+ devcompass analyze
152
+
153
+ # 2. If issues found, auto-fix them
154
+ devcompass fix
155
+
156
+ # 3. Verify the improvements
157
+ devcompass analyze
158
+ ```
159
+
160
+ ## ๐Ÿ“Š Analyze Command
161
+
162
+ ### Example Output (v2.1)
163
+ ```
164
+ ๐Ÿ” DevCompass v2.1.0 - Analyzing your project...
47
165
  โœ” Scanned 15 dependencies in project
166
+
167
+ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
168
+
169
+ ๐Ÿšจ ECOSYSTEM ALERTS (2)
170
+
171
+ ๐Ÿ”ด CRITICAL
172
+ lodash@4.17.19
173
+ Issue: Prototype pollution vulnerability
174
+ Affected: <4.17.21
175
+ Fix: 4.17.21
176
+ Source: npm advisory 1523
177
+
178
+ ๐ŸŸ  HIGH
179
+ axios@1.6.0
180
+ Issue: Memory leak in request interceptors
181
+ Affected: >=1.5.0 <1.6.2
182
+ Fix: 1.6.2
183
+ Source: GitHub Issue #5456
184
+
48
185
  โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
49
186
 
50
187
  ๐Ÿ”ด UNUSED DEPENDENCIES (2)
51
- โ— lodash
52
188
  โ— moment
189
+ โ— request
53
190
 
54
191
  โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
55
192
 
56
193
  ๐ŸŸก OUTDATED PACKAGES (3)
57
194
  react 18.2.0 โ†’ ^19.0.0 (major update)
58
- axios 1.4.0 โ†’ ^1.6.0 (minor update)
59
195
  express 4.18.0 โ†’ ^4.19.0 (patch update)
60
196
 
61
197
  โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
62
198
 
63
199
  ๐Ÿ“Š PROJECT HEALTH
64
- Overall Score: 6.5/10
200
+ Overall Score: 5.5/10
65
201
  Total Dependencies: 15
202
+ Ecosystem Alerts: 2
66
203
  Unused: 2
67
204
  Outdated: 3
68
205
 
69
206
  โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
70
207
 
71
- ๐Ÿ’ก QUICK WIN
72
- Clean up unused dependencies:
73
- npm uninstall lodash moment
208
+ ๐Ÿ’ก QUICK WINS
209
+ ๐Ÿ”ด Fix critical issues:
210
+
211
+ npm install lodash@4.17.21
212
+ npm install axios@1.6.2
213
+
214
+ ๐Ÿงน Clean up unused dependencies:
215
+
216
+ npm uninstall moment request
74
217
 
75
218
  Expected impact:
219
+ โœ“ Resolve critical security/stability issues
76
220
  โœ“ Remove 2 unused packages
77
221
  โœ“ Reduce node_modules size
78
- โœ“ Improve health score โ†’ 7.5/10
222
+ โœ“ Improve health score โ†’ 8.5/10
223
+
224
+ ๐Ÿ’ก TIP: Run 'devcompass fix' to apply these fixes automatically!
79
225
  ```
80
226
 
227
+ ## ๐Ÿšจ Ecosystem Intelligence
228
+
229
+ DevCompass tracks **real-world issues** in popular packages and warns you before they break production!
230
+
231
+ ### What Gets Detected:
232
+ - ๐Ÿ”ด **Critical security vulnerabilities** - Zero-day exploits, prototype pollution
233
+ - ๐ŸŸ  **High-severity bugs** - Memory leaks, data corruption, breaking changes
234
+ - ๐ŸŸก **Deprecated packages** - Unmaintained dependencies
235
+ - โšช **Low-priority issues** - Minor bugs, cosmetic problems
236
+
237
+ ### Severity Levels:
238
+ - **CRITICAL** - Immediate security risk or data loss (โˆ’2.0 points per issue)
239
+ - **HIGH** - Production stability issues (โˆ’1.5 points per issue)
240
+ - **MEDIUM** - Maintenance concerns, deprecations (โˆ’0.5 points per issue)
241
+ - **LOW** - Minor issues (โˆ’0.2 points per issue)
242
+
243
+ ### Currently Tracked Packages:
244
+ - **axios** - Memory leaks, breaking changes
245
+ - **lodash** - Security vulnerabilities (prototype pollution)
246
+ - **moment** - Deprecation notice
247
+ - **express** - Security issues in dependencies
248
+ - **request** - Package deprecated
249
+
250
+ > More packages being added regularly! [Suggest a package](https://github.com/AjayBThorat-20/devcompass/issues)
251
+
252
+ ### How It Works:
253
+ 1. Reads your actual installed versions from `node_modules`
254
+ 2. Matches against curated issues database
255
+ 3. Uses semantic versioning for precise detection
256
+ 4. Shows actionable fix commands
257
+
81
258
  ## ๐ŸŽฏ What It Detects
82
259
 
83
260
  ### Unused Dependencies
@@ -100,25 +277,41 @@ DevCompass won't flag these as unused (they're typically used in config files):
100
277
  - Shows current vs latest versions
101
278
  - Indicates update type (major/minor/patch)
102
279
 
103
- ### Health Score
104
- - Calculated from 0-10 based on:
105
- - Percentage of unused dependencies (-4 points per 100%)
106
- - Percentage of outdated packages (-3 points per 100%)
280
+ ### Health Score (Enhanced in v2.0)
281
+ Calculated from 0-10 based on:
282
+ - Percentage of unused dependencies (โˆ’4 points per 100%)
283
+ - Percentage of outdated packages (โˆ’3 points per 100%)
284
+ - Ecosystem alerts by severity (โˆ’0.2 to โˆ’2.0 per issue)
107
285
  - Higher score = healthier project
108
286
 
109
- ## โš™๏ธ Options
287
+ ## โš™๏ธ Commands & Options
288
+
289
+ ### Commands
110
290
  ```bash
111
- # Analyze current directory
291
+ # Analyze project dependencies
112
292
  devcompass analyze
113
293
 
114
- # Analyze specific directory
115
- devcompass analyze --path /path/to/project
294
+ # Auto-fix issues
295
+ devcompass fix
116
296
 
117
297
  # Show version
118
298
  devcompass --version
299
+ devcompass -v
119
300
 
120
301
  # Show help
121
302
  devcompass --help
303
+ devcompass -h
304
+ ```
305
+
306
+ ### Options
307
+ ```bash
308
+ # Analyze/fix specific directory
309
+ devcompass analyze --path /path/to/project
310
+ devcompass fix --path /path/to/project
311
+
312
+ # Auto-fix without confirmation
313
+ devcompass fix --yes
314
+ devcompass fix -y
122
315
  ```
123
316
 
124
317
  ## โš ๏ธ Known Issues & Best Practices
@@ -147,9 +340,10 @@ If you encounter a false positive, please [report it](https://github.com/AjayBTh
147
340
  ## ๐Ÿ’ก Tips
148
341
 
149
342
  1. **Run regularly** - Add to your CI/CD pipeline or git hooks
150
- 2. **Check before updates** - See what's outdated before updating
151
- 3. **Clean up first** - Remove unused deps before adding new ones
152
- 4. **Verify before uninstalling** - DevCompass helps identify candidates, but always verify before removing
343
+ 2. **Use fix command** - Let DevCompass handle routine maintenance
344
+ 3. **Fix critical alerts first** - Prioritize security and stability
345
+ 4. **Review major updates** - Always check changelogs before major version bumps
346
+ 5. **Verify before uninstalling** - DevCompass helps identify candidates, but always verify
153
347
 
154
348
  ## ๐Ÿค Contributing
155
349
 
@@ -161,6 +355,27 @@ Contributions are welcome! Feel free to:
161
355
  4. Push to the branch (`git push origin feature/amazing-feature`)
162
356
  5. Open a Pull Request
163
357
 
358
+ ### Adding Issues to Database
359
+ Want to add known issues for a package?
360
+
361
+ 1. Edit `data/issues-db.json`
362
+ 2. Follow the existing format:
363
+ ```json
364
+ {
365
+ "package-name": [
366
+ {
367
+ "title": "Brief issue description",
368
+ "severity": "critical|high|medium|low",
369
+ "affected": "semver range (e.g., >=1.0.0 <2.0.0)",
370
+ "fix": "Fixed version or migration advice",
371
+ "source": "GitHub Issue #123 or npm advisory",
372
+ "reported": "YYYY-MM-DD"
373
+ }
374
+ ]
375
+ }
376
+ ```
377
+ 3. Submit a PR with your additions!
378
+
164
379
  ### Development
165
380
  ```bash
166
381
  # Clone the repo
@@ -172,10 +387,15 @@ npm install
172
387
 
173
388
  # Test locally
174
389
  node bin/devcompass.js analyze
390
+ node bin/devcompass.js fix
175
391
 
176
392
  # Run on test projects
177
- cd examples/test-project
178
- node ../../bin/devcompass.js analyze
393
+ cd /tmp
394
+ mkdir test-project && cd test-project
395
+ npm init -y
396
+ npm install axios@1.6.0 lodash@4.17.19
397
+ node ~/devcompass/bin/devcompass.js analyze
398
+ node ~/devcompass/bin/devcompass.js fix
179
399
  ```
180
400
 
181
401
  ## ๐Ÿ“ License
@@ -197,6 +417,7 @@ Built with:
197
417
  - [chalk](https://github.com/chalk/chalk) - Terminal colors
198
418
  - [ora](https://github.com/sindresorhus/ora) - Spinners
199
419
  - [commander](https://github.com/tj/commander.js) - CLI framework
420
+ - [semver](https://github.com/npm/node-semver) - Semantic versioning
200
421
 
201
422
  ## ๐Ÿ“ˆ Stats
202
423
 
@@ -204,8 +425,24 @@ Check out DevCompass stats:
204
425
  - [npm trends](https://npmtrends.com/devcompass)
205
426
  - [npm-stat](https://npm-stat.com/charts.html?package=devcompass)
206
427
 
428
+ ## ๐ŸŒŸ What's Next?
429
+
430
+ ### Roadmap (v2.2+)
431
+ - [x] ~~Automatic fix command~~ โœ… **Added in v2.1!**
432
+ - [ ] Integration with `npm audit` for automated security scanning
433
+ - [ ] CI/CD integration with `--json` output
434
+ - [ ] GitHub Issues API for real-time issue tracking
435
+ - [ ] Web dashboard for team health monitoring
436
+ - [ ] More tracked packages (React, Next.js, Vue, Angular)
437
+ - [ ] Custom ignore rules via config file
438
+ - [ ] Bundle size analysis
439
+
440
+ Want to contribute? Pick an item and open an issue! ๐Ÿš€
441
+
207
442
  ---
208
443
 
209
444
  **Made with โค๏ธ by [Ajay Thorat](https://github.com/AjayBThorat-20)**
210
445
 
211
- *DevCompass - Keep your dependencies healthy!* ๐Ÿงญ
446
+ *DevCompass - Keep your dependencies healthy!* ๐Ÿงญ
447
+
448
+ **Like Lighthouse for your dependencies** โšก
package/bin/devcompass.js CHANGED
@@ -4,6 +4,7 @@ const { Command } = require('commander');
4
4
  const chalk = require('chalk');
5
5
  const path = require('path');
6
6
  const { analyze } = require('../src/commands/analyze');
7
+ const { fix } = require('../src/commands/fix');
7
8
  const packageJson = require('../package.json');
8
9
 
9
10
  // Check if running from local node_modules
@@ -31,4 +32,11 @@ program
31
32
  .option('-p, --path <path>', 'Project path', process.cwd())
32
33
  .action(analyze);
33
34
 
34
- program.parse();
35
+ program
36
+ .command('fix')
37
+ .description('Fix issues automatically (remove unused, update safe packages)')
38
+ .option('-p, --path <path>', 'Project path', process.cwd())
39
+ .option('-y, --yes', 'Skip confirmation prompt', false)
40
+ .action(fix);
41
+
42
+ program.parse();
@@ -0,0 +1,60 @@
1
+ {
2
+ "axios": [
3
+ {
4
+ "title": "Memory leak in request interceptors",
5
+ "severity": "high",
6
+ "affected": ">=1.5.0 <1.6.2",
7
+ "fix": "1.6.2",
8
+ "source": "GitHub Issue #5456",
9
+ "reported": "2024-01-15"
10
+ },
11
+ {
12
+ "title": "Breaking change in error handling",
13
+ "severity": "medium",
14
+ "affected": ">=1.4.0 <1.5.0",
15
+ "fix": "1.5.0",
16
+ "source": "GitHub Release Notes",
17
+ "reported": "2023-11-20"
18
+ }
19
+ ],
20
+ "lodash": [
21
+ {
22
+ "title": "Prototype pollution vulnerability",
23
+ "severity": "critical",
24
+ "affected": "<4.17.21",
25
+ "fix": "4.17.21",
26
+ "source": "npm advisory 1523",
27
+ "reported": "2021-02-15"
28
+ }
29
+ ],
30
+ "moment": [
31
+ {
32
+ "title": "Package is deprecated - no longer maintained",
33
+ "severity": "medium",
34
+ "affected": "*",
35
+ "fix": "Use dayjs or date-fns instead",
36
+ "source": "npm deprecation notice",
37
+ "reported": "2023-09-01"
38
+ }
39
+ ],
40
+ "request": [
41
+ {
42
+ "title": "Package deprecated - use node-fetch or axios",
43
+ "severity": "high",
44
+ "affected": "*",
45
+ "fix": "Migrate to axios or node-fetch",
46
+ "source": "npm deprecation notice",
47
+ "reported": "2020-02-11"
48
+ }
49
+ ],
50
+ "express": [
51
+ {
52
+ "title": "Security vulnerability in qs dependency",
53
+ "severity": "medium",
54
+ "affected": ">=4.0.0 <4.18.2",
55
+ "fix": "4.18.2",
56
+ "source": "npm advisory 1867",
57
+ "reported": "2022-11-26"
58
+ }
59
+ ]
60
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "devcompass",
3
- "version": "1.0.5",
4
- "description": "Analyze your JavaScript projects for unused dependencies and outdated packages",
3
+ "version": "2.1.0",
4
+ "description": "Dependency health checker with ecosystem intelligence for JavaScript/TypeScript projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "devcompass": "./bin/devcompass.js"
@@ -9,6 +9,7 @@
9
9
  "files": [
10
10
  "bin/",
11
11
  "src/",
12
+ "data/",
12
13
  "README.md",
13
14
  "LICENSE"
14
15
  ],
@@ -25,7 +26,10 @@
25
26
  "cli",
26
27
  "devtools",
27
28
  "package-manager",
28
- "dependency-analysis"
29
+ "dependency-analysis",
30
+ "security",
31
+ "ecosystem",
32
+ "alerts"
29
33
  ],
30
34
  "author": "Ajay Thorat <ajaythorat988@gmail.com>",
31
35
  "license": "MIT",
@@ -34,7 +38,8 @@
34
38
  "commander": "^11.1.0",
35
39
  "depcheck": "^1.4.7",
36
40
  "npm-check-updates": "^16.14.12",
37
- "ora": "^5.4.1"
41
+ "ora": "^5.4.1",
42
+ "semver": "^7.6.0"
38
43
  },
39
44
  "engines": {
40
45
  "node": ">=14.0.0"
@@ -0,0 +1,68 @@
1
+ const chalk = require('chalk');
2
+
3
+ /**
4
+ * Format alerts for terminal output
5
+ */
6
+ function formatAlerts(alerts) {
7
+ if (alerts.length === 0) {
8
+ return null;
9
+ }
10
+
11
+ // Group alerts by package
12
+ const grouped = {};
13
+
14
+ alerts.forEach(alert => {
15
+ if (!grouped[alert.package]) {
16
+ grouped[alert.package] = [];
17
+ }
18
+ grouped[alert.package].push(alert);
19
+ });
20
+
21
+ return grouped;
22
+ }
23
+
24
+ /**
25
+ * Get severity emoji and color
26
+ */
27
+ function getSeverityDisplay(severity) {
28
+ const displays = {
29
+ critical: { emoji: '๐Ÿ”ด', color: chalk.red.bold, label: 'CRITICAL' },
30
+ high: { emoji: '๐ŸŸ ', color: chalk.red, label: 'HIGH' },
31
+ medium: { emoji: '๐ŸŸก', color: chalk.yellow, label: 'MEDIUM' },
32
+ low: { emoji: 'โšช', color: chalk.gray, label: 'LOW' }
33
+ };
34
+
35
+ return displays[severity] || displays.medium;
36
+ }
37
+
38
+ /**
39
+ * Calculate alert impact on health score
40
+ */
41
+ function calculateAlertPenalty(alerts) {
42
+ let penalty = 0;
43
+
44
+ alerts.forEach(alert => {
45
+ switch (alert.severity) {
46
+ case 'critical':
47
+ penalty += 2.0;
48
+ break;
49
+ case 'high':
50
+ penalty += 1.5;
51
+ break;
52
+ case 'medium':
53
+ penalty += 0.5;
54
+ break;
55
+ case 'low':
56
+ penalty += 0.2;
57
+ break;
58
+ }
59
+ });
60
+
61
+ return Math.min(penalty, 5.0); // Cap at 5 points max
62
+ }
63
+
64
+ module.exports = {
65
+ formatAlerts,
66
+ getSeverityDisplay,
67
+ calculateAlertPenalty
68
+ };
@@ -0,0 +1,31 @@
1
+ const { matchIssues } = require('./matcher');
2
+ const { formatAlerts } = require('./formatter');
3
+ const { resolveInstalledVersions } = require('./resolver');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+
7
+ async function checkEcosystemAlerts(projectPath, dependencies) {
8
+ try {
9
+ // Load issues database
10
+ const issuesDbPath = path.join(__dirname, '../../data/issues-db.json');
11
+
12
+ if (!fs.existsSync(issuesDbPath)) {
13
+ return []; // No alerts if database doesn't exist
14
+ }
15
+
16
+ const issuesDb = JSON.parse(fs.readFileSync(issuesDbPath, 'utf8'));
17
+
18
+ // Resolve installed versions from node_modules
19
+ const installedVersions = await resolveInstalledVersions(projectPath, dependencies);
20
+
21
+ // Match issues against installed versions
22
+ const alerts = matchIssues(installedVersions, issuesDb);
23
+
24
+ return alerts;
25
+ } catch (error) {
26
+ console.error('Error in checkEcosystemAlerts:', error.message);
27
+ return []; // Return empty array on error, don't break analysis
28
+ }
29
+ }
30
+
31
+ module.exports = { checkEcosystemAlerts };
@@ -0,0 +1,50 @@
1
+ const semver = require('semver');
2
+
3
+ /**
4
+ * Match installed packages against known issues database
5
+ */
6
+ function matchIssues(installedVersions, issuesDb) {
7
+ const alerts = [];
8
+
9
+ for (const [packageName, versionInfo] of Object.entries(installedVersions)) {
10
+ // Check if this package has known issues
11
+ if (!issuesDb[packageName]) {
12
+ continue;
13
+ }
14
+
15
+ const packageIssues = issuesDb[packageName];
16
+ const installedVersion = versionInfo.version;
17
+
18
+ // Check each issue for this package
19
+ for (const issue of packageIssues) {
20
+ try {
21
+ // Use semver to check if installed version is affected
22
+ if (semver.satisfies(installedVersion, issue.affected)) {
23
+ alerts.push({
24
+ package: packageName,
25
+ version: installedVersion,
26
+ severity: issue.severity,
27
+ title: issue.title,
28
+ affected: issue.affected,
29
+ fix: issue.fix || null,
30
+ source: issue.source || null,
31
+ reported: issue.reported || null
32
+ });
33
+ }
34
+ } catch (error) {
35
+ // Skip if semver parsing fails
36
+ continue;
37
+ }
38
+ }
39
+ }
40
+
41
+ // Sort by severity: critical > high > medium > low
42
+ const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
43
+ alerts.sort((a, b) => {
44
+ return severityOrder[a.severity] - severityOrder[b.severity];
45
+ });
46
+
47
+ return alerts;
48
+ }
49
+
50
+ module.exports = { matchIssues };
@@ -0,0 +1,45 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ /**
5
+ * Resolve actual installed versions from node_modules
6
+ * This is CRITICAL - we need installed version, not package.json version
7
+ */
8
+ async function resolveInstalledVersions(projectPath, dependencies) {
9
+ const installedVersions = {};
10
+
11
+ for (const [packageName, declaredVersion] of Object.entries(dependencies)) {
12
+ try {
13
+ const packageJsonPath = path.join(
14
+ projectPath,
15
+ 'node_modules',
16
+ packageName,
17
+ 'package.json'
18
+ );
19
+
20
+ if (fs.existsSync(packageJsonPath)) {
21
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
22
+ installedVersions[packageName] = {
23
+ name: packageName,
24
+ version: packageJson.version, // Clean version like "1.6.0"
25
+ declaredVersion: declaredVersion // What's in package.json like "^1.6.0"
26
+ };
27
+ } else {
28
+ // Fallback: use declared version (strip prefixes)
29
+ const cleanVersion = declaredVersion.replace(/^[\^~>=<]/, '');
30
+ installedVersions[packageName] = {
31
+ name: packageName,
32
+ version: cleanVersion,
33
+ declaredVersion: declaredVersion
34
+ };
35
+ }
36
+ } catch (error) {
37
+ // Skip packages that can't be resolved
38
+ continue;
39
+ }
40
+ }
41
+
42
+ return installedVersions;
43
+ }
44
+
45
+ module.exports = { resolveInstalledVersions };
@@ -1,4 +1,4 @@
1
- function calculateScore(totalDeps, unusedCount, outdatedCount) {
1
+ function calculateScore(totalDeps, unusedCount, outdatedCount, alertsCount = 0, alertPenalty = 0) {
2
2
  let score = 10;
3
3
 
4
4
  if (totalDeps === 0) {
@@ -7,20 +7,28 @@ function calculateScore(totalDeps, unusedCount, outdatedCount) {
7
7
  breakdown: {
8
8
  unused: 0,
9
9
  outdated: 0,
10
+ alerts: 0,
10
11
  unusedPenalty: 0,
11
- outdatedPenalty: 0
12
+ outdatedPenalty: 0,
13
+ alertsPenalty: 0
12
14
  }
13
15
  };
14
16
  }
15
17
 
18
+ // Unused dependencies penalty
16
19
  const unusedRatio = unusedCount / totalDeps;
17
20
  const unusedPenalty = unusedRatio * 4;
18
21
  score -= unusedPenalty;
19
22
 
23
+ // Outdated packages penalty
20
24
  const outdatedRatio = outdatedCount / totalDeps;
21
25
  const outdatedPenalty = outdatedRatio * 3;
22
26
  score -= outdatedPenalty;
23
27
 
28
+ // Ecosystem alerts penalty (from formatter.calculateAlertPenalty)
29
+ score -= alertPenalty;
30
+
31
+ // Ensure score is between 0 and 10
24
32
  score = Math.max(0, Math.min(10, score));
25
33
 
26
34
  return {
@@ -28,8 +36,10 @@ function calculateScore(totalDeps, unusedCount, outdatedCount) {
28
36
  breakdown: {
29
37
  unused: unusedCount,
30
38
  outdated: outdatedCount,
39
+ alerts: alertsCount,
31
40
  unusedPenalty: parseFloat(unusedPenalty.toFixed(1)),
32
- outdatedPenalty: parseFloat(outdatedPenalty.toFixed(1))
41
+ outdatedPenalty: parseFloat(outdatedPenalty.toFixed(1)),
42
+ alertsPenalty: parseFloat(alertPenalty.toFixed(1))
33
43
  }
34
44
  };
35
45
  }
@@ -1,4 +1,3 @@
1
- // src/commands/analyze.js
2
1
  const chalk = require('chalk');
3
2
  const ora = require('ora');
4
3
  const path = require('path');
@@ -7,6 +6,12 @@ const fs = require('fs');
7
6
  const { findUnusedDeps } = require('../analyzers/unused-deps');
8
7
  const { findOutdatedDeps } = require('../analyzers/outdated');
9
8
  const { calculateScore } = require('../analyzers/scoring');
9
+ const { checkEcosystemAlerts } = require('../alerts');
10
+ const {
11
+ formatAlerts,
12
+ getSeverityDisplay,
13
+ calculateAlertPenalty
14
+ } = require('../alerts/formatter');
10
15
  const {
11
16
  log,
12
17
  logSection,
@@ -58,8 +63,17 @@ async function analyze(options) {
58
63
  process.exit(0);
59
64
  }
60
65
 
61
- spinner.text = 'Detecting unused dependencies...';
66
+ // Check for ecosystem alerts
67
+ spinner.text = 'Checking ecosystem alerts...';
68
+ let alerts = [];
69
+ try {
70
+ alerts = await checkEcosystemAlerts(projectPath, dependencies);
71
+ } catch (error) {
72
+ console.log(chalk.yellow('\nโš ๏ธ Could not check ecosystem alerts'));
73
+ console.log(chalk.gray(` Error: ${error.message}\n`));
74
+ }
62
75
 
76
+ spinner.text = 'Detecting unused dependencies...';
63
77
  let unusedDeps = [];
64
78
  try {
65
79
  unusedDeps = await findUnusedDeps(projectPath, dependencies);
@@ -69,7 +83,6 @@ async function analyze(options) {
69
83
  }
70
84
 
71
85
  spinner.text = 'Checking for outdated packages...';
72
-
73
86
  let outdatedDeps = [];
74
87
  try {
75
88
  outdatedDeps = await findOutdatedDeps(projectPath, dependencies);
@@ -78,15 +91,18 @@ async function analyze(options) {
78
91
  console.log(chalk.gray(` Error: ${error.message}\n`));
79
92
  }
80
93
 
94
+ const alertPenalty = calculateAlertPenalty(alerts);
81
95
  const score = calculateScore(
82
96
  totalDeps,
83
97
  unusedDeps.length,
84
- outdatedDeps.length
98
+ outdatedDeps.length,
99
+ alerts.length,
100
+ alertPenalty
85
101
  );
86
102
 
87
103
  spinner.succeed(chalk.green(`Scanned ${totalDeps} dependencies in project`));
88
104
 
89
- displayResults(unusedDeps, outdatedDeps, score, totalDeps);
105
+ displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps);
90
106
 
91
107
  } catch (error) {
92
108
  spinner.fail(chalk.red('Analysis failed'));
@@ -98,13 +114,53 @@ async function analyze(options) {
98
114
  }
99
115
  }
100
116
 
101
- function displayResults(unusedDeps, outdatedDeps, score, totalDeps) {
117
+ function displayResults(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
102
118
  logDivider();
103
119
 
120
+ // ECOSYSTEM ALERTS (NEW SECTION)
121
+ if (alerts.length > 0) {
122
+ logSection('๐Ÿšจ ECOSYSTEM ALERTS', alerts.length);
123
+
124
+ const grouped = formatAlerts(alerts);
125
+
126
+ Object.entries(grouped).forEach(([packageName, packageAlerts]) => {
127
+ const firstAlert = packageAlerts[0];
128
+ const display = getSeverityDisplay(firstAlert.severity);
129
+
130
+ log(`\n${display.emoji} ${display.color(display.label)}`);
131
+ log(` ${chalk.bold(packageName)}${chalk.gray('@' + firstAlert.version)}`);
132
+
133
+ packageAlerts.forEach((alert, index) => {
134
+ if (index > 0) {
135
+ const alertDisplay = getSeverityDisplay(alert.severity);
136
+ log(`\n ${alertDisplay.emoji} ${alertDisplay.color(alertDisplay.label)}`);
137
+ }
138
+
139
+ log(` ${chalk.yellow('Issue:')} ${alert.title}`);
140
+ log(` ${chalk.gray('Affected:')} ${alert.affected}`);
141
+
142
+ if (alert.fix) {
143
+ log(` ${chalk.green('Fix:')} ${alert.fix}`);
144
+ }
145
+
146
+ if (alert.source) {
147
+ log(` ${chalk.gray('Source:')} ${alert.source}`);
148
+ }
149
+ });
150
+ });
151
+
152
+ log('');
153
+ } else {
154
+ logSection('โœ… ECOSYSTEM ALERTS');
155
+ log(chalk.green(' No known issues detected!\n'));
156
+ }
157
+
158
+ logDivider();
159
+
160
+ // UNUSED DEPENDENCIES
104
161
  if (unusedDeps.length > 0) {
105
162
  logSection('๐Ÿ”ด UNUSED DEPENDENCIES', unusedDeps.length);
106
163
 
107
- // Show ALL unused deps
108
164
  unusedDeps.forEach(dep => {
109
165
  log(` ${chalk.red('โ—')} ${dep.name}`);
110
166
  });
@@ -120,10 +176,10 @@ function displayResults(unusedDeps, outdatedDeps, score, totalDeps) {
120
176
 
121
177
  logDivider();
122
178
 
179
+ // OUTDATED PACKAGES
123
180
  if (outdatedDeps.length > 0) {
124
181
  logSection('๐ŸŸก OUTDATED PACKAGES', outdatedDeps.length);
125
182
 
126
- // Show ALL outdated packages
127
183
  outdatedDeps.forEach(dep => {
128
184
  const nameCol = dep.name.padEnd(20);
129
185
  const currentVer = chalk.yellow(dep.current);
@@ -142,36 +198,79 @@ function displayResults(unusedDeps, outdatedDeps, score, totalDeps) {
142
198
 
143
199
  logDivider();
144
200
 
201
+ // PROJECT HEALTH
145
202
  logSection('๐Ÿ“Š PROJECT HEALTH');
146
203
 
147
204
  const scoreColor = getScoreColor(score.total);
148
205
  log(` Overall Score: ${scoreColor(score.total + '/10')}`);
149
206
  log(` Total Dependencies: ${chalk.cyan(totalDeps)}`);
207
+
208
+ if (alerts.length > 0) {
209
+ log(` Ecosystem Alerts: ${chalk.red(alerts.length)}`);
210
+ }
211
+
150
212
  log(` Unused: ${chalk.red(unusedDeps.length)}`);
151
213
  log(` Outdated: ${chalk.yellow(outdatedDeps.length)}\n`);
152
214
 
153
215
  logDivider();
154
216
 
155
- if (unusedDeps.length > 0) {
156
- logSection('๐Ÿ’ก QUICK WIN');
157
- log(' Clean up unused dependencies:\n');
158
-
159
- const packagesToRemove = unusedDeps
160
- .map(d => d.name)
161
- .join(' ');
217
+ // QUICK WINS
218
+ displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps);
219
+ }
220
+
221
+ function displayQuickWins(alerts, unusedDeps, outdatedDeps, score, totalDeps) {
222
+ const hasCriticalAlerts = alerts.some(a => a.severity === 'critical' || a.severity === 'high');
223
+
224
+ if (hasCriticalAlerts || unusedDeps.length > 0) {
225
+ logSection('๐Ÿ’ก QUICK WINS');
162
226
 
163
- log(chalk.cyan(` npm uninstall ${packagesToRemove}\n`));
227
+ // Fix critical alerts first
228
+ if (hasCriticalAlerts) {
229
+ const criticalAlerts = alerts.filter(a => a.severity === 'critical' || a.severity === 'high');
230
+
231
+ log(' ๐Ÿ”ด Fix critical issues:\n');
232
+
233
+ criticalAlerts.forEach(alert => {
234
+ if (alert.fix && alert.fix.includes('.')) {
235
+ // It's a version number
236
+ log(chalk.cyan(` npm install ${alert.package}@${alert.fix}`));
237
+ } else {
238
+ log(chalk.gray(` ${alert.package}: ${alert.fix}`));
239
+ }
240
+ });
241
+
242
+ log('');
243
+ }
164
244
 
165
- log(' Expected impact:');
166
- log(` ${chalk.green('โœ“')} Remove ${unusedDeps.length} unused package${unusedDeps.length > 1 ? 's' : ''}`);
167
- log(` ${chalk.green('โœ“')} Reduce node_modules size`);
245
+ // Remove unused deps
246
+ if (unusedDeps.length > 0) {
247
+ log(' ๐Ÿงน Clean up unused dependencies:\n');
248
+
249
+ const packagesToRemove = unusedDeps.map(d => d.name).join(' ');
250
+ log(chalk.cyan(` npm uninstall ${packagesToRemove}\n`));
251
+ }
168
252
 
253
+ // Show expected impact
254
+ const alertPenalty = calculateAlertPenalty(alerts.filter(a => a.severity !== 'critical' && a.severity !== 'high'));
169
255
  const improvedScore = calculateScore(
170
256
  totalDeps - unusedDeps.length,
171
257
  0,
172
- outdatedDeps.length
258
+ outdatedDeps.length,
259
+ alerts.length - alerts.filter(a => a.severity === 'critical' || a.severity === 'high').length,
260
+ alertPenalty
173
261
  );
174
262
 
263
+ log(' Expected impact:');
264
+
265
+ if (hasCriticalAlerts) {
266
+ log(` ${chalk.green('โœ“')} Resolve critical security/stability issues`);
267
+ }
268
+
269
+ if (unusedDeps.length > 0) {
270
+ log(` ${chalk.green('โœ“')} Remove ${unusedDeps.length} unused package${unusedDeps.length > 1 ? 's' : ''}`);
271
+ log(` ${chalk.green('โœ“')} Reduce node_modules size`);
272
+ }
273
+
175
274
  const improvedScoreColor = getScoreColor(improvedScore.total);
176
275
  log(` ${chalk.green('โœ“')} Improve health score โ†’ ${improvedScoreColor(improvedScore.total + '/10')}\n`);
177
276
 
@@ -0,0 +1,246 @@
1
+ const chalk = require('chalk');
2
+ const ora = require('ora');
3
+ const { execSync } = require('child_process');
4
+ const readline = require('readline');
5
+
6
+ const { findUnusedDeps } = require('../analyzers/unused-deps');
7
+ const { findOutdatedDeps } = require('../analyzers/outdated');
8
+ const { checkEcosystemAlerts } = require('../alerts');
9
+ const { getSeverityDisplay } = require('../alerts/formatter');
10
+
11
+ async function fix(options) {
12
+ const projectPath = options.path || process.cwd();
13
+
14
+ console.log('\n');
15
+ console.log(chalk.cyan.bold('๐Ÿ”ง DevCompass Fix') + ' - Analyzing and fixing your project...\n');
16
+
17
+ const spinner = ora({
18
+ text: 'Analyzing project...',
19
+ color: 'cyan'
20
+ }).start();
21
+
22
+ try {
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+ const packageJsonPath = path.join(projectPath, 'package.json');
26
+
27
+ if (!fs.existsSync(packageJsonPath)) {
28
+ spinner.fail(chalk.red('No package.json found'));
29
+ process.exit(1);
30
+ }
31
+
32
+ const projectPackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
33
+ const dependencies = {
34
+ ...(projectPackageJson.dependencies || {}),
35
+ ...(projectPackageJson.devDependencies || {})
36
+ };
37
+
38
+ // Check for critical alerts first
39
+ spinner.text = 'Checking for critical issues...';
40
+ const alerts = await checkEcosystemAlerts(projectPath, dependencies);
41
+ const criticalAlerts = alerts.filter(a => a.severity === 'critical' || a.severity === 'high');
42
+
43
+ // Find unused dependencies
44
+ spinner.text = 'Finding unused dependencies...';
45
+ const unusedDeps = await findUnusedDeps(projectPath, dependencies);
46
+
47
+ // Find outdated packages
48
+ spinner.text = 'Checking for updates...';
49
+ const outdatedDeps = await findOutdatedDeps(projectPath, dependencies);
50
+
51
+ spinner.succeed(chalk.green('Analysis complete!\n'));
52
+
53
+ // Show what will be fixed
54
+ await showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options);
55
+
56
+ } catch (error) {
57
+ spinner.fail(chalk.red('Analysis failed'));
58
+ console.log(chalk.red(`\nโŒ Error: ${error.message}\n`));
59
+ process.exit(1);
60
+ }
61
+ }
62
+
63
+ async function showFixPlan(criticalAlerts, unusedDeps, outdatedDeps, options) {
64
+ const actions = [];
65
+
66
+ // Critical alerts
67
+ if (criticalAlerts.length > 0) {
68
+ console.log(chalk.red.bold('๐Ÿ”ด CRITICAL ISSUES TO FIX:\n'));
69
+
70
+ criticalAlerts.forEach(alert => {
71
+ const display = getSeverityDisplay(alert.severity);
72
+ console.log(`${display.emoji} ${chalk.bold(alert.package)}@${alert.version}`);
73
+ console.log(` ${chalk.gray('Issue:')} ${alert.title}`);
74
+
75
+ if (alert.fix && /^\d+\.\d+/.test(alert.fix)) {
76
+ console.log(` ${chalk.green('Fix:')} Upgrade to ${alert.fix}\n`);
77
+ actions.push({
78
+ type: 'upgrade',
79
+ package: alert.package,
80
+ version: alert.fix,
81
+ reason: 'Critical security/stability issue'
82
+ });
83
+ } else {
84
+ console.log(` ${chalk.yellow('Fix:')} ${alert.fix}\n`);
85
+ }
86
+ });
87
+
88
+ console.log('โ”'.repeat(70) + '\n');
89
+ }
90
+
91
+ // Unused dependencies
92
+ if (unusedDeps.length > 0) {
93
+ console.log(chalk.yellow.bold('๐Ÿงน UNUSED DEPENDENCIES TO REMOVE:\n'));
94
+
95
+ unusedDeps.forEach(dep => {
96
+ console.log(` ${chalk.red('โ—')} ${dep.name}`);
97
+ actions.push({
98
+ type: 'uninstall',
99
+ package: dep.name,
100
+ reason: 'Not used in project'
101
+ });
102
+ });
103
+
104
+ console.log('\n' + 'โ”'.repeat(70) + '\n');
105
+ }
106
+
107
+ // Safe updates (patch/minor only)
108
+ const safeUpdates = outdatedDeps.filter(dep =>
109
+ dep.versionsBehind === 'patch update' || dep.versionsBehind === 'minor update'
110
+ );
111
+
112
+ if (safeUpdates.length > 0) {
113
+ console.log(chalk.cyan.bold('โฌ†๏ธ SAFE UPDATES (patch/minor):\n'));
114
+
115
+ safeUpdates.forEach(dep => {
116
+ console.log(` ${dep.name}: ${chalk.yellow(dep.current)} โ†’ ${chalk.green(dep.latest)} ${chalk.gray(`(${dep.versionsBehind})`)}`);
117
+ actions.push({
118
+ type: 'update',
119
+ package: dep.name,
120
+ version: dep.latest,
121
+ reason: dep.versionsBehind
122
+ });
123
+ });
124
+
125
+ console.log('\n' + 'โ”'.repeat(70) + '\n');
126
+ }
127
+
128
+ // Major updates (show but don't auto-apply)
129
+ const majorUpdates = outdatedDeps.filter(dep => dep.versionsBehind === 'major update');
130
+
131
+ if (majorUpdates.length > 0) {
132
+ console.log(chalk.gray.bold('โš ๏ธ MAJOR UPDATES (skipped - may have breaking changes):\n'));
133
+
134
+ majorUpdates.forEach(dep => {
135
+ console.log(` ${chalk.gray(dep.name)}: ${dep.current} โ†’ ${dep.latest}`);
136
+ });
137
+
138
+ console.log(chalk.gray('\n Run these manually after reviewing changelog:\n'));
139
+ majorUpdates.forEach(dep => {
140
+ console.log(chalk.gray(` npm install ${dep.name}@${dep.latest}`));
141
+ });
142
+
143
+ console.log('\n' + 'โ”'.repeat(70) + '\n');
144
+ }
145
+
146
+ if (actions.length === 0) {
147
+ console.log(chalk.green('โœจ Everything looks good! No fixes needed.\n'));
148
+ return;
149
+ }
150
+
151
+ // Summary
152
+ console.log(chalk.bold('๐Ÿ“Š FIX SUMMARY:\n'));
153
+ console.log(` Critical fixes: ${criticalAlerts.length}`);
154
+ console.log(` Remove unused: ${unusedDeps.length}`);
155
+ console.log(` Safe updates: ${safeUpdates.length}`);
156
+ console.log(` Skipped major: ${majorUpdates.length}\n`);
157
+
158
+ console.log('โ”'.repeat(70) + '\n');
159
+
160
+ // Confirm
161
+ if (options.yes) {
162
+ await applyFixes(actions);
163
+ } else {
164
+ const confirmed = await askConfirmation('\nโ“ Apply these fixes?');
165
+
166
+ if (confirmed) {
167
+ await applyFixes(actions);
168
+ } else {
169
+ console.log(chalk.yellow('\nโš ๏ธ Fix cancelled. No changes made.\n'));
170
+ }
171
+ }
172
+ }
173
+
174
+ async function applyFixes(actions) {
175
+ console.log(chalk.cyan.bold('\n๐Ÿ”ง Applying fixes...\n'));
176
+
177
+ const spinner = ora('Processing...').start();
178
+
179
+ try {
180
+ // Group by type
181
+ const toUninstall = actions.filter(a => a.type === 'uninstall').map(a => a.package);
182
+ const toUpgrade = actions.filter(a => a.type === 'upgrade');
183
+ const toUpdate = actions.filter(a => a.type === 'update');
184
+
185
+ // Uninstall unused
186
+ if (toUninstall.length > 0) {
187
+ spinner.text = `Removing ${toUninstall.length} unused packages...`;
188
+
189
+ const cmd = `npm uninstall ${toUninstall.join(' ')}`;
190
+ execSync(cmd, { stdio: 'pipe' });
191
+
192
+ spinner.succeed(chalk.green(`โœ… Removed ${toUninstall.length} unused packages`));
193
+ spinner.start();
194
+ }
195
+
196
+ // Upgrade critical packages
197
+ for (const action of toUpgrade) {
198
+ spinner.text = `Fixing ${action.package}@${action.version}...`;
199
+
200
+ const cmd = `npm install ${action.package}@${action.version}`;
201
+ execSync(cmd, { stdio: 'pipe' });
202
+
203
+ spinner.succeed(chalk.green(`โœ… Fixed ${action.package}@${action.version}`));
204
+ spinner.start();
205
+ }
206
+
207
+ // Update safe packages
208
+ if (toUpdate.length > 0) {
209
+ spinner.text = `Updating ${toUpdate.length} packages...`;
210
+
211
+ for (const action of toUpdate) {
212
+ const cmd = `npm install ${action.package}@${action.version}`;
213
+ execSync(cmd, { stdio: 'pipe' });
214
+ }
215
+
216
+ spinner.succeed(chalk.green(`โœ… Updated ${toUpdate.length} packages`));
217
+ } else {
218
+ spinner.stop();
219
+ }
220
+
221
+ console.log(chalk.green.bold('\nโœจ All fixes applied successfully!\n'));
222
+ console.log(chalk.cyan('๐Ÿ’ก Run') + chalk.bold(' devcompass analyze ') + chalk.cyan('to see the new health score.\n'));
223
+
224
+ } catch (error) {
225
+ spinner.fail(chalk.red('Fix failed'));
226
+ console.log(chalk.red(`\nโŒ Error: ${error.message}\n`));
227
+ console.log(chalk.yellow('๐Ÿ’ก You may need to fix this manually.\n'));
228
+ process.exit(1);
229
+ }
230
+ }
231
+
232
+ function askConfirmation(question) {
233
+ const rl = readline.createInterface({
234
+ input: process.stdin,
235
+ output: process.stdout
236
+ });
237
+
238
+ return new Promise(resolve => {
239
+ rl.question(chalk.cyan(question) + chalk.gray(' (y/N): '), answer => {
240
+ rl.close();
241
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
242
+ });
243
+ });
244
+ }
245
+
246
+ module.exports = { fix };
@@ -0,0 +1,29 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function loadConfig(projectPath) {
5
+ const configPath = path.join(projectPath, 'devcompass.config.json');
6
+
7
+ if (!fs.existsSync(configPath)) {
8
+ return getDefaultConfig();
9
+ }
10
+
11
+ try {
12
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
13
+ return { ...getDefaultConfig(), ...config };
14
+ } catch (error) {
15
+ console.warn('Warning: Could not parse devcompass.config.json, using defaults');
16
+ return getDefaultConfig();
17
+ }
18
+ }
19
+
20
+ function getDefaultConfig() {
21
+ return {
22
+ ignore: [],
23
+ ignoreSeverity: [],
24
+ minScore: 0,
25
+ cache: true
26
+ };
27
+ }
28
+
29
+ module.exports = { loadConfig };
package/src/index.js DELETED
File without changes