@docker-doctor/cli 0.3.1 → 0.3.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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as runDockerfileRules, c as parseCompose, d as package_default, i as runComposeRules, l as parseDockerfile, n as calculateScore, o as allRules, r as loadConfig, s as findRule, t as toJsonReport, u as discoverProject } from "./src-BOzcDwm-.mjs";
2
+ import { a as runDockerfileRules, c as parseCompose, d as version, i as runComposeRules, l as parseDockerfile, n as calculateScore, o as allRules, r as loadConfig, s as findRule, t as toJsonReport, u as discoverProject } from "./src-BjT5tN_H.mjs";
3
3
  import fs from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import os from "node:os";
@@ -12,11 +12,42 @@ import { Command } from "commander";
12
12
  import { spawn } from "node:child_process";
13
13
  import fs$1 from "node:fs";
14
14
 
15
- //#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
15
+ //#region ../../node_modules/.bun/chalk@6.0.0/node_modules/chalk/source/utilities.js
16
+ function stringReplaceAll(string, substring, postfix) {
17
+ let index = string.indexOf(substring);
18
+ if (index === -1) return string;
19
+ const substringLength = substring.length;
20
+ let endIndex = 0;
21
+ let returnValue = "";
22
+ do {
23
+ returnValue += string.slice(endIndex, index) + substring + postfix;
24
+ endIndex = index + substringLength;
25
+ index = string.indexOf(substring, endIndex);
26
+ } while (index !== -1);
27
+ returnValue += string.slice(endIndex);
28
+ return returnValue;
29
+ }
30
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
31
+ let endIndex = 0;
32
+ let returnValue = "";
33
+ do {
34
+ const isGotCR = string[index - 1] === "\r";
35
+ returnValue += string.slice(endIndex, isGotCR ? index - 1 : index) + prefix + (isGotCR ? "\r\n" : "\n") + postfix;
36
+ endIndex = index + 1;
37
+ index = string.indexOf("\n", endIndex);
38
+ } while (index !== -1);
39
+ returnValue += string.slice(endIndex);
40
+ return returnValue;
41
+ }
42
+
43
+ //#endregion
44
+ //#region ../../node_modules/.bun/chalk@6.0.0/node_modules/chalk/source/vendor/ansi-styles/index.js
16
45
  const ANSI_BACKGROUND_OFFSET = 10;
