@rainy-updates/cli 0.5.2-rc.2 → 0.5.2

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +29 -0
  3. package/dist/bin/cli.js +108 -2
  4. package/dist/cache/cache.d.ts +1 -0
  5. package/dist/cache/cache.js +9 -2
  6. package/dist/commands/audit/runner.js +8 -1
  7. package/dist/commands/audit/sources/index.js +8 -1
  8. package/dist/commands/doctor/parser.d.ts +2 -0
  9. package/dist/commands/doctor/parser.js +92 -0
  10. package/dist/commands/doctor/runner.d.ts +2 -0
  11. package/dist/commands/doctor/runner.js +13 -0
  12. package/dist/commands/resolve/runner.js +3 -0
  13. package/dist/commands/review/parser.d.ts +2 -0
  14. package/dist/commands/review/parser.js +174 -0
  15. package/dist/commands/review/runner.d.ts +2 -0
  16. package/dist/commands/review/runner.js +30 -0
  17. package/dist/config/loader.d.ts +3 -0
  18. package/dist/core/check.js +39 -5
  19. package/dist/core/errors.d.ts +11 -0
  20. package/dist/core/errors.js +6 -0
  21. package/dist/core/options.d.ts +8 -1
  22. package/dist/core/options.js +43 -0
  23. package/dist/core/review-model.d.ts +5 -0
  24. package/dist/core/review-model.js +382 -0
  25. package/dist/core/summary.js +11 -2
  26. package/dist/core/upgrade.d.ts +1 -0
  27. package/dist/core/upgrade.js +27 -21
  28. package/dist/core/warm-cache.js +28 -4
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.js +1 -0
  31. package/dist/output/format.d.ts +4 -1
  32. package/dist/output/format.js +29 -3
  33. package/dist/output/github.js +5 -0
  34. package/dist/output/sarif.js +11 -0
  35. package/dist/registry/npm.d.ts +20 -0
  36. package/dist/registry/npm.js +27 -4
  37. package/dist/types/index.d.ts +57 -0
  38. package/dist/ui/tui.d.ts +0 -4
  39. package/dist/ui/tui.js +78 -21
  40. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.5.2] - 2026-03-01
6
+
7
+ ### Added
8
+
9
+ - **New `review` command**: Aggregates pending updates with security, peer-conflict, license, health, and unused-dependency signals for guided dependency review.
10
+ - `--interactive` launches the upgraded Ink review TUI.
11
+ - `--security-only`, `--risk <level>`, and `--diff <level>` filter the review set.
12
+ - `--apply-selected` can apply the filtered/selected updates after review.
13
+ - **New `doctor` command**: Produces a fast dependency verdict for local triage and CI summaries.
14
+ - Verdict classes: `safe`, `review`, `blocked`, `actionable`.
15
+ - `--verdict-only` prints a one-line CI-friendly summary.
16
+ - **Interactive review TUI overhaul**:
17
+ - multi-pane layout with filters, selection state, detail panel, and status bar,
18
+ - risk/security/peer/license context inline per package,
19
+ - explicit selection controls for interactive upgrade review.
20
+ - **Additive output contract metadata**:
21
+ - summary fields: `verdict`, `riskPackages`, `securityPackages`, `peerConflictPackages`, `licenseViolationPackages`, `interactiveSession`,
22
+ - GitHub outputs: `verdict`, `risk_packages`, `security_packages`, `peer_conflict_packages`, `license_violation_packages`,
23
+ - SARIF result properties for impact/risk/advisory/license context.
24
+ - **New display controls**:
25
+ - `--interactive`
26
+ - `--show-impact`
27
+ - `--show-homepage`
28
+ - **RC3 hardening layer on top of GA surfaces**:
29
+ - centralized classified error taxonomy in `src/core/errors.ts`,
30
+ - compatibility coverage for scoped private registries and cache backend fallback,
31
+ - explicit cache fallback reason reporting for SQLite → file cache degradation,
32
+ - dedicated performance scenarios for `check`, `resolve`, and `ci`,
33
+ - new comparison document: `docs/why-rainy-vs-dependabot-renovate.md`.
34
+
35
+ ### Changed
36
+
37
+ - `check` now computes impact scores in the core pipeline and carries homepage metadata when available.
38
+ - `upgrade --interactive` now routes through the guided review flow before applying selected updates.
39
+ - CLI help and package exports now cover the new review/verdict surfaces.
40
+ - `doctor` output now follows the RC3 quick-verdict shape:
41
+ - `State`
42
+ - `PrimaryRisk`
43
+ - `NextAction`
44
+ - `check`, `warm-cache`, and `audit` now emit RC3-style classified warnings/errors for:
45
+ - registry failures,
46
+ - auth failures,
47
+ - advisory-source degradation/outage,
48
+ - cache backend fallback.
49
+
50
+ ### Tests
51
+
52
+ - Added compatibility tests for:
53
+ - scoped `.npmrc` private registry resolution,
54
+ - forced cache backend fallback behavior.
55
+ - Updated audit coverage to assert the new classified advisory degradation warning format.
56
+
5
57
  ## [0.5.2-rc.2] - 2026-02-27
