dep-brain 1.7.0 → 1.8.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
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 1.8.0
6
+
7
+ - Added `dep-brain fix --unused --dry-run` for safe unused dependency removal previews.
8
+ - Added package-manager command rendering for npm, pnpm, and yarn.
9
+ - Added `--include-caution` to include caution-level unused dependency removals.
10
+ - Added JSON output for fix plans with commands, included items, and skipped items.
11
+ - Kept analysis output contract at `1.6` because no analysis JSON result fields changed.
12
+
5
13
  ## 1.7.0
6
14
 
7
15
  - Added idempotent GitHub PR comments with `--pr-comment`.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  `dep-brain` is a CLI and library for explainable dependency intelligence in JavaScript and TypeScript projects.
8
8
 
9
- Current release `1.7.0` adds idempotent GitHub PR comments while keeping analysis output contract `1.6`.
9
+ Current release `1.8.0` adds unused dependency fix-plan dry runs while keeping analysis output contract `1.6`.
10
10
 
11
11
  ## Vision
12
12
 
@@ -30,6 +30,7 @@ Current release `1.7.0` adds idempotent GitHub PR comments while keeping analysi
30
30
  - Output upgrade-advice reports via `--advise`
31
31
  - Send Slack and Discord webhook summaries for CI runs
32
32
  - Create or update GitHub PR comments for pull request checks
33
+ - Preview safe unused dependency removal commands
33
34
  - Gate CI with score and finding policies
34
35
  - Compare new findings against a baseline report
35
36
 
@@ -39,7 +40,7 @@ The long-term goal is not just to list problems, but to answer:
39
40
  - Can I remove it safely?
40
41
  - What should I fix first?
41
42
 
42
- ## 1.7 Highlights
43
+ ## 1.8 Highlights
43
44
 
44
45
  - Duplicate dependency detection with lockfile instance tracking
45
46
  - Unused dependency detection with runtime vs dev-tool heuristics
@@ -59,6 +60,7 @@ The long-term goal is not just to list problems, but to answer:
59
60
  - Upgrade advisor output via `--advise`
60
61
  - Slack and Discord notification summaries via `--notify`
61
62
  - GitHub PR comments via `--pr-comment`
63
+ - Safe unused dependency fix plans via `dep-brain fix --unused --dry-run`
62
64
  - Ranked top issues via `--top`
63
65
  - Baseline mode via `--baseline`
64
66
  - Focused analysis via `--focus`
@@ -92,6 +94,9 @@ npx dep-brain analyze --notify
92
94
  npx dep-brain analyze --notify --notify-on always
93
95
  npx dep-brain analyze --pr-comment
94
96
  npx dep-brain analyze --pr-comment --comment-on new-findings
97
+ npx dep-brain fix --unused --dry-run
98
+ npx dep-brain fix --unused --dry-run --include-caution
99
+ npx dep-brain fix --unused --dry-run --json
95
100
  npx dep-brain analyze --focus duplicates
96
101
  npx dep-brain analyze --ci
97
102
  npx dep-brain analyze --baseline depbrain-baseline.json
@@ -177,7 +182,7 @@ Suggestions:
177
182
  dep-brain analyze --json
178
183
  ```
179
184
 
180
- Output includes `outputVersion` for schema stability. `dep-brain@1.7.0` writes contract version `1.6`.
185
+ Output includes `outputVersion` for schema stability. `dep-brain@1.8.0` writes contract version `1.6`.
181
186
 
182
187
  Validate against:
183
188
 
@@ -232,6 +237,16 @@ dep-brain analyze --ci --baseline depbrain-baseline.json --pr-comment --comment-
232
237
 
233
238
  `--pr-comment` creates or updates one GitHub pull request comment using `GITHUB_TOKEN`, `GITHUB_REPOSITORY`, and `GITHUB_EVENT_PATH`. The comment includes policy status, health score, top issues, upgrade priorities, and baseline delta counts when `--baseline` is used.
234
239
 
240
+ ## Fix Plans
241
+
242
+ ```bash
243
+ dep-brain fix --unused --dry-run
244
+ dep-brain fix --unused --dry-run --include-caution
245
+ dep-brain fix --unused --dry-run --json
246
+ ```
247
+
248
+ Fix plans print package-manager-specific uninstall commands without changing files. `dep-brain` detects npm, pnpm, or yarn lockfiles and skips caution-level removals unless `--include-caution` is set.
249
+
235
250
  ## Plugins
236
251
 
237
252
  ```json