17
- const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
18
- const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
19
- const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
46
+ const ANSI_UNDERLINE_OFFSET = 20;
47
+ const wrapAnsi16 = (offset = 0) => (code) => `\u{1B}[${code + offset}m`;
48
+ const wrapAnsi256 = (offset = 0) => (code) => `\u{1B}[${38 + offset};5;${code}m`;
49
+ const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u{1B}[${38 + offset};2;${red};${green};${blue}m`;
50
+ const wrapUnderlineAnsi = (code) => `\u{1B}[58;5;${code < 90 ? code - 30 : code - 90 + 8}m`;
20
51
  const styles$1 = {
21
52
  modifier: {
22
53
  reset: [0, 0],
@@ -24,6 +55,10 @@ const styles$1 = {
24
55
  dim: [2, 22],
25
56
  italic: [3, 23],
26
57
  underline: [4, 24],
58
+ underlineDouble: ["4:2", 24],
59
+ underlineCurly: ["4:3", 24],
60
+ underlineDotted: ["4:4", 24],
61
+ underlineDashed: ["4:5", 24],
27
62
  overline: [53, 55],
28
63
  inverse: [7, 27],
29
64
  hidden: [8, 28],
@@ -68,22 +103,43 @@ const styles$1 = {
68
103
  bgMagentaBright: [105, 49],
69
104
  bgCyanBright: [106, 49],
70
105
  bgWhiteBright: [107, 49]
106
+ },
107
+ underlineColor: {
108
+ underlineBlack: ["58;5;0", 59],
109
+ underlineRed: ["58;5;1", 59],
110
+ underlineGreen: ["58;5;2", 59],
111
+ underlineYellow: ["58;5;3", 59],
112
+ underlineBlue: ["58;5;4", 59],
113
+ underlineMagenta: ["58;5;5", 59],
114
+ underlineCyan: ["58;5;6", 59],
115
+ underlineWhite: ["58;5;7", 59],
116
+ underlineBlackBright: ["58;5;8", 59],
117
+ underlineGray: ["58;5;8", 59],
118
+ underlineGrey: ["58;5;8", 59],
119
+ underlineRedBright: ["58;5;9", 59],
120
+ underlineGreenBright: ["58;5;10", 59],
121
+ underlineYellowBright: ["58;5;11", 59],
122
+ underlineBlueBright: ["58;5;12", 59],
123
+ underlineMagentaBright: ["58;5;13", 59],
124
+ underlineCyanBright: ["58;5;14", 59],
125
+ underlineWhiteBright: ["58;5;15", 59]
71
126
  }
72
127
  };
73
128
  const modifierNames = Object.keys(styles$1.modifier);
74
129
  const foregroundColorNames = Object.keys(styles$1.color);
75
130
  const backgroundColorNames = Object.keys(styles$1.bgColor);
131
+ const underlineColorNames = Object.keys(styles$1.underlineColor);
76
132
  const colorNames = [...foregroundColorNames, ...backgroundColorNames];
77
133
  function assembleStyles() {
78
134
  const codes = /* @__PURE__ */ new Map();
79
135
  for (const [groupName, group] of Object.entries(styles$1)) {
80
136
  for (const [styleName, style] of Object.entries(group)) {
81
137
  styles$1[styleName] = {
82
- open: `\u001B[${style[0]}m`,
83
- close: `\u001B[${style[1]}m`
138
+ open: `\u{1B}[${style[0]}m`,
139
+ close: `\u{1B}[${style[1]}m`
84
140
  };
85
141
  group[styleName] = styles$1[styleName];
86
- codes.set(style[0], style[1]);
142
+ codes.set(Number.parseInt(style[0], 10), style[1]);
87
143
  }
88
144
  Object.defineProperty(styles$1, groupName, {
89
145
  value: group,
@@ -96,12 +152,16 @@ function assembleStyles() {
96
152
  });
97
153
  styles$1.color.close = "\x1B[39m";
98
154
  styles$1.bgColor.close = "\x1B[49m";
155
+ styles$1.underlineColor.close = "\x1B[59m";
99
156
  styles$1.color.ansi = wrapAnsi16();
100
157
  styles$1.color.ansi256 = wrapAnsi256();
101
158
  styles$1.color.ansi16m = wrapAnsi16m();
102
159
  styles$1.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
103
160
  styles$1.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
104
161
  styles$1.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
162
+ styles$1.underlineColor.ansi = wrapUnderlineAnsi;
163
+ styles$1.underlineColor.ansi256 = wrapAnsi256(ANSI_UNDERLINE_OFFSET);
164
+ styles$1.underlineColor.ansi16m = wrapAnsi16m(ANSI_UNDERLINE_OFFSET);
105
165
  Object.defineProperties(styles$1, {
106
166
  rgbToAnsi256: {
107
167
  value(red, green, blue) {
@@ -116,7 +176,7 @@ function assembleStyles() {
116
176
  },
117
177
  hexToRgb: {
118
178
  value(hex) {
119
- const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
179
+ const matches = /[\da-f]{6}|[\da-f]{3}/i.exec(hex.toString(16));
120
180
  if (!matches) return [
121
181
  0,
122
182
  0,
@@ -177,7 +237,7 @@ function assembleStyles() {
177
237
  const ansiStyles = assembleStyles();
178
238
 
179
239
  //#endregion
180
- //#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
240
+ //#region ../../node_modules/.bun/chalk@6.0.0/node_modules/chalk/source/vendor/supports-color/index.js
181
241
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
182
242
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
183
243
  const position = argv.indexOf(prefix + flag);
@@ -188,12 +248,15 @@ const { env } = process$1;
188
248
  let flagForceColor;
189
249
  if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
190
250
  else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
251
+ function hasNumericForceColor() {
252
+ return /^\d+$/.test(env.FORCE_COLOR);
253
+ }
191
254
  function envForceColor() {
192
- if ("FORCE_COLOR" in env) {
193
- if (env.FORCE_COLOR === "true") return 1;
194
- if (env.FORCE_COLOR === "false") return 0;
195
- return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
196
- }
255
+ if (!("FORCE_COLOR" in env)) return;
256
+ if (env.FORCE_COLOR === "false") return 0;
257
+ if (env.FORCE_COLOR === "true" || env.FORCE_COLOR.length === 0) return 1;
258
+ if (!hasNumericForceColor()) return;
259
+ return Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
197
260
  }
198
261
  function translateLevel(level) {
199
262
  if (level === 0) return false;
@@ -213,6 +276,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
213
276
  if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) return 3;
214
277
  if (hasFlag("color=256")) return 2;
215
278
  }
279
+ if (forceColor !== void 0 && hasNumericForceColor()) return forceColor;
216
280
  if ("TF_BUILD" in env && "AGENT_NAME" in env) return 1;
217
281
  if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
218
282
  const min = forceColor || 0;
@@ -237,19 +301,19 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
237
301
  ].some((sign) => sign in env) || env.CI_NAME === "codeship") return 1;
238
302
  return min;
239
303
  }
240
- if ("TEAMCITY_VERSION" in env) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
304
+ if ("TEAMCITY_VERSION" in env) return /^(?:9\.0*[1-9]\d*\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
241
305
  if (env.COLORTERM === "truecolor") return 3;
242
306
  if (env.TERM === "xterm-kitty") return 3;
243
307
  if (env.TERM === "xterm-ghostty") return 3;
244
308
  if (env.TERM === "wezterm") return 3;
245
309
  if ("TERM_PROGRAM" in env) {
246
- const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
310
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".", 1)[0], 10);
247
311
  switch (env.TERM_PROGRAM) {
248
312
  case "iTerm.app": return version >= 3 ? 3 : 2;
249
313
  case "Apple_Terminal": return 2;
250
314
  }
251
315
  }
252
- if (/-256(color)?$/i.test(env.TERM)) return 2;
316
+ if (/-256(?:color)?$/i.test(env.TERM)) return 2;
253
317
  if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) return 1;
254
318
  if ("COLORTERM" in env) return 1;
255
319
  return min;
@@ -266,51 +330,30 @@ const supportsColor = {
266
330
  };
267
331
 
268
332
  //#endregion
269
- //#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js
270
- function stringReplaceAll(string, substring, replacer) {
271
- let index = string.indexOf(substring);
272
- if (index === -1) return string;
273
- const substringLength = substring.length;
274
- let endIndex = 0;
275
- let returnValue = "";
276
- do {
277
- returnValue += string.slice(endIndex, index) + substring + replacer;
278
- endIndex = index + substringLength;
279
- index = string.indexOf(substring, endIndex);
280
- } while (index !== -1);
281
- returnValue += string.slice(endIndex);
282
- return returnValue;
283
- }
284
- function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
285
- let endIndex = 0;
286
- let returnValue = "";
287
- do {
288
- const gotCR = string[index - 1] === "\r";
289
- returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
290
- endIndex = index + 1;
291
- index = string.indexOf("\n", endIndex);
292
- } while (index !== -1);
293
- returnValue += string.slice(endIndex);
294
- return returnValue;
295
- }
296
-
297
- //#endregion
298
- //#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/index.js
333
+ //#region ../../node_modules/.bun/chalk@6.0.0/node_modules/chalk/source/index.js
299
334
  const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
300
335
  const GENERATOR = Symbol("GENERATOR");
301
336
  const STYLER = Symbol("STYLER");
302
337
  const IS_EMPTY = Symbol("IS_EMPTY");
303
- const levelMapping = [
304
- "ansi",
305
- "ansi",
306
- "ansi256",
307
- "ansi16m"
308
- ];
338
+ const LEVEL = Symbol("LEVEL");
309
339
  const styles = Object.create(null);
340
+ const assertValidLevel = (level) => {
341
+ if (!Number.isSafeInteger(level) || level < 0 || level > 3) throw new Error("The `level` should be an integer from 0 to 3");
342
+ };
343
+ const levelDescriptor = {
344
+ enumerable: true,
345
+ get() {
346
+ return this[LEVEL];
347
+ },
348
+ set(level) {
349
+ assertValidLevel(level);
350
+ this[LEVEL] = level;
351
+ }
352
+ };
310
353
  const applyOptions = (object, options = {}) => {
311
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) throw new Error("The `level` option should be an integer from 0 to 3");
354
+ if (options.level !== void 0) assertValidLevel(options.level);
312
355
  const colorLevel = stdoutColor ? stdoutColor.level : 0;
313
- object.level = options.level === void 0 ? colorLevel : options.level;
356
+ object[LEVEL] = options.level === void 0 ? colorLevel : options.level;
314
357
  };
315
358
  const chalkFactory = (options) => {
316
359
  const chalk = (...strings) => strings.join(" ");
@@ -332,35 +375,58 @@ styles.visible = { get() {
332
375
  Object.defineProperty(this, "visible", { value: builder });
333
376
  return builder;
334
377
  } };
335
- const getModelAnsi = (model, level, type, ...arguments_) => {
378
+ const createModelConverters = (model, type) => {
379
+ const style = ansiStyles[type];
336
380
  if (model === "rgb") {
337
- if (level === "ansi16m") return ansiStyles[type].ansi16m(...arguments_);
338
- if (level === "ansi256") return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
339
- return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
381
+ const ansi = (red, green, blue) => style.ansi(ansiStyles.rgbToAnsi(red, green, blue));
382
+ const ansi256 = (red, green, blue) => style.ansi256(ansiStyles.rgbToAnsi256(red, green, blue));
383
+ return [
384
+ ansi,
385
+ ansi,
386
+ ansi256,
387
+ style.ansi16m
388
+ ];
389
+ }
390
+ if (model === "hex") {
391
+ const ansi = (hex) => style.ansi(ansiStyles.hexToAnsi(hex));
392
+ const ansi256 = (hex) => style.ansi256(ansiStyles.hexToAnsi256(hex));
393
+ return [
394
+ ansi,
395
+ ansi,
396
+ ansi256,
397
+ (hex) => style.ansi16m(...ansiStyles.hexToRgb(hex))
398
+ ];
340
399
  }
341
- if (model === "hex") return getModelAnsi("rgb", level, type, ...ansiStyles.hexToRgb(...arguments_));
342
- return ansiStyles[type][model](...arguments_);
400
+ const ansi = (code) => style.ansi(ansiStyles.ansi256ToAnsi(code));
401
+ return [
402
+ ansi,
403
+ ansi,
404
+ style.ansi256,
405
+ style.ansi256
406
+ ];
343
407
  };
344
408
  for (const model of [
345
409
  "rgb",
346
410
  "hex",
347
411
  "ansi256"
348
412
  ]) {
349
- styles[model] = { get() {
350
- const { level } = this;
351
- return function(...arguments_) {
352
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansiStyles.color.close, this[STYLER]);
353
- return createBuilder(this, styler, this[IS_EMPTY]);
354
- };
355
- } };
356
- const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
357
- styles[bgModel] = { get() {
358
- const { level } = this;
359
- return function(...arguments_) {
360
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansiStyles.bgColor.close, this[STYLER]);
361
- return createBuilder(this, styler, this[IS_EMPTY]);
362
- };
363
- } };
413
+ const capitalizedModel = model[0].toUpperCase() + model.slice(1);
414
+ for (const [styleName, type] of [
415
+ [model, "color"],
416
+ ["bg" + capitalizedModel, "bgColor"],
417
+ ["underline" + capitalizedModel, "underlineColor"]
418
+ ]) {
419
+ const { close } = ansiStyles[type];
420
+ const converters = createModelConverters(model, type);
421
+ styles[styleName] = { get() {
422
+ const styleFunction = function(first, second, third) {
423
+ const open = converters[this.level](first, second, third);
424
+ return createBuilder(this, createStyler(open, close, this[STYLER]), this[IS_EMPTY]);
425
+ };
426
+ Object.defineProperty(this, styleName, { value: styleFunction });
427
+ return styleFunction;
428
+ } };
429
+ }
364
430
  }
365
431
  const proto = Object.defineProperties(() => {}, {
366
432
  ...styles,
@@ -393,15 +459,19 @@ const createStyler = (open, close, parent) => {
393
459
  };
394
460
  };
395
461
  const createBuilder = (self, _styler, _isEmpty) => {
396
- const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
462
+ const builder = (...arguments_) => {
463
+ if (arguments_.length === 1) return applyStyle(builder, "" + arguments_[0]);
464
+ if (arguments_.length === 2) return applyStyle(builder, arguments_[0] + " " + arguments_[1]);
465
+ return applyStyle(builder, arguments_.join(" "));
466
+ };
397
467
  Object.setPrototypeOf(builder, proto);
398
- builder[GENERATOR] = self;
468
+ builder[GENERATOR] = self[GENERATOR] ?? self;
399
469
  builder[STYLER] = _styler;
400
470
  builder[IS_EMPTY] = _isEmpty;
401
471
  return builder;
402
472
  };
403
473
  const applyStyle = (self, string) => {
404
- if (self.level <= 0 || !string) return self[IS_EMPTY] ? "" : string;
474
+ if (self[GENERATOR][LEVEL] <= 0 || !string) return self[IS_EMPTY] ? "" : string;
405
475
  let styler = self[STYLER];
406
476
  if (styler === void 0) return string;
407
477
  const { openAll, closeAll } = styler;
@@ -413,7 +483,10 @@ const applyStyle = (self, string) => {
413
483
  if (lfIndex !== -1) string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
414
484
  return openAll + string + closeAll;
415
485
  };
416
- Object.defineProperties(createChalk.prototype, styles);
486
+ Object.defineProperties(createChalk.prototype, {
487
+ ...styles,
488
+ level: levelDescriptor
489
+ });
417
490
  const chalk = createChalk();
418
491
  const chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
419
492
 
@@ -819,6 +892,7 @@ const formatTerminal = async (diagnostics, score, label, project, verbose = fals
819
892
 
820
893
  //#endregion
821
894
  //#region src/cli.ts
895
+ const ACTION_REF = "PunGrumpy/docker-doctor@v1";
822
896
  const askConfirm = (question, defaultYes = false) => {
823
897
  if (!process.stdin.isTTY) return Promise.resolve(defaultYes);
824
898
  return new Promise((resolve) => {
@@ -1024,26 +1098,24 @@ const runInteractiveWizard = async (context) => {
1024
1098
  const workflowDir = path.resolve(".github/workflows");
1025
1099
  await fs.mkdir(workflowDir, { recursive: true });
1026
1100
  const workflowPath = path.join(workflowDir, "docker-doctor.yml");
1027
- await fs.writeFile(workflowPath, `name: Docker Doctor Scan
1101
+ const workflowYaml = `name: Docker Doctor
1028
1102
  on:
1029
- push:
1030
- branches: [ main, master ]
1031
1103
  pull_request:
1032
- branches: [ main, master ]
1104
+ permissions:
1105
+ contents: read
1106
+ pull-requests: write
1107
+ issues: write
1033
1108
  jobs:
1034
1109
  docker-doctor:
1035
1110
  runs-on: ubuntu-latest
1036
1111
  steps:
1037
- - uses: actions/checkout@v4
1038
- - name: Setup Bun
1039
- uses: oven-sh/setup-bun@v2
1040
- - name: Install dependencies
1041
- run: bun install
1042
- - name: Run docker-doctor
1043
- run: bunx docker-doctor .
1044
- `, "utf-8");
1112
+ - uses: actions/checkout@v5
1113
+ - uses: ${ACTION_REF}
1114
+ `;
1115
+ await fs.writeFile(workflowPath, workflowYaml, "utf-8");
1045
1116
  console.log(`\n ${chalk.green("✨")} Created ${chalk.cyan(".github/workflows/docker-doctor.yml")}!`);
1046
- console.log(` Scan every pull request to prevent new Docker issues while you fix the backlog.`);
1117
+ console.log(` Every pull request gets a scan and a sticky summary comment advisory by default.`);
1118
+ console.log(` Inputs and gating: ${chalk.cyan("https://docker-doctor.vercel.app/docs/guides/github-actions")}`);
1047
1119
  }
1048
1120
  if (context.diagnostics.length === 0) return;
1049
1121
  await runAgentHandoff(context);
@@ -1099,7 +1171,7 @@ const filterDiagnostics = (diagnostics, categories) => {
1099
1171
  });
1100
1172
  };
1101
1173
  const program = new Command();
1102
- program.name("docker-doctor").description("Static analysis for Dockerfile and Docker Compose files").version(package_default.version, "-V, --version", "display the version number");
1174
+ program.name("docker-doctor").description("Static analysis for Dockerfile and Docker Compose files").version(version, "-V, --version", "display the version number");
1103
1175
  program.argument("[dir]", "directory to scan", ".").option("-v, --verbose", "show verbose diagnostics description", false).option("-s, --score", "only output numeric health score", false).option("-j, --json", "output results as JSON report", false).option("-c, --config <path>", "custom config file path").action(async (dir, options) => {
1104
1176
  const isSilent = options.score || options.json;
1105
1177
  const restoreCursor = () => {