actions-up 1.14.2 → 1.14.3

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/dist/cli/index.js CHANGED
@@ -17,192 +17,197 @@ import { mergeScanResults as h } from "./merge-scan-results.js";
17
17
  import { printModeWarning as g } from "./print-mode-warning.js";
18
18
  import { scanRecursive as _ } from "../core/scan-recursive.js";
19
19
  import { buildJsonReport as v } from "./build-json-report.js";
20
- import { scanGitHubActions as y } from "../core/scan-github-actions.js";
20
+ import { parseArguments as y } from "./parse-arguments.js";
21
+ import { scanGitHubActions as b } from "../core/scan-github-actions.js";
21
22
  import "../core/index.js";
22
- import { version as b } from "../package.js";
23
- import { createSpinner as x } from "nanospinner";
24
- import { resolve as S } from "node:path";
23
+ import { version as x } from "../package.js";
24
+ import { createSpinner as S } from "nanospinner";
25
+ import { resolve as C } from "node:path";
25
26
  import "node:worker_threads";
26
- import C from "picocolors";
27
- import w from "cac";
27
+ import w from "picocolors";
28
28
  function T() {
29
- let T = w("actions-up");
30
- T.help().version(b).option("--dir <directory>", "Directory to scan (repeatable). Default: .github, or . with --recursive").option("--dry-run", "Preview changes without applying them").option("--exclude <regex>", "Exclude actions by regex (repeatable)").option("--include-branches", "Also check actions pinned to branches (default: false)").option("--json", "Output update information as machine-readable JSON").option("--min-age <days>", "Minimum age in days for updates (default: 0)", { default: 0 }).option("--mode <mode>", "Update mode: major, minor, or patch (default: major)", { default: "major" }).option("--style <style>", "Update style: sha or preserve (default: sha)", { default: "sha" }).option("--recursive, -r", "Recursively scan directories for YAML files").option("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (b) => {
31
- let w = b.json ?? !1, T = null, E = o({
32
- recursive: b.recursive,
33
- cwd: process.cwd(),
34
- dir: b.dir
35
- }), D = E.map(({ root: e, dir: t }) => S(e, t)), O = b.includeBranches ?? !1, k = d(b.mode), A = l(b.style), j = [];
36
- Array.isArray(b.exclude) ? j.push(...b.exclude) : typeof b.exclude == "string" && j.push(b.exclude);
37
- let M = j.flatMap((e) => e.split(",")).map((e) => e.trim()).filter(Boolean);
38
- try {
39
- f({
40
- yes: b.yes,
41
- json: w
42
- }), w || (console.info(C.cyan("\n🚀 Actions Up!\n")), T = x("Scanning GitHub Actions...").start());
43
- function o({ actionsToCheckCount: e, blockedByMode: t = [], outdated: n = [], skipped: r = [], scanResult: i, status: a }) {
44
- process.stdout.write(`${JSON.stringify(v({
45
- recursive: b.recursive ?? !1,
46
- excludePatterns: M,
47
- directories: D,
48
- minAge: b.minAge,
49
- actionsToCheckCount: e,
50
- includeBranches: O,
51
- blockedByMode: t,
52
- scanResult: i,
53
- outdated: n,
54
- skipped: r,
55
- status: a,
56
- style: A,
57
- mode: k
58
- }), null, 2)}\n`);
59
- }
60
- let l = h(b.recursive ? await Promise.all(E.map(({ root: e, dir: t }) => _(e, t))) : await Promise.all(E.map(({ root: e, dir: t }) => y(e, t)))), d = l.actions.length, S = l.workflows.size, j = l.compositeActions.size;
61
- if (T?.success(`Found ${C.yellow(d)} actions in ${C.yellow(S)} workflows and ${C.yellow(j)} composite actions`), d === 0) {
62
- if (w) {
63
- o({
64
- status: "no-actions-found",
65
- actionsToCheckCount: 0,
66
- scanResult: l
67
- });
68
- return;
69
- }
70
- console.info(C.green("\n✨ No GitHub Actions found in this repository"));
29
+ let e = y(process.argv.slice(2), x);
30
+ if (e.kind === "help" || e.kind === "version") {
31
+ console.info(e.text);
32
+ return;
33
+ }
34
+ e.kind === "error" && (console.error(w.redBright("\nError:"), e.message), process.exit(1)), E(e.options);
35
+ }
36
+ async function E(y) {
37
+ let x = y.json ?? !1, T = null, E = o({
38
+ recursive: y.recursive,
39
+ cwd: process.cwd(),
40
+ dir: y.dir
41
+ }), D = E.map(({ root: e, dir: t }) => C(e, t)), O = y.includeBranches ?? !1, k = d(y.mode), A = l(y.style), j = [];
42
+ Array.isArray(y.exclude) ? j.push(...y.exclude) : typeof y.exclude == "string" && j.push(y.exclude);
43
+ let M = j.flatMap((e) => e.split(",")).map((e) => e.trim()).filter(Boolean);
44
+ try {
45
+ f({
46
+ yes: y.yes,
47
+ json: x
48
+ }), x || (console.info(w.cyan("\n🚀 Actions Up!\n")), T = S("Scanning GitHub Actions...").start());
49
+ function o({ actionsToCheckCount: e, blockedByMode: t = [], outdated: n = [], skipped: r = [], scanResult: i, status: a }) {
50
+ process.stdout.write(`${JSON.stringify(v({
51
+ recursive: y.recursive ?? !1,
52
+ excludePatterns: M,
53
+ directories: D,
54
+ minAge: y.minAge,
55
+ actionsToCheckCount: e,
56
+ includeBranches: O,
57
+ blockedByMode: t,
58
+ scanResult: i,
59
+ outdated: n,
60
+ skipped: r,
61
+ status: a,
62
+ style: A,
63
+ mode: k
64
+ }), null, 2)}\n`);
65
+ }
66
+ let l = h(y.recursive ? await Promise.all(E.map(({ root: e, dir: t }) => _(e, t))) : await Promise.all(E.map(({ root: e, dir: t }) => b(e, t)))), d = l.actions.length, C = l.workflows.size, j = l.compositeActions.size;
67
+ if (T?.success(`Found ${w.yellow(d)} actions in ${w.yellow(C)} workflows and ${w.yellow(j)} composite actions`), d === 0) {
68
+ if (x) {
69
+ o({
70
+ status: "no-actions-found",
71
+ actionsToCheckCount: 0,
72
+ scanResult: l
73
+ });
71
74
  return;
72
75
  }
73
- let N = l.actions;
74
- if (M.length > 0) {
75
- let { parseExcludePatterns: e } = await import("../core/filters/parse-exclude-patterns.js"), t = e(M);
76
- t.length > 0 && (N = N.filter((e) => {
77
- let { name: n } = e;
78
- for (let e of t) if (e.test(n)) return !1;
79
- return !0;
80
- }));
81
- }
82
- if (w || (T = x("Checking for updates...").start()), N.length === 0) {
83
- if (T?.success("No actions to check after excludes"), w) {
84
- o({
85
- status: "nothing-to-check",
86
- actionsToCheckCount: 0,
87
- scanResult: l
88
- });
89
- return;
90
- }
91
- console.info(C.green("\n✨ Nothing to check after excludes\n"));
76
+ console.info(w.green("\n✨ No GitHub Actions found in this repository"));
77
+ return;
78
+ }
79
+ let N = l.actions;
80
+ if (M.length > 0) {
81
+ let { parseExcludePatterns: e } = await import("../core/filters/parse-exclude-patterns.js"), t = e(M);
82
+ t.length > 0 && (N = N.filter((e) => {
83
+ let { name: n } = e;
84
+ for (let e of t) if (e.test(n)) return !1;
85
+ return !0;
86
+ }));
87
+ }
88
+ if (x || (T = S("Checking for updates...").start()), N.length === 0) {
89
+ if (T?.success("No actions to check after excludes"), x) {
90
+ o({
91
+ status: "nothing-to-check",
92
+ actionsToCheckCount: 0,
93
+ scanResult: l
94
+ });
92
95
  return;
93
96
  }
94
- let P = process.env.GITHUB_TOKEN, F = a(P), I = await m(N, P, {
95
- client: F,
96
- includeBranches: O,
97
- style: A
98
- }), L = [];
99
- await Promise.all(I.map(async (e) => {
100
- await p(e.action.file, e.action.line) || L.push(e);
101
- }));
102
- let R = L.filter((e) => e.status === "skipped"), z = L.filter((e) => e.hasUpdate), B = b.minAge * 24 * 60 * 60 * 1e3, V = Date.now();
103
- z = z.filter((e) => e.publishedAt ? V - e.publishedAt.getTime() >= B : !0);
104
- let H = [];
105
- if (k !== "major") {
106
- let n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = await Promise.all(z.map(async (n) => {
107
- let r = n.currentVersion;
108
- if (t(n.currentVersion)) {
109
- let t = await e(n.action.file, n.action.line, a);
110
- t && (r = t);
111
- }
112
- let i = s(r, n.latestVersion);
113
- return {
114
- effectiveCurrentVersion: r,
115
- allowed: k === "minor" ? i === "minor" || i === "patch" || i === "none" : i === "patch" || i === "none",
116
- update: n
117
- };
118
- })), c = [], l = await Promise.all(o.map(async (e) => {
119
- if (e.allowed) return { update: e.update };
120
- let t = await i(F, {
121
- currentVersion: e.effectiveCurrentVersion,
122
- actionName: e.update.action.name,
123
- tagsCache: n,
124
- shaCache: r,
125
- mode: k
126
- });
127
- return t ? { update: {
128
- ...e.update,
129
- latestVersion: t.version,
130
- latestSha: t.sha,
131
- isBreaking: !1,
132
- hasUpdate: !0
133
- } } : { blocked: e.update };
134
- }));
135
- for (let e of l) {
136
- if (e.update) {
137
- c.push(e.update);
138
- continue;
139
- }
140
- H.push(e.blocked);
97
+ console.info(w.green("\n✨ Nothing to check after excludes\n"));
98
+ return;
99
+ }
100
+ let P = process.env.GITHUB_TOKEN, F = a(P), I = await m(N, P, {
101
+ client: F,
102
+ includeBranches: O,
103
+ style: A
104
+ }), L = [];
105
+ await Promise.all(I.map(async (e) => {
106
+ await p(e.action.file, e.action.line) || L.push(e);
107
+ }));
108
+ let R = L.filter((e) => e.status === "skipped"), z = L.filter((e) => e.hasUpdate), B = y.minAge * 24 * 60 * 60 * 1e3, V = Date.now();
109
+ z = z.filter((e) => e.publishedAt ? V - e.publishedAt.getTime() >= B : !0);
110
+ let H = [];
111
+ if (k !== "major") {
112
+ let n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = await Promise.all(z.map(async (n) => {
113
+ let r = n.currentVersion;
114
+ if (t(n.currentVersion)) {
115
+ let t = await e(n.action.file, n.action.line, a);
116
+ t && (r = t);
141
117
  }
142
- z = c;
143
- }
144
- z = z.map((e) => r(e, A));
145
- let U = z.filter((e) => !e.targetRef).map((e) => ({
146
- ...e,
147
- skipReason: "unsupported-style",
148
- status: "skipped",
149
- hasUpdate: !1
118
+ let i = s(r, n.latestVersion);
119
+ return {
120
+ effectiveCurrentVersion: r,
121
+ allowed: k === "minor" ? i === "minor" || i === "patch" || i === "none" : i === "patch" || i === "none",
122
+ update: n
123
+ };
124
+ })), c = [], l = await Promise.all(o.map(async (e) => {
125
+ if (e.allowed) return { update: e.update };
126
+ let t = await i(F, {
127
+ currentVersion: e.effectiveCurrentVersion,
128
+ actionName: e.update.action.name,
129
+ tagsCache: n,
130
+ shaCache: r,
131
+ mode: k
132
+ });
133
+ return t ? { update: {
134
+ ...e.update,
135
+ latestVersion: t.version,
136
+ latestSha: t.sha,
137
+ isBreaking: !1,
138
+ hasUpdate: !0
139
+ } } : { blocked: e.update };
150
140
  }));
151
- R.push(...U), z = z.filter((e) => e.targetRef);
152
- let W = z.filter((e) => e.isBreaking);
153
- if (z.length === 0) {
154
- if (T?.success("All actions are up to date!"), w) {
155
- o({
156
- actionsToCheckCount: N.length,
157
- status: "up-to-date",
158
- blockedByMode: H,
159
- scanResult: l,
160
- skipped: R
161
- });
162
- return;
141
+ for (let e of l) {
142
+ if (e.update) {
143
+ c.push(e.update);
144
+ continue;
163
145
  }
164
- R.length > 0 && u(R, O, A), H.length > 0 && g(H, k), console.info(C.green("\n✨ Everything is already at the latest version!\n"));
165
- return;
146
+ H.push(e.blocked);
166
147
  }
167
- if (T?.success(`Found ${C.yellow(z.length)} updates available${W.length > 0 ? ` (${C.redBright(W.length)} breaking)` : ""}`), w) {
148
+ z = c;
149
+ }
150
+ z = z.map((e) => r(e, A));
151
+ let U = z.filter((e) => !e.targetRef).map((e) => ({
152
+ ...e,
153
+ skipReason: "unsupported-style",
154
+ status: "skipped",
155
+ hasUpdate: !1
156
+ }));
157
+ R.push(...U), z = z.filter((e) => e.targetRef);
158
+ let W = z.filter((e) => e.isBreaking);
159
+ if (z.length === 0) {
160
+ if (T?.success("All actions are up to date!"), x) {
168
161
  o({
169
162
  actionsToCheckCount: N.length,
170
- status: "updates-available",
163
+ status: "up-to-date",
171
164
  blockedByMode: H,
172
165
  scanResult: l,
173
- outdated: z,
174
166
  skipped: R
175
167
  });
176
168
  return;
177
169
  }
178
- if (R.length > 0 && u(R, O, A), H.length > 0 && g(H, k), b.dryRun) {
179
- console.info(C.yellow("\n📋 Dry Run - No changes will be made\n"));
180
- for (let e of z) {
181
- let t = e.targetRefStyle === "sha" && e.targetRef ? `${e.latestVersion} ${C.gray(`(${e.targetRef.slice(0, 7)})`)}` : e.targetRef ?? e.latestVersion;
182
- console.info(`${C.cyan(e.action.file ?? "unknown")}:\n${e.action.name}: ${C.redBright(e.currentVersion)} → ${C.green(t)}\n`);
183
- }
184
- console.info(C.gray(`\n${z.length} actions would be updated\n`));
170
+ R.length > 0 && u(R, O, A), H.length > 0 && g(H, k), console.info(w.green("\n✨ Everything is already at the latest version!\n"));
171
+ return;
172
+ }
173
+ if (T?.success(`Found ${w.yellow(z.length)} updates available${W.length > 0 ? ` (${w.redBright(W.length)} breaking)` : ""}`), x) {
174
+ o({
175
+ actionsToCheckCount: N.length,
176
+ status: "updates-available",
177
+ blockedByMode: H,
178
+ scanResult: l,
179
+ outdated: z,
180
+ skipped: R
181
+ });
182
+ return;
183
+ }
184
+ if (R.length > 0 && u(R, O, A), H.length > 0 && g(H, k), y.dryRun) {
185
+ console.info(w.yellow("\n📋 Dry Run - No changes will be made\n"));
186
+ for (let e of z) {
187
+ let t = e.targetRefStyle === "sha" && e.targetRef ? `${e.latestVersion} ${w.gray(`(${e.targetRef.slice(0, 7)})`)}` : e.targetRef ?? e.latestVersion;
188
+ console.info(`${w.cyan(e.action.file ?? "unknown")}:\n${e.action.name}: ${w.redBright(e.currentVersion)} → ${w.green(t)}\n`);
189
+ }
190
+ console.info(w.gray(`\n${z.length} actions would be updated\n`));
191
+ return;
192
+ }
193
+ if (y.yes) {
194
+ let e = z.filter((e) => e.targetRef);
195
+ if (e.length === 0) {
196
+ console.info(w.yellow("\n⚠️ No actionable updates available\n"));
185
197
  return;
186
198
  }
187
- if (b.yes) {
188
- let e = z.filter((e) => e.targetRef);
189
- if (e.length === 0) {
190
- console.info(C.yellow("\n⚠️ No actionable updates available\n"));
191
- return;
192
- }
193
- console.info(C.yellow(`\n🔄 Updating ${e.length} actions...\n`)), await c(e), console.info(C.green("\n✓ Updates applied successfully!"));
194
- } else {
195
- (R.length > 0 || H.length > 0) && console.info("");
196
- let e = await n(z, { showAge: b.minAge > 0 });
197
- if (!e || e.length === 0) {
198
- console.info(C.gray("\nNo updates applied"));
199
- return;
200
- }
201
- console.info(C.yellow(`\n🔄 Updating ${e.length} selected actions...\n`)), await c(e), console.info(C.green("\n✓ Updates applied successfully!"));
199
+ console.info(w.yellow(`\n🔄 Updating ${e.length} actions...\n`)), await c(e), console.info(w.green("\n✓ Updates applied successfully!"));
200
+ } else {
201
+ (R.length > 0 || H.length > 0) && console.info("");
202
+ let e = await n(z, { showAge: y.minAge > 0 });
203
+ if (!e || e.length === 0) {
204
+ console.info(w.gray("\nNo updates applied"));
205
+ return;
202
206
  }
203
- } catch (e) {
204
- T?.error("Failed"), e instanceof Error && e.name === "GitHubRateLimitError" ? (console.error(C.yellow("\n⚠️ Rate Limit Exceeded\n")), console.error(e.message), console.error(C.gray("\nExample: GITHUB_TOKEN=ghp_xxxx actions-up\n"))) : console.error(C.redBright("\nError:"), e instanceof Error ? e.message : String(e)), process.exit(1);
207
+ console.info(w.yellow(`\n🔄 Updating ${e.length} selected actions...\n`)), await c(e), console.info(w.green("\n✓ Updates applied successfully!"));
205
208
  }
206
- }), T.parse();
209
+ } catch (e) {
210
+ T?.error("Failed"), e instanceof Error && e.name === "GitHubRateLimitError" ? (console.error(w.yellow("\n⚠️ Rate Limit Exceeded\n")), console.error(e.message), console.error(w.gray("\nExample: GITHUB_TOKEN=ghp_xxxx actions-up\n"))) : console.error(w.redBright("\nError:"), e instanceof Error ? e.message : String(e)), process.exit(1);
211
+ }
207
212
  }
208
213
  export { T as run };
@@ -0,0 +1,74 @@
1
+ /**
2
+ * CLI Options.
3
+ */
4
+ export interface CLIOptions {
5
+ /**
6
+ * Regex patterns to exclude actions by name (repeatable).
7
+ */
8
+ exclude?: string[] | string;
9
+ /**
10
+ * Whether to include branch references in update checks.
11
+ */
12
+ includeBranches?: boolean;
13
+ /**
14
+ * Custom directory name (e.g., '.gitea' instead of '.github').
15
+ */
16
+ dir?: string[] | string;
17
+ /**
18
+ * Recursively scan directories for YAML files.
19
+ */
20
+ recursive?: boolean;
21
+ /**
22
+ * Preview changes without applying them.
23
+ */
24
+ dryRun: boolean;
25
+ /**
26
+ * Update style (sha or preserve).
27
+ */
28
+ style?: string;
29
+ /**
30
+ * Output a machine-readable JSON report.
31
+ */
32
+ json?: boolean;
33
+ /**
34
+ * Minimum age in days for updates.
35
+ */
36
+ minAge: number;
37
+ /**
38
+ * Update mode (major, minor, patch).
39
+ */
40
+ mode?: string;
41
+ /**
42
+ * Skip all confirmations.
43
+ */
44
+ yes: boolean;
45
+ }
46
+ /**
47
+ * Result of parsing CLI arguments. `kind` discriminates what the caller should
48
+ * do next.
49
+ */
50
+ export type ParseArgumentsResult = {
51
+ options: CLIOptions;
52
+ kind: 'options';
53
+ } | {
54
+ message: string;
55
+ kind: 'error';
56
+ } | {
57
+ kind: 'version';
58
+ text: string;
59
+ } | {
60
+ kind: 'help';
61
+ text: string;
62
+ };
63
+ /**
64
+ * Parse CLI arguments into normalized options.
65
+ *
66
+ * Reproduces the previous cac behavior without its runtime magic: numeric
67
+ * coercion for `--min-age` and the option defaults are applied manually here,
68
+ * and kebab-case flags are mapped to the camelCase option shape.
69
+ *
70
+ * @param argv - Raw arguments, typically `process.argv.slice(2)`.
71
+ * @param appVersion - Version string used for `--version`.
72
+ * @returns A discriminated result describing what the caller should do.
73
+ */
74
+ export declare function parseArguments(argv: string[], appVersion: string): ParseArgumentsResult;
@@ -0,0 +1,76 @@
1
+ import { parseArgs as e } from "node:util";
2
+ var t = "Usage:\n $ actions-up [options]\n\nOptions:\n --dir <directory> Directory to scan (repeatable). Default: .github, or . with --recursive\n --dry-run Preview changes without applying them\n --exclude <regex> Exclude actions by regex (repeatable)\n --include-branches Also check actions pinned to branches (default: false)\n --json Output update information as machine-readable JSON\n --min-age <days> Minimum age in days for updates (default: 0)\n --mode <mode> Update mode: major, minor, or patch (default: major)\n --style <style> Update style: sha or preserve (default: sha)\n -r, --recursive Recursively scan directories for YAML files\n -y, --yes Skip all confirmations\n -h, --help Display this message\n -v, --version Display version number", n = {
3
+ exclude: {
4
+ type: "string",
5
+ multiple: !0
6
+ },
7
+ recursive: {
8
+ type: "boolean",
9
+ short: "r"
10
+ },
11
+ version: {
12
+ type: "boolean",
13
+ short: "v"
14
+ },
15
+ "include-branches": { type: "boolean" },
16
+ dir: {
17
+ type: "string",
18
+ multiple: !0
19
+ },
20
+ help: {
21
+ type: "boolean",
22
+ short: "h"
23
+ },
24
+ yes: {
25
+ type: "boolean",
26
+ short: "y"
27
+ },
28
+ "dry-run": { type: "boolean" },
29
+ "min-age": { type: "string" },
30
+ style: { type: "string" },
31
+ json: { type: "boolean" },
32
+ mode: { type: "string" }
33
+ };
34
+ function r(r, i) {
35
+ try {
36
+ let { values: a } = e({
37
+ allowPositionals: !1,
38
+ options: n,
39
+ strict: !0,
40
+ args: r
41
+ });
42
+ if (a.help) return {
43
+ text: t,
44
+ kind: "help"
45
+ };
46
+ if (a.version) return {
47
+ text: `actions-up/${i} ${process.platform}-${process.arch} node-${process.version}`,
48
+ kind: "version"
49
+ };
50
+ let o = a["min-age"], s = o === void 0 ? 0 : Number(o);
51
+ return !Number.isFinite(s) || s < 0 ? {
52
+ message: `Invalid --min-age "${o}". Expected a non-negative number.`,
53
+ kind: "error"
54
+ } : {
55
+ options: {
56
+ includeBranches: a["include-branches"],
57
+ dryRun: a["dry-run"] ?? !1,
58
+ style: a.style ?? "sha",
59
+ mode: a.mode ?? "major",
60
+ recursive: a.recursive,
61
+ yes: a.yes ?? !1,
62
+ exclude: a.exclude,
63
+ json: a.json,
64
+ dir: a.dir,
65
+ minAge: s
66
+ },
67
+ kind: "options"
68
+ };
69
+ } catch (e) {
70
+ return {
71
+ message: e.message,
72
+ kind: "error"
73
+ };
74
+ }
75
+ }
76
+ export { r as parseArguments };
package/dist/package.js CHANGED
@@ -1,2 +1,2 @@
1
- var e = "1.14.2";
1
+ var e = "1.14.3";
2
2
  export { e as version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "actions-up",
3
- "version": "1.14.2",
3
+ "version": "1.14.3",
4
4
  "description": "Interactive CLI tool to update GitHub Actions with SHA pinning or preserved refs",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -36,14 +36,13 @@
36
36
  "./dist"
37
37
  ],
38
38
  "dependencies": {
39
- "cac": "^7.0.0",
40
39
  "enquirer": "^2.4.1",
41
40
  "nanospinner": "^1.2.2",
42
41
  "picocolors": "^1.1.1",
43
- "semver": "^7.8.0",
42
+ "semver": "^7.8.4",
44
43
  "yaml": "^2.9.0"
45
44
  },
46
45
  "engines": {
47
- "node": "^18.0.0 || >=20.0.0"
46
+ "node": "^18.3.0 || >=20.0.0"
48
47
  }
49
48
  }