@@ -420,7 +435,7 @@ src/
420
435
 
421
436
  ## Product Direction
422
437
 
423
- `dep-brain` is in `v1.7.0` production CLI stage, with current focus on actionable dependency decisions and PR workflow integration.
438
+ `dep-brain` is in `v1.8.0` production CLI stage, with current focus on safe dependency removal previews and PR workflow integration.
424
439
 
425
440
  Recent releases added:
426
441
 
@@ -430,6 +445,7 @@ Recent releases added:
430
445
  - structured upgrade advice with release-note links
431
446
  - Slack and Discord notification summaries
432
447
  - idempotent GitHub PR comments
448
+ - unused dependency fix-plan dry runs
433
449
 
434
450
  Project should optimize for trust, clarity, and actionability over flashy UI, generic graphs, or simply adding more checks.
435
451
 
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { analyzeProject } from "./core/analyzer.js";
3
+ import { buildUnusedFixPlan, renderFixPlan } from "./core/fix-plan.js";
3
4
  import { renderConsoleReport } from "./reporters/console.js";
4
5
  import { renderJsonReport } from "./reporters/json.js";
5
6
  import { renderMarkdownReport } from "./reporters/markdown.js";
@@ -45,6 +46,44 @@ async function main() {
45
46
  return;
46
47
  }