6
58
 
7
59
  ### Added
package/README.md CHANGED
@@ -4,6 +4,9 @@ The fastest DevOps-first dependency CLI. Checks, audits, upgrades, bisects, and
4
4
 
5
5
  `@rainy-updates/cli` is built for teams that need fast dependency intelligence, security auditing, policy-aware upgrades, and automation-ready output for CI/CD and pull request workflows.
6
6
 
7
+ Comparison:
8
+ [Why Rainy vs Dependabot and Renovate](./docs/why-rainy-vs-dependabot-renovate.md)
9
+
7
10
  ## Why this package
8
11
 
9
12
  - Detects updates quickly across single-package repos and workspaces.
@@ -56,6 +59,8 @@ npx @rainy-updates/cli ci --workspace --mode strict
56
59
  - `ci` — run CI-focused dependency automation (warm cache, check/upgrade, policy gates)
57
60
  - `warm-cache` — prefetch package metadata for fast and offline checks
58
61
  - `baseline` — save and compare dependency baseline snapshots
62
+ - `review` — guided review across updates, security, peer conflicts, licenses, and risk
63
+ - `doctor` — fast verdict command for local triage and CI summaries
59
64
 
60
65
  ### Security & health (_new in v0.5.1_)
61
66
 
@@ -117,6 +122,15 @@ npx @rainy-updates/cli bisect axios --cmd "bun test"
117
122
  npx @rainy-updates/cli bisect react --range "18.0.0..19.0.0" --cmd "npm test"
118
123
  npx @rainy-updates/cli bisect lodash --cmd "npm run test:unit" --dry-run
119
124
  rup bisect axios --cmd "bun test" # if installed
