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 +8 -0
- package/README.md +20 -4
- package/dist/cli.js +43 -0
- package/dist/core/fix-plan.d.ts +32 -0
- package/dist/core/fix-plan.js +109 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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";
|