@kaynooo/cli-doctor 0.2.0 → 0.4.0

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.js CHANGED
@@ -2,16 +2,19 @@
2
2
  // @bun
3
3
 
4
4
  // src/cli.ts
5
- import process7 from "process";
5
+ import process11 from "process";
6
6
 
7
7
  // ../kit/src/args.ts
8
- import process2 from "process";
8
+ import process4 from "process";
9
9
  import { parseArgs } from "util";
10
10
 
11
+ // ../kit/src/format.ts
12
+ import process2 from "process";
13
+
11
14
  // ../kit/src/style.ts
12
15
  import process from "process";
13
16
 
14
- // ../../node_modules/.bun/@kaynooo+utils@2.31.0+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
17
+ // ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
15
18
  function x(s) {
16
19
  let r = s.startsWith("#") ? s.slice(1).toLowerCase() : s.toLowerCase();
17
20
  if (!/^[a-f0-9]+$/.test(r))
@@ -231,7 +234,7 @@ class e {
231
234
  }
232
235
  }
233
236
 
234
- // ../../node_modules/.bun/@kaynooo+utils@2.31.0+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-y1msbssb.js
237
+ // ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-y1msbssb.js
235
238
  var r = 39;
236
239
  var o = 49;
237
240
  var f2 = "\x1B[";
@@ -293,11 +296,102 @@ function upTo(text, separator) {
293
296
  const end = text.indexOf(separator);
294
297
  return end === -1 ? text : text.slice(0, end);
295
298
  }
299
+ function truncate(text, width) {
300
+ return text.length <= width ? text : `${text.slice(0, Math.max(0, width - 1))}\u2026`;
301
+ }
302
+ var LINE_BREAKS = /\s*\n\s*/g;
296
303
  var ESCAPE = String.fromCharCode(27);
304
+ function textWidth(text) {
305
+ return Bun.stringWidth(text);
306
+ }
307
+ function table(rows, { cellWidth, header = false, align = [], fit } = {}) {
308
+ const cells = cellWidth === undefined ? rows : rows.map((row) => row.map((cell) => truncate(cell.replaceAll(LINE_BREAKS, " "), cellWidth)));
309
+ const widths = [];
310
+ for (const row of cells) {
311
+ for (const [index, cell] of row.entries())
312
+ widths[index] = Math.max(widths[index] ?? 0, textWidth(cell));
313
+ }
314
+ const shown = fit === undefined ? cells : narrow(cells, widths, fit);
315
+ const colors = paint(process2.stdout);
316
+ const lines = shown.map((row) => row.map((cell, index) => {
317
+ const width = widths[index] ?? 0;
318
+ const gap = " ".repeat(Math.max(0, width - textWidth(cell)));
319
+ if (align[index] === "right")
320
+ return `${gap}${cell}`;
321
+ return index === row.length - 1 ? cell : `${cell}${gap}`;
322
+ }).join(" ").trimEnd());
323
+ return lines.map((line, index) => header && index === 0 ? colors.bold(line) : line).join(`
324
+ `);
325
+ }
326
+ function narrow(rows, widths, limit) {
327
+ const used = () => widths.reduce((sum, width) => sum + width, 0) + 2 * Math.max(0, widths.length - 1);
328
+ const cuttable = (index) => rows.every((row) => !(row[index] ?? "").includes(ESCAPE));
329
+ const floor = 8;
330
+ while (used() > limit) {
331
+ let widest = -1;
332
+ for (const [index, width] of widths.entries()) {
333
+ if (cuttable(index) && width > floor && width > (widths[widest] ?? 0))
334
+ widest = index;
335
+ }
336
+ if (widest === -1)
337
+ break;
338
+ widths[widest] = Math.max(floor, (widths[widest] ?? 0) - (used() - limit));
339
+ }
340
+ return rows.map((row) => row.map((cell, index) => textWidth(cell) > (widths[index] ?? 0) ? truncate(cell, widths[index] ?? 0) : cell));
341
+ }
297
342
  function printJson(value) {
298
343
  console.log(JSON.stringify(value, undefined, 2));
299
344
  }
300
345
 
346
+ // ../kit/src/help.ts
347
+ import process3 from "process";
348
+ var OPTIONAL = /\[[^\]]+\]/g;
349
+ var USAGE_PREFIX = /^usage:\s*/i;
350
+ var FULL_STOP = /\.$/;
351
+ function usageLine(usage, colors = paint(process3.stdout)) {
352
+ return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
353
+ }
354
+ function helpText(usage, options, colors = paint(process3.stdout), { examples = [], replaces } = {}) {
355
+ return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exampleRows(examples, colors)].join(`
356
+ `);
357
+ }
358
+ function replacesRows(replaces, colors = paint(process3.stdout)) {
359
+ return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
360
+ }
361
+ function wantsHelpJson(env = process3.env) {
362
+ return env.KIT_HELP === "json";
363
+ }
364
+ function description(usage, { examples = [], replaces } = {}) {
365
+ const lines = usage.replace(USAGE_PREFIX, "").split(`
366
+ `);
367
+ const first = lines[0];
368
+ const colon = first.indexOf(": ");
369
+ const prose = lines[lines.indexOf("") + 1] ?? "";
370
+ const fallback = lines.includes("") ? `${prose.charAt(0).toLowerCase()}${prose.slice(1)}`.replace(FULL_STOP, "") : "";
371
+ return {
372
+ synopsis: colon === -1 ? first : first.slice(0, colon),
373
+ summary: colon === -1 ? fallback : first.slice(colon + 2),
374
+ ...replaces === undefined ? {} : { replaces },
375
+ examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] })
376
+ };
377
+ }
378
+ function exampleRows(examples, colors = paint(process3.stdout)) {
379
+ if (examples.length === 0)
380
+ return [];
381
+ return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
382
+ }
383
+ function optionRows(options, colors = paint(process3.stdout)) {
384
+ const rows = Object.entries(options).map(([name, option]) => {
385
+ const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
386
+ const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
387
+ const placeholder = option.optional === undefined ? named : `[${named}]`;
388
+ const value = option.type === "string" ? ` ${colors.dim(placeholder)}` : "";
389
+ return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? placeholder.length + 1 : 0), description: option.description ?? "" };
390
+ });
391
+ const width = Math.max(0, ...rows.map((row) => row.width));
392
+ return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
393
+ }
394
+
301
395
  // ../kit/src/text.ts