125
+
126
+ # 11) Review updates with risk and security context ── NEW in v0.5.2 GA
127
+ npx @rainy-updates/cli review --security-only
128
+ rup review --interactive
129
+ rup review --risk high --diff major
130
+
131
+ # 12) Get a fast dependency verdict for CI or local triage ── NEW in v0.5.2 GA
132
+ npx @rainy-updates/cli doctor
133
+ rup doctor --verdict-only
120
134
  ```
121
135
 
122
136
  ## What it does in production
@@ -129,6 +143,7 @@ rup bisect axios --cmd "bun test" # if installed
129
143
  - Supports explicit registry retry/timeout tuning (`--registry-retries`, `--registry-timeout-ms`).
130
144
  - Supports stale-cache fallback when registry calls fail.
131
145
  - Supports streamed progress output for long CI runs (`--stream`).
146
+ - Exposes impact/risk metadata and homepage context in update output (`--show-impact`, `--show-homepage`).
132
147
 
133
148
  ### Workspace support
134
149
 
@@ -229,6 +244,9 @@ Schedule:
229
244
  - `--cooldown-days <n>`
230
245
  - `--pr-limit <n>`
231
246
  - `--only-changed`
247
+ - `--interactive`
248
+ - `--show-impact`
249
+ - `--show-homepage`
232
250
  - `--mode minimal|strict|enterprise` (for `ci`)
233
251
  - `--fix-pr-batch-size <n>` (for batched fix branches in `ci`)
234
252
  - `--policy-file <path>`
@@ -251,6 +269,17 @@ Schedule:
251
269
  - `--pm auto|npm|pnpm`
252
270
  - `--sync`
253
271
 
272
+ ### Review-only
273
+
274
+ - `--security-only`
275
+ - `--risk critical|high|medium|low`
276
+ - `--diff patch|minor|major|latest`
277
+ - `--apply-selected`
278
+
279
+ ### Doctor-only
280
+
281
+ - `--verdict-only`
282
+
254
283
  ### Baseline-only
255
284
 
256
285
  - `--save`
package/dist/bin/cli.js CHANGED
@@ -111,6 +111,39 @@ async function main() {
111
111
  process.exitCode = result.errors.length > 0 ? 1 : 0;
112
112
  return;
113
113
  }
114
+ if (parsed.command === "review") {
115
+ const { runReview } = await import("../commands/review/runner.js");
116
+ const result = await runReview(parsed.options);
117
+ process.exitCode =
118
+ result.summary.verdict === "blocked" ||
119
+ result.summary.verdict === "actionable" ||
120
+ result.summary.verdict === "review"
121
+ ? 1
122
+ : 0;
123
+ return;
124
+ }
125
+ if (parsed.command === "doctor") {
126
+ const { runDoctor } = await import("../commands/doctor/runner.js");
127
+ const result = await runDoctor(parsed.options);
128
+ process.exitCode = result.verdict === "safe" ? 0 : 1;
129
+ return;
130
+ }
131
+ if (parsed.options.interactive &&
132
+ (parsed.command === "check" ||
133
+ parsed.command === "upgrade" ||
134
+ parsed.command === "ci")) {
135
+ const { runReview } = await import("../commands/review/runner.js");
136
+ const result = await runReview({
137
+ ...parsed.options,
138
+ securityOnly: false,
139
+ risk: undefined,
140
+ diff: undefined,
141
+ applySelected: parsed.command === "upgrade",
142
+ });
143
+ process.exitCode =
144
+ result.summary.verdict === "safe" && result.updates.length === 0 ? 0 : 1;
145
+ return;
146
+ }
114
147
  const result = await runCommand(parsed);
115
148
  if (parsed.options.fixPr &&
116
149
  (parsed.command === "check" ||
@@ -148,11 +181,17 @@ async function main() {
148
181
  }
149
182
  result.summary.failReason = resolveFailReason(result.updates, result.errors, parsed.options.failOn, parsed.options.maxUpdates, parsed.options.ci);
150
183
  const renderStartedAt = Date.now();
151
- let rendered = renderResult(result, parsed.options.format);
184
+ let rendered = renderResult(result, parsed.options.format, {
185
+ showImpact: parsed.options.showImpact,
186
+ showHomepage: parsed.options.showHomepage,
187
+ });
152
188
  result.summary.durationMs.render = Math.max(0, Date.now() - renderStartedAt);
153
189
  if (parsed.options.format === "json" ||
154
190
  parsed.options.format === "metrics") {
155
- rendered = renderResult(result, parsed.options.format);
191
+ rendered = renderResult(result, parsed.options.format, {
192
+ showImpact: parsed.options.showImpact,
193
+ showHomepage: parsed.options.showHomepage,
194
+ });
156
195
  }
157
196
  if (parsed.options.onlyChanged &&
158
197
  result.updates.length === 0 &&
@@ -220,6 +259,9 @@ Options:
220
259
  --cooldown-days <n>
221
260
  --pr-limit <n>
222
261
  --only-changed
262
+ --interactive
263
+ --show-impact
264
+ --show-homepage
223
265
  --lockfile-mode preserve|update|error
224
266
  --log-level error|warn|info|debug
225
267
  --ci`;
@@ -267,6 +309,7 @@ Options:
267
309
  --fix-dry-run
268
310
  --fix-pr-no-checkout
269
311
  --fix-pr-batch-size <n>
312
+ --interactive
270
313
  --lockfile-mode preserve|update|error
271
314
  --no-pr-report
272
315
  --json-file <path>
@@ -349,6 +392,34 @@ Options:
349
392
  --json-file <path>
350
393
  --concurrency <n>
351
394
  --registry-timeout-ms <n>`;
395
+ }
396
+ if (isCommand && command === "review") {
397
+ return `rainy-updates review [options]
398
+
399
+ Review updates with risk, security, peer, and policy context.
400
+
401
+ Options:
402
+ --workspace
403
+ --interactive
404
+ --security-only
405
+ --risk critical|high|medium|low
406
+ --diff patch|minor|major|latest
407
+ --apply-selected
408
+ --policy-file <path>
409
+ --json-file <path>
410
+ --concurrency <n>
411
+ --registry-timeout-ms <n>
412
+ --registry-retries <n>`;
413
+ }
414
+ if (isCommand && command === "doctor") {
415
+ return `rainy-updates doctor [options]
416
+
417
+ Produce a fast overall dependency verdict.
418
+
419
+ Options:
420
+ --workspace
421
+ --verdict-only
422
+ --json-file <path>`;
352
423
  }
353
424
  return `rainy-updates (rup / rainy-up) <command> [options]
