licenseguard-cli 2.1.1 → 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/CHANGELOG.md CHANGED
@@ -5,6 +5,95 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.3.0] - 2026-02-21
9
+
10
+ ### Added
11
+
12
+ - **ESM (ECMAScript Module) Support** - Git hooks now work in ESM projects
13
+ - Auto-detects ESM projects via `package.json` `"type": "module"`
14
+ - Generates ESM-compatible git hooks using `import` syntax for ESM projects
15
+ - Generates CommonJS hooks using `require` syntax for CJS projects
16
+ - `isEsmProject()` utility function for ESM detection
17
+ - ESM hook generators: `generatePostCheckoutScriptEsm()`, `generatePreCommitScriptEsm()`
18
+ - ESM global hooks in `postinstall.js` for `npm install -g` compatibility
19
+ - Full test coverage: 23 unit tests + 5 integration tests
20
+ - Backward compatible - existing CJS projects unaffected
21
+
22
+ ## [2.2.0] - 2025-11-25
23
+
24
+ ### Added
25
+
26
+ - **Friction-Free Adoption (Dual-Mode Init)** - `scan` command now adapts to environment
27
+ - **Interactive Mode**: Prompts user to initialize configuration when missing (TTY)
28
+ - **CI/CD Mode**: Auto-detects project license from package manager files (no TTY or CI env)
29
+ - **Multi-Ecosystem Auto-Detection**: Supports Node.js, Rust, Python, Go, and C++
30
+ - **Graceful Fallback**: Clear error messages with setup instructions when auto-detect fails
31
+ - License auto-detection functions: `autoDetectLicense()`, `detectNodeLicense()`, `detectRustLicense()`, `detectPythonLicense()`, `detectGoLicense()`, `detectCppLicense()`
32
+ - `isInteractive()` helper to detect TTY vs CI/CD environments
33
+ - `isValidLicense()` validator to check for valid license strings (excludes UNLICENSED and empty)
34
+
35
+ - **Deep Scan Engine** - Complete dependency visibility for Node.js projects
36
+ - Parses `package-lock.json` to find ALL packages including transitive dependencies
37
+ - Supports lockfile v1 (npm 5-6), v2 (npm 7-8), v3 (npm 9+)
38
+ - Automatically detects lockfile version and uses appropriate parser
39
+ - Graceful fallback to flat scan when lockfile missing or corrupt
40
+ - **30x improvement** in package discovery: Typical React project goes from 50 packages (flat) → 1500+ packages (deep)
41
+ - **~99% coverage** with deep scan vs ~15% with flat scan
42
+ - Zero configuration required - works automatically when lockfile present
43
+
44
+ - **Dependency Path Visualization** - Shows exact dependency chains for license conflicts
45
+ - Automatically traces paths for GPL conflicts: "app → @facebook/folly → liburing"
46
+ - Uses npm's built-in `npm explain` command (npm 7+ required)
47
+ - Lazy evaluation: Only traces paths when conflicts detected (performance optimized)
48
+ - Caching to avoid duplicate subprocess calls (5 second timeout per package)
49
+ - Graceful fallback: Displays conflicts without paths when npm explain unavailable
50
+ - Answers the key question: "Where did this GPL package come from?"
51
+ - Enables instant decision-making: Remove direct dependency or find alternative
52
+
53
+ - **Coverage Report** - Automatic scan transparency for trust building
54
+ - Shows "X/Y packages identified (Z%)" after every scan
55
+ - Visual indicators: ✅ (90%+ excellent), ⚠️ (70-89% good), ❌ (<70% needs attention)
56
+ - Percentage formatted to 1 decimal place for precision
57
+ - Always displayed by default (no flag needed)
58
+ - Educational tip shown when coverage < 80%: "💡 Tip: Some packages may need manual LICENSE file inspection"
59
+ - Displays BEFORE conflict report in `init` command
60
+ - Displays at end of output in `scan` command
61
+ - Builds user trust through transparency about scan completeness
62
+
63
+ - **HTML Attribution Generator** - Mobile-ready CREDITS.html for App Store compliance
64
+ - New `--format html` flag on `scan` command generates attribution file
65
+ - Mobile-optimized responsive design (max-width 800px desktop, full-width mobile)
66
+ - System fonts for instant loading: `-apple-system, BlinkMacSystemFont, Segoe UI, Roboto`
67
+ - Touch-friendly: 44px minimum touch targets (iOS accessibility guideline)
68
+ - Dark mode support: Automatic light/dark theme adaptation
69
+ - Expandable license text: Click "Show license text" to view full license
70
+ - Alphabetical sorting: Packages sorted by name for easy navigation
71
+ - XSS safe: All user content properly escaped (prevents script injection)
72
+ - Single file: Inline CSS and JavaScript (no external dependencies)
73
+ - Ready to bundle: Works with iOS (Xcode + WKWebView) and Android (assets + WebView)
74
+ - Meets App Store requirements: iOS App Store and Google Play Store attribution compliance
75
+ - Zero configuration: `licenseguard scan --format html` generates `CREDITS.html`
76
+
77
+ ### Changed
78
+ - **`scan` command behavior**: Now checks for `.licenseguardrc` before requiring license specification
79
+ - Interactive mode offers to run `init` instead of throwing error
80
+ - CI/CD mode attempts auto-detection before erroring out
81
+ - Scan command continues seamlessly after interactive init completes
82
+ - Node.js scanner now uses deep scan (lockfile parsing) by default when lockfile available
83
+ - Flat scan preserved as fallback for projects without lockfiles
84
+ - Scan output now includes coverage statistics by default
85
+ - Coverage report appears in both `init` and `scan` commands automatically
86
+ - Significantly improved dependency discovery accuracy for Node.js projects
87
+
88
+ ### Technical Details
89
+ - New module: `lib/scanner/deep-scan.js` - Lockfile parser (v1/v2/v3 support)
90
+ - New module: `lib/scanner/path-tracer.js` - npm explain adapter for dependency paths
91
+ - Modified: `lib/scanner/plugins/node.js` - Integrated deep scan with fallback logic
92
+ - Modified: `lib/scanner/index.js` - displayConflictReport now async, traces paths for conflicts
93
+ - Modified: `lib/commands/scan.js` - Awaits displayConflictReport for path tracing
94
+ - Test coverage: 100% for deep-scan.js and path-tracer.js modules
95
+ - All 762 tests passing with zero regressions
96
+
8
97
  ## [2.1.1] - 2025-11-25