302
396
  var ANSI = new RegExp(`${String.fromCharCode(27)}\\[[\\d;?]*[a-z]`, "gi");
303
397
  function distance(a, b) {
@@ -317,8 +411,21 @@ function closest(name, names) {
317
411
  const [best] = names.map((known) => ({ known, far: distance(name, known) })).sort((a, b) => a.far - b.far);
318
412
  return best !== undefined && best.far <= (name.length < 4 ? 1 : 2) ? best.known : undefined;
319
413
  }
414
+ // ../kit/src/input.ts
415
+ var DURATION = /^(\d+(?:\.\d+)?)(ms|[smhd])?$/;
416
+ var UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
417
+ function duration(value, name, fallback, unit = "s") {
418
+ if (value === undefined)
419
+ return fallback;
420
+ const match = DURATION.exec(value.trim());
421
+ const ms = match === null ? 0 : Number(match[1]) * UNIT_MS[match[2] ?? unit];
422
+ if (ms < 1)
423
+ badUsage(`--${name} takes a duration such as 30s, 5m, 1h or 7d, not ${value}`);
424
+ return ms;
425
+ }
320
426
 
321
427
  // ../kit/src/args.ts
428
+ var DASHES = /^-+/;
322
429
  function jsonOption(holds) {
323
430
  return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
324
431
  }
@@ -349,61 +456,20 @@ class HelpShown extends Exit {
349
456
 
350
457
  class Completing {
351
458
  options;
352
- constructor(options) {
459
+ positionals;
460
+ candidates;
461
+ constructor(options, positionals = [], candidates = {}) {
353
462
  this.options = options;
463
+ this.positionals = positionals;
464
+ this.candidates = candidates;
354
465
  }
355
466
  }
356
467
  var completion = { active: false };
357
- var OPTIONAL = /\[[^\]]+\]/g;
358
- var USAGE_PREFIX = /^usage:\s*/i;
359
- var FULL_STOP = /\.$/;
360
- var DASHES = /^-+/;
361
- function usageLine(usage, colors = paint(process2.stdout)) {
362
- return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
363
- }
364
- function helpText(usage, options, colors = paint(process2.stdout), { examples = [], replaces } = {}) {
365
- return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exampleRows(examples, colors)].join(`
366
- `);
367
- }
368
- function replacesRows(replaces, colors = paint(process2.stdout)) {
369
- return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
370
- }
371
- function wantsHelpJson(env = process2.env) {
372
- return env.KIT_HELP === "json";
373
- }
374
- function description(usage, { examples = [], replaces } = {}) {
375
- const lines = usage.replace(USAGE_PREFIX, "").split(`
376
- `);
377
- const first = lines[0];
378
- const colon = first.indexOf(": ");
379
- const prose = lines[lines.indexOf("") + 1] ?? "";
380
- const fallback = lines.includes("") ? `${prose.charAt(0).toLowerCase()}${prose.slice(1)}`.replace(FULL_STOP, "") : "";
381
- return {
382
- synopsis: colon === -1 ? first : first.slice(0, colon),
383
- summary: colon === -1 ? fallback : first.slice(colon + 2),
384
- ...replaces === undefined ? {} : { replaces },
385
- examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] })
386
- };
387
- }
388
- function exampleRows(examples, colors = paint(process2.stdout)) {
389
- if (examples.length === 0)
390
- return [];
391
- return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
392
- }
393
- function optionRows(options, colors = paint(process2.stdout)) {
394
- const rows = Object.entries(options).map(([name, option]) => {
395
- const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
396
- const value = option.type === "string" ? ` ${colors.dim("<value>")}` : "";
397
- return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? " <value>".length : 0), description: option.description ?? "" };
398
- });
399
- const width = Math.max(0, ...rows.map((row) => row.width));
400
- return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
401
- }
402
468
  var OUTPUT_OPTIONS = {
403
469
  color: { type: "string", description: "auto (on a terminal alone), always or never" },
404
470
  plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
405
471
  };
