@rainy-updates/cli 0.5.7 → 0.6.1

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 (105) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +90 -31
  3. package/dist/bin/cli.js +11 -126
  4. package/dist/bin/dispatch.js +35 -32
  5. package/dist/bin/help.js +79 -2
  6. package/dist/bin/main.d.ts +1 -0
  7. package/dist/bin/main.js +126 -0
  8. package/dist/cache/cache.js +13 -11
  9. package/dist/commands/audit/parser.js +38 -2
  10. package/dist/commands/audit/runner.js +41 -61
  11. package/dist/commands/audit/targets.js +13 -13
  12. package/dist/commands/bisect/oracle.js +31 -11
  13. package/dist/commands/bisect/parser.js +3 -3
  14. package/dist/commands/bisect/runner.js +16 -8
  15. package/dist/commands/changelog/fetcher.js +11 -5
  16. package/dist/commands/dashboard/parser.js +144 -1
  17. package/dist/commands/dashboard/runner.d.ts +2 -2
  18. package/dist/commands/dashboard/runner.js +67 -37
  19. package/dist/commands/doctor/parser.js +53 -4
  20. package/dist/commands/doctor/runner.js +2 -2
  21. package/dist/commands/ga/parser.js +43 -4
  22. package/dist/commands/ga/runner.js +22 -13
  23. package/dist/commands/health/parser.js +38 -2
  24. package/dist/commands/health/runner.js +5 -1
  25. package/dist/commands/hook/parser.d.ts +2 -0
  26. package/dist/commands/hook/parser.js +40 -0
  27. package/dist/commands/hook/runner.d.ts +2 -0
  28. package/dist/commands/hook/runner.js +174 -0
  29. package/dist/commands/licenses/parser.js +39 -0
  30. package/dist/commands/licenses/runner.js +9 -5
  31. package/dist/commands/resolve/graph/builder.js +5 -1
  32. package/dist/commands/resolve/parser.js +39 -0
  33. package/dist/commands/resolve/runner.js +14 -4
  34. package/dist/commands/review/parser.js +101 -4
  35. package/dist/commands/review/runner.js +31 -5
  36. package/dist/commands/snapshot/parser.js +39 -0
  37. package/dist/commands/snapshot/runner.js +21 -18
  38. package/dist/commands/snapshot/store.d.ts +0 -12
  39. package/dist/commands/snapshot/store.js +26 -38
  40. package/dist/commands/unused/parser.js +39 -0
  41. package/dist/commands/unused/runner.js +10 -8
  42. package/dist/commands/unused/scanner.d.ts +2 -1
  43. package/dist/commands/unused/scanner.js +65 -52
  44. package/dist/config/loader.d.ts +2 -2
  45. package/dist/config/loader.js +2 -5
  46. package/dist/config/policy.js +20 -11
  47. package/dist/core/analysis/run-silenced.js +0 -1
  48. package/dist/core/artifacts.js +6 -5
  49. package/dist/core/baseline.js +3 -5
  50. package/dist/core/check.js +7 -3
  51. package/dist/core/ci.js +52 -1
  52. package/dist/core/decision-plan.d.ts +14 -0
  53. package/dist/core/decision-plan.js +107 -0
  54. package/dist/core/doctor/result.js +8 -5
  55. package/dist/core/fix-pr-batch.js +38 -28
  56. package/dist/core/fix-pr.js +27 -24
  57. package/dist/core/init-ci.js +34 -28
  58. package/dist/core/options.d.ts +4 -1
  59. package/dist/core/options.js +152 -4
  60. package/dist/core/review-model.js +3 -0
  61. package/dist/core/summary.js +6 -0
  62. package/dist/core/upgrade.js +64 -2
  63. package/dist/core/verification.d.ts +2 -0
  64. package/dist/core/verification.js +108 -0
  65. package/dist/core/warm-cache.js +7 -3
  66. package/dist/generated/version.d.ts +1 -0
  67. package/dist/generated/version.js +2 -0
  68. package/dist/git/scope.d.ts +19 -0
  69. package/dist/git/scope.js +167 -0
  70. package/dist/index.d.ts +2 -1
  71. package/dist/index.js +1 -0
  72. package/dist/output/format.js +15 -0
  73. package/dist/output/github.js +6 -0
  74. package/dist/output/sarif.js +12 -18
  75. package/dist/parsers/package-json.js +2 -4
  76. package/dist/pm/detect.d.ts +40 -1
  77. package/dist/pm/detect.js +152 -9
  78. package/dist/pm/install.d.ts +3 -1
  79. package/dist/pm/install.js +18 -17
  80. package/dist/registry/npm.js +34 -76
  81. package/dist/rup +0 -0
  82. package/dist/types/index.d.ts +134 -5
  83. package/dist/ui/tui.d.ts +4 -1
  84. package/dist/ui/tui.js +156 -67
  85. package/dist/utils/io.js +5 -6
  86. package/dist/utils/lockfile.js +24 -19
  87. package/dist/utils/runtime-paths.d.ts +4 -0
  88. package/dist/utils/runtime-paths.js +35 -0
  89. package/dist/utils/runtime.d.ts +7 -0
  90. package/dist/utils/runtime.js +32 -0
  91. package/dist/workspace/discover.d.ts +7 -1
  92. package/dist/workspace/discover.js +67 -54
  93. package/package.json +24 -19
  94. package/dist/ui/dashboard/DashboardTUI.d.ts +0 -6
  95. package/dist/ui/dashboard/DashboardTUI.js +0 -34
  96. package/dist/ui/dashboard/components/DetailPanel.d.ts +0 -4
  97. package/dist/ui/dashboard/components/DetailPanel.js +0 -30
  98. package/dist/ui/dashboard/components/Footer.d.ts +0 -4
  99. package/dist/ui/dashboard/components/Footer.js +0 -9
  100. package/dist/ui/dashboard/components/Header.d.ts +0 -4
  101. package/dist/ui/dashboard/components/Header.js +0 -12
  102. package/dist/ui/dashboard/components/Sidebar.d.ts +0 -4
  103. package/dist/ui/dashboard/components/Sidebar.js +0 -23
  104. package/dist/ui/dashboard/store.d.ts +0 -34
  105. package/dist/ui/dashboard/store.js +0 -148
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
- import process from "node:process";
3
2
  import { loadConfig } from "../config/loader.js";
