@rainy-updates/cli 0.5.4 → 0.5.7
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 +136 -0
- package/README.md +5 -0
- package/dist/bin/cli.js +16 -438
- package/dist/bin/dispatch.d.ts +16 -0
- package/dist/bin/dispatch.js +150 -0
- package/dist/bin/help.d.ts +1 -0
- package/dist/bin/help.js +284 -0
- package/dist/commands/audit/runner.js +43 -26
- package/dist/commands/dashboard/parser.d.ts +2 -0
- package/dist/commands/dashboard/parser.js +59 -0
- package/dist/commands/dashboard/runner.d.ts +2 -0
- package/dist/commands/dashboard/runner.js +47 -0
- package/dist/commands/doctor/parser.js +12 -0
- package/dist/commands/doctor/runner.js +5 -2
- package/dist/commands/ga/parser.d.ts +2 -0
- package/dist/commands/ga/parser.js +50 -0
- package/dist/commands/ga/runner.d.ts +2 -0
- package/dist/commands/ga/runner.js +129 -0
- package/dist/commands/resolve/runner.js +7 -3
- package/dist/commands/review/parser.js +6 -0
- package/dist/commands/review/runner.js +4 -3
- package/dist/core/analysis/options.d.ts +6 -0
- package/dist/core/analysis/options.js +69 -0
- package/dist/core/analysis/review-items.d.ts +4 -0
- package/dist/core/analysis/review-items.js +128 -0
- package/dist/core/analysis/run-silenced.d.ts +1 -0
- package/dist/core/analysis/run-silenced.js +14 -0
- package/dist/core/analysis-bundle.d.ts +4 -0
- package/dist/core/analysis-bundle.js +33 -0
- package/dist/core/artifacts.d.ts +3 -0
- package/dist/core/artifacts.js +48 -0
- package/dist/core/check.js +6 -1
- package/dist/core/doctor/findings.d.ts +2 -0
- package/dist/core/doctor/findings.js +166 -0
- package/dist/core/doctor/render.d.ts +3 -0
- package/dist/core/doctor/render.js +44 -0
- package/dist/core/doctor/result.d.ts +2 -0
- package/dist/core/doctor/result.js +55 -0
- package/dist/core/doctor/score.d.ts +5 -0
- package/dist/core/doctor/score.js +28 -0
- package/dist/core/options.d.ts +7 -1
- package/dist/core/options.js +14 -0
- package/dist/core/review-model.d.ts +3 -3
- package/dist/core/review-model.js +55 -245
- package/dist/core/review-verdict.d.ts +2 -0
- package/dist/core/review-verdict.js +14 -0
- package/dist/core/summary.js +19 -0
- package/dist/output/format.js +22 -0
- package/dist/output/github.js +12 -0
- package/dist/output/sarif.js +16 -0
- package/dist/types/index.d.ts +120 -0
- package/dist/ui/dashboard/DashboardTUI.d.ts +6 -0
- package/dist/ui/dashboard/DashboardTUI.js +34 -0
- package/dist/ui/dashboard/components/DetailPanel.d.ts +4 -0
- package/dist/ui/dashboard/components/DetailPanel.js +30 -0
- package/dist/ui/dashboard/components/Footer.d.ts +4 -0
- package/dist/ui/dashboard/components/Footer.js +9 -0
- package/dist/ui/dashboard/components/Header.d.ts +4 -0
- package/dist/ui/dashboard/components/Header.js +12 -0
- package/dist/ui/dashboard/components/Sidebar.d.ts +4 -0
- package/dist/ui/dashboard/components/Sidebar.js +23 -0
- package/dist/ui/dashboard/store.d.ts +34 -0
- package/dist/ui/dashboard/store.js +148 -0
- package/dist/ui/tui.d.ts +2 -2
- package/dist/ui/tui.js +310 -79
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { check } from "../core/check.js";
|
|
3
|
+
import { upgrade } from "../core/upgrade.js";
|
|
4
|
+
import { warmCache } from "../core/warm-cache.js";
|
|
5
|
+
import { runCi } from "../core/ci.js";
|
|
6
|
+
import { initCiWorkflow } from "../core/init-ci.js";
|
|
7
|
+
import { diffBaseline, saveBaseline } from "../core/baseline.js";
|
|
8
|
+
export async function handleDirectCommand(parsed) {
|
|
9
|
+
if (parsed.command === "init-ci") {
|
|
10
|
+
const workflow = await initCiWorkflow(parsed.options.cwd, parsed.options.force, {
|
|
11
|
+
mode: parsed.options.mode,
|
|
12
|
+
schedule: parsed.options.schedule,
|
|
13
|
+
});
|
|
14
|
+
process.stdout.write(workflow.created
|
|
15
|
+
? `Created CI workflow at ${workflow.path}\n`
|
|
16
|
+
: `CI workflow already exists at ${workflow.path}. Use --force to overwrite.\n`);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (parsed.command === "baseline") {
|
|
20
|
+
if (parsed.options.action === "save") {
|
|
21
|
+
const saved = await saveBaseline(parsed.options);
|
|
22
|
+
process.stdout.write(`Saved baseline at ${saved.filePath} (${saved.entries} entries)\n`);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
const diff = await diffBaseline(parsed.options);
|
|
26
|
+
const changes = diff.added.length + diff.removed.length + diff.changed.length;
|
|
27
|
+
if (changes === 0) {
|
|
28
|
+
process.stdout.write(`No baseline drift detected (${diff.filePath}).\n`);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
process.stdout.write(`Baseline drift detected (${diff.filePath}).\n`);
|
|
32
|
+
if (diff.added.length > 0)
|
|
33
|
+
process.stdout.write(`Added: ${diff.added.length}\n`);
|
|
34
|
+
if (diff.removed.length > 0)
|
|
35
|
+
process.stdout.write(`Removed: ${diff.removed.length}\n`);
|
|
36
|
+
if (diff.changed.length > 0)
|
|
37
|
+
process.stdout.write(`Changed: ${diff.changed.length}\n`);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (parsed.command === "bisect") {
|
|
42
|
+
const { runBisect } = await import("../commands/bisect/runner.js");
|
|
43
|
+
const result = await runBisect(parsed.options);
|
|
44
|
+
process.exitCode = result.breakingVersion ? 1 : 0;
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (parsed.command === "audit") {
|
|
48
|
+
const { runAudit } = await import("../commands/audit/runner.js");
|
|
49
|
+
const result = await runAudit(parsed.options);
|
|
50
|
+
process.exitCode = result.advisories.length > 0 ? 1 : 0;
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (parsed.command === "health") {
|
|
54
|
+
const { runHealth } = await import("../commands/health/runner.js");
|
|
55
|
+
const result = await runHealth(parsed.options);
|
|
56
|
+
process.exitCode = result.totalFlagged > 0 ? 1 : 0;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (parsed.command === "unused") {
|
|
60
|
+
const { runUnused } = await import("../commands/unused/runner.js");
|
|
61
|
+
const result = await runUnused(parsed.options);
|
|
62
|
+
process.exitCode = result.totalUnused > 0 || result.totalMissing > 0 ? 1 : 0;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (parsed.command === "resolve") {
|
|
66
|
+
const { runResolve } = await import("../commands/resolve/runner.js");
|
|
67
|
+
const result = await runResolve(parsed.options);
|
|
68
|
+
process.exitCode = result.errorConflicts > 0 ? 1 : 0;
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (parsed.command === "licenses") {
|
|
72
|
+
const { runLicenses } = await import("../commands/licenses/runner.js");
|
|
73
|
+
const result = await runLicenses(parsed.options);
|
|
74
|
+
process.exitCode = result.totalViolations > 0 ? 1 : 0;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (parsed.command === "snapshot") {
|
|
78
|
+
const { runSnapshot } = await import("../commands/snapshot/runner.js");
|
|
79
|
+
const result = await runSnapshot(parsed.options);
|
|
80
|
+
process.exitCode = result.errors.length > 0 ? 1 : 0;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (parsed.command === "review") {
|
|
84
|
+
const { runReview } = await import("../commands/review/runner.js");
|
|
85
|
+
const result = await runReview(parsed.options);
|
|
86
|
+
process.exitCode =
|
|
87
|
+
result.summary.verdict === "blocked" ||
|
|
88
|
+
result.summary.verdict === "actionable" ||
|
|
89
|
+
result.summary.verdict === "review"
|
|
90
|
+
? 1
|
|
91
|
+
: 0;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (parsed.command === "doctor") {
|
|
95
|
+
const { runDoctor } = await import("../commands/doctor/runner.js");
|
|
96
|
+
const result = await runDoctor(parsed.options);
|
|
97
|
+
process.exitCode = result.verdict === "safe" ? 0 : 1;
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (parsed.command === "dashboard") {
|
|
101
|
+
const { runDashboard } = await import("../commands/dashboard/runner.js");
|
|
102
|
+
const result = await runDashboard(parsed.options);
|
|
103
|
+
process.exitCode = result.errors.length > 0 ? 1 : 0;
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (parsed.command === "ga") {
|
|
107
|
+
const { runGa } = await import("../commands/ga/runner.js");
|
|
108
|
+
const result = await runGa(parsed.options);
|
|
109
|
+
process.exitCode = result.ready ? 0 : 1;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (parsed.options.interactive &&
|
|
113
|
+
(parsed.command === "check" ||
|
|
114
|
+
parsed.command === "upgrade" ||
|
|
115
|
+
parsed.command === "ci")) {
|
|
116
|
+
const { runReview } = await import("../commands/review/runner.js");
|
|
117
|
+
const result = await runReview({
|
|
118
|
+
...parsed.options,
|
|
119
|
+
securityOnly: false,
|
|
120
|
+
risk: undefined,
|
|
121
|
+
diff: undefined,
|
|
122
|
+
applySelected: parsed.command === "upgrade",
|
|
123
|
+
});
|
|
124
|
+
process.exitCode =
|
|
125
|
+
result.summary.verdict === "safe" && result.updates.length === 0 ? 0 : 1;
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
export async function runPrimaryCommand(parsed) {
|
|
131
|
+
if (parsed.command === "upgrade") {
|
|
132
|
+
return upgrade(parsed.options);
|
|
133
|
+
}
|
|
134
|
+
if (parsed.command === "warm-cache") {
|
|
135
|
+
return warmCache(parsed.options);
|
|
136
|
+
}
|
|
137
|
+
if (parsed.command === "ci") {
|
|
138
|
+
return runCi(parsed.options);
|
|
139
|
+
}
|
|
140
|
+
if (parsed.options.fixPr) {
|
|
141
|
+
const upgradeOptions = {
|
|
142
|
+
...parsed.options,
|
|
143
|
+
install: false,
|
|
144
|
+
packageManager: "auto",
|
|
145
|
+
sync: false,
|
|
146
|
+
};
|
|
147
|
+
return upgrade(upgradeOptions);
|
|
148
|
+
}
|
|
149
|
+
return check(parsed.options);
|
|
150
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderHelp(command?: string): string;
|
package/dist/bin/help.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
export function renderHelp(command) {
|
|
2
|
+
const isCommand = command && !command.startsWith("-");
|
|
3
|
+
if (isCommand && command === "check") {
|
|
4
|
+
return `rainy-updates check [options]
|
|
5
|
+
|
|
6
|
+
Detect candidate dependency updates. This is the first step in the flow:
|
|
7
|
+
check detects
|
|
8
|
+
doctor summarizes
|
|
9
|
+
review decides
|
|
10
|
+
upgrade applies
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--workspace
|
|
14
|
+
--target patch|minor|major|latest
|
|
15
|
+
--filter <pattern>
|
|
16
|
+
--reject <pattern>
|
|
17
|
+
--dep-kinds deps,dev,optional,peer
|
|
18
|
+
--concurrency <n>
|
|
19
|
+
--registry-timeout-ms <n>
|
|
20
|
+
--registry-retries <n>
|
|
21
|
+
--cache-ttl <seconds>
|
|
22
|
+
--stream
|
|
23
|
+
--policy-file <path>
|
|
24
|
+
--offline
|
|
25
|
+
--fix-pr
|
|
26
|
+
--fix-branch <name>
|
|
27
|
+
--fix-commit-message <text>
|
|
28
|
+
--fix-dry-run
|
|
29
|
+
--fix-pr-no-checkout
|
|
30
|
+
--fix-pr-batch-size <n>
|
|
31
|
+
--no-pr-report
|
|
32
|
+
--json-file <path>
|
|
33
|
+
--github-output <path>
|
|
34
|
+
--sarif-file <path>
|
|
35
|
+
--pr-report-file <path>
|
|
36
|
+
--fail-on none|patch|minor|major|any
|
|
37
|
+
--max-updates <n>
|
|
38
|
+
--group-by none|name|scope|kind|risk
|
|
39
|
+
--group-max <n>
|
|
40
|
+
--cooldown-days <n>
|
|
41
|
+
--pr-limit <n>
|
|
42
|
+
--only-changed
|
|
43
|
+
--interactive
|
|
44
|
+
--show-impact
|
|
45
|
+
--show-links
|
|
46
|
+
--show-homepage
|
|
47
|
+
--lockfile-mode preserve|update|error
|
|
48
|
+
--log-level error|warn|info|debug
|
|
49
|
+
--ci`;
|
|
50
|
+
}
|
|
51
|
+
if (isCommand && command === "warm-cache") {
|
|
52
|
+
return `rainy-updates warm-cache [options]
|
|
53
|
+
|
|
54
|
+
Pre-warm local metadata cache for faster CI checks.
|
|
55
|
+
|
|
56
|
+
Options:
|
|
57
|
+
--workspace
|
|
58
|
+
--target patch|minor|major|latest
|
|
59
|
+
--filter <pattern>
|
|
60
|
+
--reject <pattern>
|
|
61
|
+
--dep-kinds deps,dev,optional,peer
|
|
62
|
+
--concurrency <n>
|
|
63
|
+
--registry-timeout-ms <n>
|
|
64
|
+
--registry-retries <n>
|
|
65
|
+
--cache-ttl <seconds>
|
|
66
|
+
--offline
|
|
67
|
+
--stream
|
|
68
|
+
--json-file <path>
|
|
69
|
+
--github-output <path>
|
|
70
|
+
--sarif-file <path>
|
|
71
|
+
--pr-report-file <path>`;
|
|
72
|
+
}
|
|
73
|
+
if (isCommand && command === "upgrade") {
|
|
74
|
+
return `rainy-updates upgrade [options]
|
|
75
|
+
|
|
76
|
+
Apply an approved change set to package.json manifests.
|
|
77
|
+
|
|
78
|
+
Options:
|
|
79
|
+
--workspace
|
|
80
|
+
--sync
|
|
81
|
+
--install
|
|
82
|
+
--pm auto|npm|pnpm
|
|
83
|
+
--target patch|minor|major|latest
|
|
84
|
+
--policy-file <path>
|
|
85
|
+
--concurrency <n>
|
|
86
|
+
--registry-timeout-ms <n>
|
|
87
|
+
--registry-retries <n>
|
|
88
|
+
--fix-pr
|
|
89
|
+
--fix-branch <name>
|
|
90
|
+
--fix-commit-message <text>
|
|
91
|
+
--fix-dry-run
|
|
92
|
+
--fix-pr-no-checkout
|
|
93
|
+
--fix-pr-batch-size <n>
|
|
94
|
+
--interactive
|
|
95
|
+
--lockfile-mode preserve|update|error
|
|
96
|
+
--no-pr-report
|
|
97
|
+
--json-file <path>
|
|
98
|
+
--pr-report-file <path>`;
|
|
99
|
+
}
|
|
100
|
+
if (isCommand && command === "ci") {
|
|
101
|
+
return `rainy-updates ci [options]
|
|
102
|
+
|
|
103
|
+
Run CI-oriented automation around the same lifecycle:
|
|
104
|
+
check detects
|
|
105
|
+
doctor summarizes
|
|
106
|
+
review decides
|
|
107
|
+
upgrade applies
|
|
108
|
+
|
|
109
|
+
Options:
|
|
110
|
+
--workspace
|
|
111
|
+
--mode minimal|strict|enterprise
|
|
112
|
+
--group-by none|name|scope|kind|risk
|
|
113
|
+
--group-max <n>
|
|
114
|
+
--cooldown-days <n>
|
|
115
|
+
--pr-limit <n>
|
|
116
|
+
--only-changed
|
|
117
|
+
--offline
|
|
118
|
+
--concurrency <n>
|
|
119
|
+
--registry-timeout-ms <n>
|
|
120
|
+
--registry-retries <n>
|
|
121
|
+
--stream
|
|
122
|
+
--fix-pr
|
|
123
|
+
--fix-branch <name>
|
|
124
|
+
--fix-commit-message <text>
|
|
125
|
+
--fix-dry-run
|
|
126
|
+
--fix-pr-no-checkout
|
|
127
|
+
--fix-pr-batch-size <n>
|
|
128
|
+
--no-pr-report
|
|
129
|
+
--json-file <path>
|
|
130
|
+
--github-output <path>
|
|
131
|
+
--sarif-file <path>
|
|
132
|
+
--pr-report-file <path>
|
|
133
|
+
--fail-on none|patch|minor|major|any
|
|
134
|
+
--max-updates <n>
|
|
135
|
+
--lockfile-mode preserve|update|error
|
|
136
|
+
--log-level error|warn|info|debug
|
|
137
|
+
--ci`;
|
|
138
|
+
}
|
|
139
|
+
if (isCommand && command === "init-ci") {
|
|
140
|
+
return `rainy-updates init-ci [options]
|
|
141
|
+
|
|
142
|
+
Create a GitHub Actions workflow template at:
|
|
143
|
+
.github/workflows/rainy-updates.yml
|
|
144
|
+
|
|
145
|
+
Options:
|
|
146
|
+
--force
|
|
147
|
+
--mode minimal|strict|enterprise
|
|
148
|
+
--schedule weekly|daily|off`;
|
|
149
|
+
}
|
|
150
|
+
if (isCommand && command === "baseline") {
|
|
151
|
+
return `rainy-updates baseline [options]
|
|
152
|
+
|
|
153
|
+
Save or compare dependency baseline snapshots.
|
|
154
|
+
|
|
155
|
+
Options:
|
|
156
|
+
--save
|
|
157
|
+
--check
|
|
158
|
+
--file <path>
|
|
159
|
+
--workspace
|
|
160
|
+
--dep-kinds deps,dev,optional,peer
|
|
161
|
+
--ci`;
|
|
162
|
+
}
|
|
163
|
+
if (isCommand && command === "audit") {
|
|
164
|
+
return `rainy-updates audit [options]
|
|
165
|
+
|
|
166
|
+
Scan dependencies for CVEs using OSV.dev and GitHub Advisory Database.
|
|
167
|
+
|
|
168
|
+
Options:
|
|
169
|
+
--workspace
|
|
170
|
+
--severity critical|high|medium|low
|
|
171
|
+
--summary
|
|
172
|
+
--report table|summary|json
|
|
173
|
+
--source auto|osv|github|all
|
|
174
|
+
--fix
|
|
175
|
+
--dry-run
|
|
176
|
+
--commit
|
|
177
|
+
--pm auto|npm|pnpm|bun|yarn
|
|
178
|
+
--json-file <path>
|
|
179
|
+
--concurrency <n>
|
|
180
|
+
--registry-timeout-ms <n>`;
|
|
181
|
+
}
|
|
182
|
+
if (isCommand && command === "review") {
|
|
183
|
+
return `rainy-updates review [options]
|
|
184
|
+
|
|
185
|
+
Review is the decision center of Rainy Updates.
|
|
186
|
+
Use it to inspect risk, security, peer, license, and policy context before applying changes.
|
|
187
|
+
|
|
188
|
+
Options:
|
|
189
|
+
--workspace
|
|
190
|
+
--interactive
|
|
191
|
+
--security-only
|
|
192
|
+
--risk critical|high|medium|low
|
|
193
|
+
--diff patch|minor|major|latest
|
|
194
|
+
--apply-selected
|
|
195
|
+
--show-changelog
|
|
196
|
+
--policy-file <path>
|
|
197
|
+
--json-file <path>
|
|
198
|
+
--concurrency <n>
|
|
199
|
+
--registry-timeout-ms <n>
|
|
200
|
+
--registry-retries <n>`;
|
|
201
|
+
}
|
|
202
|
+
if (isCommand && command === "doctor") {
|
|
203
|
+
return `rainy-updates doctor [options]
|
|
204
|
+
|
|
205
|
+
Produce a fast summary verdict and point the operator to review when action is needed.
|
|
206
|
+
|
|
207
|
+
Options:
|
|
208
|
+
--workspace
|
|
209
|
+
--verdict-only
|
|
210
|
+
--include-changelog
|
|
211
|
+
--json-file <path>`;
|
|
212
|
+
}
|
|
213
|
+
if (isCommand && command === "ga") {
|
|
214
|
+
return `rainy-updates ga [options]
|
|
215
|
+
|
|
216
|
+
Audit release and CI readiness for Rainy Updates.
|
|
217
|
+
|
|
218
|
+
Options:
|
|
219
|
+
--workspace
|
|
220
|
+
--json-file <path>
|
|
221
|
+
--cwd <path>`;
|
|
222
|
+
}
|
|
223
|
+
return `rainy-updates (rup / rainy-up) <command> [options]
|
|
224
|
+
|
|
225
|
+
Commands:
|
|
226
|
+
check Detect candidate updates
|
|
227
|
+
doctor Summarize what matters
|
|
228
|
+
review Decide what to do
|
|
229
|
+
upgrade Apply the approved change set
|
|
230
|
+
dashboard Open the interactive DevOps dashboard (Ink TUI)
|
|
231
|
+
ci Run CI-focused orchestration
|
|
232
|
+
warm-cache Warm local cache for fast/offline checks
|
|
233
|
+
init-ci Scaffold GitHub Actions workflow
|
|
234
|
+
baseline Save/check dependency baseline snapshots
|
|
235
|
+
audit Scan dependencies for CVEs (OSV.dev + GitHub)
|
|
236
|
+
health Detect stale/deprecated/unmaintained packages
|
|
237
|
+
bisect Find which version of a dep introduced a failure
|
|
238
|
+
unused Detect unused or missing npm dependencies
|
|
239
|
+
resolve Check peer dependency conflicts (pure-TS, no subprocess)
|
|
240
|
+
licenses Scan dependency licenses and generate SPDX SBOM
|
|
241
|
+
snapshot Save, list, restore, and diff dependency state snapshots
|
|
242
|
+
ga Audit GA and CI readiness for this checkout
|
|
243
|
+
|
|
244
|
+
Global options:
|
|
245
|
+
--cwd <path>
|
|
246
|
+
--workspace
|
|
247
|
+
--target patch|minor|major|latest
|
|
248
|
+
--format table|json|minimal|github|metrics
|
|
249
|
+
--json-file <path>
|
|
250
|
+
--github-output <path>
|
|
251
|
+
--sarif-file <path>
|
|
252
|
+
--pr-report-file <path>
|
|
253
|
+
--policy-file <path>
|
|
254
|
+
--fail-on none|patch|minor|major|any
|
|
255
|
+
--max-updates <n>
|
|
256
|
+
--group-by none|name|scope|kind|risk
|
|
257
|
+
--group-max <n>
|
|
258
|
+
--cooldown-days <n>
|
|
259
|
+
--pr-limit <n>
|
|
260
|
+
--only-changed
|
|
261
|
+
--interactive
|
|
262
|
+
--show-impact
|
|
263
|
+
--show-links
|
|
264
|
+
--show-homepage
|
|
265
|
+
--mode minimal|strict|enterprise
|
|
266
|
+
--fix-pr
|
|
267
|
+
--fix-branch <name>
|
|
268
|
+
--fix-commit-message <text>
|
|
269
|
+
--fix-dry-run
|
|
270
|
+
--fix-pr-no-checkout
|
|
271
|
+
--fix-pr-batch-size <n>
|
|
272
|
+
--no-pr-report
|
|
273
|
+
--log-level error|warn|info|debug
|
|
274
|
+
--concurrency <n>
|
|
275
|
+
--registry-timeout-ms <n>
|
|
276
|
+
--registry-retries <n>
|
|
277
|
+
--cache-ttl <seconds>
|
|
278
|
+
--offline
|
|
279
|
+
--stream
|
|
280
|
+
--lockfile-mode preserve|update|error
|
|
281
|
+
--ci
|
|
282
|
+
--help, -h
|
|
283
|
+
--version, -v`;
|
|
284
|
+
}
|
|
@@ -54,7 +54,9 @@ export async function runAudit(options) {
|
|
|
54
54
|
result.warnings.push("No dependencies found to audit.");
|
|
55
55
|
return result;
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
if (!options.silent) {
|
|
58
|
+
process.stderr.write(`[audit] Querying ${describeSourceMode(options.sourceMode)} for ${targetResolution.targets.length} dependency version${targetResolution.targets.length === 1 ? "" : "s"}...\n`);
|
|
59
|
+
}
|
|
58
60
|
const fetched = await fetchAdvisories(targetResolution.targets, {
|
|
59
61
|
concurrency: options.concurrency,
|
|
60
62
|
registryTimeoutMs: options.registryTimeoutMs,
|
|
@@ -77,15 +79,17 @@ export async function runAudit(options) {
|
|
|
77
79
|
result.advisories = advisories;
|
|
78
80
|
result.packages = summarizeAdvisories(advisories);
|
|
79
81
|
result.autoFixable = advisories.filter((a) => a.patchedVersion !== null).length;
|
|
80
|
-
if (options.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
if (!options.silent) {
|
|
83
|
+
if (options.reportFormat === "summary") {
|
|
84
|
+
process.stdout.write(renderAuditSummary(result.packages) +
|
|
85
|
+
renderAuditSourceHealth(result.sourceHealth) +
|
|
86
|
+
"\n");
|
|
87
|
+
}
|
|
88
|
+
else if (options.reportFormat === "table" || !options.jsonFile) {
|
|
89
|
+
process.stdout.write(renderAuditTable(advisories) +
|
|
90
|
+
renderAuditSourceHealth(result.sourceHealth) +
|
|
91
|
+
"\n");
|
|
92
|
+
}
|
|
89
93
|
}
|
|
90
94
|
if (options.jsonFile) {
|
|
91
95
|
await writeFileAtomic(options.jsonFile, stableStringify({
|
|
@@ -97,7 +101,9 @@ export async function runAudit(options) {
|
|
|
97
101
|
errors: result.errors,
|
|
98
102
|
warnings: result.warnings,
|
|
99
103
|
}, 2) + "\n");
|
|
100
|
-
|
|
104
|
+
if (!options.silent) {
|
|
105
|
+
process.stderr.write(`[audit] JSON report written to ${options.jsonFile}\n`);
|
|
106
|
+
}
|
|
101
107
|
}
|
|
102
108
|
if (options.fix && result.autoFixable > 0) {
|
|
103
109
|
await applyFix(advisories, options);
|
|
@@ -120,27 +126,35 @@ async function applyFix(advisories, options) {
|
|
|
120
126
|
const installArgs = buildInstallArgs(pm, patchMap);
|
|
121
127
|
const installCmd = `${pm} ${installArgs.join(" ")}`;
|
|
122
128
|
if (options.dryRun) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
if (!options.silent) {
|
|
130
|
+
process.stderr.write(`[audit] --dry-run: would execute:\n ${installCmd}\n`);
|
|
131
|
+
if (options.commit) {
|
|
132
|
+
const msg = buildCommitMessage(patchMap);
|
|
133
|
+
process.stderr.write(`[audit] --dry-run: would commit:\n git commit -m "${msg}"\n`);
|
|
134
|
+
}
|
|
127
135
|
}
|
|
128
136
|
return;
|
|
129
137
|
}
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
if (!options.silent) {
|
|
139
|
+
process.stderr.write(`[audit] Applying ${patchMap.size} fix(es)...\n`);
|
|
140
|
+
process.stderr.write(` → ${installCmd}\n`);
|
|
141
|
+
}
|
|
132
142
|
try {
|
|
133
143
|
await runCommand(pm, installArgs, options.cwd);
|
|
134
144
|
}
|
|
135
145
|
catch (err) {
|
|
136
|
-
|
|
146
|
+
if (!options.silent) {
|
|
147
|
+
process.stderr.write(`[audit] Install failed: ${String(err)}\n`);
|
|
148
|
+
}
|
|
137
149
|
return;
|
|
138
150
|
}
|
|
139
|
-
|
|
151
|
+
if (!options.silent) {
|
|
152
|
+
process.stderr.write(`[audit] ✔ Patches applied successfully.\n`);
|
|
153
|
+
}
|
|
140
154
|
if (options.commit) {
|
|
141
|
-
await commitFix(patchMap, options.cwd);
|
|
155
|
+
await commitFix(patchMap, options.cwd, options.silent);
|
|
142
156
|
}
|
|
143
|
-
else {
|
|
157
|
+
else if (!options.silent) {
|
|
144
158
|
process.stderr.write(`[audit] Tip: run with --commit to automatically commit the changes.\n`);
|
|
145
159
|
}
|
|
146
160
|
}
|
|
@@ -157,7 +171,7 @@ function buildInstallArgs(pm, patchMap) {
|
|
|
157
171
|
return ["install", ...packages]; // npm
|
|
158
172
|
}
|
|
159
173
|
}
|
|
160
|
-
async function commitFix(patchMap, cwd) {
|
|
174
|
+
async function commitFix(patchMap, cwd, silent) {
|
|
161
175
|
const msg = buildCommitMessage(patchMap);
|
|
162
176
|
try {
|
|
163
177
|
// Stage all modified files (package.json + lockfiles)
|
|
@@ -171,12 +185,15 @@ async function commitFix(patchMap, cwd) {
|
|
|
171
185
|
"bun.lockb",
|
|
172
186
|
], cwd, true);
|
|
173
187
|
await runCommand("git", ["commit", "-m", msg], cwd);
|
|
174
|
-
|
|
188
|
+
if (!silent)
|
|
189
|
+
process.stderr.write(`[audit] ✔ Committed: "${msg}"\n`);
|
|
175
190
|
}
|
|
176
191
|
catch (err) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
if (!silent) {
|
|
193
|
+
process.stderr.write(`[audit] Git commit failed: ${String(err)}\n`);
|
|
194
|
+
process.stderr.write(`[audit] Changes are applied — commit manually with:\n`);
|
|
195
|
+
process.stderr.write(` git add -A && git commit -m "${msg}"\n`);
|
|
196
|
+
}
|
|
180
197
|
}
|
|
181
198
|
}
|
|
182
199
|
function buildCommitMessage(patchMap) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function parseDashboardArgs(args) {
|
|
2
|
+
const options = {
|
|
3
|
+
cwd: process.cwd(),
|
|
4
|
+
target: "latest",
|
|
5
|
+
includeKinds: [
|
|
6
|
+
"dependencies",
|
|
7
|
+
"devDependencies",
|
|
8
|
+
"optionalDependencies",
|
|
9
|
+
"peerDependencies",
|
|
10
|
+
],
|
|
11
|
+
cacheTtlSeconds: 3600,
|
|
12
|
+
ci: false,
|
|
13
|
+
format: "table",
|
|
14
|
+
workspace: false,
|
|
15
|
+
concurrency: 16,
|
|
16
|
+
registryTimeoutMs: 8000,
|
|
17
|
+
registryRetries: 3,
|
|
18
|
+
offline: false,
|
|
19
|
+
stream: false,
|
|
20
|
+
logLevel: "info",
|
|
21
|
+
groupBy: "none",
|
|
22
|
+
onlyChanged: false,
|
|
23
|
+
ciProfile: "minimal",
|
|
24
|
+
lockfileMode: "preserve",
|
|
25
|
+
interactive: true,
|
|
26
|
+
showImpact: false,
|
|
27
|
+
showHomepage: true,
|
|
28
|
+
};
|
|
29
|
+
for (let i = 0; i < args.length; i++) {
|
|
30
|
+
const arg = args[i];
|
|
31
|
+
const nextArg = args[i + 1];
|
|
32
|
+
if (arg === "--view" && nextArg) {
|
|
33
|
+
if (nextArg === "dependencies" ||
|
|
34
|
+
nextArg === "security" ||
|
|
35
|
+
nextArg === "health") {
|
|
36
|
+
options.view = nextArg;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
throw new Error(`Invalid --view: ${nextArg}`);
|
|
40
|
+
}
|
|
41
|
+
i++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg === "--view") {
|
|
45
|
+
throw new Error("Missing value for --view");
|
|
46
|
+
}
|
|
47
|
+
// Pass through common workspace / cwd args
|
|
48
|
+
if (arg === "--workspace") {
|
|
49
|
+
options.workspace = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (arg === "--cwd" && nextArg) {
|
|
53
|
+
options.cwd = nextArg;
|
|
54
|
+
i++;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return options;
|
|
59
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "ink";
|
|
3
|
+
import { loadConfig } from "../../config/loader.js";
|
|
4
|
+
import { DashboardTUI } from "../../ui/dashboard/DashboardTUI.js";
|
|
5
|
+
// We'll need to load initial state or data before or during the render
|
|
6
|
+
import { check } from "../../core/check.js";
|
|
7
|
+
export async function runDashboard(options) {
|
|
8
|
+
// Load configuration
|
|
9
|
+
const resolvedConfig = await loadConfig(options.cwd);
|
|
10
|
+
// Create an initial check result. In a real scenario, this could run
|
|
11
|
+
// progressively in the TUI, but for simplicity we fetch initial data first.
|
|
12
|
+
const checkResult = await check({
|
|
13
|
+
...options,
|
|
14
|
+
// We do not want `check` to exit or log heavily here, the UI will take over.
|
|
15
|
+
logLevel: "error",
|
|
16
|
+
});
|
|
17
|
+
// Render the interactive Ink Dashboard
|
|
18
|
+
const { waitUntilExit } = render(React.createElement(DashboardTUI, {
|
|
19
|
+
options,
|
|
20
|
+
initialResult: checkResult,
|
|
21
|
+
}));
|
|
22
|
+
await waitUntilExit();
|
|
23
|
+
const finalStore = await import("../../ui/dashboard/store.js");
|
|
24
|
+
const finalState = finalStore.getStore()?.getState();
|
|
25
|
+
if (finalState?.shouldApply) {
|
|
26
|
+
process.stderr.write("[dashboard] Applying updates...\n");
|
|
27
|
+
const { applySelectedUpdates } = await import("../../core/upgrade.js");
|
|
28
|
+
const { detectPackageManager } = await import("../../pm/detect.js");
|
|
29
|
+
const { installDependencies } = await import("../../pm/install.js");
|
|
30
|
+
await applySelectedUpdates({
|
|
31
|
+
...options,
|
|
32
|
+
install: false, // We handle installation explicitly below
|
|
33
|
+
packageManager: "auto",
|
|
34
|
+
sync: true,
|
|
35
|
+
lockfileMode: options.lockfileMode || "preserve",
|
|
36
|
+
}, finalState.updates);
|
|
37
|
+
// Install using the correct package manager if desired
|
|
38
|
+
const detected = await detectPackageManager(options.cwd);
|
|
39
|
+
await installDependencies(options.cwd, "auto", detected);
|
|
40
|
+
process.stderr.write("[dashboard] Successfully applied updates and installed dependencies.\n");
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
completed: true,
|
|
44
|
+
errors: [],
|
|
45
|
+
warnings: [],
|
|
46
|
+
};
|
|
47
|
+
}
|