354
425
 
@@ -366,6 +437,8 @@ Commands:
366
437
  resolve Check peer dependency conflicts (pure-TS, no subprocess)
367
438
  licenses Scan dependency licenses and generate SPDX SBOM
368
439
  snapshot Save, list, restore, and diff dependency state snapshots
440
+ review Guided dependency review with risk/security context
441
+ doctor Fast dependency verdict for local or CI use
369
442
 
370
443
  Global options:
371
444
  --cwd <path>
@@ -384,6 +457,9 @@ Global options:
384
457
  --cooldown-days <n>
385
458
  --pr-limit <n>
386
459
  --only-changed
460
+ --interactive
461
+ --show-impact
462
+ --show-homepage
387
463
  --mode minimal|strict|enterprise
388
464
  --fix-pr
389
465
  --fix-branch <name>
@@ -405,6 +481,36 @@ Global options:
405
481
  --version, -v`;
406
482
  }
407
483
  async function runCommand(parsed) {
484
+ if (parsed.command === "review") {
485
+ const { runReview } = await import("../commands/review/runner.js");
486
+ const result = await runReview(parsed.options);
487
+ return {
488
+ projectPath: result.projectPath,
489
+ packagePaths: result.items.map((item) => item.update.packagePath),
490
+ packageManager: "unknown",
491
+ target: result.target,
492
+ timestamp: new Date().toISOString(),
493
+ summary: result.summary,
494
+ updates: result.updates,
495
+ errors: result.errors,
496
+ warnings: result.warnings,
497
+ };
498
+ }
499
+ if (parsed.command === "doctor") {
500
+ const { runDoctor } = await import("../commands/doctor/runner.js");
501
+ const result = await runDoctor(parsed.options);
502
+ return {
503
+ projectPath: result.review.projectPath,
504
+ packagePaths: result.review.items.map((item) => item.update.packagePath),
505
+ packageManager: "unknown",
506
+ target: result.review.target,
507
+ timestamp: new Date().toISOString(),
508
+ summary: result.summary,
509
+ updates: result.review.updates,
510
+ errors: result.review.errors,
511
+ warnings: result.review.warnings,
512
+ };
513
+ }
408
514
  if (parsed.command === "upgrade") {
409
515
  return await upgrade(parsed.options);
410
516
  }
@@ -3,6 +3,7 @@ export declare class VersionCache {
3
3
  private readonly store;
4
4
  readonly backend: "sqlite" | "file";
5
5
  readonly degraded: boolean;
6
+ readonly fallbackReason?: string;
6
7
  private constructor();
7
8
  static create(customPath?: string): Promise<VersionCache>;
8
9
  getValid(packageName: string, target: TargetLevel): Promise<CachedVersion | null>;
@@ -1,6 +1,7 @@
1
1
  import { promises as fs } from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
+ import process from "node:process";
4
5
  class FileCacheStore {
5
6
  filePath;
6
7
  constructor(filePath) {
@@ -108,20 +109,26 @@ export class VersionCache {
108
109
  store;
109
110
  backend;
110
111
  degraded;
111
- constructor(store, backend, degraded) {
112
+ fallbackReason;
113
+ constructor(store, backend, degraded, fallbackReason) {
112
114
  this.store = store;
113
115
  this.backend = backend;
114
116
  this.degraded = degraded;
117
+ this.fallbackReason = fallbackReason;
115
118
  }
116
119
  static async create(customPath) {
117
120
  const basePath = customPath ?? path.join(os.homedir(), ".cache", "rainy-updates");
121
+ if (process.env.RAINY_UPDATES_CACHE_BACKEND === "file") {
122
+ const jsonPath = path.join(basePath, "cache.json");
123
+ return new VersionCache(new FileCacheStore(jsonPath), "file", true, "forced via RAINY_UPDATES_CACHE_BACKEND=file");
124
+ }
118
125
  const sqlitePath = path.join(basePath, "cache.db");
119
126
  const sqliteStore = await tryCreateSqliteStore(sqlitePath);
120
127
  if (sqliteStore)
121
128
  return new VersionCache(sqliteStore, "sqlite", false);
122
129
  const jsonPath = path.join(basePath, "cache.json");
123
130
  const degraded = typeof Bun !== "undefined";
124
- return new VersionCache(new FileCacheStore(jsonPath), "file", degraded);
131
+ return new VersionCache(new FileCacheStore(jsonPath), "file", degraded, degraded ? "bun:sqlite unavailable; using file cache backend" : undefined);
125
132
  }
126
133
  async getValid(packageName, target) {
127
134
  const entry = await this.store.get(packageName, target);
@@ -8,6 +8,7 @@ import { stableStringify } from "../../utils/stable-json.js";
8
8
  import { fetchAdvisories } from "./fetcher.js";
9
9
  import { resolveAuditTargets } from "./targets.js";
10
10
  import { filterBySeverity, buildPatchMap, renderAuditSourceHealth, renderAuditSummary, renderAuditTable, summarizeAdvisories, } from "./mapper.js";
11
+ import { formatClassifiedMessage } from "../../core/errors.js";
11
12
  /**
12
13
  * Entry point for `rup audit`. Lazy-loaded by cli.ts.
13
14
  * Discovers packages, fetches CVE advisories, filters by severity, and
@@ -63,7 +64,13 @@ export async function runAudit(options) {
63
64
  result.sourceHealth = fetched.sourceHealth;
64
65
  result.warnings.push(...fetched.warnings);
65
66
  if (fetched.sourceHealth.every((item) => item.status === "failed")) {
66
- result.errors.push("All advisory sources failed. Audit coverage is unavailable for this run.");
67
+ result.errors.push(formatClassifiedMessage({
68
+ code: "ADVISORY_SOURCE_DOWN",
69
+ whatFailed: "All advisory sources failed.",
70
+ intact: "Dependency target resolution completed, but no advisory coverage was returned.",
71
+ validity: "invalid",
72
+ next: "Retry `rup audit` later or select a single healthy source with --source.",
73
+ }));
67
74
  }
68
75
  let advisories = fetched.advisories;
69
76
  advisories = filterBySeverity(advisories, options.severity);
@@ -1,6 +1,7 @@
1
1
  import { compareVersions, parseVersion } from "../../../utils/semver.js";
2
2
  import { githubAuditSource } from "./github.js";
3
3
  import { osvAuditSource } from "./osv.js";
4
+ import { formatClassifiedMessage } from "../../../core/errors.js";
4
5
  const SOURCE_MAP = {
5
6
  osv: osvAuditSource,
6
7
  github: githubAuditSource,
@@ -62,7 +63,13 @@ function normalizeSourceWarnings(warnings, sourceHealth) {
62
63
  const successfulNames = successful
63
64
  .map((item) => formatSourceName(item.source))
64
65
  .join(", ");
65
- normalized.push(`Continuing with partial advisory coverage: ${failedNames} failed, ${successfulNames} still returned results.`);
66
+ normalized.push(formatClassifiedMessage({
67
+ code: "ADVISORY_SOURCE_DEGRADED",
68
+ whatFailed: `${failedNames} advisory source(s) failed during the audit query.`,
69
+ intact: `${successfulNames} still returned advisory results.`,
70
+ validity: "partial",
71
+ next: "Retry `rup audit` later or pin `--source` to a healthy backend.",
72
+ }));
66
73
  }
67
74
  return normalized;
68
75
  }
@@ -0,0 +1,2 @@
1
+ import type { DoctorOptions } from "../../types/index.js";
2
+ export declare function parseDoctorArgs(args: string[]): DoctorOptions;
@@ -0,0 +1,92 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+ export function parseDoctorArgs(args) {
4
+ const options = {
5
+ cwd: process.cwd(),
6
+ target: "latest",
7
+ filter: undefined,
8
+ reject: undefined,
9
+ cacheTtlSeconds: 3600,
10
+ includeKinds: ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"],
11
+ ci: false,
12
+ format: "table",
13
+ workspace: false,
14
+ jsonFile: undefined,
15
+ githubOutputFile: undefined,
16
+ sarifFile: undefined,
17
+ concurrency: 16,
18
+ registryTimeoutMs: 8000,
19
+ registryRetries: 3,
20
+ offline: false,
21
+ stream: false,
22
+ policyFile: undefined,
23
+ prReportFile: undefined,
24
+ failOn: "none",
25
+ maxUpdates: undefined,
26
+ fixPr: false,
27
+ fixBranch: "chore/rainy-updates",
28
+ fixCommitMessage: undefined,
29
+ fixDryRun: false,
30
+ fixPrNoCheckout: false,
31
+ fixPrBatchSize: undefined,
32
+ noPrReport: false,
33
+ logLevel: "info",
34
+ groupBy: "risk",
35
+ groupMax: undefined,
36
+ cooldownDays: undefined,
37
+ prLimit: undefined,
38
+ onlyChanged: false,
39
+ ciProfile: "minimal",
40
+ lockfileMode: "preserve",
41
+ interactive: false,
42
+ showImpact: true,
43
+ showHomepage: true,
44
+ verdictOnly: false,
45
+ };
46
+ for (let i = 0; i < args.length; i += 1) {
47
+ const current = args[i];
48
+ const next = args[i + 1];
49
+ if (current === "--cwd" && next) {
50
+ options.cwd = path.resolve(next);
51
+ i += 1;
52
+ continue;
53
+ }
54
+ if (current === "--cwd")
55
+ throw new Error("Missing value for --cwd");
56
+ if (current === "--workspace") {
57
+ options.workspace = true;
58
+ continue;
59
+ }
60
+ if (current === "--verdict-only") {
61
+ options.verdictOnly = true;
62
+ continue;
63
+ }
64
+ if (current === "--json-file" && next) {
65
+ options.jsonFile = path.resolve(options.cwd, next);
66
+ i += 1;
67
+ continue;
68
+ }
69
+ if (current === "--json-file")
70
+ throw new Error("Missing value for --json-file");
71
+ if (current === "--help" || current === "-h") {
72
+ process.stdout.write(DOCTOR_HELP);
73
+ process.exit(0);
74
+ }
75
+ if (current.startsWith("-"))
76
+ throw new Error(`Unknown doctor option: ${current}`);
77
+ throw new Error(`Unexpected doctor argument: ${current}`);
78
+ }
79
+ return options;
80
+ }
81
+ const DOCTOR_HELP = `
82
+ rup doctor — Fast dependency verdict across updates, security, policy, and peer conflicts
83
+
84
+ Usage:
85
+ rup doctor [options]
86
+
87
+ Options:
88
+ --verdict-only Print one-line verdict for CI summaries
89
+ --workspace Scan all workspace packages
90
+ --json-file <path> Write JSON doctor report to file
91
+ --cwd <path>
92
+ `.trimStart();
@@ -0,0 +1,2 @@
1
+ import type { DoctorOptions, DoctorResult } from "../../types/index.js";
2
+ export declare function runDoctor(options: DoctorOptions): Promise<DoctorResult>;
@@ -0,0 +1,13 @@
1
+ import process from "node:process";
2
+ import { buildReviewResult, createDoctorResult, renderDoctorResult } from "../../core/review-model.js";
3
+ import { stableStringify } from "../../utils/stable-json.js";
4
+ import { writeFileAtomic } from "../../utils/io.js";
5
+ export async function runDoctor(options) {
6
+ const review = await buildReviewResult(options);
7
+ const doctor = createDoctorResult(review);
8
+ process.stdout.write(renderDoctorResult(doctor, options.verdictOnly) + "\n");
9
+ if (options.jsonFile) {
10
+ await writeFileAtomic(options.jsonFile, stableStringify(doctor, 2) + "\n");
11
+ }
12
+ return doctor;
13
+ }
@@ -93,6 +93,9 @@ async function fetchProposedVersions(options) {
93
93
  onlyChanged: false,
94
94
  ciProfile: "minimal",
95
95
  lockfileMode: "preserve",
96
+ interactive: false,
97
+ showImpact: false,
98
+ showHomepage: false,
96
99
  });
97
100
  for (const update of checkResult.updates ?? []) {
98
101
  overrides.set(update.name, update.toVersionResolved);
@@ -0,0 +1,2 @@
1
+ import type { ReviewOptions } from "../../types/index.js";
2
+ export declare function parseReviewArgs(args: string[]): ReviewOptions;