3
+ import { getRuntimeCwd } from "../utils/runtime.js";
4
4
  const DEFAULT_INCLUDE_KINDS = [
5
5
  "dependencies",
6
6
  "devDependencies",
@@ -25,6 +25,7 @@ const KNOWN_COMMANDS = [
25
25
  "doctor",
26
26
  "dashboard",
27
27
  "ga",
28
+ "hook",
28
29
  ];
29
30
  export async function parseCliArgs(argv) {
30
31
  const firstArg = argv[0];
@@ -82,8 +83,12 @@ export async function parseCliArgs(argv) {
82
83
  const { parseGaArgs } = await import("../commands/ga/parser.js");
83
84
  return { command, options: parseGaArgs(args) };
84
85
  }
86
+ if (command === "hook") {
87
+ const { parseHookArgs } = await import("../commands/hook/parser.js");
88
+ return { command, options: parseHookArgs(args) };
89
+ }
85
90
  const base = {
86
- cwd: process.cwd(),
91
+ cwd: getRuntimeCwd(),
87
92
  target: "latest",
88
93
  filter: undefined,
89
94
  reject: undefined,
@@ -117,11 +122,21 @@ export async function parseCliArgs(argv) {
117
122
  cooldownDays: undefined,
118
123
  prLimit: undefined,
119
124
  onlyChanged: false,
125
+ affected: false,
126
+ staged: false,
127
+ baseRef: undefined,
128
+ headRef: undefined,
129
+ sinceRef: undefined,
120
130
  ciProfile: "minimal",
121
131
  lockfileMode: "preserve",
122
132
  interactive: false,
123
133
  showImpact: false,
124
134
  showHomepage: false,
135
+ decisionPlanFile: undefined,
136
+ verify: "none",
137
+ testCommand: undefined,
138
+ verificationReportFile: undefined,
139
+ ciGate: "check",
125
140
  };
126
141
  let force = false;
127
142
  let initCiMode = "enterprise";
@@ -452,6 +467,38 @@ export async function parseCliArgs(argv) {
452
467
  base.onlyChanged = true;
453
468
  continue;
454
469
  }
470
+ if (current === "--affected") {
471
+ base.affected = true;
472
+ continue;
473
+ }
474
+ if (current === "--staged") {
475
+ base.staged = true;
476
+ continue;
477
+ }
478
+ if (current === "--base" && next) {
479
+ base.baseRef = next;
480
+ index += 1;
481
+ continue;
482
+ }
483
+ if (current === "--base") {
484
+ throw new Error("Missing value for --base");
485
+ }
486
+ if (current === "--head" && next) {
487
+ base.headRef = next;
488
+ index += 1;
489
+ continue;
490
+ }
491
+ if (current === "--head") {
492
+ throw new Error("Missing value for --head");
493
+ }
494
+ if (current === "--since" && next) {
495
+ base.sinceRef = next;
496
+ index += 1;
497
+ continue;
498
+ }
499
+ if (current === "--since") {
500
+ throw new Error("Missing value for --since");
501
+ }
455
502
  if (current === "--interactive") {
456
503
  base.interactive = true;
457
504
  continue;
@@ -492,6 +539,54 @@ export async function parseCliArgs(argv) {
492
539
  if (current === "--file") {
493
540
  throw new Error("Missing value for --file");
494
541
  }
542
+ if (current === "--plan-file" && next) {
543
+ base.decisionPlanFile = path.resolve(base.cwd, next);
544
+ index += 1;
545
+ continue;
546
+ }
547
+ if (current === "--plan-file") {
548
+ throw new Error("Missing value for --plan-file");
549
+ }
550
+ if (current === "--from-plan" && next) {
551
+ base.decisionPlanFile = path.resolve(base.cwd, next);
552
+ index += 1;
553
+ continue;
554
+ }
555
+ if (current === "--from-plan") {
556
+ throw new Error("Missing value for --from-plan");
557
+ }
558
+ if (current === "--verify" && next) {
559
+ base.verify = ensureVerificationMode(next);
560
+ index += 1;
561
+ continue;
562
+ }
563
+ if (current === "--verify") {
564
+ throw new Error("Missing value for --verify");
565
+ }
566
+ if (current === "--test-command" && next) {
567
+ base.testCommand = next;
568
+ index += 1;
569
+ continue;
570
+ }
571
+ if (current === "--test-command") {
572
+ throw new Error("Missing value for --test-command");
573
+ }
574
+ if (current === "--verification-report-file" && next) {
575
+ base.verificationReportFile = path.resolve(base.cwd, next);
576
+ index += 1;
577
+ continue;
578
+ }
579
+ if (current === "--verification-report-file") {
580
+ throw new Error("Missing value for --verification-report-file");
581
+ }
582
+ if (current === "--gate" && next) {
583
+ base.ciGate = ensureCiGate(next);
584
+ index += 1;
585
+ continue;
586
+ }
587
+ if (current === "--gate") {
588
+ throw new Error("Missing value for --gate");
589
+ }
495
590
  if (current.startsWith("-")) {
496
591
  throw new Error(`Unknown option: ${current}`);
497
592
  }
@@ -526,6 +621,7 @@ export async function parseCliArgs(argv) {
526
621
  install: args.includes("--install") || resolvedConfig.install === true,
527
622
  packageManager: cliPm === "auto" ? (configPm ?? "auto") : cliPm,
528
623
  sync: args.includes("--sync") || resolvedConfig.sync === true,
624
+ fromPlanFile: base.decisionPlanFile,
529
625
  };
530
626
  return { command, options: upgradeOptions };
531
627
  }
@@ -672,6 +768,21 @@ function applyConfig(base, config) {
672
768
  if (typeof config.onlyChanged === "boolean") {
673
769
  base.onlyChanged = config.onlyChanged;
674
770
  }
771
+ if (typeof config.affected === "boolean") {
772
+ base.affected = config.affected;
773
+ }
774
+ if (typeof config.staged === "boolean") {
775
+ base.staged = config.staged;
776
+ }
777
+ if (typeof config.baseRef === "string" && config.baseRef.length > 0) {
778
+ base.baseRef = config.baseRef;
779
+ }
780
+ if (typeof config.headRef === "string" && config.headRef.length > 0) {
781
+ base.headRef = config.headRef;
782
+ }
783
+ if (typeof config.sinceRef === "string" && config.sinceRef.length > 0) {
784
+ base.sinceRef = config.sinceRef;
785
+ }
675
786
  if (typeof config.ciProfile === "string") {
676
787
  base.ciProfile = ensureCiProfile(config.ciProfile);
677
788
  }
@@ -687,16 +798,35 @@ function applyConfig(base, config) {
687
798
  if (typeof config.showHomepage === "boolean") {
688
799
  base.showHomepage = config.showHomepage;
689
800
  }
801
+ if (typeof config.decisionPlanFile === "string") {
802
+ base.decisionPlanFile = path.resolve(base.cwd, config.decisionPlanFile);
803
+ }
804
+ if (typeof config.verify === "string") {
805
+ base.verify = ensureVerificationMode(config.verify);
806
+ }
807
+ if (typeof config.testCommand === "string") {
808
+ base.testCommand = config.testCommand;
809
+ }
810
+ if (typeof config.verificationReportFile === "string") {
811
+ base.verificationReportFile = path.resolve(base.cwd, config.verificationReportFile);
812
+ }
813
+ if (typeof config.ciGate === "string") {
814
+ base.ciGate = ensureCiGate(config.ciGate);
815
+ }
690
816
  }
691
817
  function parsePackageManager(args) {
692
818
  const index = args.indexOf("--pm");
693
819
  if (index === -1)
694
820
  return "auto";
695
821
  const value = args[index + 1] ?? "auto";
696
- if (value === "auto" || value === "npm" || value === "pnpm") {
822
+ if (value === "auto" ||
823
+ value === "bun" ||
824
+ value === "npm" ||
825
+ value === "pnpm" ||
826
+ value === "yarn") {
697
827
  return value;
698
828
  }
699
- throw new Error("--pm must be auto, npm or pnpm");
829
+ throw new Error("--pm must be auto, bun, npm, pnpm or yarn");
700
830
  }
701
831
  function ensureTarget(value) {
702
832
  if (value === "patch" ||
@@ -800,3 +930,21 @@ export function ensureRiskLevel(value) {
800
930
  }
801
931
  throw new Error("--risk must be critical, high, medium or low");
802
932
  }
933
+ function ensureVerificationMode(value) {
934
+ if (value === "none" ||
935
+ value === "install" ||
936
+ value === "test" ||
937
+ value === "install,test") {
938
+ return value;
939
+ }
940
+ throw new Error("--verify must be none, install, test or install,test");
941
+ }
942
+ function ensureCiGate(value) {
943
+ if (value === "check" ||
944
+ value === "doctor" ||
945
+ value === "review" ||
946
+ value === "upgrade") {
947
+ return value;
948
+ }
949
+ throw new Error("--gate must be check, doctor, review or upgrade");
950
+ }
@@ -109,6 +109,9 @@ export function renderReviewResult(review) {
109
109
  }
110
110
  lines.push("");
111
111
  lines.push(`Summary: ${review.summary.updatesFound} updates, riskPackages=${review.summary.riskPackages ?? 0}, securityPackages=${review.summary.securityPackages ?? 0}, peerConflictPackages=${review.summary.peerConflictPackages ?? 0}`);
112
+ if (review.summary.decisionPlan) {
113
+ lines.push(`DecisionPlan: ${review.summary.decisionPlan}`);
114
+ }
112
115
  return lines.join("\n");
113
116
  }
114
117
  function matchesReviewFilters(item, options) {
@@ -69,6 +69,12 @@ export function createSummary(input) {
69
69
  primaryFindingCode: undefined,
70
70
  primaryFindingCategory: undefined,
71
71
  nextActionReason: undefined,
72
+ suggestedCommand: undefined,
73
+ decisionPlan: undefined,
74
+ interactiveSurface: undefined,
75
+ queueFocus: undefined,
76
+ verificationState: "not-run",
77
+ verificationFailures: 0,
72
78
  };
73
79
  }
74
80
  export function finalizeSummary(summary) {
@@ -5,17 +5,25 @@ import { detectPackageManager } from "../pm/detect.js";
5
5
  import { applyRangeStyle, parseVersion, compareVersions } from "../utils/semver.js";
6
6
  import { buildWorkspaceGraph } from "../workspace/graph.js";
7
7
  import { captureLockfileSnapshot, changedLockfiles, validateLockfileMode } from "../utils/lockfile.js";
8
+ import { createSummary, finalizeSummary } from "./summary.js";
9
+ import { readDecisionPlan, selectedUpdatesFromPlan } from "./decision-plan.js";
10
+ import { runVerification } from "./verification.js";
8
11
  export async function upgrade(options) {
9
12
  validateLockfileMode(options.lockfileMode, options.install);
10
13
  const lockfilesBefore = await captureLockfileSnapshot(options.cwd);
11
- const checkResult = await check(options);
14
+ const checkResult = options.fromPlanFile
15
+ ? await createUpgradeResultFromPlan(options)
16
+ : await check(options);
12
17
  if (checkResult.updates.length === 0) {
13
18
  return {
14
19
  ...checkResult,
15
20
  changed: false,
16
21
  };
17
22
  }
18
- await applySelectedUpdates(options, checkResult.updates);
23
+ const selectedUpdates = options.fromPlanFile
24
+ ? checkResult.updates
25
+ : checkResult.updates;
26
+ await applySelectedUpdates(options, selectedUpdates);
19
27
  const lockfileChanges = await changedLockfiles(options.cwd, lockfilesBefore);
20
28
  if (lockfileChanges.length > 0 && (options.lockfileMode === "preserve" || options.lockfileMode === "error")) {
21
29
  throw new Error(`Lockfile changes detected in ${options.lockfileMode} mode: ${lockfileChanges.join(", ")}`);
@@ -23,6 +31,18 @@ export async function upgrade(options) {
23
31
  if (lockfileChanges.length > 0 && options.lockfileMode === "update") {
24
32
  checkResult.warnings.push(`Lockfiles changed: ${lockfileChanges.map((item) => item.split("/").pop()).join(", ")}`);
25
33
  }
34
+ if (options.verify !== "none") {
35
+ const verification = await runVerification(options);
36
+ checkResult.summary.verificationState = verification.passed
37
+ ? "passed"
38
+ : "failed";
39
+ checkResult.summary.verificationFailures = verification.checks.filter((check) => !check.passed).length;
40
+ if (!verification.passed) {
41
+ checkResult.errors.push(...verification.checks
42
+ .filter((check) => !check.passed)
43
+ .map((check) => `Verification failed for ${check.name}: ${check.error ?? check.command}`));
44
+ }
45
+ }
26
46
  return {
27
47
  ...checkResult,
28
48
  changed: true,
@@ -59,6 +79,48 @@ export async function applySelectedUpdates(options, updates) {
59
79
  await installDependencies(options.cwd, options.packageManager, detected);
60
80
  }
61
81
  }
82
+ async function createUpgradeResultFromPlan(options) {
83
+ if (!options.fromPlanFile) {
84
+ throw new Error("Missing decision plan file.");
85
+ }
86
+ const plan = await readDecisionPlan(options.fromPlanFile);
87
+ const packageManager = await detectPackageManager(options.cwd);
88
+ const updates = selectedUpdatesFromPlan(plan);
89
+ const packagePaths = Array.from(new Set(updates.map((update) => update.packagePath))).sort((left, right) => left.localeCompare(right));
90
+ const summary = finalizeSummary(createSummary({
91
+ scannedPackages: packagePaths.length,
92
+ totalDependencies: updates.length,
93
+ checkedDependencies: updates.length,
94
+ updatesFound: updates.length,
95
+ upgraded: 0,
96
+ skipped: 0,
97
+ warmedPackages: 0,
98
+ errors: [],
99
+ warnings: [],
100
+ durations: {
101
+ totalMs: 0,
102
+ discoveryMs: 0,
103
+ registryMs: 0,
104
+ cacheMs: 0,
105
+ },
106
+ }));
107
+ summary.decisionPlan = options.fromPlanFile;
108
+ summary.interactiveSurface = plan.interactiveSurface;
109
+ summary.queueFocus = plan.focus;
110
+ summary.updatesFound = updates.length;
111
+ return {
112
+ projectPath: options.cwd,
113
+ packagePaths,
114
+ packageManager,
115
+ target: plan.target,
116
+ timestamp: new Date().toISOString(),
117
+ summary,
118
+ updates,
119
+ errors: [],
120
+ warnings: [],
121
+ changed: false,
122
+ };
123
+ }
62
124
  function applyWorkspaceSync(manifestsByPath, orderedPaths, localPackageNames, includeKinds, updates) {
63
125
  const desiredByPackage = new Map();
64
126
  for (const update of updates) {
@@ -0,0 +1,2 @@
1
+ import type { UpgradeOptions, VerificationResult } from "../types/index.js";
2
+ export declare function runVerification(options: Pick<UpgradeOptions, "cwd" | "verify" | "testCommand" | "verificationReportFile" | "packageManager">): Promise<VerificationResult>;
@@ -0,0 +1,108 @@
1
+ import { buildInstallInvocation, buildTestCommand, createPackageManagerProfile, detectPackageManagerDetails, } from "../pm/detect.js";
2
+ import { installDependencies } from "../pm/install.js";
3
+ import { stableStringify } from "../utils/stable-json.js";
4
+ import { writeFileAtomic } from "../utils/io.js";
5
+ import { readEnv } from "../utils/runtime.js";
6
+ export async function runVerification(options) {
7
+ const mode = options.verify;
8
+ if (mode === "none") {
9
+ const result = {
10
+ mode,
11
+ passed: true,
12
+ checks: [],
13
+ };
14
+ await maybeWriteVerificationReport(options.verificationReportFile, result);
15
+ return result;
16
+ }
17
+ const checks = [];
18
+ const detected = await detectPackageManagerDetails(options.cwd);
19
+ const profile = createPackageManagerProfile(options.packageManager, detected, "bun");
20
+ if (includesInstall(mode)) {
21
+ const installInvocation = buildInstallInvocation(profile);
22
+ checks.push(await runCheck("install", installInvocation.display, async () => {
23
+ await installDependencies(options.cwd, options.packageManager, detected);
24
+ }));
25
+ }
26
+ if (includesTest(mode)) {
27
+ const command = options.testCommand ??
28
+ defaultTestCommand(profile);
29
+ checks.push(await runShellCheck(options.cwd, command));
30
+ }
31
+ const result = {
32
+ mode,
33
+ passed: checks.every((check) => check.passed),
34
+ checks,
35
+ };
36
+ await maybeWriteVerificationReport(options.verificationReportFile, result);
37
+ return result;
38
+ }
39
+ function includesInstall(mode) {
40
+ return mode === "install" || mode === "install,test";
41
+ }
42
+ function includesTest(mode) {
43
+ return mode === "test" || mode === "install,test";
44
+ }
45
+ function defaultTestCommand(profile) {
46
+ return buildTestCommand(profile);
47
+ }
48
+ async function runShellCheck(cwd, command) {
49
+ const startedAt = Date.now();
50
+ try {
51
+ const shell = readEnv("SHELL") || "sh";
52
+ const proc = Bun.spawn([shell, "-lc", command], {
53
+ cwd,
54
+ stdin: "inherit",
55
+ stdout: "inherit",
56
+ stderr: "inherit",
57
+ });
58
+ const exitCode = await proc.exited;
59
+ return {
60
+ name: "test",
61
+ command,
62
+ passed: exitCode === 0,
63
+ exitCode,
64
+ durationMs: Math.max(0, Date.now() - startedAt),
65
+ error: exitCode === 0
66
+ ? undefined
67
+ : `${command} failed with exit code ${exitCode}`,
68
+ };
69
+ }
70
+ catch (error) {
71
+ return {
72
+ name: "test",
73
+ command,
74
+ passed: false,
75
+ exitCode: 1,
76
+ durationMs: Math.max(0, Date.now() - startedAt),
77
+ error: String(error),
78
+ };
79
+ }
80
+ }
81
+ async function runCheck(name, command, action) {
82
+ const startedAt = Date.now();
83
+ try {
84
+ await action();
85
+ return {
86
+ name,
87
+ command,
88
+ passed: true,
89
+ exitCode: 0,
90
+ durationMs: Math.max(0, Date.now() - startedAt),
91
+ };
92
+ }
93
+ catch (error) {
94
+ return {
95
+ name,
96
+ command,
97
+ passed: false,
98
+ exitCode: 1,
99
+ durationMs: Math.max(0, Date.now() - startedAt),
100
+ error: String(error),
101
+ };
102
+ }
103
+ }
104
+ async function maybeWriteVerificationReport(filePath, result) {
105
+ if (!filePath)
106
+ return;
107
+ await writeFileAtomic(filePath, stableStringify(result, 2) + "\n");
108
+ }
@@ -1,4 +1,3 @@
1
- import process from "node:process";
2
1
  import { collectDependencies, readManifest } from "../parsers/package-json.js";
3
2
  import { matchesPattern } from "../utils/pattern.js";
4
3
  import { VersionCache } from "../cache/cache.js";
@@ -7,6 +6,7 @@ import { detectPackageManager } from "../pm/detect.js";
7
6
  import { discoverPackageDirs } from "../workspace/discover.js";
8
7
  import { createSummary, finalizeSummary } from "./summary.js";
9
8
  import { formatClassifiedMessage } from "./errors.js";
9
+ import { writeStdout } from "../utils/runtime.js";
10
10
  export async function warmCache(options) {
11
11
  const startedAt = Date.now();
12
12
  let discoveryMs = 0;
@@ -14,7 +14,11 @@ export async function warmCache(options) {
14
14
  let registryMs = 0;
15
15
  const discoveryStartedAt = Date.now();
16
16
  const packageManager = await detectPackageManager(options.cwd);
17
- const packageDirs = await discoverPackageDirs(options.cwd, options.workspace);
17
+ const packageDirs = await discoverPackageDirs(options.cwd, options.workspace, {
18
+ git: options,
19
+ includeKinds: options.includeKinds,
20
+ includeDependents: options.affected === true,
21
+ });
18
22
  discoveryMs += Date.now() - discoveryStartedAt;
19
23
  const cache = await VersionCache.create();
20
24
  const registryClient = new NpmRegistryClient(options.cwd, {
@@ -39,7 +43,7 @@ export async function warmCache(options) {
39
43
  if (!options.stream)
40
44
  return;
41
45
  streamedEvents += 1;
42
- process.stdout.write(`${message}\n`);
46
+ writeStdout(`${message}\n`);
43
47
  };
44
48
  for (const packageDir of packageDirs) {
45
49
  try {
@@ -0,0 +1 @@
1
+ export declare const CLI_VERSION = "0.6.1";
@@ -0,0 +1,2 @@
1
+ // This file is generated by scripts/sync-version.mjs.
2
+ export const CLI_VERSION = "0.6.1";
@@ -0,0 +1,19 @@
1
+ import type { DependencyKind } from "../types/index.js";
2
+ export interface GitScopeOptions {
3
+ onlyChanged?: boolean;
4
+ affected?: boolean;
5
+ staged?: boolean;
6
+ baseRef?: string;
7
+ headRef?: string;
8
+ sinceRef?: string;
9
+ }
10
+ export interface ScopedPackageDirsResult {
11
+ packageDirs: string[];
12
+ warnings: string[];
13
+ changedFiles: string[];
14
+ }
15
+ export declare function hasGitScope(options: GitScopeOptions): boolean;
16
+ export declare function scopePackageDirsByGit(cwd: string, packageDirs: string[], options: GitScopeOptions, config?: {
17
+ includeKinds?: DependencyKind[];
18
+ includeDependents?: boolean;
19
+ }): Promise<ScopedPackageDirsResult>;