dependency-radar 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,6 +17,18 @@ Dependency Radar is a local-first CLI tool that inspects a Node.js project’s i
17
17
  - Not a bundler or build tool
18
18
  - Not a dependency updater
19
19
 
20
+
21
+ ## License Scanning
22
+
23
+ Dependency Radar validates SPDX licenses declared in `package.json` and can infer licenses from `LICENSE` files when declarations are missing or invalid. It works offline and uses a bundled SPDX identifier list (generated at build time) with no runtime network access. Each dependency gets a structured license record with:
24
+
25
+ - Declared SPDX validation (including deprecated IDs and `WITH` exceptions)
26
+ - Inferred SPDX license (with confidence: `high`, `medium`, `low`) based on deterministic text matching
27
+ - A status (`declared-only`, `inferred-only`, `match`, `mismatch`, `invalid-spdx`, `unknown`) to make review decisions easier
28
+
29
+ This logic applies to all dependencies (direct and transitive). Inferred licenses are never treated as authoritative over valid declared SPDX expressions.
30
+
31
+
20
32
  ## Setup
21
33
 
22
34
  ```bash
@@ -53,10 +65,10 @@ Keep the temporary `.dependency-radar` folder for debugging raw tool outputs:
53
65
  npx dependency-radar --keep-temp
54
66
  ```
55
67
 
56
- Skip `npm audit` (useful for offline scans):
68
+ Skip `npm audit` and `npm outdated` (useful for offline scans):
57
69
 
58
70
  ```bash
59
- npx dependency-radar --no-audit
71
+ npx dependency-radar --offline
60
72
  ```
61
73
 
62
74
  Output JSON instead of HTML report:
@@ -65,6 +77,12 @@ Output JSON instead of HTML report:
65
77
  npx dependency-radar --json
66
78
  ```
67
79
 
80
+ Open the generated report using the system default:
81
+
82
+ ```bash
83
+ npx dependency-radar --open
84
+ ```
85
+
68
86
  Show options:
69
87
 
70
88
  ```bash
@@ -81,7 +99,7 @@ npx dependency-radar --help
81
99
 
82
100
  - The target project must have node_modules installed (run npm install first).
83
101
  - The scan is local-first and does not upload your code or dependencies anywhere.
84
- - `npm audit` performs registry lookups; use `--no-audit` for offline-only scans.
102
+ - `npm audit` and `npm outdated` perform registry lookups; use `--offline` for offline-only scans.
85
103
  - A temporary `.dependency-radar` folder is created during the scan to store intermediate tool output.
86
104
  - Use `--keep-temp` to retain this folder for debugging; otherwise it is deleted automatically.
87
105
  - If a tool fails, its section is marked as unavailable, but the report is still generated.
@@ -99,27 +117,167 @@ The JSON schema matches the `AggregatedData` TypeScript interface in `src/types.
99
117
 
100
118
  ```ts
