@rainy-updates/cli 0.6.0 → 0.6.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.
- package/CHANGELOG.md +111 -0
- package/README.md +12 -0
- package/dist/bin/cli.js +12 -127
- package/dist/bin/dispatch.js +6 -0
- package/dist/bin/help.js +48 -0
- package/dist/bin/main.d.ts +1 -0
- package/dist/bin/main.js +126 -0
- package/dist/commands/audit/parser.js +36 -0
- package/dist/commands/audit/runner.js +17 -18
- package/dist/commands/bisect/oracle.js +21 -17
- package/dist/commands/bisect/runner.js +4 -3
- package/dist/commands/dashboard/parser.js +41 -0
- package/dist/commands/dashboard/runner.js +3 -0
- package/dist/commands/doctor/parser.js +44 -0
- package/dist/commands/ga/parser.js +39 -0
- package/dist/commands/ga/runner.js +73 -9
- package/dist/commands/health/parser.js +36 -0
- package/dist/commands/health/runner.js +5 -1
- package/dist/commands/hook/parser.d.ts +2 -0
- package/dist/commands/hook/parser.js +40 -0
- package/dist/commands/hook/runner.d.ts +2 -0
- package/dist/commands/hook/runner.js +174 -0
- package/dist/commands/licenses/parser.js +39 -0
- package/dist/commands/licenses/runner.js +5 -1
- package/dist/commands/resolve/graph/builder.js +5 -1
- package/dist/commands/resolve/parser.js +39 -0
- package/dist/commands/resolve/runner.js +5 -0
- package/dist/commands/review/parser.js +44 -0
- package/dist/commands/snapshot/parser.js +39 -0
- package/dist/commands/snapshot/runner.js +4 -1
- package/dist/commands/unused/parser.js +39 -0
- package/dist/commands/unused/runner.js +4 -1
- package/dist/commands/unused/scanner.d.ts +2 -1
- package/dist/commands/unused/scanner.js +60 -44
- package/dist/core/check.js +5 -1
- package/dist/core/doctor/findings.js +4 -4
- package/dist/core/init-ci.js +28 -26
- package/dist/core/options.d.ts +4 -1
- package/dist/core/options.js +57 -0
- package/dist/core/verification.js +11 -9
- package/dist/core/warm-cache.js +5 -1
- package/dist/generated/version.d.ts +1 -0
- package/dist/generated/version.js +2 -0
- package/dist/git/scope.d.ts +19 -0
- package/dist/git/scope.js +167 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/output/sarif.js +2 -8
- package/dist/pm/detect.d.ts +37 -0
- package/dist/pm/detect.js +133 -2
- package/dist/pm/install.d.ts +2 -1
- package/dist/pm/install.js +7 -5
- package/dist/rup +0 -0
- package/dist/types/index.d.ts +59 -1
- package/dist/ui/dashboard-state.d.ts +7 -0
- package/dist/ui/dashboard-state.js +44 -0
- package/dist/ui/tui.d.ts +3 -0
- package/dist/ui/tui.js +311 -111
- package/dist/utils/shell.d.ts +6 -0
- package/dist/utils/shell.js +18 -0
- package/dist/workspace/discover.d.ts +7 -1
- package/dist/workspace/discover.js +12 -3
- package/package.json +16 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,117 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.6.2] - 2026-03-04
|
|
6
|
+
|
|
7
|
+
Dashboard hardening, cross-platform execution cleanup, and portable release operations for the next `v0.6` patch.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Portable operator entrypoints**:
|
|
12
|
+
- added a root `Makefile` for common build/check/release flows,
|
|
13
|
+
- added a `ga` package script so readiness checks can be invoked consistently from Bun scripts and `make`.
|
|
14
|
+
- **Shared shell invocation layer** for Windows, macOS, and Linux command execution in verification and bisect flows.
|
|
15
|
+
- **Dedicated binary release workflow**:
|
|
16
|
+
- GitHub Releases now have a separate workflow from npm publishing,
|
|
17
|
+
- tag builds can produce standalone binaries for Linux, macOS, and Windows,
|
|
18
|
+
- packaged archives are uploaded with SHA-256 checksum files.
|
|
19
|
+
- **Distribution manifest generator**:
|
|
20
|
+
- generates a Homebrew formula from release asset checksums,
|
|
21
|
+
- generates a Scoop manifest from the Windows release asset checksum,
|
|
22
|
+
- release artifacts now include copy-ready Homebrew and Scoop metadata.
|
|
23
|
+
- **New test coverage** for:
|
|
24
|
+
- shared shell invocation behavior across POSIX and Windows,
|
|
25
|
+
- dashboard startup state derived from `--view` and `--focus`,
|
|
26
|
+
- updated doctor dashboard-first recommendations,
|
|
27
|
+
- GA readiness checks for automation entrypoints.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Dashboard review operations were tightened for larger queues and cross-platform operators:
|
|
32
|
+
- initial dashboard focus and detail tabs now respect `--view` and `--focus`,
|
|
33
|
+
- the Ink queue renderer now windows large result sets instead of rendering the full queue every frame,
|
|
34
|
+
- bulk actions now include actionable/review selection in addition to safe and blocked flows,
|
|
35
|
+
- keyboard navigation now works cleanly with arrows and `hjkl`,
|
|
36
|
+
- terminal sizing is handled more defensively for smaller shells,
|
|
37
|
+
- the dashboard TUI was split into smaller focused components to reduce maintenance overhead.
|
|
38
|
+
- Doctor findings now point operators to the dashboard-first workflow instead of the older `review --interactive` wording.
|
|
39
|
+
- Verification and bisect shell execution are now portable across Windows, macOS, and Linux by routing command execution through a shared shell invocation layer.
|
|
40
|
+
- Release automation scripts were made portable:
|
|
41
|
+
- `clean` no longer depends on `rm -rf`,
|
|
42
|
+
- `test:prod` no longer depends on POSIX `test -x`,
|
|
43
|
+
- build and production validation now work with compiled Bun artifacts on Windows (`dist/rup.exe`) as well as POSIX (`dist/rup`).
|
|
44
|
+
- Release automation is now intentionally split:
|
|
45
|
+
- one workflow publishes the npm package,
|
|
46
|
+
- one workflow creates and uploads GitHub binary assets for standalone installation.
|
|
47
|
+
- `ga` readiness checks now also verify:
|
|
48
|
+
- portable automation entrypoints,
|
|
49
|
+
- obvious platform-specific script risks,
|
|
50
|
+
- compiled runtime artifacts in either POSIX or Windows form.
|
|
51
|
+
|
|
52
|
+
### Tests
|
|
53
|
+
|
|
54
|
+
- Validation completed for `0.6.2`:
|
|
55
|
+
- `bun run lint`
|
|
56
|
+
- `bun run build`
|
|
57
|
+
- `bun run check`
|
|
58
|
+
- `bun run test:prod`
|
|
59
|
+
- `bun run ga`
|
|
60
|
+
- `bun run perf:check`
|
|
61
|
+
- `npx -y react-doctor@latest . --verbose --diff` (`99/100`)
|
|
62
|
+
|
|
63
|
+
## [0.6.1] - 2026-03-03
|
|
64
|
+
|
|
65
|
+
Compatibility, git-aware workspace scoping, and release-readiness stabilization for the `v0.6` line.
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- **First-class package-manager profile layer**:
|
|
70
|
+
- detection now prefers `package.json.packageManager` before falling back to lockfiles,
|
|
71
|
+
- additive package-manager metadata for lockfile source and Yarn flavor detection,
|
|
72
|
+
- centralized install, add, and test command construction for npm, pnpm, Bun, and Yarn.
|
|
73
|
+
- **Git-aware workspace scoping**:
|
|
74
|
+
- `--affected`,
|
|
75
|
+
- `--staged`,
|
|
76
|
+
- `--base <ref>`,
|
|
77
|
+
- `--head <ref>`,
|
|
78
|
+
- `--since <ref>`.
|
|
79
|
+
- **Workspace dependent expansion for affected scans**:
|
|
80
|
+
- changed packages can now expand to dependent workspace packages instead of stopping at direct file matches.
|
|
81
|
+
- **New `hook` command**:
|
|
82
|
+
- `rup hook install`,
|
|
83
|
+
- `rup hook uninstall`,
|
|
84
|
+
- `rup hook doctor`.
|
|
85
|
+
- **Rainy-managed git hooks**:
|
|
86
|
+
- `pre-commit` runs `rup unused --workspace --staged` and `rup resolve --workspace --staged`,
|
|
87
|
+
- `pre-push` runs `rup audit --workspace --affected --report summary`.
|
|
88
|
+
- **New test coverage** for:
|
|
89
|
+
- package-manager field precedence and Yarn Berry behavior,
|
|
90
|
+
- git-scoped workspace discovery,
|
|
91
|
+
- hook install/doctor/uninstall lifecycle,
|
|
92
|
+
- scoped standalone parser support.
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
|
|
96
|
+
- `init-ci` workflow generation now uses the centralized package-manager profile layer instead of special-casing npm/pnpm/Bun only.
|
|
97
|
+
- Yarn support is now explicit in generated workflows:
|
|
98
|
+
- Corepack enablement for Yarn/pnpm repos,
|
|
99
|
+
- Yarn Berry uses immutable installs,
|
|
100
|
+
- Yarn package adds no longer fall back to npm command construction.
|
|
101
|
+
- `verification`, `audit --fix`, and `bisect` now reuse the same package-manager command model as `upgrade`.
|
|
102
|
+
- `ga` package-manager reporting now includes detection source details and respects the git-scoped workspace discovery flow.
|
|
103
|
+
- `check`, `warm-cache`, `audit`, `unused`, `resolve`, `health`, `licenses`, `snapshot`, and `ga` now share the same git-aware workspace scoping path.
|
|
104
|
+
- Command help and parser support were aligned so git-scoping flags are consistently accepted across the primary and standalone command surfaces.
|
|
105
|
+
|
|
106
|
+
### Tests
|
|
107
|
+
|
|
108
|
+
- Full release validation passed:
|
|
109
|
+
- `pnpm -s exec tsc --noEmit`
|
|
110
|
+
- `bun test`
|
|
111
|
+
- `pnpm run build`
|
|
112
|
+
- `bun run build:exe`
|
|
113
|
+
- `bun run test:prod`
|
|
114
|
+
- `bun ./dist/bin/cli.js ga --workspace`
|
|
115
|
+
|
|
5
116
|
## [0.6.0] - 2026-03-01
|
|
6
117
|
|
|
7
118
|
Dashboard-first release candidate for the `v0.6` series, focused on unifying the interactive surface, introducing replayable decision plans, tightening CI/apply verification flows, and undergoing a complete native Bun performance optimization.
|
package/README.md
CHANGED
|
@@ -79,6 +79,18 @@ pnpm add -D @rainy-updates/cli
|
|
|
79
79
|
bun add -d @rainy-updates/cli
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
### Standalone binaries from GitHub Releases
|
|
83
|
+
|
|
84
|
+
If you do not want to depend on global npm or a project-local `node_modules`, use the standalone compiled binaries from GitHub Releases.
|
|
85
|
+
|
|
86
|
+
Release assets are published for:
|
|
87
|
+
|
|
88
|
+
- Linux x64
|
|
89
|
+
- Linux arm64
|
|
90
|
+
- macOS x64
|
|
91
|
+
- macOS arm64
|
|
92
|
+
- Windows x64
|
|
93
|
+
|
|
82
94
|
Once installed, three binary aliases are available in your `node_modules/.bin/`:
|
|
83
95
|
|
|
84
96
|
| Alias | Use case |
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,134 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { applyFixPrBatches } from "../core/fix-pr-batch.js";
|
|
6
|
-
import { createRunId, writeArtifactManifest } from "../core/artifacts.js";
|
|
7
|
-
import { renderResult } from "../output/format.js";
|
|
8
|
-
import { writeGitHubOutput } from "../output/github.js";
|
|
9
|
-
import { createSarifReport } from "../output/sarif.js";
|
|
10
|
-
import { renderPrReport } from "../output/pr-report.js";
|
|
11
|
-
import { writeFileAtomic } from "../utils/io.js";
|
|
12
|
-
import { resolveFailReason } from "../core/summary.js";
|
|
13
|
-
import { stableStringify } from "../utils/stable-json.js";
|
|
14
|
-
import { getRuntimeArgv, setRuntimeExitCode, writeStderr, writeStdout, } from "../utils/runtime.js";
|
|
15
|
-
import { handleDirectCommand, runPrimaryCommand } from "./dispatch.js";
|
|
16
|
-
import { renderHelp } from "./help.js";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { runCli } from "./main.js";
|
|
17
5
|
async function main() {
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (argv.includes("--help") || argv.includes("-h")) {
|
|
25
|
-
writeStdout(renderHelp(argv[0]) + "\n");
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const parsed = await parseCliArgs(argv);
|
|
29
|
-
if (await handleDirectCommand(parsed))
|
|
30
|
-
return;
|
|
31
|
-
if (parsed.command !== "check" &&
|
|
32
|
-
parsed.command !== "upgrade" &&
|
|
33
|
-
parsed.command !== "warm-cache" &&
|
|
34
|
-
parsed.command !== "ci") {
|
|
35
|
-
throw new Error(`Unhandled command: ${parsed.command}`);
|
|
36
|
-
}
|
|
37
|
-
const result = await runPrimaryCommand(parsed);
|
|
38
|
-
result.summary.runId = createRunId(parsed.command, parsed.options, result);
|
|
39
|
-
if (parsed.options.fixPr &&
|
|
40
|
-
(parsed.command === "check" ||
|
|
41
|
-
parsed.command === "upgrade" ||
|
|
42
|
-
parsed.command === "ci")) {
|
|
43
|
-
result.summary.fixPrApplied = false;
|
|
44
|
-
result.summary.fixBranchName =
|
|
45
|
-
parsed.options.fixBranch ?? "chore/rainy-updates";
|
|
46
|
-
result.summary.fixCommitSha = "";
|
|
47
|
-
result.summary.fixPrBranchesCreated = 0;
|
|
48
|
-
if (parsed.command === "ci") {
|
|
49
|
-
const batched = await applyFixPrBatches(parsed.options, result);
|
|
50
|
-
result.summary.fixPrApplied = batched.applied;
|
|
51
|
-
result.summary.fixBranchName =
|
|
52
|
-
batched.branches[0] ??
|
|
53
|
-
parsed.options.fixBranch ??
|
|
54
|
-
"chore/rainy-updates";
|
|
55
|
-
result.summary.fixCommitSha = batched.commits[0] ?? "";
|
|
56
|
-
result.summary.fixPrBranchesCreated = batched.branches.length;
|
|
57
|
-
if (batched.branches.length > 1) {
|
|
58
|
-
result.warnings.push(`Created ${batched.branches.length} fix-pr batch branches.`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
const fixResult = await applyFixPr(parsed.options, result, []);
|
|
63
|
-
result.summary.fixPrApplied = fixResult.applied;
|
|
64
|
-
result.summary.fixBranchName = fixResult.branchName ?? "";
|
|
65
|
-
result.summary.fixCommitSha = fixResult.commitSha ?? "";
|
|
66
|
-
result.summary.fixPrBranchesCreated = fixResult.applied ? 1 : 0;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (parsed.options.prReportFile) {
|
|
70
|
-
const markdown = renderPrReport(result);
|
|
71
|
-
await writeFileAtomic(parsed.options.prReportFile, markdown + "\n");
|
|
72
|
-
}
|
|
73
|
-
const artifactManifest = await writeArtifactManifest(parsed.command, parsed.options, result);
|
|
74
|
-
if (artifactManifest) {
|
|
75
|
-
result.summary.artifactManifest = artifactManifest.artifactManifestPath;
|
|
76
|
-
}
|
|
77
|
-
result.summary.failReason = resolveFailReason(result.updates, result.errors, parsed.options.failOn, parsed.options.maxUpdates, parsed.options.ci);
|
|
78
|
-
const renderStartedAt = Date.now();
|
|
79
|
-
let rendered = renderResult(result, parsed.options.format, {
|
|
80
|
-
showImpact: parsed.options.showImpact,
|
|
81
|
-
showHomepage: parsed.options.showHomepage,
|
|
6
|
+
if (typeof Bun === "undefined") {
|
|
7
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
8
|
+
const result = spawnSync("bun", [currentFile, ...process.argv.slice(2)], {
|
|
9
|
+
stdio: "inherit",
|
|
82
10
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
rendered = renderResult(result, parsed.options.format, {
|
|
87
|
-
showImpact: parsed.options.showImpact,
|
|
88
|
-
showHomepage: parsed.options.showHomepage,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (parsed.options.onlyChanged &&
|
|
92
|
-
result.updates.length === 0 &&
|
|
93
|
-
result.errors.length === 0 &&
|
|
94
|
-
result.warnings.length === 0 &&
|
|
95
|
-
(parsed.options.format === "table" ||
|
|
96
|
-
parsed.options.format === "minimal" ||
|
|
97
|
-
parsed.options.format === "github")) {
|
|
98
|
-
rendered = "";
|
|
99
|
-
}
|
|
100
|
-
if (parsed.options.jsonFile) {
|
|
101
|
-
await writeFileAtomic(parsed.options.jsonFile, stableStringify(result, 2) + "\n");
|
|
11
|
+
if (result.error) {
|
|
12
|
+
process.stderr.write("rainy-updates (rup): Bun is required to run the published JavaScript entrypoint. Install Bun or use the compiled binary release.\n");
|
|
13
|
+
process.exit(1);
|
|
102
14
|
}
|
|
103
|
-
|
|
104
|
-
await writeGitHubOutput(parsed.options.githubOutputFile, result);
|
|
105
|
-
}
|
|
106
|
-
if (parsed.options.sarifFile) {
|
|
107
|
-
const sarif = createSarifReport(result);
|
|
108
|
-
await writeFileAtomic(parsed.options.sarifFile, stableStringify(sarif, 2) + "\n");
|
|
109
|
-
}
|
|
110
|
-
writeStdout(rendered + "\n");
|
|
111
|
-
setRuntimeExitCode(resolveExitCode(result, result.summary.failReason));
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
writeStderr(`rainy-updates (rup): ${String(error)}\n`);
|
|
115
|
-
setRuntimeExitCode(2);
|
|
15
|
+
process.exit(result.status ?? 1);
|
|
116
16
|
}
|
|
17
|
+
await runCli();
|
|
117
18
|
}
|
|
118
19
|
void main();
|
|
119
|
-
async function readPackageVersion() {
|
|
120
|
-
try {
|
|
121
|
-
const packageJson = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
122
|
-
return packageJson.version ?? "0.0.0";
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
return "0.0.0";
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function resolveExitCode(result, failReason) {
|
|
129
|
-
if (result.errors.length > 0)
|
|
130
|
-
return 2;
|
|
131
|
-
if (failReason !== "none")
|
|
132
|
-
return 1;
|
|
133
|
-
return 0;
|
|
134
|
-
}
|
package/dist/bin/dispatch.js
CHANGED
|
@@ -108,6 +108,12 @@ export async function handleDirectCommand(parsed) {
|
|
|
108
108
|
setRuntimeExitCode(result.ready ? 0 : 1);
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
|
+
if (parsed.command === "hook") {
|
|
112
|
+
const { runHook } = await import("../commands/hook/runner.js");
|
|
113
|
+
const result = await runHook(parsed.options);
|
|
114
|
+
setRuntimeExitCode(result.errors.length > 0 ? 1 : 0);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
111
117
|
if (parsed.options.interactive &&
|
|
112
118
|
(parsed.command === "check" ||
|
|
113
119
|
parsed.command === "upgrade" ||
|
package/dist/bin/help.js
CHANGED
|
@@ -40,6 +40,11 @@ Options:
|
|
|
40
40
|
--cooldown-days <n>
|
|
41
41
|
--pr-limit <n>
|
|
42
42
|
--only-changed
|
|
43
|
+
--affected
|
|
44
|
+
--staged
|
|
45
|
+
--base <ref>
|
|
46
|
+
--head <ref>
|
|
47
|
+
--since <ref>
|
|
43
48
|
--interactive
|
|
44
49
|
--plan-file <path>
|
|
45
50
|
--verify none|install|test|install,test
|
|
@@ -123,6 +128,11 @@ Options:
|
|
|
123
128
|
--cooldown-days <n>
|
|
124
129
|
--pr-limit <n>
|
|
125
130
|
--only-changed
|
|
131
|
+
--affected
|
|
132
|
+
--staged
|
|
133
|
+
--base <ref>
|
|
134
|
+
--head <ref>
|
|
135
|
+
--since <ref>
|
|
126
136
|
--offline
|
|
127
137
|
--concurrency <n>
|
|
128
138
|
--registry-timeout-ms <n>
|
|
@@ -180,6 +190,11 @@ Scan dependencies for CVEs using OSV.dev and GitHub Advisory Database.
|
|
|
180
190
|
|
|
181
191
|
Options:
|
|
182
192
|
--workspace
|
|
193
|
+
--affected
|
|
194
|
+
--staged
|
|
195
|
+
--base <ref>
|
|
196
|
+
--head <ref>
|
|
197
|
+
--since <ref>
|
|
183
198
|
--severity critical|high|medium|low
|
|
184
199
|
--summary
|
|
185
200
|
--report table|summary|json
|
|
@@ -200,6 +215,12 @@ Use it to inspect risk, security, peer, license, and policy context before apply
|
|
|
200
215
|
|
|
201
216
|
Options:
|
|
202
217
|
--workspace
|
|
218
|
+
--only-changed
|
|
219
|
+
--affected
|
|
220
|
+
--staged
|
|
221
|
+
--base <ref>
|
|
222
|
+
--head <ref>
|
|
223
|
+
--since <ref>
|
|
203
224
|
--interactive
|
|
204
225
|
--security-only
|
|
205
226
|
--risk critical|high|medium|low
|
|
@@ -220,6 +241,12 @@ Produce a fast summary verdict and point the operator to review when action is n
|
|
|
220
241
|
|
|
221
242
|
Options:
|
|
222
243
|
--workspace
|
|
244
|
+
--only-changed
|
|
245
|
+
--affected
|
|
246
|
+
--staged
|
|
247
|
+
--base <ref>
|
|
248
|
+
--head <ref>
|
|
249
|
+
--since <ref>
|
|
223
250
|
--verdict-only
|
|
224
251
|
--include-changelog
|
|
225
252
|
--json-file <path>`;
|
|
@@ -231,6 +258,13 @@ Open the primary interactive dependency operations console.
|
|
|
231
258
|
|
|
232
259
|
Options:
|
|
233
260
|
--workspace
|
|
261
|
+
--only-changed
|
|
262
|
+
--affected
|
|
263
|
+
--staged
|
|
264
|
+
--base <ref>
|
|
265
|
+
--head <ref>
|
|
266
|
+
--since <ref>
|
|
267
|
+
--view dependencies|security|health
|
|
234
268
|
--mode check|review|upgrade
|
|
235
269
|
--focus all|security|risk|major|blocked|workspace
|
|
236
270
|
--apply-selected
|
|
@@ -248,6 +282,14 @@ Audit release and CI readiness for Rainy Updates.
|
|
|
248
282
|
Options:
|
|
249
283
|
--workspace
|
|
250
284
|
--json-file <path>
|
|
285
|
+
--cwd <path>`;
|
|
286
|
+
}
|
|
287
|
+
if (isCommand && command === "hook") {
|
|
288
|
+
return `rainy-updates hook <install|uninstall|doctor> [options]
|
|
289
|
+
|
|
290
|
+
Install, remove, or inspect Rainy-managed git hooks.
|
|
291
|
+
|
|
292
|
+
Options:
|
|
251
293
|
--cwd <path>`;
|
|
252
294
|
}
|
|
253
295
|
return `rainy-updates (rup / rainy-up) <command> [options]
|
|
@@ -270,6 +312,7 @@ Commands:
|
|
|
270
312
|
licenses Scan dependency licenses and generate SPDX SBOM
|
|
271
313
|
snapshot Save, list, restore, and diff dependency state snapshots
|
|
272
314
|
ga Audit GA and CI readiness for this checkout
|
|
315
|
+
hook Install or inspect Rainy-managed git hooks
|
|
273
316
|
|
|
274
317
|
Global options:
|
|
275
318
|
--cwd <path>
|
|
@@ -288,6 +331,11 @@ Global options:
|
|
|
288
331
|
--cooldown-days <n>
|
|
289
332
|
--pr-limit <n>
|
|
290
333
|
--only-changed
|
|
334
|
+
--affected
|
|
335
|
+
--staged
|
|
336
|
+
--base <ref>
|
|
337
|
+
--head <ref>
|
|
338
|
+
--since <ref>
|
|
291
339
|
--interactive
|
|
292
340
|
--show-impact
|
|
293
341
|
--show-links
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runCli(): Promise<void>;
|
package/dist/bin/main.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { parseCliArgs } from "../core/options.js";
|
|
2
|
+
import { createRunId, writeArtifactManifest } from "../core/artifacts.js";
|
|
3
|
+
import { renderResult } from "../output/format.js";
|
|
4
|
+
import { writeGitHubOutput } from "../output/github.js";
|
|
5
|
+
import { createSarifReport } from "../output/sarif.js";
|
|
6
|
+
import { renderPrReport } from "../output/pr-report.js";
|
|
7
|
+
import { writeFileAtomic } from "../utils/io.js";
|
|
8
|
+
import { resolveFailReason } from "../core/summary.js";
|
|
9
|
+
import { stableStringify } from "../utils/stable-json.js";
|
|
10
|
+
import { getRuntimeArgv, setRuntimeExitCode, writeStderr, writeStdout, } from "../utils/runtime.js";
|
|
11
|
+
import { CLI_VERSION } from "../generated/version.js";
|
|
12
|
+
import { handleDirectCommand, runPrimaryCommand } from "./dispatch.js";
|
|
13
|
+
import { renderHelp } from "./help.js";
|
|
14
|
+
export async function runCli() {
|
|
15
|
+
try {
|
|
16
|
+
const argv = getRuntimeArgv();
|
|
17
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
18
|
+
writeStdout((await readPackageVersion()) + "\n");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
22
|
+
writeStdout(renderHelp(argv[0]) + "\n");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const parsed = await parseCliArgs(argv);
|
|
26
|
+
if (await handleDirectCommand(parsed))
|
|
27
|
+
return;
|
|
28
|
+
if (parsed.command !== "check" &&
|
|
29
|
+
parsed.command !== "upgrade" &&
|
|
30
|
+
parsed.command !== "warm-cache" &&
|
|
31
|
+
parsed.command !== "ci") {
|
|
32
|
+
throw new Error(`Unhandled command: ${parsed.command}`);
|
|
33
|
+
}
|
|
34
|
+
const result = await runPrimaryCommand(parsed);
|
|
35
|
+
result.summary.runId = createRunId(parsed.command, parsed.options, result);
|
|
36
|
+
if (parsed.options.fixPr &&
|
|
37
|
+
(parsed.command === "check" ||
|
|
38
|
+
parsed.command === "upgrade" ||
|
|
39
|
+
parsed.command === "ci")) {
|
|
40
|
+
result.summary.fixPrApplied = false;
|
|
41
|
+
result.summary.fixBranchName =
|
|
42
|
+
parsed.options.fixBranch ?? "chore/rainy-updates";
|
|
43
|
+
result.summary.fixCommitSha = "";
|
|
44
|
+
result.summary.fixPrBranchesCreated = 0;
|
|
45
|
+
if (parsed.command === "ci") {
|
|
46
|
+
const { applyFixPrBatches } = await import("../core/fix-pr-batch.js");
|
|
47
|
+
const batched = await applyFixPrBatches(parsed.options, result);
|
|
48
|
+
result.summary.fixPrApplied = batched.applied;
|
|
49
|
+
result.summary.fixBranchName =
|
|
50
|
+
batched.branches[0] ??
|
|
51
|
+
parsed.options.fixBranch ??
|
|
52
|
+
"chore/rainy-updates";
|
|
53
|
+
result.summary.fixCommitSha = batched.commits[0] ?? "";
|
|
54
|
+
result.summary.fixPrBranchesCreated = batched.branches.length;
|
|
55
|
+
if (batched.branches.length > 1) {
|
|
56
|
+
result.warnings.push(`Created ${batched.branches.length} fix-pr batch branches.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const { applyFixPr } = await import("../core/fix-pr.js");
|
|
61
|
+
const fixResult = await applyFixPr(parsed.options, result, []);
|
|
62
|
+
result.summary.fixPrApplied = fixResult.applied;
|
|
63
|
+
result.summary.fixBranchName = fixResult.branchName ?? "";
|
|
64
|
+
result.summary.fixCommitSha = fixResult.commitSha ?? "";
|
|
65
|
+
result.summary.fixPrBranchesCreated = fixResult.applied ? 1 : 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (parsed.options.prReportFile) {
|
|
69
|
+
const markdown = renderPrReport(result);
|
|
70
|
+
await writeFileAtomic(parsed.options.prReportFile, markdown + "\n");
|
|
71
|
+
}
|
|
72
|
+
const artifactManifest = await writeArtifactManifest(parsed.command, parsed.options, result);
|
|
73
|
+
if (artifactManifest) {
|
|
74
|
+
result.summary.artifactManifest = artifactManifest.artifactManifestPath;
|
|
75
|
+
}
|
|
76
|
+
result.summary.failReason = resolveFailReason(result.updates, result.errors, parsed.options.failOn, parsed.options.maxUpdates, parsed.options.ci);
|
|
77
|
+
const renderStartedAt = Date.now();
|
|
78
|
+
let rendered = renderResult(result, parsed.options.format, {
|
|
79
|
+
showImpact: parsed.options.showImpact,
|
|
80
|
+
showHomepage: parsed.options.showHomepage,
|
|
81
|
+
});
|
|
82
|
+
result.summary.durationMs.render = Math.max(0, Date.now() - renderStartedAt);
|
|
83
|
+
if (parsed.options.format === "json" ||
|
|
84
|
+
parsed.options.format === "metrics") {
|
|
85
|
+
rendered = renderResult(result, parsed.options.format, {
|
|
86
|
+
showImpact: parsed.options.showImpact,
|
|
87
|
+
showHomepage: parsed.options.showHomepage,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (parsed.options.onlyChanged &&
|
|
91
|
+
result.updates.length === 0 &&
|
|
92
|
+
result.errors.length === 0 &&
|
|
93
|
+
result.warnings.length === 0 &&
|
|
94
|
+
(parsed.options.format === "table" ||
|
|
95
|
+
parsed.options.format === "minimal" ||
|
|
96
|
+
parsed.options.format === "github")) {
|
|
97
|
+
rendered = "";
|
|
98
|
+
}
|
|
99
|
+
if (parsed.options.jsonFile) {
|
|
100
|
+
await writeFileAtomic(parsed.options.jsonFile, stableStringify(result, 2) + "\n");
|
|
101
|
+
}
|
|
102
|
+
if (parsed.options.githubOutputFile) {
|
|
103
|
+
await writeGitHubOutput(parsed.options.githubOutputFile, result);
|
|
104
|
+
}
|
|
105
|
+
if (parsed.options.sarifFile) {
|
|
106
|
+
const sarif = createSarifReport(result);
|
|
107
|
+
await writeFileAtomic(parsed.options.sarifFile, stableStringify(sarif, 2) + "\n");
|
|
108
|
+
}
|
|
109
|
+
writeStdout(rendered + "\n");
|
|
110
|
+
setRuntimeExitCode(resolveExitCode(result, result.summary.failReason));
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
writeStderr(`rainy-updates (rup): ${String(error)}\n`);
|
|
114
|
+
setRuntimeExitCode(2);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function readPackageVersion() {
|
|
118
|
+
return CLI_VERSION;
|
|
119
|
+
}
|
|
120
|
+
function resolveExitCode(result, failReason) {
|
|
121
|
+
if (result.errors.length > 0)
|
|
122
|
+
return 2;
|
|
123
|
+
if (failReason !== "none")
|
|
124
|
+
return 1;
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
@@ -12,6 +12,11 @@ export function parseAuditArgs(args) {
|
|
|
12
12
|
const options = {
|
|
13
13
|
cwd: getRuntimeCwd(),
|
|
14
14
|
workspace: false,
|
|
15
|
+
affected: false,
|
|
16
|
+
staged: false,
|
|
17
|
+
baseRef: undefined,
|
|
18
|
+
headRef: undefined,
|
|
19
|
+
sinceRef: undefined,
|
|
15
20
|
severity: undefined,
|
|
16
21
|
fix: false,
|
|
17
22
|
dryRun: false,
|
|
@@ -39,6 +44,37 @@ export function parseAuditArgs(args) {
|
|
|
39
44
|
index += 1;
|
|
40
45
|
continue;
|
|
41
46
|
}
|
|
47
|
+
if (current === "--affected") {
|
|
48
|
+
options.affected = true;
|
|
49
|
+
index += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (current === "--staged") {
|
|
53
|
+
options.staged = true;
|
|
54
|
+
index += 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (current === "--base" && next) {
|
|
58
|
+
options.baseRef = next;
|
|
59
|
+
index += 2;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (current === "--base")
|
|
63
|
+
throw new Error("Missing value for --base");
|
|
64
|
+
if (current === "--head" && next) {
|
|
65
|
+
options.headRef = next;
|
|
66
|
+
index += 2;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (current === "--head")
|
|
70
|
+
throw new Error("Missing value for --head");
|
|
71
|
+
if (current === "--since" && next) {
|
|
72
|
+
options.sinceRef = next;
|
|
73
|
+
index += 2;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (current === "--since")
|
|
77
|
+
throw new Error("Missing value for --since");
|
|
42
78
|
if (current === "--severity" && next) {
|
|
43
79
|
options.severity = parseSeverity(next);
|
|
44
80
|
index += 2;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { collectDependencies, readManifest, } from "../../parsers/package-json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { buildAddInvocation, createPackageManagerProfile, detectPackageManagerDetails, } from "../../pm/detect.js";
|
|
3
3
|
import { discoverPackageDirs } from "../../workspace/discover.js";
|
|
4
4
|
import { writeFileAtomic } from "../../utils/io.js";
|
|
5
5
|
import { stableStringify } from "../../utils/stable-json.js";
|
|
@@ -28,7 +28,15 @@ export async function runAudit(options) {
|
|
|
28
28
|
unresolved: 0,
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
|
-
const packageDirs = await discoverPackageDirs(options.cwd, options.workspace
|
|
31
|
+
const packageDirs = await discoverPackageDirs(options.cwd, options.workspace, {
|
|
32
|
+
git: options,
|
|
33
|
+
includeKinds: [
|
|
34
|
+
"dependencies",
|
|
35
|
+
"devDependencies",
|
|
36
|
+
"optionalDependencies",
|
|
37
|
+
],
|
|
38
|
+
includeDependents: options.affected === true,
|
|
39
|
+
});
|
|
32
40
|
const depsByDir = new Map();
|
|
33
41
|
for (const dir of packageDirs) {
|
|
34
42
|
let manifest;
|
|
@@ -121,10 +129,10 @@ async function applyFix(advisories, options) {
|
|
|
121
129
|
const patchMap = buildPatchMap(advisories);
|
|
122
130
|
if (patchMap.size === 0)
|
|
123
131
|
return;
|
|
124
|
-
const detected = await
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
const installCmd =
|
|
132
|
+
const detected = await detectPackageManagerDetails(options.cwd);
|
|
133
|
+
const profile = createPackageManagerProfile(options.packageManager, detected);
|
|
134
|
+
const install = buildInstallArgs(profile, patchMap);
|
|
135
|
+
const installCmd = install.display;
|
|
128
136
|
if (options.dryRun) {
|
|
129
137
|
if (!options.silent) {
|
|
130
138
|
writeStderr(`[audit] --dry-run: would execute:\n ${installCmd}\n`);
|
|
@@ -140,7 +148,7 @@ async function applyFix(advisories, options) {
|
|
|
140
148
|
writeStderr(` → ${installCmd}\n`);
|
|
141
149
|
}
|
|
142
150
|
try {
|
|
143
|
-
await runCommand(
|
|
151
|
+
await runCommand(install.command, install.args, options.cwd);
|
|
144
152
|
}
|
|
145
153
|
catch (err) {
|
|
146
154
|
if (!options.silent) {
|
|
@@ -158,18 +166,9 @@ async function applyFix(advisories, options) {
|
|
|
158
166
|
writeStderr(`[audit] Tip: run with --commit to automatically commit the changes.\n`);
|
|
159
167
|
}
|
|
160
168
|
}
|
|
161
|
-
function buildInstallArgs(
|
|
169
|
+
function buildInstallArgs(profile, patchMap) {
|
|
162
170
|
const packages = [...patchMap.entries()].map(([n, v]) => `${n}@${v}`);
|
|
163
|
-
|
|
164
|
-
case "pnpm":
|
|
165
|
-
return ["add", ...packages];
|
|
166
|
-
case "bun":
|
|
167
|
-
return ["add", ...packages];
|
|
168
|
-
case "yarn":
|
|
169
|
-
return ["add", ...packages];
|
|
170
|
-
default:
|
|
171
|
-
return ["install", ...packages]; // npm
|
|
172
|
-
}
|
|
171
|
+
return buildAddInvocation(profile, packages);
|
|
173
172
|
}
|
|
174
173
|
async function commitFix(patchMap, cwd, silent) {
|
|
175
174
|
const msg = buildCommitMessage(patchMap);
|