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