101
119
  export interface AggregatedData {
102
- generatedAt: string;
103
- projectPath: string;
104
- gitBranch?: string;
105
- dependencyRadarVersion?: string;
106
- maintenanceEnabled: boolean;
120
+ schemaVersion: '1.2'; // Report schema version for compatibility checks
121
+ generatedAt: string; // ISO timestamp when the scan finished
122
+ dependencyRadarVersion: string; // CLI version that produced the report
123
+ git: {
124
+ branch: string; // Git branch name, empty when unavailable/detached
125
+ };
126
+ project: {
127
+ projectDir: string; // Project path relative to the user's home directory (e.g. /Developer/app)
128
+ };
107
129
  environment: {
108
- node: {
109
- runtimeVersion: string;
110
- runtimeMajor: number;
111
- minRequiredMajor?: number;
112
- source: 'dependency-engines' | 'project-engines' | 'unknown';
130
+ nodeVersion: string; // Node.js version from process.versions.node
131
+ runtimeVersion: string; // Node.js runtime version from process.version
132
+ minRequiredMajor: number; // Strictest Node major required by dependency engines (0 if unknown)
133
+ platform?: string; // OS platform (process.platform)
134
+ arch?: string; // CPU architecture (process.arch)
135
+ ci?: boolean; // True when running in CI (process.env.CI === 'true')
136
+ packageManagerField?: string; // package.json packageManager field (e.g. pnpm@9.1.0)
137
+ packageManager?: 'npm' | 'pnpm' | 'yarn'; // Package manager used to scan
138
+ packageManagerVersion?: string; // Version of the package manager used to scan
139
+ toolVersions?: {
140
+ npm?: string;
141
+ pnpm?: string;
142
+ yarn?: string;
143
+ };
144
+ };
145
+ workspaces: {
146
+ enabled: boolean; // True when the scan used workspace aggregation
147
+ type?: 'npm' | 'pnpm' | 'yarn' | 'none'; // Workspace type if detected
148
+ packageCount?: number; // Number of workspace packages scanned
149
+ };
150
+ summary: {
151
+ dependencyCount: number; // Total dependencies in the graph
152
+ directCount: number; // Dependencies listed in package.json
153
+ transitiveCount: number; // Dependencies pulled in by other dependencies
154
+ };
155
+ dependencies: Record<string, DependencyRecord>; // Keyed by name@version
156
+ }
157
+
158
+ export interface DependencyRecord {
159
+ package: {
160
+ id: string; // Stable identifier in the form name@version
161
+ name: string; // Package name from npm metadata
162
+ version: string; // Installed version from npm ls
163
+ description?: string; // Description from the installed package.json (if present)
164
+ deprecated: boolean; // True if the package.json has a deprecated flag
165
+ links: {
166
+ npm: string; // npm package page URL
167
+ repository?: string; // Repository URL (if present)
168
+ homepage?: string; // Homepage URL (if present)
169
+ bugs?: string; // Issue tracker URL (if present)
170
+ };
171
+ };
172
+ compliance: {
173
+ license: {
174
+ declared?: {
175
+ spdxId: string; // SPDX ID or expression from package.json
176
+ expression: boolean; // True when SPDX expression (AND/OR/WITH)
177
+ deprecated: boolean; // True if SPDX ID is deprecated
178
+ valid: boolean; // True if SPDX ID/expression is valid
179
+ };
180
+ inferred?: {
181
+ spdxId: string; // SPDX ID inferred from LICENSE text
182
+ confidence: 'high' | 'medium' | 'low'; // Heuristic confidence
183
+ };
184
+ exception?: {
185
+ id: string; // SPDX exception id
186
+ deprecated: boolean; // True if exception is deprecated
187
+ valid: boolean; // True if exception id is valid
188
+ };
189
+ status:
190
+ | 'declared-only'
191
+ | 'inferred-only'
192
+ | 'match'
193
+ | 'mismatch'
194
+ | 'invalid-spdx'
195
+ | 'unknown';
196
+ };
197
+ licenseRisk: 'green' | 'amber' | 'red'; // Risk classification derived from declared/inferred SPDX ids
198
+ };
199
+ security: {
200
+ summary: {
201
+ critical: number; // npm audit counts for critical issues
202
+ high: number; // npm audit counts for high issues
203
+ moderate: number; // npm audit counts for moderate issues
204
+ low: number; // npm audit counts for low issues
205
+ highest: 'low' | 'moderate' | 'high' | 'critical' | 'none'; // Highest severity present
206
+ risk: 'green' | 'amber' | 'red'; // Risk classification derived from audit counts
207
+ };
208
+ advisories?: Array<{
209
+ id: string; // GHSA identifier
210
+ title: string; // Human-readable advisory title
211
+ severity: 'low' | 'moderate' | 'high' | 'critical';
212
+ vulnerableRange: string; // Semver range
213
+ fixAvailable: boolean; // True if npm audit indicates a fix exists
214
+ url: string; // Advisory URL
215
+ }>;
216
+ };
217
+ upgrade: {
218
+ nodeEngine: string | null; // engines.node from the package.json (if present)
219
+ outdatedStatus?: 'current' | 'patch' | 'minor' | 'major' | 'unknown'; // Derived from npm outdated (if present)
220
+ latestVersion?: string; // npm latest version (present only when status is not current)
221
+ blockers?: Array<'nodeEngine' | 'peerDependency' | 'nativeBindings' | 'deprecated'>; // Reasons for upgrade friction
222
+ blocksNodeMajor?: boolean; // True if local signals indicate a node major bump is risky
223
+ };
224
+ usage: {
225
+ direct: boolean; // True if declared in package.json (dependencies/devDependencies/etc.)
226
+ scope: 'runtime' | 'dev' | 'optional' | 'peer'; // Scope inferred from the declaring root package(s)
227
+ depth: number; // Minimum dependency tree depth observed in npm ls
228
+ origins: {
229
+ rootPackageCount: number; // Number of direct roots that introduce this dependency
230
+ topRootPackages: Array<{ name: string; version: string }>; // Up to 10 root packages (name/version)
231
+ parentPackageCount: number; // Number of direct parents
232
+ topParentPackages: string[]; // Up to 5 direct parent ids (name@version)
233
+ workspaces?: string[]; // Workspace packages that declare/use this dependency
234
+ };
235
+ introduction?: 'direct' | 'tooling' | 'framework' | 'testing' | 'transitive' | 'unknown'; // Heuristic for why the dependency exists
236
+ runtimeImpact?: 'runtime' | 'build' | 'testing' | 'tooling' | 'mixed'; // Heuristic based on import locations
237
+ importUsage?: {
238
+ fileCount: number; // Number of project files importing this package (import graph)
239
+ topFiles: string[]; // Top import locations (bounded to 5)
240
+ };
241
+ tsTypes: 'bundled' | 'definitelyTyped' | 'none' | 'unknown'; // TypeScript type availability
242
+ };
243
+ graph: {
244
+ fanIn: number; // Number of packages that depend on this package
245
+ fanOut: number; // Number of packages this package depends on
246
+ subDeps?: {
247
+ // Declared outgoing dependency edges; values are tuples.
248
+ // tuple[0] = declared version range, tuple[1] = resolved dependency id or null if not installed.
249
+ // Only installed dependencies have full dependency records in the top-level list.
250
+ dep?: Record<string, [string, string | null]>; // Declared runtime deps
251
+ dev?: Record<string, [string, string | null]>; // Declared dev deps
252
+ peer?: Record<string, [string, string | null]>; // Declared peer deps
253
+ opt?: Record<string, [string, string | null]>; // Declared optional deps
254
+ };
255
+ };
256
+ execution?: {
257
+ risk: 'amber' | 'red'; // Install-time risk (green implied when absent)
258
+ native?: true; // True if native bindings or build tooling are detected
259
+ scripts?: {
260
+ hooks: Array<'preinstall' | 'install' | 'postinstall' | 'prepare'>; // Lifecycle hooks detected
261
+ complexity?: number; // Heuristic complexity (stored only when high)
262
+ signals?: Array<
263
+ | 'network-access'
264
+ | 'dynamic-exec'
265
+ | 'child-process'
266
+ | 'encoding'
267
+ | 'obfuscated'
268
+ | 'reads-env'
269
+ | 'reads-home'
270
+ | 'uses-ssh'
271
+ >; // Review-worthy install-time signals (sparse)
113
272
  };
114
273
  };
115
- dependencies: DependencyRecord[];
116
- toolErrors: Record<string, string>;
117
- raw: RawOutputs;
118
- importAnalysis?: ImportAnalysisSummary;
119
274
  }
120
275
  ```
121
276
 
122
- For full details on `DependencyRecord`, `RawOutputs`, and related types, see `src/types.ts`.
277
+ For full details and any future changes, see `src/types.ts`.
278
+
279
+ Environment data includes Node.js version, OS platform, CPU architecture, and package manager versions.
280
+ No personal information, usernames, paths, or environment variables are collected.
123
281
 
124
282
  ## Development
125
283
 
@@ -149,4 +307,3 @@ This opens the report UI in your browser with sample data covering all dependenc
149
307
  - `report-ui/sample-data.json` – Sample data for development
150
308
  - `report-ui/types.ts` – Client-side TypeScript types
151
309
  - `src/report-assets.ts` – Auto-generated file with bundled CSS/JS (do not edit directly)
152
-