@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
|
@@ -1,93 +1,54 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import process from "node:process";
|
|
3
|
-
import { check } from "./check.js";
|
|
4
2
|
import { createSummary, finalizeSummary } from "./summary.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
3
|
+
import { buildAnalysisBundle } from "./analysis-bundle.js";
|
|
4
|
+
export { createDoctorResult } from "./doctor/result.js";
|
|
5
|
+
export { renderDoctorAgentReport, renderDoctorResult, } from "./doctor/render.js";
|
|
6
|
+
import { deriveReviewVerdict } from "./review-verdict.js";
|
|
7
7
|
export async function buildReviewResult(options) {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
interactive
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const checkResult = await check(baseCheckOptions);
|
|
15
|
-
const [auditResult, resolveResult, healthResult, licenseResult, unusedResult] = await runSilenced(() => Promise.all([
|
|
16
|
-
import("../commands/audit/runner.js").then((mod) => mod.runAudit(toAuditOptions(options))),
|
|
17
|
-
import("../commands/resolve/runner.js").then((mod) => mod.runResolve(toResolveOptions(options))),
|
|
18
|
-
import("../commands/health/runner.js").then((mod) => mod.runHealth(toHealthOptions(options))),
|
|
19
|
-
import("../commands/licenses/runner.js").then((mod) => mod.runLicenses(toLicenseOptions(options))),
|
|
20
|
-
import("../commands/unused/runner.js").then((mod) => mod.runUnused(toUnusedOptions(options))),
|
|
21
|
-
]));
|
|
22
|
-
const advisoryPackages = new Set(auditResult.packages.map((pkg) => pkg.packageName));
|
|
23
|
-
const impactedUpdates = applyImpactScores(checkResult.updates, {
|
|
24
|
-
advisoryPackages,
|
|
25
|
-
workspaceDependentCount: (name) => checkResult.updates.filter((item) => item.name === name).length,
|
|
26
|
-
});
|
|
27
|
-
const healthByName = new Map(healthResult.metrics.map((metric) => [metric.name, metric]));
|
|
28
|
-
const advisoriesByName = new Map();
|
|
29
|
-
const conflictsByName = new Map();
|
|
30
|
-
const licenseByName = new Map(licenseResult.packages.map((pkg) => [pkg.name, pkg]));
|
|
31
|
-
const licenseViolationNames = new Set(licenseResult.violations.map((pkg) => pkg.name));
|
|
32
|
-
const unusedByName = new Map();
|
|
33
|
-
for (const advisory of auditResult.advisories) {
|
|
34
|
-
const list = advisoriesByName.get(advisory.packageName) ?? [];
|
|
35
|
-
list.push(advisory);
|
|
36
|
-
advisoriesByName.set(advisory.packageName, list);
|
|
37
|
-
}
|
|
38
|
-
for (const conflict of resolveResult.conflicts) {
|
|
39
|
-
const list = conflictsByName.get(conflict.requester) ?? [];
|
|
40
|
-
list.push(conflict);
|
|
41
|
-
conflictsByName.set(conflict.requester, list);
|
|
42
|
-
const peerList = conflictsByName.get(conflict.peer) ?? [];
|
|
43
|
-
peerList.push(conflict);
|
|
44
|
-
conflictsByName.set(conflict.peer, peerList);
|
|
45
|
-
}
|
|
46
|
-
for (const issue of [...unusedResult.unused, ...unusedResult.missing]) {
|
|
47
|
-
const list = unusedByName.get(issue.name) ?? [];
|
|
48
|
-
list.push(issue);
|
|
49
|
-
unusedByName.set(issue.name, list);
|
|
50
|
-
}
|
|
51
|
-
const baseItems = impactedUpdates
|
|
52
|
-
.map((update) => enrichUpdate(update, advisoriesByName, conflictsByName, healthByName, licenseByName, licenseViolationNames, unusedByName))
|
|
53
|
-
.filter((item) => matchesReviewFilters(item, options));
|
|
54
|
-
const items = applyRiskAssessments(baseItems, {
|
|
55
|
-
knownPackageNames: new Set(checkResult.updates.map((item) => item.name)),
|
|
56
|
-
}).filter((item) => matchesReviewFilters(item, options));
|
|
8
|
+
const includeChangelog = ("showChangelog" in options && options.showChangelog === true) ||
|
|
9
|
+
("includeChangelog" in options && options.includeChangelog === true) ||
|
|
10
|
+
options.interactive === true;
|
|
11
|
+
const analysis = await buildAnalysisBundle(options, { includeChangelog });
|
|
12
|
+
const items = analysis.items.filter((item) => matchesReviewFilters(item, options));
|
|
13
|
+
const checkResult = analysis.check;
|
|
57
14
|
const summary = createReviewSummary(checkResult.summary, items, [
|
|
58
15
|
...checkResult.errors,
|
|
59
|
-
...
|
|
60
|
-
...
|
|
61
|
-
...
|
|
62
|
-
...
|
|
63
|
-
...
|
|
16
|
+
...analysis.audit.errors,
|
|
17
|
+
...analysis.resolve.errors,
|
|
18
|
+
...analysis.health.errors,
|
|
19
|
+
...analysis.licenses.errors,
|
|
20
|
+
...analysis.unused.errors,
|
|
64
21
|
], [
|
|
65
22
|
...checkResult.warnings,
|
|
66
|
-
...
|
|
67
|
-
...
|
|
68
|
-
...
|
|
69
|
-
...
|
|
70
|
-
...
|
|
71
|
-
], options.interactive === true);
|
|
23
|
+
...analysis.audit.warnings,
|
|
24
|
+
...analysis.resolve.warnings,
|
|
25
|
+
...analysis.health.warnings,
|
|
26
|
+
...analysis.licenses.warnings,
|
|
27
|
+
...analysis.unused.warnings,
|
|
28
|
+
], options.interactive === true, analysis.degradedSources);
|
|
72
29
|
return {
|
|
73
30
|
projectPath: checkResult.projectPath,
|
|
74
31
|
target: checkResult.target,
|
|
75
32
|
summary,
|
|
33
|
+
analysis,
|
|
76
34
|
items,
|
|
77
35
|
updates: items.map((item) => item.update),
|
|
78
|
-
errors: [
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
36
|
+
errors: [
|
|
37
|
+
...checkResult.errors,
|
|
38
|
+
...analysis.audit.errors,
|
|
39
|
+
...analysis.resolve.errors,
|
|
40
|
+
...analysis.health.errors,
|
|
41
|
+
...analysis.licenses.errors,
|
|
42
|
+
...analysis.unused.errors,
|
|
43
|
+
],
|
|
44
|
+
warnings: [
|
|
45
|
+
...checkResult.warnings,
|
|
46
|
+
...analysis.audit.warnings,
|
|
47
|
+
...analysis.resolve.warnings,
|
|
48
|
+
...analysis.health.warnings,
|
|
49
|
+
...analysis.licenses.warnings,
|
|
50
|
+
...analysis.unused.warnings,
|
|
51
|
+
],
|
|
91
52
|
};
|
|
92
53
|
}
|
|
93
54
|
export function renderReviewResult(review) {
|
|
@@ -115,6 +76,7 @@ export function renderReviewResult(review) {
|
|
|
115
76
|
item.update.licenseStatus && item.update.licenseStatus !== "allowed"
|
|
116
77
|
? `license=${item.update.licenseStatus}`
|
|
117
78
|
: undefined,
|
|
79
|
+
item.update.policyAction ? `policy=${item.update.policyAction}` : undefined,
|
|
118
80
|
].filter(Boolean);
|
|
119
81
|
lines.push(`- ${path.basename(item.update.packagePath)} :: ${item.update.name} ${item.update.fromRange} -> ${item.update.toRange} (${notes.join(", ")})`);
|
|
120
82
|
if (item.update.riskReasons && item.update.riskReasons.length > 0) {
|
|
@@ -123,6 +85,9 @@ export function renderReviewResult(review) {
|
|
|
123
85
|
if (item.update.recommendedAction) {
|
|
124
86
|
lines.push(` action: ${item.update.recommendedAction}`);
|
|
125
87
|
}
|
|
88
|
+
if (item.update.releaseNotesSummary) {
|
|
89
|
+
lines.push(` notes: ${item.update.releaseNotesSummary.title} - ${item.update.releaseNotesSummary.excerpt}`);
|
|
90
|
+
}
|
|
126
91
|
if (item.update.homepage) {
|
|
127
92
|
lines.push(` homepage: ${item.update.homepage}`);
|
|
128
93
|
}
|
|
@@ -146,47 +111,6 @@ export function renderReviewResult(review) {
|
|
|
146
111
|
lines.push(`Summary: ${review.summary.updatesFound} updates, riskPackages=${review.summary.riskPackages ?? 0}, securityPackages=${review.summary.securityPackages ?? 0}, peerConflictPackages=${review.summary.peerConflictPackages ?? 0}`);
|
|
147
112
|
return lines.join("\n");
|
|
148
113
|
}
|
|
149
|
-
export function renderDoctorResult(result, verdictOnly = false) {
|
|
150
|
-
const lines = [
|
|
151
|
-
`State: ${result.verdict}`,
|
|
152
|
-
`PrimaryRisk: ${result.primaryFindings[0] ?? "No blocking findings."}`,
|
|
153
|
-
`NextAction: ${result.recommendedCommand}`,
|
|
154
|
-
];
|
|
155
|
-
if (!verdictOnly) {
|
|
156
|
-
lines.push(`Counts: updates=${result.summary.updatesFound}, security=${result.summary.securityPackages ?? 0}, risk=${result.summary.riskPackages ?? 0}, peer=${result.summary.peerConflictPackages ?? 0}, license=${result.summary.licenseViolationPackages ?? 0}`);
|
|
157
|
-
}
|
|
158
|
-
return lines.join("\n");
|
|
159
|
-
}
|
|
160
|
-
function enrichUpdate(update, advisoriesByName, conflictsByName, healthByName, licenseByName, licenseViolationNames, unusedByName) {
|
|
161
|
-
const advisories = advisoriesByName.get(update.name) ?? [];
|
|
162
|
-
const peerConflicts = conflictsByName.get(update.name) ?? [];
|
|
163
|
-
const health = healthByName.get(update.name);
|
|
164
|
-
const license = licenseByName.get(update.name);
|
|
165
|
-
const unusedIssues = unusedByName.get(update.name) ?? [];
|
|
166
|
-
return {
|
|
167
|
-
update: {
|
|
168
|
-
...update,
|
|
169
|
-
advisoryCount: advisories.length,
|
|
170
|
-
peerConflictSeverity: peerConflicts.some((item) => item.severity === "error")
|
|
171
|
-
? "error"
|
|
172
|
-
: peerConflicts.length > 0
|
|
173
|
-
? "warning"
|
|
174
|
-
: "none",
|
|
175
|
-
licenseStatus: licenseViolationNames.has(update.name)
|
|
176
|
-
? "denied"
|
|
177
|
-
: license
|
|
178
|
-
? "allowed"
|
|
179
|
-
: "review",
|
|
180
|
-
healthStatus: health?.flags[0] ?? "healthy",
|
|
181
|
-
},
|
|
182
|
-
advisories,
|
|
183
|
-
health,
|
|
184
|
-
peerConflicts,
|
|
185
|
-
license,
|
|
186
|
-
unusedIssues,
|
|
187
|
-
selected: true,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
114
|
function matchesReviewFilters(item, options) {
|
|
191
115
|
if ("securityOnly" in options && options.securityOnly && item.advisories.length === 0) {
|
|
192
116
|
return false;
|
|
@@ -208,7 +132,7 @@ function riskMatches(current, threshold) {
|
|
|
208
132
|
};
|
|
209
133
|
return order[current ?? "low"] >= order[threshold];
|
|
210
134
|
}
|
|
211
|
-
function createReviewSummary(base, items, errors, warnings, interactiveSession) {
|
|
135
|
+
function createReviewSummary(base, items, errors, warnings, interactiveSession, degradedSources) {
|
|
212
136
|
const summary = finalizeSummary(createSummary({
|
|
213
137
|
scannedPackages: base.scannedPackages,
|
|
214
138
|
totalDependencies: base.totalDependencies,
|
|
@@ -242,131 +166,17 @@ function createReviewSummary(base, items, errors, warnings, interactiveSession)
|
|
|
242
166
|
summary.riskPackages = items.filter((item) => item.update.riskLevel === "critical" || item.update.riskLevel === "high").length;
|
|
243
167
|
summary.peerConflictPackages = items.filter((item) => item.update.peerConflictSeverity && item.update.peerConflictSeverity !== "none").length;
|
|
244
168
|
summary.licenseViolationPackages = items.filter((item) => item.update.licenseStatus === "denied").length;
|
|
245
|
-
summary.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
item.update.licenseStatus === "denied")) {
|
|
251
|
-
return "blocked";
|
|
252
|
-
}
|
|
253
|
-
if (items.some((item) => item.advisories.length > 0 || item.update.riskLevel === "critical")) {
|
|
254
|
-
return "actionable";
|
|
255
|
-
}
|
|
256
|
-
if (errors.length > 0 ||
|
|
257
|
-
items.some((item) => item.update.riskLevel === "high" || item.update.diffType === "major")) {
|
|
258
|
-
return "review";
|
|
259
|
-
}
|
|
260
|
-
return "safe";
|
|
261
|
-
}
|
|
262
|
-
function buildPrimaryFindings(review) {
|
|
263
|
-
const findings = [];
|
|
264
|
-
if ((review.summary.peerConflictPackages ?? 0) > 0) {
|
|
265
|
-
findings.push(`${review.summary.peerConflictPackages} package(s) have peer conflicts.`);
|
|
266
|
-
}
|
|
267
|
-
if ((review.summary.licenseViolationPackages ?? 0) > 0) {
|
|
268
|
-
findings.push(`${review.summary.licenseViolationPackages} package(s) violate license policy.`);
|
|
269
|
-
}
|
|
270
|
-
if ((review.summary.securityPackages ?? 0) > 0) {
|
|
271
|
-
findings.push(`${review.summary.securityPackages} package(s) have security advisories.`);
|
|
272
|
-
}
|
|
273
|
-
if ((review.summary.riskPackages ?? 0) > 0) {
|
|
274
|
-
findings.push(`${review.summary.riskPackages} package(s) are high risk.`);
|
|
275
|
-
}
|
|
276
|
-
if (review.errors.length > 0) {
|
|
277
|
-
findings.push(`${review.errors.length} execution error(s) need review before treating the result as clean.`);
|
|
278
|
-
}
|
|
279
|
-
if (findings.length === 0) {
|
|
280
|
-
findings.push("No blocking findings; remaining updates are low-risk.");
|
|
281
|
-
}
|
|
282
|
-
return findings;
|
|
283
|
-
}
|
|
284
|
-
function recommendCommand(review, verdict) {
|
|
285
|
-
if (verdict === "blocked")
|
|
286
|
-
return "rup review --interactive";
|
|
287
|
-
if ((review.summary.securityPackages ?? 0) > 0)
|
|
288
|
-
return "rup review --security-only";
|
|
289
|
-
if (review.errors.length > 0 || review.items.length > 0)
|
|
290
|
-
return "rup review --interactive";
|
|
291
|
-
return "rup check";
|
|
292
|
-
}
|
|
293
|
-
async function runSilenced(fn) {
|
|
294
|
-
const stdoutWrite = process.stdout.write.bind(process.stdout);
|
|
295
|
-
const stderrWrite = process.stderr.write.bind(process.stderr);
|
|
296
|
-
process.stdout.write = (() => true);
|
|
297
|
-
process.stderr.write = (() => true);
|
|
298
|
-
try {
|
|
299
|
-
return await fn();
|
|
300
|
-
}
|
|
301
|
-
finally {
|
|
302
|
-
process.stdout.write = stdoutWrite;
|
|
303
|
-
process.stderr.write = stderrWrite;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
function toAuditOptions(options) {
|
|
307
|
-
return {
|
|
308
|
-
cwd: options.cwd,
|
|
309
|
-
workspace: options.workspace,
|
|
310
|
-
severity: undefined,
|
|
311
|
-
fix: false,
|
|
312
|
-
dryRun: true,
|
|
313
|
-
commit: false,
|
|
314
|
-
packageManager: "auto",
|
|
315
|
-
reportFormat: "json",
|
|
316
|
-
sourceMode: "auto",
|
|
317
|
-
jsonFile: undefined,
|
|
318
|
-
concurrency: options.concurrency,
|
|
319
|
-
registryTimeoutMs: options.registryTimeoutMs,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
function toResolveOptions(options) {
|
|
323
|
-
return {
|
|
324
|
-
cwd: options.cwd,
|
|
325
|
-
workspace: options.workspace,
|
|
326
|
-
afterUpdate: true,
|
|
327
|
-
safe: false,
|
|
328
|
-
jsonFile: undefined,
|
|
329
|
-
concurrency: options.concurrency,
|
|
330
|
-
registryTimeoutMs: options.registryTimeoutMs,
|
|
331
|
-
cacheTtlSeconds: options.cacheTtlSeconds,
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
function toHealthOptions(options) {
|
|
335
|
-
return {
|
|
336
|
-
cwd: options.cwd,
|
|
337
|
-
workspace: options.workspace,
|
|
338
|
-
staleDays: 365,
|
|
339
|
-
includeDeprecated: true,
|
|
340
|
-
includeAlternatives: false,
|
|
341
|
-
reportFormat: "json",
|
|
342
|
-
jsonFile: undefined,
|
|
343
|
-
concurrency: options.concurrency,
|
|
344
|
-
registryTimeoutMs: options.registryTimeoutMs,
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
function toLicenseOptions(options) {
|
|
348
|
-
return {
|
|
349
|
-
cwd: options.cwd,
|
|
350
|
-
workspace: options.workspace,
|
|
351
|
-
allow: undefined,
|
|
352
|
-
deny: undefined,
|
|
353
|
-
sbomFile: undefined,
|
|
354
|
-
jsonFile: undefined,
|
|
355
|
-
diffMode: false,
|
|
356
|
-
concurrency: options.concurrency,
|
|
357
|
-
registryTimeoutMs: options.registryTimeoutMs,
|
|
358
|
-
cacheTtlSeconds: options.cacheTtlSeconds,
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
function toUnusedOptions(options) {
|
|
362
|
-
return {
|
|
363
|
-
cwd: options.cwd,
|
|
364
|
-
workspace: options.workspace,
|
|
365
|
-
srcDirs: ["src", "."],
|
|
366
|
-
includeDevDependencies: true,
|
|
367
|
-
fix: false,
|
|
368
|
-
dryRun: true,
|
|
369
|
-
jsonFile: undefined,
|
|
370
|
-
concurrency: options.concurrency,
|
|
169
|
+
summary.policyActionCounts = {
|
|
170
|
+
allow: items.filter((item) => item.update.policyAction === "allow").length,
|
|
171
|
+
review: items.filter((item) => item.update.policyAction === "review").length,
|
|
172
|
+
block: items.filter((item) => item.update.policyAction === "block").length,
|
|
173
|
+
monitor: items.filter((item) => item.update.policyAction === "monitor").length,
|
|
371
174
|
};
|
|
175
|
+
summary.blockedPackages = items.filter((item) => item.update.decisionState === "blocked").length;
|
|
176
|
+
summary.reviewPackages = items.filter((item) => item.update.decisionState === "review").length;
|
|
177
|
+
summary.monitorPackages = items.filter((item) => item.update.policyAction === "monitor").length;
|
|
178
|
+
summary.decisionPackages = items.length;
|
|
179
|
+
summary.degradedSources = degradedSources;
|
|
180
|
+
summary.verdict = deriveReviewVerdict(items, errors);
|
|
181
|
+
return summary;
|
|
372
182
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function deriveReviewVerdict(items, errors) {
|
|
2
|
+
if (items.some((item) => item.update.peerConflictSeverity === "error" ||
|
|
3
|
+
item.update.licenseStatus === "denied")) {
|
|
4
|
+
return "blocked";
|
|
5
|
+
}
|
|
6
|
+
if (items.some((item) => item.advisories.length > 0 || item.update.riskLevel === "critical")) {
|
|
7
|
+
return "actionable";
|
|
8
|
+
}
|
|
9
|
+
if (errors.length > 0 ||
|
|
10
|
+
items.some((item) => item.update.riskLevel === "high" || item.update.diffType === "major")) {
|
|
11
|
+
return "review";
|
|
12
|
+
}
|
|
13
|
+
return "safe";
|
|
14
|
+
}
|
package/dist/core/summary.js
CHANGED
|
@@ -50,6 +50,25 @@ export function createSummary(input) {
|
|
|
50
50
|
peerConflictPackages: 0,
|
|
51
51
|
licenseViolationPackages: 0,
|
|
52
52
|
privateRegistryPackages: 0,
|
|
53
|
+
runId: undefined,
|
|
54
|
+
artifactManifest: undefined,
|
|
55
|
+
policyActionCounts: undefined,
|
|
56
|
+
blockedPackages: 0,
|
|
57
|
+
reviewPackages: 0,
|
|
58
|
+
monitorPackages: 0,
|
|
59
|
+
decisionPackages: 0,
|
|
60
|
+
releaseVolatilityPackages: 0,
|
|
61
|
+
engineConflictPackages: 0,
|
|
62
|
+
degradedSources: [],
|
|
63
|
+
cacheBackend: undefined,
|
|
64
|
+
binaryRecommended: false,
|
|
65
|
+
gaReady: undefined,
|
|
66
|
+
dependencyHealthScore: undefined,
|
|
67
|
+
findingCountsByCategory: undefined,
|
|
68
|
+
findingCountsBySeverity: undefined,
|
|
69
|
+
primaryFindingCode: undefined,
|
|
70
|
+
primaryFindingCategory: undefined,
|
|
71
|
+
nextActionReason: undefined,
|
|
53
72
|
};
|
|
54
73
|
}
|
|
55
74
|
export function finalizeSummary(summary) {
|
package/dist/output/format.js
CHANGED
|
@@ -62,6 +62,18 @@ export function renderResult(result, format, display = {}) {
|
|
|
62
62
|
`security_packages=${result.summary.securityPackages ?? 0}`,
|
|
63
63
|
`peer_conflict_packages=${result.summary.peerConflictPackages ?? 0}`,
|
|
64
64
|
`license_violation_packages=${result.summary.licenseViolationPackages ?? 0}`,
|
|
65
|
+
`run_id=${result.summary.runId ?? ""}`,
|
|
66
|
+
`artifact_manifest=${result.summary.artifactManifest ?? ""}`,
|
|
67
|
+
`blocked_packages=${result.summary.blockedPackages ?? 0}`,
|
|
68
|
+
`review_packages=${result.summary.reviewPackages ?? 0}`,
|
|
69
|
+
`monitor_packages=${result.summary.monitorPackages ?? 0}`,
|
|
70
|
+
`cache_backend=${result.summary.cacheBackend ?? ""}`,
|
|
71
|
+
`degraded_sources=${(result.summary.degradedSources ?? []).join(",")}`,
|
|
72
|
+
`ga_ready=${result.summary.gaReady === true ? "1" : "0"}`,
|
|
73
|
+
`dependency_health_score=${result.summary.dependencyHealthScore ?? ""}`,
|
|
74
|
+
`primary_finding_code=${result.summary.primaryFindingCode ?? ""}`,
|
|
75
|
+
`primary_finding_category=${result.summary.primaryFindingCategory ?? ""}`,
|
|
76
|
+
`next_action_reason=${result.summary.nextActionReason ?? ""}`,
|
|
65
77
|
].join("\n");
|
|
66
78
|
}
|
|
67
79
|
const lines = [];
|
|
@@ -89,12 +101,16 @@ export function renderResult(result, format, display = {}) {
|
|
|
89
101
|
display.showHomepage && update.homepage ? update.homepage : undefined,
|
|
90
102
|
update.riskLevel ? `risk=${update.riskLevel}` : undefined,
|
|
91
103
|
typeof update.riskScore === "number" ? `score=${update.riskScore}` : undefined,
|
|
104
|
+
update.policyAction ? `policy=${update.policyAction}` : undefined,
|
|
92
105
|
]
|
|
93
106
|
.filter(Boolean)
|
|
94
107
|
.join(", ")})`);
|
|
95
108
|
if (update.recommendedAction) {
|
|
96
109
|
lines.push(` action: ${update.recommendedAction}`);
|
|
97
110
|
}
|
|
111
|
+
if (update.releaseNotesSummary) {
|
|
112
|
+
lines.push(` notes: ${update.releaseNotesSummary.title} — ${update.releaseNotesSummary.excerpt}`);
|
|
113
|
+
}
|
|
98
114
|
}
|
|
99
115
|
}
|
|
100
116
|
if (result.errors.length > 0) {
|
|
@@ -118,6 +134,12 @@ export function renderResult(result, format, display = {}) {
|
|
|
118
134
|
if (result.summary.verdict) {
|
|
119
135
|
lines.push(`Verdict=${result.summary.verdict}, riskPackages=${result.summary.riskPackages ?? 0}, securityPackages=${result.summary.securityPackages ?? 0}, peerConflictPackages=${result.summary.peerConflictPackages ?? 0}, licenseViolationPackages=${result.summary.licenseViolationPackages ?? 0}`);
|
|
120
136
|
}
|
|
137
|
+
if (typeof result.summary.dependencyHealthScore === "number") {
|
|
138
|
+
lines.push(`DependencyHealthScore=${result.summary.dependencyHealthScore}, primaryFinding=${result.summary.primaryFindingCode ?? "none"}, category=${result.summary.primaryFindingCategory ?? "none"}`);
|
|
139
|
+
}
|
|
140
|
+
if (result.summary.runId) {
|
|
141
|
+
lines.push(`RunId=${result.summary.runId}, artifactManifest=${result.summary.artifactManifest ?? "none"}, blockedPackages=${result.summary.blockedPackages ?? 0}, reviewPackages=${result.summary.reviewPackages ?? 0}, monitorPackages=${result.summary.monitorPackages ?? 0}`);
|
|
142
|
+
}
|
|
121
143
|
lines.push(`Contract v${result.summary.contractVersion}, failReason=${result.summary.failReason}, duration=${result.summary.durationMs.total}ms`);
|
|
122
144
|
if (result.summary.fixPrApplied) {
|
|
123
145
|
lines.push(`Fix PR: applied on branch ${result.summary.fixBranchName ?? "unknown"} (${result.summary.fixCommitSha ?? "no-commit"})`);
|
package/dist/output/github.js
CHANGED
|
@@ -26,6 +26,18 @@ export async function writeGitHubOutput(filePath, result) {
|
|
|
26
26
|
`security_packages=${result.summary.securityPackages ?? 0}`,
|
|
27
27
|
`peer_conflict_packages=${result.summary.peerConflictPackages ?? 0}`,
|
|
28
28
|
`license_violation_packages=${result.summary.licenseViolationPackages ?? 0}`,
|
|
29
|
+
`run_id=${result.summary.runId ?? ""}`,
|
|
30
|
+
`artifact_manifest=${result.summary.artifactManifest ?? ""}`,
|
|
31
|
+
`blocked_packages=${result.summary.blockedPackages ?? 0}`,
|
|
32
|
+
`review_packages=${result.summary.reviewPackages ?? 0}`,
|
|
33
|
+
`monitor_packages=${result.summary.monitorPackages ?? 0}`,
|
|
34
|
+
`cache_backend=${result.summary.cacheBackend ?? ""}`,
|
|
35
|
+
`degraded_sources=${(result.summary.degradedSources ?? []).join(",")}`,
|
|
36
|
+
`ga_ready=${result.summary.gaReady === true ? "1" : "0"}`,
|
|
37
|
+
`dependency_health_score=${result.summary.dependencyHealthScore ?? ""}`,
|
|
38
|
+
`primary_finding_code=${result.summary.primaryFindingCode ?? ""}`,
|
|
39
|
+
`primary_finding_category=${result.summary.primaryFindingCategory ?? ""}`,
|
|
40
|
+
`next_action_reason=${result.summary.nextActionReason ?? ""}`,
|
|
29
41
|
`fix_pr_applied=${result.summary.fixPrApplied === true ? "1" : "0"}`,
|
|
30
42
|
`fix_pr_branches_created=${result.summary.fixPrBranchesCreated}`,
|
|
31
43
|
`fix_pr_branch=${result.summary.fixBranchName ?? ""}`,
|
package/dist/output/sarif.js
CHANGED
|
@@ -39,6 +39,11 @@ export function createSarifReport(result) {
|
|
|
39
39
|
advisoryCount: update.advisoryCount ?? 0,
|
|
40
40
|
peerConflictSeverity: update.peerConflictSeverity ?? "none",
|
|
41
41
|
licenseStatus: update.licenseStatus ?? "allowed",
|
|
42
|
+
policyAction: update.policyAction,
|
|
43
|
+
decisionState: update.decisionState,
|
|
44
|
+
releaseNotesSummary: update.releaseNotesSummary?.excerpt,
|
|
45
|
+
engineStatus: update.engineStatus?.state,
|
|
46
|
+
runId: result.summary.runId,
|
|
42
47
|
},
|
|
43
48
|
}));
|
|
44
49
|
const errorResults = [...result.errors].sort((a, b) => a.localeCompare(b)).map((error) => ({
|
|
@@ -89,6 +94,17 @@ export function createSarifReport(result) {
|
|
|
89
94
|
securityPackages: result.summary.securityPackages ?? 0,
|
|
90
95
|
peerConflictPackages: result.summary.peerConflictPackages ?? 0,
|
|
91
96
|
licenseViolationPackages: result.summary.licenseViolationPackages ?? 0,
|
|
97
|
+
runId: result.summary.runId,
|
|
98
|
+
artifactManifest: result.summary.artifactManifest,
|
|
99
|
+
blockedPackages: result.summary.blockedPackages ?? 0,
|
|
100
|
+
reviewPackages: result.summary.reviewPackages ?? 0,
|
|
101
|
+
monitorPackages: result.summary.monitorPackages ?? 0,
|
|
102
|
+
degradedSources: result.summary.degradedSources ?? [],
|
|
103
|
+
cacheBackend: result.summary.cacheBackend,
|
|
104
|
+
dependencyHealthScore: result.summary.dependencyHealthScore,
|
|
105
|
+
primaryFindingCode: result.summary.primaryFindingCode,
|
|
106
|
+
primaryFindingCategory: result.summary.primaryFindingCategory,
|
|
107
|
+
nextActionReason: result.summary.nextActionReason,
|
|
92
108
|
},
|
|
93
109
|
},
|
|
94
110
|
],
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,8 +5,13 @@ export type CiProfile = "minimal" | "strict" | "enterprise";
|
|
|
5
5
|
export type LockfileMode = "preserve" | "update" | "error";
|
|
6
6
|
export type Verdict = "safe" | "review" | "blocked" | "actionable";
|
|
7
7
|
export type RiskLevel = "critical" | "high" | "medium" | "low";
|
|
8
|
+
export type DoctorFindingSeverity = "error" | "warning";
|
|
9
|
+
export type DoctorScoreLabel = "Strong" | "Needs Review" | "Action Needed" | "Blocked / Critical";
|
|
10
|
+
export type DoctorFindingCategory = "Security" | "Compatibility" | "Policy" | "Operational Health" | "Licensing" | "Unused / Cleanup" | "Release Risk" | "Registry / Execution" | "Workspace Integrity";
|
|
8
11
|
export type RiskCategory = "known-vulnerability" | "behavioral-risk" | "operational-health";
|
|
9
12
|
export type MaintainerChurnStatus = "unknown" | "stable" | "elevated-change";
|
|
13
|
+
export type PolicyAction = "allow" | "review" | "block" | "monitor";
|
|
14
|
+
export type DecisionState = "safe" | "review" | "blocked" | "actionable";
|
|
10
15
|
export type OutputFormat = "table" | "json" | "minimal" | "github" | "metrics";
|
|
11
16
|
export type FailOnLevel = "none" | "patch" | "minor" | "major" | "any";
|
|
12
17
|
export type LogLevel = "error" | "warn" | "info" | "debug";
|
|
@@ -108,6 +113,40 @@ export interface PackageUpdate {
|
|
|
108
113
|
peerConflictSeverity?: "none" | PeerConflictSeverity;
|
|
109
114
|
licenseStatus?: "allowed" | "review" | "denied";
|
|
110
115
|
healthStatus?: "healthy" | HealthFlag;
|
|
116
|
+
policyAction?: PolicyAction;
|
|
117
|
+
decisionState?: DecisionState;
|
|
118
|
+
releaseNotesSummary?: ReleaseNotesSummary;
|
|
119
|
+
engineStatus?: EngineStatus;
|
|
120
|
+
workspaceGroup?: string;
|
|
121
|
+
groupKey?: string;
|
|
122
|
+
selectedByDefault?: boolean;
|
|
123
|
+
blockedReason?: string;
|
|
124
|
+
monitorReason?: string;
|
|
125
|
+
}
|
|
126
|
+
export interface ReleaseNotesSummary {
|
|
127
|
+
source: "github-release" | "changelog-file" | "none";
|
|
128
|
+
title: string;
|
|
129
|
+
excerpt: string;
|
|
130
|
+
}
|
|
131
|
+
export interface EngineStatus {
|
|
132
|
+
state: "compatible" | "review" | "blocked" | "unknown";
|
|
133
|
+
required?: string;
|
|
134
|
+
current?: string;
|
|
135
|
+
reason?: string;
|
|
136
|
+
}
|
|
137
|
+
export interface ArtifactManifest {
|
|
138
|
+
runId: string;
|
|
139
|
+
createdAt: string;
|
|
140
|
+
command: string;
|
|
141
|
+
projectPath: string;
|
|
142
|
+
ciProfile: CiProfile;
|
|
143
|
+
artifactManifestPath: string;
|
|
144
|
+
outputs: {
|
|
145
|
+
jsonFile?: string;
|
|
146
|
+
githubOutputFile?: string;
|
|
147
|
+
sarifFile?: string;
|
|
148
|
+
prReportFile?: string;
|
|
149
|
+
};
|
|
111
150
|
}
|
|
112
151
|
export interface Summary {
|
|
113
152
|
contractVersion: "2";
|
|
@@ -155,6 +194,25 @@ export interface Summary {
|
|
|
155
194
|
peerConflictPackages?: number;
|
|
156
195
|
licenseViolationPackages?: number;
|
|
157
196
|
privateRegistryPackages?: number;
|
|
197
|
+
runId?: string;
|
|
198
|
+
artifactManifest?: string;
|
|
199
|
+
policyActionCounts?: Record<PolicyAction, number>;
|
|
200
|
+
blockedPackages?: number;
|
|
201
|
+
reviewPackages?: number;
|
|
202
|
+
monitorPackages?: number;
|
|
203
|
+
decisionPackages?: number;
|
|
204
|
+
releaseVolatilityPackages?: number;
|
|
205
|
+
engineConflictPackages?: number;
|
|
206
|
+
degradedSources?: string[];
|
|
207
|
+
cacheBackend?: "sqlite" | "file";
|
|
208
|
+
binaryRecommended?: boolean;
|
|
209
|
+
gaReady?: boolean;
|
|
210
|
+
dependencyHealthScore?: number;
|
|
211
|
+
findingCountsByCategory?: Partial<Record<DoctorFindingCategory, number>>;
|
|
212
|
+
findingCountsBySeverity?: Partial<Record<DoctorFindingSeverity, number>>;
|
|
213
|
+
primaryFindingCode?: string;
|
|
214
|
+
primaryFindingCategory?: DoctorFindingCategory;
|
|
215
|
+
nextActionReason?: string;
|
|
158
216
|
}
|
|
159
217
|
export interface CheckResult {
|
|
160
218
|
projectPath: string;
|
|
@@ -208,6 +266,7 @@ export interface AuditOptions {
|
|
|
208
266
|
jsonFile?: string;
|
|
209
267
|
concurrency: number;
|
|
210
268
|
registryTimeoutMs: number;
|
|
269
|
+
silent?: boolean;
|
|
211
270
|
}
|
|
212
271
|
export interface CveAdvisory {
|
|
213
272
|
cveId: string;
|
|
@@ -324,6 +383,7 @@ export interface ResolveOptions {
|
|
|
324
383
|
concurrency: number;
|
|
325
384
|
registryTimeoutMs: number;
|
|
326
385
|
cacheTtlSeconds: number;
|
|
386
|
+
silent?: boolean;
|
|
327
387
|
}
|
|
328
388
|
export interface ResolveResult {
|
|
329
389
|
conflicts: PeerConflict[];
|
|
@@ -367,6 +427,7 @@ export interface ReviewResult {
|
|
|
367
427
|
projectPath: string;
|
|
368
428
|
target: TargetLevel;
|
|
369
429
|
summary: Summary;
|
|
430
|
+
analysis: AnalysisBundle;
|
|
370
431
|
items: ReviewItem[];
|
|
371
432
|
updates: PackageUpdate[];
|
|
372
433
|
errors: string[];
|
|
@@ -377,16 +438,55 @@ export interface ReviewOptions extends CheckOptions {
|
|
|
377
438
|
risk?: RiskLevel;
|
|
378
439
|
diff?: TargetLevel;
|
|
379
440
|
applySelected: boolean;
|
|
441
|
+
showChangelog?: boolean;
|
|
380
442
|
}
|
|
381
443
|
export interface DoctorOptions extends CheckOptions {
|
|
382
444
|
verdictOnly: boolean;
|
|
445
|
+
includeChangelog?: boolean;
|
|
446
|
+
agentReport?: boolean;
|
|
447
|
+
}
|
|
448
|
+
export interface DoctorFinding {
|
|
449
|
+
id: string;
|
|
450
|
+
code: string;
|
|
451
|
+
category: DoctorFindingCategory;
|
|
452
|
+
severity: DoctorFindingSeverity;
|
|
453
|
+
scope: "project" | "package";
|
|
454
|
+
packageName?: string;
|
|
455
|
+
workspace?: string;
|
|
456
|
+
summary: string;
|
|
457
|
+
details?: string;
|
|
458
|
+
help?: string;
|
|
459
|
+
recommendedAction?: string;
|
|
460
|
+
evidence?: string[];
|
|
383
461
|
}
|
|
384
462
|
export interface DoctorResult {
|
|
385
463
|
verdict: Verdict;
|
|
464
|
+
score: number;
|
|
465
|
+
scoreLabel: DoctorScoreLabel;
|
|
386
466
|
summary: Summary;
|
|
387
467
|
review: ReviewResult;
|
|
468
|
+
findings: DoctorFinding[];
|
|
388
469
|
primaryFindings: string[];
|
|
389
470
|
recommendedCommand: string;
|
|
471
|
+
nextActionReason: string;
|
|
472
|
+
}
|
|
473
|
+
export interface AnalysisBundle {
|
|
474
|
+
check: CheckResult;
|
|
475
|
+
audit: AuditResult;
|
|
476
|
+
resolve: ResolveResult;
|
|
477
|
+
health: HealthResult;
|
|
478
|
+
licenses: LicenseResult;
|
|
479
|
+
unused: UnusedResult;
|
|
480
|
+
items: ReviewItem[];
|
|
481
|
+
degradedSources: string[];
|
|
482
|
+
}
|
|
483
|
+
export interface DashboardOptions extends CheckOptions {
|
|
484
|
+
view?: "dependencies" | "security" | "health";
|
|
485
|
+
}
|
|
486
|
+
export interface DashboardResult {
|
|
487
|
+
completed: boolean;
|
|
488
|
+
errors: string[];
|
|
489
|
+
warnings: string[];
|
|
390
490
|
}
|
|
391
491
|
export type UnusedKind = "declared-not-imported" | "imported-not-declared";
|
|
392
492
|
export interface UnusedDependency {
|
|
@@ -495,3 +595,23 @@ export interface SnapshotResult {
|
|
|
495
595
|
errors: string[];
|
|
496
596
|
warnings: string[];
|
|
497
597
|
}
|
|
598
|
+
export interface GaOptions {
|
|
599
|
+
cwd: string;
|
|
600
|
+
workspace: boolean;
|
|
601
|
+
jsonFile?: string;
|
|
602
|
+
}
|
|
603
|
+
export interface GaCheck {
|
|
604
|
+
name: "package-manager" | "workspace-discovery" | "lockfile" | "cache-backend" | "dist-build" | "benchmark-gates" | "docs-contract";
|
|
605
|
+
status: "pass" | "warn" | "fail";
|
|
606
|
+
detail: string;
|
|
607
|
+
}
|
|
608
|
+
export interface GaResult {
|
|
609
|
+
ready: boolean;
|
|
610
|
+
projectPath: string;
|
|
611
|
+
packageManager: "npm" | "pnpm" | "unknown";
|
|
612
|
+
workspacePackages: number;
|
|
613
|
+
cacheBackend: "sqlite" | "file";
|
|
614
|
+
checks: GaCheck[];
|
|
615
|
+
warnings: string[];
|
|
616
|
+
errors: string[];
|
|
617
|
+
}
|