9
98
 
10
99
  ### Added
@@ -0,0 +1,43 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## The "No Elitism" Clause
10
+
11
+ LicenseGuard was built by a solo developer learning the ropes. We value **grit** and **learning** over certificates and titles.
12
+
13
+ * **No Gatekeeping:** Do not belittle contributors for "bad code" or "being junior." Teach, don't preach.
14
+ * **Practicality over Purity:** We prefer code that works and is readable over "clever" one-liners that no one understands.
15
+ * **Respect the Craft:** Take pride in what you ship. Code is communication.
16
+
17
+ ## Our Standards
18
+
19
+ Examples of behavior that contributes to a positive environment for our community include:
20
+
21
+ * Demonstrating empathy and kindness toward other people
22
+ * Being respectful of differing opinions, viewpoints, and experiences
23
+ * Giving and gracefully accepting constructive feedback
24
+ * Accepting responsibility and apologizing to those affected by our mistakes
25
+ * Focusing on what is best not just for us as individuals, but for the overall community
26
+
27
+ Examples of unacceptable behavior include:
28
+
29
+ * The use of sexualized language or imagery, and sexual attention or advances of any kind
30
+ * Trolling, insulting or derogatory comments, and personal or political attacks
31
+ * Public or private harassment
32
+ * Publishing others' private information, such as a physical or email address, without their explicit permission
33
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
34
+
35
+ ## Enforcement Responsibilities
36
+
37
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
38
+
39
+ ## Attribution
40
+
41
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
42
+
43
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,68 @@
1
+ # Contributing to LicenseGuard
2
+
3
+ First off, thank you for considering contributing to LicenseGuard. This project is built on the belief that license compliance should be **fast, free, and accessible** to every developer.
4
+
5
+ ## The LicenseGuard Philosophy
6
+
7
+ Before you write a single line of code, please understand the core values that built this tool:
8
+
9
+ 1. **Zero Bloat Policy** 🚀
10
+ * We prefer native Node.js APIs (`fs`, `child_process`, `path`) over adding heavy dependencies.
11
+ * Current dependencies are minimal (chalk, commander, inquirer). Keep it that way.
12
+ * If you can write it in 20 lines of utility code, don't install a 5MB library.
13
+
14
+ 2. **Ecosystem Native** 🧠
15
+ * Don't force one logic on all languages.
16
+ * **Node.js** uses file parsing (`package.json`) because it's fast.
17
+ * **Python** uses IPC bridge (`python-license-scanner.py`) because pip is chaotic.
18
+ * **Go/Rust** uses CLI tools (`go list`, `cargo metadata`) because they are authoritative.
19
+ * *Rule:* Research the ecosystem's standard first. Don't guess.
20
+
21
+ 3. **Fail-Safe Architecture** 🛡️
22
+ * This is a polyglot tool. If the user doesn't have `conan` installed, the C++ scanner should fail silently with a warning. It MUST NOT crash the Node.js scan.
23
+ * Always wrap plugin execution in `try-catch`.
24
+
25
+ 4. **"Feel Code"** ✍️
26
+ * Understand what you are parsing. Don't just regex blindly.
27
+ * Read the lockfiles. Understand the graph.
28
+
29
+ ## Development Setup
30
+
31
+ 1. **Clone and Install:**
32
+ ```bash
33
+ git clone https://github.com/rfxlamia/licenseguard.git
34
+ cd licenseguard
35
+ npm install
36
+ ```
37
+
38
+ 2. **Run Tests:**
39
+ We take testing seriously.
40
+ ```bash
41
+ npm test
42
+ ```
43
+ *Current Benchmark:* 635+ tests passing in ~3 seconds. Do not make it slower.
44
+
45
+ 3. **Manual Testing:**
46
+ Automated tests are not enough. Verify your changes against real projects.
47
+ See `manual-test/` directory for reference projects (Node, C++, Python).
48
+
49
+ ## Pull Request Guidelines
50
+
51
+ * **Branch Naming:** `feat/feature-name` or `fix/bug-name`.
52
+ * **Commit Messages:** Follow [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat: add ruby support`, `fix: handle corrupt lockfile`).
53
+ * **Tests:** Every PR **MUST** include unit tests. Code coverage should not drop below 90%.
54
+ * **Documentation:** Update `README.md` if you add a new feature or flag.
55
+
56
+ ## Adding a New Ecosystem Plugin
57
+
58
+ Want to add support for Ruby, PHP, or Java?
59
+ 1. Create `lib/scanner/plugins/language.js`.
60
+ 2. Implement the standard interface:
61
+ * `detect()`: Boolean
62
+ * `scanDependencies(projectLicense)`: Promise<Result>
63
+ 3. Register it in `lib/scanner/index.js`.
64
+ 4. Add comprehensive unit tests in `tests/unit/scanner-language.test.js`.
65
+
66
+ ## License
67
+
68
+ By contributing, you agree that your contributions will be licensed under its MIT License.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  > License setup & compliance guard for developers
7
7
 
8
- LicenseGuard helps you set up open source licenses and protects your project from license conflicts. It scans your dependencies for incompatible licenses and automatically notifies developers about licensing requirements - works with any language (Node.js, Python, Rust, Go, etc.).
8
+ LicenseGuard helps you set up open source licenses and protects your project from license conflicts. It scans your dependencies for incompatible licenses and automatically notifies developers about licensing requirements - works across ecosystems (Node.js, Python, Rust, Go, C++).
9
9
 
10
10
  ## Key Features
11
11
 
@@ -15,7 +15,6 @@ LicenseGuard helps you set up open source licenses and protects your project fro
15
15
  - **Scan Results** - Save scan results to `.licenseguardrc` for transparency
16
16
  - **Automatic Notifications** - See license info immediately after `git clone`
17
17
  - **Zero Effort** - Global hooks install once, work forever
18
- - **Language Agnostic** - Works for Python, Rust, Go, Ruby, any project
19
18
  - **Offline** - All license templates bundled, no internet required
20
19
 
21
20
  ---
@@ -189,7 +188,7 @@ Fix conflicts or use --force to proceed anyway:
189
188
  licenseguard init --force
190
189
  ```
191
190
 
192
- **With Explanation (`--explain`):**
191
+ ### `init --explain` - With Explanation
193
192
  ```bash
194
193
  licenseguard init --explain
195
194
  # ...
@@ -269,73 +268,8 @@ Reads existing `.licenseguardrc` and installs hooks. Used in npm prepare scripts
269
268
 
270
269
  ---
271
270
 
272
- ## Color-coded Output
271
+ ## Supported License Setup
273
272
 
274
- LicenseGuard uses visual safety hierarchy with color-coding to help you quickly identify dangerous licenses:
275
-
276
- ### Safety Level Legend
277
-
278
- | Color | Emoji | License Type | Examples |
279
- |-------|-------|--------------|----------|
280
- | 🟢 **Green** | Safe | Permissive licenses | MIT, Apache-2.0, BSD-*, ISC, 0BSD, Unlicense |
281
- | ⚠️ **Yellow** | Caution | Weak copyleft | MPL-2.0, LGPL-*, EPL-* |
282
- | ❌ **Red** | Dangerous | Strong copyleft | GPL-*, AGPL-* |
283
- | ❔ **Gray** | Unknown | Requires manual review | UNKNOWN, unrecognized licenses |
284
-
285
- ### How It Works
286
-
287
- Licenses are automatically color-coded in all commands (`init`, `scan`) based on their safety level:
288
-
289
- - **Green licenses** (🟢) are permissive and safe to use - they allow you to do almost anything
290
- - **Yellow licenses** (⚠️) require caution - they have some copyleft restrictions
291
- - **Red licenses** (❌) are strong copyleft - they may require your project to use the same license
292
- - **Gray licenses** (❔) are unknown or unrecognized - manual review required
293
-
294
- **Example Output:**
295
- ```bash
296
- licenseguard scan
297
-
298
- ❌ 2 issue(s) found:
299
-
300
- ❌ some-gpl-lib@2.0.0 (❌ GPL-3.0)
301
- Conflict: Copyleft incompatible with MIT
302
- Location: node_modules/some-gpl-lib/package.json
303
-
304
- ⚠️ unknown-lib@1.0.0 (❔ UNKNOWN)
305
- No license field found
306
- Location: node_modules/unknown-lib/package.json
307
- ```
308
-
309
- ### Accessibility
310
-
311
- Colors work in both light and dark terminal themes, and emojis are used as secondary indicators for colorblind users:
312
- - Green = 🟢 (green circle)
313
- - Yellow = ⚠️ (warning triangle)
314
- - Red = ❌ (red X)
315
- - Gray = ❔ (question mark)
316
-
317
- ---
318
-
319
- ## Update Notifications
320
-
321
- LicenseGuard automatically checks for updates once per day (cached for 24 hours). When a new version is available, you'll see:
322
-
323
- ```bash
324
- ╔═══════════════════════════════════════════════╗
325
- ║ Update available: 2.1.0 → 2.1.1 ║
326
- ║ Run: npm install -g licenseguard-cli@latest ║
327
- ╚═══════════════════════════════════════════════╝
328
- ```
329
-
330
- **Update check behavior:**
331
- - Checks npm registry once per 24 hours
332
- - Non-blocking (doesn't slow down CLI startup)
333
- - Fails silently if network unavailable
334
- - Result cached in OS temp directory
335
-
336
- ---
337
-
338
- ## Supported Licenses
339
273
 
340
274
  | Key | Name | Description |
341
275
  |-----|------|-------------|
@@ -535,12 +469,46 @@ Yes! Fully cross-platform (Linux, macOS, Windows).
535
469
  ## Contributing
536
470
 
537
471
  Contributions welcome!
472
+ **We need your help to make LicenseGuard better.**
473
+
474
+ ---
475
+
476
+ ### How to Contribute
477
+
478
+ 1. Read [CONTRIBUTING.md](CONTRIBUTING.md) - Philosophy and guidelines
479
+ 2. Check [GitHub Issues](https://github.com/rfxlamia/licenseguard-development/issues) for "good first issue" label
480
+ 3. Fork repository
481
+ 4. Create branch: `git checkout -b feat/license-mpl2`
482
+ 5. Write tests (90%+ coverage required)
483
+ 6. Submit Pull Request
484
+
485
+ **Philosophy:**
486
+ - **Zero Bloat** - Prefer native APIs over dependencies
487
+ - **Ecosystem Native** - Research the right tool, don't guess
488
+ - **Fail-Safe** - Plugins fail gracefully, never crash
489
+ - **Feel Code** - Understand what you parse
538
490
 
539
- 1. Fork the repository
540
- 2. Create feature branch: `git checkout -b feature/amazing`
541
- 3. Commit changes: `git commit -m 'Add feature'`
542
- 4. Push: `git push origin feature/amazing`
543
- 5. Open Pull Request
491
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines.
492
+
493
+ ---
494
+
495
+ ## Code of Conduct
496
+
497
+ We're committed to an inclusive community. Read our [Code of Conduct](CODE_OF_CONDUCT.md).
498
+
499
+ **Key principles:**
500
+ - **No Elitism** - Grit and learning > credentials
501
+ - **No Gatekeeping** - Teach, don't preach
502
+ - **Practicality > Purity** - Readable > clever
503
+ - **Respect the Craft** - Code is communication
504
+
505
+ ---
506
+
507
+ ## Documentation
508
+
509
+ - **[QUICK-USE.md](QUICK-USE.md)** - Complete command reference and examples
510
+ - **[CONTRIBUTING.md](CONTRIBUTING.md)** - How to contribute
511
+ - **[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)** - Community standards
544
512
 
545
513
  ---
546
514
 
@@ -553,5 +521,9 @@ MIT License - see [LICENSE](LICENSE) file.
553
521
  ## Links
554
522
 
555
523
  - [npm Package](https://www.npmjs.com/package/licenseguard-cli)
524
+ - [GitHub Repository](https://github.com/rfxlamia/licenseguard)
525
+ - [Quick Use Guide](QUICK-USE.md)
526
+ - [Contributing Guide](CONTRIBUTING.md)
556
527
  - [Choose a License](https://choosealicense.com)
557
- - [Open Source Initiative](https://opensource.org/licenses)
528
+ - [SPDX License List](https://spdx.org/licenses/)
529
+
@@ -52,6 +52,7 @@ program
52
52
  .option('--allow', 'Allow conflicts (exit 0 even if conflicts found)')
53
53
  .option('--fail-on-unknown', 'Fail if unknown licenses detected')
54
54
  .option('--explain', 'Show authoritative source citations for license compatibility decisions')
55
+ .option('--format <type>', 'Output format (html) - generates CREDITS.html for mobile apps')
55
56
  .option('--cwd <path>', 'Working directory to scan')
56
57
  .action(async (options) => {
57
58
  try {
@@ -74,7 +74,7 @@ async function runInitFast(options) {
74
74
  console.log(chalk.blue('🔍 Scanning dependencies for license conflicts...\n'))
75
75
 
76
76
  scanResult = await scanDependencies(spdxLicense)
77
- const hasConflicts = displayConflictReport(scanResult, spdxLicense)
77
+ const hasConflicts = await displayConflictReport(scanResult, spdxLicense)
78
78
 
79
79
  if (hasConflicts && !options.force) {
80
80
  // Block LICENSE creation due to conflicts
@@ -5,6 +5,7 @@ const { writeLicenseFile, writeConfig } = require('../utils/file-ops')
5
5
  const { isGitRepo, initGitRepo, installHooks } = require('../utils/git-helpers')
6
6
  const { scanDependencies, displayConflictReport } = require('../scanner')
7
7
  const { toSPDX } = require('../utils/license-mapper')
8
+ const { calculateCoverage, displayCoverage } = require('../scanner/coverage-reporter')
8
9
 
9
10
  async function runInit(options = {}) {
10
11
  try {
@@ -59,7 +60,12 @@ async function runInit(options = {}) {
59
60
  console.log(chalk.blue('\n🔍 Scanning dependencies for license conflicts...\n'))
60
61
 
61
62
  scanResult = await scanDependencies(spdxLicense)
62
- const hasConflicts = displayConflictReport(scanResult, spdxLicense, { explain: options.explain })
63
+
64
+ // Display coverage BEFORE conflict report (AC #3)
65
+ const coverage = calculateCoverage(scanResult)
66
+ displayCoverage(coverage)
67
+
68
+ const hasConflicts = await displayConflictReport(scanResult, spdxLicense, { explain: options.explain })
63
69
 
64
70
  if (hasConflicts && !options.force) {
65
71
  // Block LICENSE creation due to conflicts