406
- function applyOutput(color, plain, env = process2.env) {
472
+ function applyOutput(color, plain, env = process4.env) {
407
473
  const when = plain === true ? "never" : color ?? "auto";
408
474
  if (when === "auto")
409
475
  return;
@@ -420,14 +486,13 @@ function applyOutput(color, plain, env = process2.env) {
420
486
  function parse(args, usage, options, settings = {}) {
421
487
  const output = Object.fromEntries(Object.entries(OUTPUT_OPTIONS).filter(([name]) => !(name in options)));
422
488
  const all = { ...options, ...output, help: { type: "boolean", short: "h", description: "show this help" } };
489
+ const listing = listed(all, settings.allowNegative === true);
423
490
  if (completion.active)
424
- throw new Completing(all);
425
- const separator = settings.rest === true ? args.indexOf("--") : -1;
426
- const own = separator === -1 ? args : args.slice(0, separator);
427
- const rest = separator === -1 ? undefined : args.slice(separator + 1);
491
+ throw new Completing(listing, settings.positionals, settings.candidates);
492
+ const { own, rest } = settings.trailing === true ? splitTrailing(args, all, settings.positionals?.length ?? 0) : splitRest(args, settings.rest === true);
428
493
  let parsed;
429
494
  try {
430
- parsed = parseArgs({ args: joinDashValues(own, all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
495
+ parsed = parseArgs({ args: joinDashValues(withBare(own, all), all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
431
496
  } catch (error) {
432
497
  const message = parseError(error);
433
498
  throw new UsageError(message, nearestOption(message, all, settings.allowNegative === true));
@@ -435,12 +500,84 @@ function parse(args, usage, options, settings = {}) {
435
500
  const values = parsed.values;
436
501
  applyOutput("color" in output ? values.color : undefined, "plain" in output ? values.plain : undefined);
437
502
  if (values.help === true) {
438
- console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings)) : helpText(usage, all, undefined, settings));
503
+ console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings)) : helpText(usage, listing, undefined, settings));
439
504
  throw new HelpShown;
440
505
  }
506
+ checkChoices(parsed.values, all);
507
+ checkConflicts(parsed.values, all);
441
508
  if (settings.positionals !== undefined)
442
509
  checkPositionals(parsed.positionals, settings.positionals);
443
- return { ...parsed, positionals: parsed.positionals, rest };
510
+ return { ...parsed, values: parsed.values, positionals: parsed.positionals, rest };
511
+ }
512
+ function splitRest(args, passes) {
513
+ const separator = passes ? args.indexOf("--") : -1;
514
+ return { own: separator === -1 ? args : args.slice(0, separator), rest: separator === -1 ? undefined : args.slice(separator + 1) };
515
+ }
516
+ function splitTrailing(args, options, count) {
517
+ const takesValue = (word) => !word.includes("=") && Object.entries(options).some(([name, { short, type }]) => type === "string" && (word === `--${name}` || word === `-${short}`));
518
+ let seen = 0;
519
+ if (count === 0)
520
+ return { own: args, rest: undefined };
521
+ for (let at = 0;at < args.length; at++) {
522
+ const word = args[at];
523
+ if (word === "--")
524
+ break;
525
+ if (word.startsWith("-")) {
526
+ if (takesValue(word))
527
+ at++;
528
+ continue;
529
+ }
530
+ seen++;
531
+ if (seen === count)
532
+ return { own: args.slice(0, at + 1), rest: args.slice(at + 1) };
533
+ }
534
+ return { own: args, rest: undefined };
535
+ }
536
+ function listed(options, allowNegative) {
537
+ if (!allowNegative)
538
+ return options;
539
+ return Object.fromEntries(Object.entries(options).flatMap(([name, option]) => {
540
+ if (option.type !== "boolean" || option.negative === undefined)
541
+ return [[name, option]];
542
+ return [...option.description === undefined ? [] : [[name, option]], [`no-${name}`, { type: "boolean", description: option.negative }]];
543
+ }));
544
+ }
545
+ function withBare(args, options) {
546
+ const bare = new Map(Object.entries(options).flatMap(([name, { short, optional }]) => optional === undefined ? [] : [[`--${name}`, optional], ...short === undefined ? [] : [[`-${short}`, optional]]]));
547
+ if (bare.size === 0)
548
+ return args;
549
+ const separator = args.indexOf("--");
550
+ const own = separator === -1 ? args : args.slice(0, separator);
551
+ return [...own.flatMap((arg, index) => {
552
+ const optional = bare.get(arg);
553
+ const next = own[index + 1];
554
+ const value = next !== undefined && (optional?.accepts === undefined ? !next.startsWith("-") : optional.accepts.test(next));
555
+ return optional === undefined || value ? [arg] : [arg, optional.bare];
556
+ }), ...separator === -1 ? [] : args.slice(separator)];
557
+ }
558
+ function checkConflicts(values, options) {
559
+ const given = (name) => values[name] !== undefined && values[name] !== false;
560
+ for (const [name, { conflicts = [] }] of Object.entries(options)) {
561
+ const other = given(name) ? conflicts.find(given) : undefined;
562
+ if (other !== undefined)
563
+ badUsage(`--${name} cannot be used with --${other}`);
564
+ }
565
+ }
566
+ function checkChoices(values, options) {
567
+ for (const [name, option] of Object.entries(options)) {
568
+ if (option.choices === undefined)
569
+ continue;
570
+ const given = values[name];
571
+ for (const value of Array.isArray(given) ? given : [given]) {
572
+ if (typeof value === "string")
573
+ oneOf(value, name, option.choices);
574
+ }
575
+ }
576
+ }
577
+ function oneOf(value, name, choices) {
578
+ if (!choices.includes(value))
579
+ badUsage(`${name.startsWith("<") ? name : `--${name}`} takes one of ${choices.join(", ")}, not ${value}`);
580
+ return value;
444
581
  }
445
582
  function checkPositionals(given, names) {
446
583
  const variadic = names.at(-1)?.replace("]", "").endsWith("...") === true;
@@ -491,7 +628,7 @@ function nearestOption(message, options, allowNegative) {
491
628
  }
492
629
  // ../kit/src/process.ts
493
630
  import { constants } from "os";
494
- import process3 from "process";
631
+ import process5 from "process";
495
632
  var KILL_GRACE_MS = 2000;
496
633
  function exitCodeOf(code, signal) {
497
634
  if (code !== null)
@@ -511,7 +648,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
511
648
  return;
512
649
  try {
513
650
  if (grouped)
514
- process3.kill(-proc.pid, killing);
651
+ process5.kill(-proc.pid, killing);
515
652
  else
516
653
  proc.kill(killing);
517
654
  } catch {}
@@ -585,14 +722,103 @@ var ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x
585
722
  var RESET_STYLE = `${ESC}[0m`;
586
723
  var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
587
724
  // ../kit/src/cli.ts
588
- import process4 from "process";
725
+ import process7 from "process";
726
+
727
+ // ../kit/src/usage.ts
728
+ import { appendFileSync, mkdirSync } from "fs";
729
+ import { homedir } from "os";
730
+ import { dirname, isAbsolute, join } from "path";
731
+ import process6 from "process";
732
+
733
+ // ../kit/src/logs.ts
734
+ var DAY_MS = 24 * 60 * 60 * 1000;
735
+ var CLI_FOLDER = "kaynooo-cli";
736
+
737
+ // ../kit/src/usage.ts
738
+ var UNKNOWN_OPTION2 = /unknown option '(--[a-z][a-z0-9-]*)[=']/;
739
+ var FLAG_NAME = /^(?:--[a-z][a-z0-9-]*|-[a-zA-Z])$/;
740
+ var LONGEST_NAME = 40;
741
+ var usageError;
742
+ function noteUsageError(message) {
743
+ usageError = message;
744
+ }
745
+ function stateHome(env = process6.env) {
746
+ const dir = env.XDG_STATE_HOME;
747
+ return dir !== undefined && isAbsolute(dir) ? dir : join(homedir(), ".local", "state");
748
+ }
749
+ function usagePath(env = process6.env) {
750
+ return join(stateHome(env), CLI_FOLDER, "usage.jsonl");
751
+ }
752
+ function usageRecorded(env = process6.env) {
753
+ const off = env.KAYNOOO_CLI_NO_USAGE;
754
+ return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
755
+ }
756
+ function flagNames(argv) {
757
+ const end = argv.indexOf("--");
758
+ const names = (end === -1 ? argv : argv.slice(0, end)).filter((word) => word.startsWith("-") && word !== "-").map((word) => word.includes("=") ? word.slice(0, word.indexOf("=")) : word);
759
+ return [...new Set(names)].filter((name) => name.length <= LONGEST_NAME && FLAG_NAME.test(name));
760
+ }
761
+ function usageEntry(bin, command, argv, code, now = new Date) {
762
+ const unknown = code === 2 && usageError !== undefined ? UNKNOWN_OPTION2.exec(usageError)?.[1] : undefined;
763
+ usageError = undefined;
764
+ return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
765
+ }
766
+ function recordUsage(entry, env = process6.env) {
767
+ if (!usageRecorded(env))
768
+ return;
769
+ try {
770
+ const path = usagePath(env);
771
+ mkdirSync(dirname(path), { recursive: true, mode: 448 });
772
+ appendFileSync(path, `${JSON.stringify(entry)}
773
+ `, { mode: 384 });
774
+ } catch {}
775
+ }
776
+ async function readUsage(path = usagePath(), since = 0) {
777
+ const file = Bun.file(path);
778
+ if (!await file.exists())
779
+ return [];
780
+ return (await file.text()).split(`
781
+ `).flatMap((line) => {
782
+ try {
783
+ const entry = JSON.parse(line);
784
+ return Date.parse(entry.at) >= since ? [entry] : [];
785
+ } catch {
786
+ return [];
787
+ }
788
+ });
789
+ }
790
+ function summarizeUsage(entries) {
791
+ const bins = new Map;
792
+ const errors = new Map;
793
+ for (const entry of entries) {
794
+ const bin = bins.get(entry.bin) ?? { runs: 0, failed: 0, usageErrors: 0 };
795
+ bin.runs++;
796
+ bin.failed += entry.code === 0 ? 0 : 1;
797
+ bin.usageErrors += entry.code === 2 ? 1 : 0;
798
+ bins.set(entry.bin, bin);
799
+ if (entry.code === 2 && entry.unknown !== undefined) {
800
+ const key = `${entry.bin} ${entry.command ?? ""} ${entry.unknown}`;
801
+ const error = errors.get(key) ?? { bin: entry.bin, ...entry.command === undefined ? {} : { command: entry.command }, unknown: entry.unknown, count: 0 };
802
+ error.count++;
803
+ errors.set(key, error);
804
+ }
805
+ }
806
+ return {
807
+ runs: entries.length,
808
+ bins: [...bins].map(([bin, counts]) => ({ bin, ...counts })).toSorted((a, b) => b.runs - a.runs),
809
+ usageErrors: [...errors.values()].toSorted((a, b) => b.count - a.count)
810
+ };
811
+ }
812
+
813
+ // ../kit/src/cli.ts
589
814
  var LEVEL_OPTIONS = {
590
815
  ...OUTPUT_OPTIONS,
591
816
  help: { type: "boolean", short: "h", description: "show this help" }
592
817
  };
593
818
  var TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
594
- async function commandRows(commands, colors) {
595
- const width = Math.max(...Object.keys(commands).map((name) => name.length));
819
+ async function commandRows(all, colors) {
820
+ const commands = shown(all);
821
+ const width = Math.max(0, ...Object.keys(commands).map((name) => name.length));
596
822
  const groups = new Map([["Commands:", []]]);
597
823
  const summaries = await Promise.all(Object.values(commands).map(async ({ summary }) => resolveSummary(summary)));
598
824
  for (const [index, [name, { group }]] of Object.entries(commands).entries()) {
@@ -603,6 +829,9 @@ async function commandRows(commands, colors) {
603
829
  }
604
830
  return [...groups].filter(([, rows]) => rows.length > 0).flatMap(([heading, rows], index) => [...index === 0 ? [] : [""], colors.bold(heading), ...rows]);
605
831
  }
832
+ function shown(commands) {
833
+ return Object.fromEntries(Object.entries(commands).filter(([, { hidden }]) => hidden !== true));
834
+ }
606
835
  function takeOutputFlags(argv) {
607
836
  let index = 0;
608
837
  for (;index < argv.length; index++) {
@@ -634,7 +863,7 @@ async function expand(scope, words) {
634
863
  }
635
864
  return { ...scope, commands, lazy: [] };
636
865
  }
637
- async function help({ path, header, summary: lazySummary, commands, defaultCommand, examples, replaces }, stream) {
866
+ async function help2({ path, header, summary: lazySummary, commands, defaultCommand, examples, replaces }, stream) {
638
867
  const colors = paint(stream);
639
868
  const prefix = path.join(" ");
640
869
  const summary = await resolveSummary(lazySummary);
@@ -661,8 +890,8 @@ async function help({ path, header, summary: lazySummary, commands, defaultComma
661
890
  `);
662
891
  }
663
892
  function printError(prefix, message, hint, cause) {
664
- const colors = paint(process4.stderr);
665
- const styled = takesControlCodes(process4.stderr);
893
+ const colors = paint(process7.stderr);
894
+ const styled = takesControlCodes(process7.stderr);
666
895
  const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
667
896
  const under = (label, text, tint) => text === undefined ? "" : `
668
897
  ${styled ? tint(label) : `${label}:`} ${text}`;
@@ -681,6 +910,8 @@ function reportThrown(prefix, error, redact = (text) => text, json = false) {
681
910
  const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
682
911
  const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
683
912
  const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
913
+ if (error instanceof UsageError)
914
+ noteUsageError(error.message);
684
915
  const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
685
916
  report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
686
917
  return error instanceof Exit ? error.code : 1;
@@ -694,12 +925,20 @@ async function dispatch(level, typed, { version, redact }) {
694
925
  return reportThrown(prefix, error);
695
926
  }
696
927
  const [name, ...args] = argv;
928
+ const fallback = level.defaultCommand === undefined ? undefined : level.commands[level.defaultCommand];
929
+ if (name === undefined && level.runBare && fallback !== undefined && "run" in fallback) {
930
+ try {
931
+ return await fallback.run([]);
932
+ } catch (error) {
933
+ return reportThrown(`${prefix} ${level.defaultCommand}`, error, redact, false);
934
+ }
935
+ }
697
936
  if (name === undefined && level.path.length > 1) {
698
- console.error(await help(await expand(level, [...level.path.slice(1), ...argv]), process4.stderr));
937
+ console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process7.stderr));
699
938
  return 2;
700
939
  }
701
940
  if (name === undefined || name === "help" || name === "--help" || name === "-h") {
702
- console.log(await help(await expand(level, [...level.path.slice(1), ...argv]), process4.stdout));
941
+ console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process7.stdout));
703
942
  return 0;
704
943
  }
705
944
  if (level.path.length === 1 && (name === "--version" || name === "-v")) {
@@ -708,6 +947,7 @@ async function dispatch(level, typed, { version, redact }) {
708
947
  }
709
948
  let command = level.commands[level.aliases?.[name] ?? name];
710
949
  let rest = args;
950
+ let ran = name;
711
951
  if (command === undefined && level.lazy.length > 0) {
712
952
  level = await expand(level, [...level.path.slice(1), ...argv]);
713
953
  command = level.commands[level.aliases?.[name] ?? name];
@@ -715,40 +955,77 @@ async function dispatch(level, typed, { version, redact }) {
715
955
  if (command === undefined && level.defaultCommand !== undefined) {
716
956
  command = level.commands[level.defaultCommand];
717
957
  rest = argv;
958
+ ran = level.defaultCommand;
718
959
  }
719
960
  if (command === undefined) {
720
- const meant = closest(name, Object.keys(level.commands));
961
+ const meant = closest(name, Object.keys(shown(level.commands)));
721
962
  printError(prefix, `no command ${name}`, meant === undefined ? `run ${prefix} --help for its commands` : `did you mean ${meant}?`);
722
963
  return 2;
723
964
  }
724
965
  if ("commands" in command) {
725
966
  const { summary } = command;
726
- return dispatch({ path: [...level.path, name], header: (colors, text) => `${colors.bold(`${prefix} ${name}`)} ${text}`, summary, ...scopeOf(command.commands, command.extraCommands, command.aliases), defaultCommand: undefined, examples: command.examples, replaces: undefined }, rest, { version, redact });
967
+ return dispatch({ path: [...level.path, name], header: (colors, text) => `${colors.bold(`${prefix} ${name}`)} ${text}`, summary, ...scopeOf(command.commands, command.extraCommands, command.aliases), defaultCommand: undefined, runBare: false, examples: command.examples, replaces: undefined }, rest, { version, redact });
727
968
  }
728
969
  try {
729
970
  return await command.run(rest);
730
971
  } catch (error) {
731
- return reportThrown(`${prefix} ${name}`, error, redact, wantsJson(rest));
972
+ return reportThrown(`${prefix} ${ran}`, error, redact, wantsJson(rest));
732
973
  }
733
974
  }
734
975
  var COMPLETE = "__complete";
735
976
  var FILES = "__files__";
736
- async function optionsOf(run) {
977
+ async function completingOf(run) {
737
978
  completion.active = true;
738
979
  try {
739
980
  await run([]);
740
981
  } catch (error) {
741
982
  if (error instanceof Completing)
742
- return error.options;
983
+ return error;
743
984
  } finally {
744
985
  completion.active = false;
745
986
  }
746
- return {};
987
+ return new Completing({});
988
+ }
989
+ async function optionsOf(run) {
990
+ return (await completingOf(run)).options;
991
+ }
992
+ function candidateLine(candidate) {
993
+ return typeof candidate === "string" ? candidate : candidate.join("\t");
994
+ }
995
+ function positionalBeingTyped(before, { options, positionals }) {
996
+ const takesValue = (word) => !word.includes("=") && Object.entries(options).some(([name, { short, type }]) => type === "string" && (word === `--${name}` || word === `-${short}`));
997
+ let index = 0;
998
+ let at = 0;
999
+ while (at < before.length) {
1000
+ const word = before[at];
1001
+ if (word === "--") {
1002
+ index += before.length - at - 1;
1003
+ break;
1004
+ }
1005
+ if (!word.startsWith("-"))
1006
+ index++;
1007
+ else if (takesValue(word))
1008
+ at++;
1009
+ at++;
1010
+ }
1011
+ const last = positionals.at(-1);
1012
+ if (index < positionals.length)
1013
+ return positionals[index];
1014
+ return last?.replace("]", "").endsWith("...") === true ? last : undefined;
747
1015
  }
748
1016
  async function leafCandidates(run, words) {
749
- if (!(words.at(-1) ?? "").startsWith("-"))
750
- return [FILES];
751
- return Object.entries(await optionsOf(run)).map(([name, option]) => option.description === undefined ? `--${name}` : `--${name} ${option.description}`);
1017
+ const completing = await completingOf(run);
1018
+ if ((words.at(-1) ?? "").startsWith("-"))
1019
+ return Object.entries(completing.options).map(([name, option]) => option.description === undefined ? `--${name}` : `--${name} ${option.description}`);
1020
+ const flag = words.at(-2);
1021
+ const option = flag?.startsWith("-") === true ? Object.entries(completing.options).find(([name, { short }]) => flag === `--${name}` || flag === `-${short}`)?.[1] : undefined;
1022
+ if (option?.type === "string") {
1023
+ const values = option.choices === undefined ? await option.candidates?.() : option.choices;
1024
+ return values === undefined ? [FILES] : values.map(candidateLine);
1025
+ }
1026
+ const name = positionalBeingTyped(words.slice(0, -1), completing);
1027
+ const values = name === undefined ? undefined : await completing.candidates[name]?.();
1028
+ return values === undefined ? [FILES] : values.map(candidateLine);
752
1029
  }
753
1030
  async function candidates(scope, defaultCommand, words, before = []) {
754
1031
  const [word = "", ...rest] = words;
@@ -759,8 +1036,13 @@ async function candidates(scope, defaultCommand, words, before = []) {
759
1036
  ({ commands, aliases } = await expand(scope, [...before, ...words]));
760
1037
  command = commands[aliases?.[word] ?? word];
761
1038
  }
762
- if (listing)
763
- return Promise.all(Object.entries(commands).map(async ([name, { summary }]) => `${name} ${await resolveSummary(summary)}`));
1039
+ if (listing) {
1040
+ const own = await Promise.all(Object.entries(shown(commands)).map(async ([name, { summary }]) => `${name} ${await resolveSummary(summary)}`));
1041
+ const fallback = defaultCommand === undefined ? undefined : commands[defaultCommand];
1042
+ const values = fallback !== undefined && "run" in fallback ? await leafCandidates(fallback.run, [word]) : [];
1043
+ const valueOf = (line) => line.slice(0, line.includes("\t") ? line.indexOf("\t") : undefined);
1044
+ return [...own, ...values.filter((line) => line !== FILES && !(valueOf(line) in commands))];
1045
+ }
764
1046
  if (command === undefined) {
765
1047
  const fallback = defaultCommand === undefined ? undefined : commands[defaultCommand];
766
1048
  return fallback !== undefined && "run" in fallback ? leafCandidates(fallback.run, words) : [];
@@ -772,26 +1054,49 @@ async function printCandidates(found) {
772
1054
  console.log(line);
773
1055
  return 0;
774
1056
  }
775
- async function runCli(cli, argv = process4.argv.slice(2)) {
1057
+ async function runCli(cli, argv = process7.argv.slice(2)) {
776
1058
  if (argv[0] === COMPLETE)
777
1059
  return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
778
- return dispatch({ path: [cli.name], header: (colors, about) => `${colors.bold(cli.name)} ${colors.dim(cli.version)} ${about}`, summary: cli.about, ...scopeOf(cli.commands, cli.extraCommands, cli.aliases), defaultCommand: cli.defaultCommand, examples: cli.examples, replaces: cli.replaces }, argv, { version: cli.version, redact: cli.redact });
1060
+ const code = await dispatch({ path: [cli.name], header: (colors, about) => `${colors.bold(cli.name)} ${colors.dim(cli.version)} ${about}`, summary: cli.about, ...scopeOf(cli.commands, cli.extraCommands, cli.aliases), defaultCommand: cli.defaultCommand, runBare: cli.runBare === true, examples: cli.examples, replaces: cli.replaces }, argv, { version: cli.version, redact: cli.redact });
1061
+ if (cli.usage !== false) {
1062
+ try {
1063
+ recordUsage(usageEntry(cli.name, commandPath(scopeOf(cli.commands, cli.extraCommands, cli.aliases), argv), argv, code));
1064
+ } catch {}
1065
+ }
1066
+ return code;
1067
+ }
1068
+ function commandPath(scope, argv) {
1069
+ const path = [];
1070
+ let level = scope;
1071
+ for (const word of argv.filter((each) => !each.startsWith("-"))) {
1072
+ const name = level.aliases !== undefined && Object.hasOwn(level.aliases, word) ? level.aliases[word] ?? word : word;
1073
+ const command = Object.hasOwn(level.commands, name) ? level.commands[name] : undefined;
1074
+ if (command === undefined)
1075
+ break;
1076
+ path.push(word);
1077
+ if (!("commands" in command))
1078
+ break;
1079
+ level = scopeOf(command.commands, command.extraCommands, command.aliases);
1080
+ }
1081
+ return path.length === 0 ? undefined : path.join(" ");
779
1082
  }
780
- async function runMain({ name, version, run, redact }, argv = process4.argv.slice(2)) {
1083
+ async function runMain({ name, version, run, redact, usage }, argv = process7.argv.slice(2)) {
781
1084
  if (argv[0] === COMPLETE)
782
1085
  return printCandidates(leafCandidates(run, argv.slice(1)));
783
1086
  if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
784
1087
  console.log(version);
785
1088
  return 0;
786
1089
  }
1090
+ let code;
787
1091
  try {
788
- return await run(argv);
1092
+ code = await run(argv);
789
1093
  } catch (error) {
790
- return reportThrown(name, error, redact, wantsJson(argv));
1094
+ code = reportThrown(name, error, redact, wantsJson(argv));
791
1095
  }
1096
+ if (usage !== false)
1097
+ recordUsage(usageEntry(name, undefined, argv, code));
1098
+ return code;
792
1099
  }
793
- // ../kit/src/logs.ts
794
- var DAY_MS = 24 * 60 * 60 * 1000;
795
1100
  // ../kit/src/secrets.ts
796
1101
  var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
797
1102
  // ../kit/src/sessions.ts
@@ -799,11 +1104,55 @@ var {Glob } = globalThis.Bun;
799
1104
  var SESSION_FILES = new Glob("*.json");
800
1105
  var ACCOUNT_DIRS = new Glob("*/sessions");
801
1106
  // package.json
802
- var version = "0.2.0";
1107
+ var version = "0.4.0";
1108
+
1109
+ // src/checks.ts
1110
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
1111
+ import { basename, join as join3 } from "path";
1112
+
1113
+ // src/completions.ts
1114
+ import { existsSync, mkdirSync as mkdirSync2, readdirSync, readFileSync, rmSync } from "fs";
1115
+ import { join as join2 } from "path";
1116
+ import process9 from "process";
1117
+ var MARKER = "# Generated by `cli completions fish`";
1118
+ var FISH_FILE = /\.fish$/;
1119
+ var FUNCTION = `functions -q __kaynooo_cli_complete; or function __kaynooo_cli_complete --argument-names bin --description 'what a @kaynooo/cli-* bin offers for the word being typed'
1120
+ set -l tokens (commandline -xpc 2>/dev/null; or commandline -opc)
1121
+ set -l current (commandline -ct)
1122
+ for line in ($bin __complete $tokens[2..-1] $current 2>/dev/null)
1123
+ if test "$line" = __files__
1124
+ __fish_complete_path $current
1125
+ else
1126
+ echo $line
1127
+ end
1128
+ end
1129
+ end`;
1130
+ function completionDir(home, env = process9.env) {
1131
+ return join2(env.XDG_CACHE_HOME ?? join2(home, ".cache"), "fish", "kaynooo-cli");
1132
+ }
1133
+ function installedBins(host) {
1134
+ return Object.values(TOOLS).flat().filter((bin) => host.which(bin) !== null);
1135
+ }
1136
+ function completionFile(bin) {
1137
+ return `${MARKER}
1138
+ ${FUNCTION}
1139
+ complete -c ${bin} -f -a '(__kaynooo_cli_complete ${bin})'
1140
+ `;
1141
+ }
1142
+ async function installCompletions(host, dir) {
1143
+ const bins = installedBins(host);
1144
+ mkdirSync2(dir, { recursive: true });
1145
+ const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) && readFileSync(join2(dir, name), "utf8").startsWith(MARKER));
1146
+ for (const name of removed)
1147
+ rmSync(join2(dir, name));
1148
+ await Promise.all(bins.map(async (bin) => Bun.write(join2(dir, `${bin}.fish`), completionFile(bin))));
1149
+ return { written: bins, removed: removed.map((name) => name.replace(FISH_FILE, "")) };
1150
+ }
1151
+ function missingCompletions(host, dir) {
1152
+ return installedBins(host).filter((bin) => !existsSync(join2(dir, `${bin}.fish`)));
1153
+ }
803
1154
 
804
1155
  // src/checks.ts
805
- import { existsSync, readFileSync } from "fs";
806
- import { basename, join } from "path";
807
1156
  var TOOLS = {
808
1157
  "@kaynooo/cli-base": ["base", "proof"],
809
1158
  "@kaynooo/cli-changelog": ["changelog"],
@@ -818,8 +1167,14 @@ var TOOLS = {
818
1167
  "@kaynooo/cli-gitlab": ["gl"],
819
1168
  "@kaynooo/cli-guard": ["guard"],
820
1169
  "@kaynooo/cli-out": ["out"],
1170
+ "@kaynooo/cli-dev": ["dev"],
1171
+ "@kaynooo/cli-pick": ["pick"],
821
1172
  "@kaynooo/cli-pkg": ["pkg"],
1173
+ "@kaynooo/cli-probe": ["probe"],
1174
+ "@kaynooo/cli-repos": ["repos"],
822
1175
  "@kaynooo/cli-stack": ["stack"],
1176
+ "@kaynooo/cli-sweep": ["sweep"],
1177
+ "@kaynooo/cli-view": ["view"],
823
1178
  "@kaynooo/cli-wait": ["waitfor", "slot"]
824
1179
  };
825
1180
  var FORGE = "git.kaynooo.fr";
@@ -837,7 +1192,7 @@ function readJsonText(text) {
837
1192
  }
838
1193
  }
839
1194
  function readJson(path) {
840
- return existsSync(path) ? readJsonText(readFileSync(path, "utf8")) : undefined;
1195
+ return existsSync2(path) ? readJsonText(readFileSync2(path, "utf8")) : undefined;
841
1196
  }
842
1197
  function firstLine(text) {
843
1198
  const trimmed = text.trim();
@@ -846,12 +1201,12 @@ function firstLine(text) {
846
1201
  return end === -1 ? trimmed : trimmed.slice(0, end);
847
1202
  }
848
1203
  function installed(host, name) {
849
- return readJson(join(host.globalModules, name, "package.json"));
1204
+ return readJson(join3(host.globalModules, name, "package.json"));
850
1205
  }
851
1206
  function ownBin(host, name, bin) {
852
1207
  const declared = installed(host, name)?.bin;
853
1208
  const file = typeof declared === "string" ? declared : declared?.[bin];
854
- return file === undefined ? undefined : join(host.globalModules, name, file);
1209
+ return file === undefined ? undefined : join3(host.globalModules, name, file);
855
1210
  }
856
1211
  async function checkTool(host, name, bins) {
857
1212
  const check = name.slice(name.indexOf("/") + 1);
@@ -860,7 +1215,7 @@ async function checkTool(host, name, bins) {
860
1215
  return { check, ok: false, detail: "not installed", fix: `bun install -g ${name}` };
861
1216
  const off = bins.filter((bin) => host.which(bin) === null);
862
1217
  if (off.length > 0)
863
- return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${join(host.globalModules, "..", "..", "..", "bin")} to the PATH` };
1218
+ return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${join3(host.globalModules, "..", "..", "..", "bin")} to the PATH` };
864
1219
  const info = await host.run(["bun", "info", name, "version", "--no-cache"]);
865
1220
  const answered = info.code === 0 ? firstLine(info.stdout.trim().split(`
866
1221
  `).at(-1) ?? "") : "";
@@ -887,9 +1242,9 @@ async function checkTea(host) {
887
1242
  return { check: "tea", ok: true, detail: `logged in to ${forge} as ${login.name}, Forgejo ${served}` };
888
1243
  }
889
1244
  function checkHooks(host) {
890
- const settings = readJson(join(host.home, ".claude", "settings.json")) ?? {};
1245
+ const settings = readJson(join3(host.home, ".claude", "settings.json")) ?? {};
891
1246
  const plugin = settings.enabledPlugins?.[PLUGIN] === true;
892
- const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" && existsSync(join(dir, "hooks", "hooks.json")));
1247
+ const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" && existsSync2(join3(dir, "hooks", "hooks.json")));
893
1248
  if (plugin && mod !== undefined)
894
1249
  return { check: "hooks", ok: false, detail: `both the ${PLUGIN} plugin and the mod in ${mod} run guard, so every call is checked twice`, fix: `claude plugin disable ${PLUGIN}` };
895
1250
  if (plugin)
@@ -905,28 +1260,37 @@ function checkBun(host) {
905
1260
  return { check: "bun", ok: false, detail: `${host.bunVersion}, the tools ask for ${[...new Set(unmet)].join(" and ")}`, fix: "bun upgrade" };
906
1261
  return { check: "bun", ok: true, detail: floors.length === 0 ? host.bunVersion : `${host.bunVersion}, the tools ask for ${[...new Set(floors)].join(" and ")}` };
907
1262
  }
1263
+ function checkCompletions(host) {
1264
+ if (host.which("fish") === null)
1265
+ return { check: "completions", ok: true, detail: "fish is not installed" };
1266
+ const dir = completionDir(host.home);
1267
+ const missing = missingCompletions(host, dir);
1268
+ if (missing.length > 0)
1269
+ return { check: "completions", ok: false, detail: `no fish completion in ${dir} for ${missing.join(", ")}`, fix: "cli completions fish --install" };
1270
+ return { check: "completions", ok: true, detail: dir };
1271
+ }
908
1272
  async function runChecks(host) {
909
1273
  const entries = Object.entries(TOOLS);
910
1274
  const tools = [];
911
1275
  for (let at = 0;at < entries.length; at += INFO_AT_ONCE)
912
1276
  tools.push(...await Promise.all(entries.slice(at, at + INFO_AT_ONCE).map(async ([name, bins]) => checkTool(host, name, bins))));
913
- return [...tools, await checkTea(host), checkHooks(host), checkBun(host)];
1277
+ return [...tools, await checkTea(host), checkHooks(host), checkBun(host), checkCompletions(host)];
914
1278
  }
915
1279
 
916
1280
  // src/host.ts
917
- import { homedir } from "os";
918
- import { join as join2 } from "path";
919
- import process6 from "process";
1281
+ import { homedir as homedir2 } from "os";
1282
+ import { join as join4 } from "path";
1283
+ import process10 from "process";
920
1284
  var RUN_TIMEOUT_MS = 20000;
921
1285
  function hostHere() {
922
- const home = homedir();
1286
+ const home = homedir2();
923
1287
  return {
924
1288
  home,
925
- globalModules: join2(process6.env.BUN_INSTALL ?? join2(home, ".bun"), "install", "global", "node_modules"),
1289
+ globalModules: join4(process10.env.BUN_INSTALL ?? join4(home, ".bun"), "install", "global", "node_modules"),
926
1290
  bunVersion: Bun.version,
927
1291
  which: (bin) => Bun.which(bin),
928
1292
  run: async (argv, env) => {
929
- const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...process6.env, ...env } } });
1293
+ const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...process10.env, ...env } } });
930
1294
  if (ran.timedOut)
931
1295
  return { code: 1, stdout: "", stderr: `timed out after ${RUN_TIMEOUT_MS / 1000}s` };
932
1296
  const of = (stream) => Buffer.concat(ran.chunks.filter((chunk) => chunk.stream === stream).map((chunk) => chunk.data)).toString();
@@ -945,7 +1309,7 @@ var OPTIONS = {
945
1309
  json: jsonOption("[{check, ok, detail, fix?}]")
946
1310
  };
947
1311
  function print(results) {
948
- const { green, red, dim } = paint(process7.stdout);
1312
+ const { green, red, dim } = paint(process11.stdout);
949
1313
  const width = Math.max(...results.map((result) => result.check.length));
950
1314
  for (const { check, ok, detail, fix } of results)
951
1315
  console.log(`${ok ? green("ok ") : red("FAIL")} ${check.padEnd(width)} ${detail}${fix === undefined ? "" : ` ${dim("fix:")} ${fix}`}`);
@@ -964,7 +1328,7 @@ async function main(args, host = hostHere()) {
964
1328
  return results.every((result) => result.ok) ? 0 : 1;
965
1329
  }
966
1330
  if (import.meta.main)
967
- process7.exitCode = await runMain({ name: "doctor", version, run: async (args) => main(args) });
1331
+ process11.exitCode = await runMain({ name: "doctor", version, run: async (args) => main(args) });
968
1332
  export {
969
1333
  main
970
1334
  };