47
48
  if (command !== "analyze") {
49
+ if (command === "fix") {
50
+ if (!flags.has("--unused")) {
51
+ console.error("Missing --unused for fix");
52
+ printHelp();
53
+ process.exitCode = 1;
54
+ return;
55
+ }
56
+ if (!flags.has("--dry-run")) {
57
+ console.error("Fix currently supports --dry-run only.");
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+ if (!(await hasPackageJson(targetPath))) {
62
+ console.error(`No package.json found at ${sanitizeForLog(targetPath)}`);
63
+ process.exitCode = 1;
64
+ return;
65
+ }
66
+ try {
67
+ const cliConfig = buildCliConfig(flags, optionValues);
68
+ const result = await analyzeProject({
69
+ rootDir: targetPath,
70
+ configPath: optionValues.get("--config"),
71
+ config: cliConfig,
72
+ focus: "unused"
73
+ });
74
+ const plan = await buildUnusedFixPlan(result, {
75
+ includeCaution: flags.has("--include-caution")
76
+ });
77
+ await writeOutput(flags.has("--json") ? JSON.stringify(plan, null, 2) : renderFixPlan(plan), optionValues.get("--out"));
78
+ return;
79
+ }
80
+ catch (error) {
81
+ console.error("Failed to build fix plan.");
82
+ console.error(error);
83
+ process.exitCode = 1;
84
+ return;
85
+ }
86
+ }
48
87
  if (command === "report") {
49
88
  const fromPath = optionValues.get("--from") ?? positionals[0];
50
89
  if (!fromPath) {
@@ -272,6 +311,7 @@ function printHelp() {
272
311
  console.log("Usage:");
273
312
  console.log(" dep-brain analyze [path] [--json] [--md] [--sarif] [--top] [--dashboard] [--notify] [--pr-comment] [--comment-on kind] [--focus kind] [--ci] [--out path] [--config path] [--baseline path] [--min-score n] [--fail-on-risks]");
274
313
  console.log(" dep-brain report --from <file> [--md] [--json] [--sarif] [--top] [--advise] [--dashboard] [--out path]");
314
+ console.log(" dep-brain fix [path] --unused --dry-run [--include-caution] [--json] [--out path]");
275
315
  console.log(" dep-brain config [path] [--config path]");
276
316
  console.log(" dep-brain init [--out depbrain.config.json]");
277
317
  console.log(" dep-brain help");
@@ -295,6 +335,9 @@ function printHelp() {
295
335
  console.log(" --baseline <path> Ignore findings already present in a baseline JSON report");
296
336
  console.log(" --from <file> Read analysis JSON from file");
297
337
  console.log(" --out <path> Write output to a file");
338
+ console.log(" --unused Build an unused dependency fix plan");
339
+ console.log(" --dry-run Print fix commands without changing files");
340
+ console.log(" --include-caution Include caution-level unused dependency removals");
298
341
  console.log(" --min-score <n> Minimum score required to pass");
299
342
  console.log(" --fail-on-risks Fail when risky dependencies exist");
300
343
  console.log(" --fail-on-outdated Fail when outdated dependencies exist");
@@ -0,0 +1,32 @@
1
+ import type { AnalysisResult } from "./analyzer.js";
2
+ export type PackageManager = "npm" | "pnpm" | "yarn";
3
+ export interface FixPlanOptions {
4
+ includeCaution?: boolean;
5
+ }
6
+ export interface FixPlanItem {
7
+ name: string;
8
+ section: "dependencies" | "devDependencies";
9
+ package?: string;
10
+ confidence: number;
11
+ safety: "safe" | "caution" | "unknown";
12
+ command: string;
13
+ args: string[];
14
+ }
15
+ export interface SkippedFixItem {
16
+ name: string;
17
+ section: "dependencies" | "devDependencies";
18
+ package?: string;
19
+ confidence: number;
20
+ safety: "safe" | "caution" | "unknown";
21
+ reason: string;
22
+ }
23
+ export interface FixPlan {
24
+ packageManager: PackageManager;
25
+ dryRun: true;
26
+ commands: string[];
27
+ items: FixPlanItem[];
28
+ skipped: SkippedFixItem[];
29
+ }
30
+ export declare function buildUnusedFixPlan(result: AnalysisResult, options?: FixPlanOptions): Promise<FixPlan>;
31
+ export declare function detectPackageManager(rootDir: string): Promise<PackageManager>;
32
+ export declare function renderFixPlan(plan: FixPlan): string;
@@ -0,0 +1,109 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ export async function buildUnusedFixPlan(result, options = {}) {
4
+ const packageManager = await detectPackageManager(result.rootDir);
5
+ const items = [];
6
+ const skipped = [];
7
+ for (const item of result.unused) {
8
+ const skipReason = getSkipReason(item, options);
9
+ if (skipReason) {
10
+ skipped.push({
11
+ name: item.name,
12
+ section: item.section,
13
+ package: item.package,
14
+ confidence: item.confidence,
15
+ safety: item.recommendation.safety,
16
+ reason: skipReason
17
+ });
18
+ continue;
19
+ }
20
+ const command = buildRemoveCommand(packageManager, item);
21
+ items.push({
22
+ name: item.name,
23
+ section: item.section,
24
+ package: item.package,
25
+ confidence: item.confidence,
26
+ safety: item.recommendation.safety,
27
+ command: command.join(" "),
28
+ args: command
29
+ });
30
+ }
31
+ return {
32
+ packageManager,
33
+ dryRun: true,
34
+ commands: items.map((item) => item.command),
35
+ items,
36
+ skipped
37
+ };
38
+ }
39
+ export async function detectPackageManager(rootDir) {
40
+ if (await fileExists(path.join(rootDir, "pnpm-lock.yaml"))) {
41
+ return "pnpm";
42
+ }
43
+ if (await fileExists(path.join(rootDir, "yarn.lock"))) {
44
+ return "yarn";
45
+ }
46
+ return "npm";
47
+ }
48
+ export function renderFixPlan(plan) {
49
+ const lines = [
50
+ "Dependency Brain Fix Plan",
51
+ "",
52
+ `Package manager: ${plan.packageManager}`,
53
+ "Mode: dry-run",
54
+ ""
55
+ ];
56
+ if (plan.commands.length === 0) {
57
+ lines.push("No safe unused dependency removals found.");
58
+ }
59
+ else {
60
+ lines.push("Commands:");
61
+ for (const command of plan.commands) {
62
+ lines.push(`- ${command}`);
63
+ }
64
+ }
65
+ if (plan.skipped.length > 0) {
66
+ lines.push("");
67
+ lines.push("Skipped:");
68
+ for (const item of plan.skipped) {
69
+ lines.push(`- ${item.name}${item.package ? ` [${item.package}]` : ""}: ${item.reason}`);
70
+ }
71
+ }
72
+ return lines.join("\n");
73
+ }
74
+ function getSkipReason(item, options) {
75
+ if (item.recommendation.safety !== "safe" &&
76
+ !(options.includeCaution && item.recommendation.safety === "caution")) {
77
+ return "requires --include-caution";
78
+ }
79
+ if (item.section === "dependencies" &&
80
+ item.confidence < 0.88 &&
81
+ !options.includeCaution) {
82
+ return "runtime dependency confidence below 88%";
83
+ }
84
+ return null;
85
+ }
86
+ function buildRemoveCommand(packageManager, item) {
87
+ if (packageManager === "pnpm") {
88
+ return item.package
89
+ ? ["pnpm", "--filter", item.package, "remove", item.name]
90
+ : ["pnpm", "remove", item.name];
91
+ }
92
+ if (packageManager === "yarn") {
93
+ return item.package
94
+ ? ["yarn", "workspace", item.package, "remove", item.name]
95
+ : ["yarn", "remove", item.name];
96
+ }
97
+ return item.package
98
+ ? ["npm", "uninstall", item.name, "--workspace", item.package]
99
+ : ["npm", "uninstall", item.name];
100
+ }
101
+ async function fileExists(filePath) {
102
+ try {
103
+ await fs.access(filePath);
104
+ return true;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  export { analyzeProject } from "./core/analyzer.js";
2
+ export { buildUnusedFixPlan, detectPackageManager, renderFixPlan } from "./core/fix-plan.js";
2
3
  export type { AnalysisOptions, AnalysisFocus, AnalysisResult, DepBrainBaseline, DuplicateDependency, OutdatedDependency, PolicyResult, PackageAnalysisResult, Recommendation, RiskFactors, RiskTransitiveDependency, ScoreBreakdown, RiskDependency, TopIssue, TrustScore, UnusedDependency, WorkspaceDependencyUsage, WorkspaceOwnershipSummary } from "./core/analyzer.js";
3
4
  export { OUTPUT_VERSION } from "./core/analyzer.js";
4
5
  export { PluginManager } from "./core/plugin-manager.js";
5
6
  export type { DepBrainPlugin, PluginDiagnostic, ProjectContext } from "./core/plugin-manager.js";
6
7
  export type { AnalysisContext, CheckResult, Issue } from "./core/types.js";
8
+ export type { FixPlan, FixPlanItem, FixPlanOptions, PackageManager, SkippedFixItem } from "./core/fix-plan.js";
7
9
  export type { DepBrainConfig, DepBrainConfigOverrides } from "./utils/config.js";
8
10
  export { renderNotificationMessage, sendConfiguredNotifications, shouldSendNotification } from "./utils/notifications.js";
9
11
  export { shouldPostPrComment, upsertGitHubPrComment } from "./utils/github.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { analyzeProject } from "./core/analyzer.js";
2
+ export { buildUnusedFixPlan, detectPackageManager, renderFixPlan } from "./core/fix-plan.js";
2
3
  export { OUTPUT_VERSION } from "./core/analyzer.js";
3
4
  export { PluginManager } from "./core/plugin-manager.js";
4
5
  export { renderNotificationMessage, sendConfiguredNotifications, shouldSendNotification } from "./utils/notifications.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dep-brain",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "CLI and library for explainable dependency intelligence",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",