@kaynooo/cli-doctor 0.11.0 → 0.13.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,13 +2,13 @@
2
2
  // @bun
3
3
 
4
4
  // src/cli.ts
5
- import process18 from "process";
5
+ import process20 from "process";
6
6
  // ../kit/src/args.ts
7
- import process7 from "process";
7
+ import process9 from "process";
8
8
  import { parseArgs } from "util";
9
9
 
10
10
  // ../kit/src/format.ts
11
- import process5 from "process";
11
+ import process7 from "process";
12
12
 
13
13
  // ../kit/src/mode.ts
14
14
  import process2 from "process";
@@ -32,7 +32,7 @@ function isInteractive(streams = process2) {
32
32
  }
33
33
 
34
34
  // ../kit/src/style.ts
35
- import process4 from "process";
35
+ import process6 from "process";
36
36
 
37
37
  // ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
38
38
  function x(s) {
@@ -295,28 +295,188 @@ function le(i = {}) {
295
295
  }
296
296
  var t = le();
297
297
 
298
+ // ../kit/src/theme.ts
299
+ import { existsSync as existsSync3, readFileSync, statSync } from "fs";
300
+ import { homedir as homedir2 } from "os";
301
+ import { join as join3, resolve as resolve2 } from "path";
302
+ import process5 from "process";
303
+
304
+ // ../kit/src/config.ts
305
+ import { existsSync } from "fs";
306
+ import { dirname, join, resolve } from "path";
307
+ import process3 from "process";
308
+ function findUp(names, from = process3.cwd(), stop = () => false) {
309
+ const wanted = typeof names === "string" ? [names] : names;
310
+ for (let dir = resolve(from);; dir = dirname(dir)) {
311
+ const found = wanted.map((name) => join(dir, name)).find((path) => existsSync(path));
312
+ if (found !== undefined)
313
+ return found;
314
+ if (stop(dir) || dirname(dir) === dir)
315
+ return;
316
+ }
317
+ }
318
+
298
319
  // ../kit/src/user-config.ts
320
+ import { existsSync as existsSync2 } from "fs";
299
321
  import { homedir } from "os";
300
- import { join } from "path";
301
- import process3 from "process";
322
+ import { join as join2 } from "path";
323
+ import process4 from "process";
302
324
  function configBase(where = {}) {
303
- const xdg = where.xdg ?? (where.home === undefined ? process3.env.XDG_CONFIG_HOME : undefined);
304
- return xdg !== undefined && xdg !== "" ? xdg : join(where.home ?? homedir(), ".config");
325
+ const xdg = where.xdg ?? (where.home === undefined ? process4.env.XDG_CONFIG_HOME : undefined);
326
+ return xdg !== undefined && xdg !== "" ? xdg : join2(where.home ?? homedir(), ".config");
305
327
  }
306
328
  function userConfigPath(bin, where = {}) {
307
- return join(configBase(where), "kaynooo-cli", `${bin}.json`);
329
+ return join2(configBase(where), "kaynooo-cli", `${bin}.json`);
330
+ }
331
+ function userConfigReadPath(bin, legacy = [], where = {}) {
332
+ const current = userConfigPath(bin, where);
333
+ if (existsSync2(current))
334
+ return current;
335
+ const base = configBase(where);
336
+ return legacy.map((parts) => join2(base, ...parts)).find((path) => existsSync2(path)) ?? current;
308
337
  }
309
338
 
310
339
  // ../kit/src/theme.ts
340
+ var DEFAULT = {
341
+ colors: { accent: "cyan", id: "yellow", path: "blue", label: "dim", value: "bold", ok: "green", warn: "yellow", problem: "red", note: "dim", passed: "green", failed: "red", running: "cyan", queued: "yellow", skipped: "dim" },
342
+ glyphs: { ok: "\u2713", warn: "\u25B2", problem: "\u2717", note: "\u203A", passed: "\u2713", failed: "\u2717", running: "\u25CF", queued: "\u25CB", skipped: "-", bar: "\u2501" },
343
+ accents: ["cyan", "magenta", "green", "blue", "yellow", "redBright"],
344
+ bins: {}
345
+ };
346
+ var BRIGHT = { accent: "cyanBright", id: "yellowBright", path: "blueBright", label: "white", value: "bold whiteBright", ok: "greenBright", warn: "yellowBright", problem: "redBright", note: "white", passed: "greenBright", failed: "redBright", running: "cyanBright", queued: "yellowBright", skipped: "white" };
347
+ var MONO = { accent: "bold", id: "bold", path: "underline", label: "dim", value: "bold", ok: "bold", warn: "bold", problem: "bold", note: "dim", passed: "bold", failed: "bold", running: "bold", queued: "dim", skipped: "dim" };
348
+ var ASCII = { ok: "+", warn: "!", problem: "x", note: ">", passed: "+", failed: "x", running: "*", queued: "o", skipped: "-", bar: "#" };
349
+ var PRESETS = {
350
+ default: {},
351
+ "high-contrast": { colors: BRIGHT, accents: ["cyanBright", "magentaBright", "greenBright", "blueBright", "yellowBright", "redBright"] },
352
+ mono: { colors: MONO, accents: ["bold"] },
353
+ ascii: { glyphs: ASCII }
354
+ };
311
355
  var STYLES = new Set(["bold", "dim", "italic", "underline", "inverse", "strikethrough", "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "gray", "grey", "blackBright", "redBright", "greenBright", "yellowBright", "blueBright", "magentaBright", "cyanBright", "whiteBright"]);
356
+ var HEX = /^#[0-9a-f]{6}$/i;
357
+ var CONTROL = /\p{Cc}/u;
312
358
  var MAX_FILE_BYTES = 64 * 1024;
359
+ var SPACES = /\s+/;
360
+ function isColorSpec(spec) {
361
+ if (typeof spec === "number")
362
+ return Number.isInteger(spec) && spec >= 0 && spec <= 255;
363
+ return typeof spec === "string" && spec.trim() !== "" && spec.trim().split(SPACES).every((token) => STYLES.has(token) || HEX.test(token));
364
+ }
365
+ function isRecord(value) {
366
+ return typeof value === "object" && value !== null && !Array.isArray(value);
367
+ }
368
+ function readThemeFile(path, warn) {
369
+ try {
370
+ const stat = statSync(path, { throwIfNoEntry: false });
371
+ if (stat === undefined)
372
+ return;
373
+ if (!stat.isFile() || stat.size > MAX_FILE_BYTES) {
374
+ warn(`${path} is not a regular file under ${MAX_FILE_BYTES / 1024} KiB, theme ignored`);
375
+ return;
376
+ }
377
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
378
+ if (isRecord(parsed))
379
+ return parsed;
380
+ warn(`${path} is not a JSON object, theme ignored`);
381
+ } catch (error) {
382
+ warn(`${path} does not parse (${error instanceof Error ? error.message : String(error)}), theme ignored`);
383
+ }
384
+ return;
385
+ }
386
+ function applyPreset(theme, name, warn, where) {
387
+ if (name === undefined)
388
+ return;
389
+ if (typeof name !== "string" || !Object.hasOwn(PRESETS, name)) {
390
+ warn(`${where}: no preset ${String(name)}, one of ${Object.keys(PRESETS).join(", ")}`);
391
+ return;
392
+ }
393
+ const preset = PRESETS[name];
394
+ Object.assign(theme.colors, preset.colors);
395
+ Object.assign(theme.glyphs, preset.glyphs);
396
+ if (preset.accents !== undefined)
397
+ theme.accents = [...preset.accents];
398
+ return name;
399
+ }
400
+ function applyFile(theme, file, where, warn) {
401
+ if (isRecord(file.colors)) {
402
+ for (const [key, value] of Object.entries(file.colors)) {
403
+ if (!Object.hasOwn(DEFAULT.colors, key))
404
+ warn(`${where}: no colour ${key}, one of ${Object.keys(DEFAULT.colors).join(", ")}`);
405
+ else if (!isColorSpec(value))
406
+ warn(`${where}: colour ${key} is not an ANSI name, \`#rrggbb\` or a number up to 255`);
407
+ else
408
+ theme.colors[key] = value;
409
+ }
410
+ }
411
+ if (isRecord(file.glyphs)) {
412
+ for (const [key, value] of Object.entries(file.glyphs)) {
413
+ if (!Object.hasOwn(DEFAULT.glyphs, key))
414
+ warn(`${where}: no glyph ${key}, one of ${Object.keys(DEFAULT.glyphs).join(", ")}`);
415
+ else if (typeof value !== "string" || CONTROL.test(value) || Bun.stringWidth(value) !== 1)
416
+ warn(`${where}: glyph ${key} must be one visible character wide, with no control character`);
417
+ else
418
+ theme.glyphs[key] = value;
419
+ }
420
+ }
421
+ if (Array.isArray(file.accents) && file.accents.length > 0 && file.accents.every(isColorSpec))
422
+ theme.accents = [...file.accents];
423
+ else if (file.accents !== undefined)
424
+ warn(`${where}: accents must be a non-empty list of colours`);
425
+ if (isRecord(file.bins)) {
426
+ for (const [bin, value] of Object.entries(file.bins)) {
427
+ if (isColorSpec(value))
428
+ theme.bins[bin] = value;
429
+ else
430
+ warn(`${where}: bin ${bin} has no valid colour`);
431
+ }
432
+ }
433
+ }
434
+ function endsWalk(home) {
435
+ return (dir) => dir === resolve2(home) || existsSync3(join3(dir, ".git"));
436
+ }
313
437
  var warned = new Set;
438
+ function warnOnce(message) {
439
+ if (warned.has(message))
440
+ return;
441
+ warned.add(message);
442
+ console.error(`warning: theme ${message}`);
443
+ }
444
+ function isPath(chosen) {
445
+ return chosen.includes("/") || chosen.endsWith(".json");
446
+ }
447
+ function loadTheme({ env = process5.env, from = process5.cwd(), home = homedir2(), warn = warnOnce } = {}) {
448
+ const theme = { colors: { ...DEFAULT.colors }, glyphs: { ...DEFAULT.glyphs }, accents: [...DEFAULT.accents], bins: Object.create(null) };
449
+ const sources = [];
450
+ const chosen = env.KIT_THEME ?? "";
451
+ const wanted = chosen === "" ? [userConfigPath("theme", { home, xdg: env.XDG_CONFIG_HOME }), findUp(join3(".kaynooo", "theme.json"), from, endsWalk(home))] : [];
452
+ if (isPath(chosen))
453
+ wanted.push(resolve2(from, chosen));
454
+ const files = [];
455
+ for (const path of wanted) {
456
+ const file = path === undefined ? undefined : readThemeFile(path, warn);
457
+ if (path !== undefined && file !== undefined)
458
+ files.push({ path, file });
459
+ }
460
+ let preset = "default";
461
+ if (chosen !== "" && !isPath(chosen)) {
462
+ preset = applyPreset(theme, chosen, warn, "KIT_THEME") ?? preset;
463
+ } else {
464
+ const named = files.findLast(({ file }) => file.preset !== undefined);
465
+ if (named !== undefined)
466
+ preset = applyPreset(theme, named.file.preset, warn, named.path) ?? preset;
467
+ }
468
+ for (const { path, file } of files) {
469
+ applyFile(theme, file, path, warn);
470
+ sources.push(path);
471
+ }
472
+ return { theme, sources, preset };
473
+ }
314
474
 
315
475
  // ../kit/src/style.ts
316
- function takesControlCodes(stream, env = process4.env) {
476
+ function takesControlCodes(stream, env = process6.env) {
317
477
  return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb" && outputMode(stream, env) === "terminal";
318
478
  }
319
- function paint(stream, env = process4.env) {
479
+ function paint(stream, env = process6.env) {
320
480
  return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
321
481
  }
322
482
  var STATUS_WORDS = {
@@ -341,7 +501,7 @@ var ESCAPE = String.fromCharCode(27);
341
501
  function textWidth(text) {
342
502
  return Bun.stringWidth(text);
343
503
  }
344
- function table(rows, { cellWidth, header = false, align = [], fit, stream = process5.stdout, env = process5.env } = {}) {
504
+ function table(rows, { cellWidth, header = false, align = [], fit, stream = process7.stdout, env = process7.env } = {}) {
345
505
  const cells = cellWidth === undefined ? rows : rows.map((row) => row.map((cell) => truncate(cell.replaceAll(LINE_BREAKS, " "), cellWidth)));
346
506
  if (outputMode(stream, env) === "agent")
347
507
  return cells.map((row) => row.map((cell) => Bun.stripANSI(cell).replaceAll(/[\t\r\n]+/g, " ")).join("\t")).join(`
@@ -380,7 +540,7 @@ function narrow(rows, widths, limit) {
380
540
  }
381
541
  return rows.map((row) => row.map((cell, index) => textWidth(cell) > (widths[index] ?? 0) ? truncate(cell, widths[index] ?? 0) : cell));
382
542
  }
383
- function jsonText(value, replacer, { stream = process5.stdout, env = process5.env } = {}) {
543
+ function jsonText(value, replacer, { stream = process7.stdout, env = process7.env } = {}) {
384
544
  return JSON.stringify(value, replacer, outputMode(stream, env) === "agent" ? undefined : 2);
385
545
  }
386
546
  function printJson(value) {
@@ -388,27 +548,27 @@ function printJson(value) {
388
548
  }
389
549
 
390
550
  // ../kit/src/help.ts
391
- import process6 from "process";
551
+ import process8 from "process";
392
552
  var OPTIONAL = /\[[^\]]+\]/g;
393
553
  var USAGE_PREFIX = /^usage:\s*/i;
394
554
  var FULL_STOP = /\.$/;
395
- function usageLine(usage, colors = paint(process6.stdout)) {
555
+ function usageLine(usage, colors = paint(process8.stdout)) {
396
556
  return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
397
557
  }
398
- function helpText(usage, options, colors = paint(process6.stdout), { examples = [], replaces, exits = [] } = {}) {
558
+ function helpText(usage, options, colors = paint(process8.stdout), { examples = [], replaces, exits = [] } = {}) {
399
559
  return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
400
560
  `);
401
561
  }
402
- function exitRows(exits, colors = paint(process6.stdout)) {
562
+ function exitRows(exits, colors = paint(process8.stdout)) {
403
563
  if (exits.length === 0)
404
564
  return [];
405
565
  const width = Math.max(...exits.map(([code]) => String(code).length));
406
566
  return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
407
567
  }
408
- function replacesRows(replaces, colors = paint(process6.stdout)) {
568
+ function replacesRows(replaces, colors = paint(process8.stdout)) {
409
569
  return replaces === undefined || outputMode() === "agent" ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
410
570
  }
411
- function wantsHelpJson(env = process6.env) {
571
+ function wantsHelpJson(env = process8.env) {
412
572
  return env.KIT_HELP === "json";
413
573
  }
414
574
  function description(usage, { examples = [], replaces, exits } = {}, options) {
@@ -427,12 +587,12 @@ function description(usage, { examples = [], replaces, exits } = {}, options) {
427
587
  ...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
428
588
  };
429
589
  }
430
- function exampleRows(examples, colors = paint(process6.stdout)) {
590
+ function exampleRows(examples, colors = paint(process8.stdout)) {
431
591
  if (examples.length === 0 || outputMode() === "agent")
432
592
  return [];
433
593
  return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
434
594
  }
435
- function optionRows(options, colors = paint(process6.stdout)) {
595
+ function optionRows(options, colors = paint(process8.stdout)) {
436
596
  const rows = Object.entries(options).map(([name, option]) => {
437
597
  const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
438
598
  const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
@@ -524,7 +684,7 @@ var OUTPUT_OPTIONS = {
524
684
  color: { type: "string", description: "auto (on a terminal alone), always or never" },
525
685
  plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
526
686
  };
527
- function applyOutput(color, plain, env = process7.env) {
687
+ function applyOutput(color, plain, env = process9.env) {
528
688
  const when = plain === true ? "never" : color ?? "auto";
529
689
  if (when === "auto")
530
690
  return;
@@ -695,7 +855,7 @@ function nearestOption(message, options, allowNegative) {
695
855
  }
696
856
  // ../kit/src/process.ts
697
857
  import { constants } from "os";
698
- import process8 from "process";
858
+ import process10 from "process";
699
859
  var KILL_GRACE_MS = 2000;
700
860
  function exitCodeOf(code, signal) {
701
861
  if (code !== null)
@@ -715,7 +875,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
715
875
  return;
716
876
  try {
717
877
  if (grouped)
718
- process8.kill(-proc.pid, killing);
878
+ process10.kill(-proc.pid, killing);
719
879
  else
720
880
  proc.kill(killing);
721
881
  } catch {}
@@ -789,15 +949,15 @@ var ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x
789
949
  var RESET_STYLE = `${ESC}[0m`;
790
950
  var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
791
951
  // ../kit/src/cli.ts
792
- import { readFileSync, realpathSync } from "fs";
793
- import { dirname as dirname2, join as join3 } from "path";
794
- import process10 from "process";
952
+ import { readFileSync as readFileSync2, realpathSync } from "fs";
953
+ import { dirname as dirname3, join as join5 } from "path";
954
+ import process12 from "process";
795
955
 
796
956
  // ../kit/src/usage.ts
797
957
  import { appendFileSync, mkdirSync } from "fs";
798
- import { homedir as homedir2 } from "os";
799
- import { dirname, isAbsolute, join as join2 } from "path";
800
- import process9 from "process";
958
+ import { homedir as homedir3 } from "os";
959
+ import { dirname as dirname2, isAbsolute, join as join4 } from "path";
960
+ import process11 from "process";
801
961
 
802
962
  // ../kit/src/logs.ts
803
963
  var DAY_MS = 24 * 60 * 60 * 1000;
@@ -811,14 +971,14 @@ var usageError;
811
971
  function noteUsageError(message) {
812
972
  usageError = message;
813
973
  }
814
- function stateHome(env = process9.env) {
974
+ function stateHome(env = process11.env) {
815
975
  const dir = env.XDG_STATE_HOME;
816
- return dir !== undefined && isAbsolute(dir) ? dir : join2(homedir2(), ".local", "state");
976
+ return dir !== undefined && isAbsolute(dir) ? dir : join4(homedir3(), ".local", "state");
817
977
  }
818
- function usagePath(env = process9.env) {
819
- return join2(stateHome(env), CLI_FOLDER, "usage.jsonl");
978
+ function usagePath(env = process11.env) {
979
+ return join4(stateHome(env), CLI_FOLDER, "usage.jsonl");
820
980
  }
821
- function usageRecorded(env = process9.env) {
981
+ function usageRecorded(env = process11.env) {
822
982
  const off = env.KAYNOOO_CLI_NO_USAGE;
823
983
  return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
824
984
  }
@@ -832,12 +992,12 @@ function usageEntry(bin, command, argv, code, now = new Date) {
832
992
  usageError = undefined;
833
993
  return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
834
994
  }
835
- function recordUsage(entry, env = process9.env) {
995
+ function recordUsage(entry, env = process11.env) {
836
996
  if (!usageRecorded(env))
837
997
  return;
838
998
  try {
839
999
  const path = usagePath(env);
840
- mkdirSync(dirname(path), { recursive: true, mode: 448 });
1000
+ mkdirSync(dirname2(path), { recursive: true, mode: 448 });
841
1001
  appendFileSync(path, `${JSON.stringify(entry)}
842
1002
  `, { mode: 384 });
843
1003
  } catch {}
@@ -971,8 +1131,8 @@ async function help2({ path, header, summary: lazySummary, commands, defaultComm
971
1131
  `);
972
1132
  }
973
1133
  function printError(prefix, message, hint, cause) {
974
- const colors = paint(process10.stderr);
975
- const styled = takesControlCodes(process10.stderr);
1134
+ const colors = paint(process12.stderr);
1135
+ const styled = takesControlCodes(process12.stderr);
976
1136
  const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
977
1137
  const under = (label, text, tint) => text === undefined ? "" : `
978
1138
  ${styled ? tint(label) : `${label}:`} ${text}`;
@@ -1015,11 +1175,11 @@ async function dispatch(level, typed, { version, redact }) {
1015
1175
  }
1016
1176
  }
1017
1177
  if (name === undefined && level.path.length > 1) {
1018
- console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stderr));
1178
+ console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process12.stderr));
1019
1179
  return 2;
1020
1180
  }
1021
1181
  if (name === undefined || name === "help" || name === "--help" || name === "-h") {
1022
- console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stdout));
1182
+ console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process12.stdout));
1023
1183
  return 0;
1024
1184
  }
1025
1185
  if (level.path.length === 1 && (name === "--version" || name === "-v")) {
@@ -1136,17 +1296,17 @@ async function printCandidates(found) {
1136
1296
  return 0;
1137
1297
  }
1138
1298
  function packageVersion(entry = Bun.main) {
1139
- for (let dir = dirname2(realpathSync(entry));; dir = dirname2(dir)) {
1299
+ for (let dir = dirname3(realpathSync(entry));; dir = dirname3(dir)) {
1140
1300
  try {
1141
- const { version } = JSON.parse(readFileSync(join3(dir, "package.json"), "utf8"));
1301
+ const { version } = JSON.parse(readFileSync2(join5(dir, "package.json"), "utf8"));
1142
1302
  if (typeof version === "string")
1143
1303
  return version;
1144
1304
  } catch {}
1145
- if (dirname2(dir) === dir)
1305
+ if (dirname3(dir) === dir)
1146
1306
  return "0.0.0";
1147
1307
  }
1148
1308
  }
1149
- async function runCli(cli, argv = process10.argv.slice(2)) {
1309
+ async function runCli(cli, argv = process12.argv.slice(2)) {
1150
1310
  const version = cli.version ?? packageVersion();
1151
1311
  if (argv[0] === COMPLETE)
1152
1312
  return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
@@ -1173,7 +1333,7 @@ function commandPath(scope, argv) {
1173
1333
  }
1174
1334
  return path.length === 0 ? undefined : path.join(" ");
1175
1335
  }
1176
- async function runMain({ name, version, run, redact, usage }, argv = process10.argv.slice(2)) {
1336
+ async function runMain({ name, version, run, redact, usage }, argv = process12.argv.slice(2)) {
1177
1337
  if (argv[0] === COMPLETE)
1178
1338
  return printCandidates(leafCandidates(run, argv.slice(1)));
1179
1339
  if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
@@ -1193,6 +1353,8 @@ async function runMain({ name, version, run, redact, usage }, argv = process10.a
1193
1353
  }
1194
1354
  return code;
1195
1355
  }
1356
+ // ../kit/src/folders.ts
1357
+ var SKIPPED_FOLDERS = new Set(["node_modules", "vendor", "dist", "build", "target", "coverage", "venv", "__pycache__"]);
1196
1358
  // ../kit/src/secrets.ts
1197
1359
  var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
1198
1360
  // ../kit/src/sessions.ts
@@ -1200,40 +1362,40 @@ var {Glob } = globalThis.Bun;
1200
1362
  var SESSION_FILES = new Glob("*.json");
1201
1363
  var ACCOUNT_DIRS = new Glob("*/sessions");
1202
1364
  // ../kit/src/workspace-root.ts
1203
- import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
1204
- import { homedir as homedir3 } from "os";
1205
- import { dirname as dirname3, join as join4, resolve } from "path";
1206
- import process11 from "process";
1365
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync } from "fs";
1366
+ import { homedir as homedir4 } from "os";
1367
+ import { dirname as dirname4, join as join6, resolve as resolve3 } from "path";
1368
+ import process13 from "process";
1207
1369
  function expandHome(path, home) {
1208
1370
  if (path === "~")
1209
1371
  return home;
1210
- return path.startsWith("~/") ? join4(home, path.slice(2)) : path;
1372
+ return path.startsWith("~/") ? join6(home, path.slice(2)) : path;
1211
1373
  }
1212
1374
  function configured(env, home) {
1213
1375
  const path = userConfigPath("config", { home, xdg: env.XDG_CONFIG_HOME });
1214
- if (!existsSync(path))
1376
+ if (!existsSync4(path))
1215
1377
  return;
1216
1378
  try {
1217
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
1379
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
1218
1380
  const folder = typeof parsed === "object" && parsed !== null ? parsed.workspace : undefined;
1219
1381
  return typeof folder === "string" && folder !== "" ? folder : undefined;
1220
1382
  } catch {
1221
1383
  return;
1222
1384
  }
1223
1385
  }
1224
- function workspaceRoot({ given, env = process11.env, home = homedir3() } = {}) {
1386
+ function workspaceRoot({ given, env = process13.env, home = homedir4() } = {}) {
1225
1387
  const fromEnv = env.KAYNOOO_WORKSPACE === "" ? undefined : env.KAYNOOO_WORKSPACE;
1226
- return resolve(expandHome(given ?? fromEnv ?? configured(env, home) ?? join4(home, "Workspace"), home));
1388
+ return resolve3(expandHome(given ?? fromEnv ?? configured(env, home) ?? join6(home, "Workspace"), home));
1227
1389
  }
1228
- function workspaceChosen({ env = process11.env, home = homedir3() } = {}) {
1390
+ function workspaceChosen({ env = process13.env, home = homedir4() } = {}) {
1229
1391
  return (env.KAYNOOO_WORKSPACE ?? "") !== "" || configured(env, home) !== undefined;
1230
1392
  }
1231
- function saveWorkspace(folder, { env = process11.env, home = homedir3() } = {}) {
1393
+ function saveWorkspace(folder, { env = process13.env, home = homedir4() } = {}) {
1232
1394
  const path = userConfigPath("config", { home, xdg: env.XDG_CONFIG_HOME });
1233
1395
  let current = {};
1234
- if (existsSync(path)) {
1396
+ if (existsSync4(path)) {
1235
1397
  try {
1236
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
1398
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
1237
1399
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
1238
1400
  return false;
1239
1401
  current = parsed;
@@ -1241,17 +1403,17 @@ function saveWorkspace(folder, { env = process11.env, home = homedir3() } = {})
1241
1403
  return false;
1242
1404
  }
1243
1405
  }
1244
- mkdirSync2(dirname3(path), { recursive: true });
1406
+ mkdirSync2(dirname4(path), { recursive: true });
1245
1407
  writeFileSync(path, `${JSON.stringify({ ...current, workspace: folder }, undefined, 2)}
1246
1408
  `);
1247
1409
  return true;
1248
1410
  }
1249
1411
  // src/doctor.ts
1250
- import process17 from "process";
1412
+ import process19 from "process";
1251
1413
 
1252
1414
  // src/checks.ts
1253
- import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
1254
- import { basename, join as join6 } from "path";
1415
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1416
+ import { basename, join as join8 } from "path";
1255
1417
 
1256
1418
  // src/catalog.ts
1257
1419
  var HOOKS_REQUIRES = "@kaynooo/cli-guard";
@@ -1287,9 +1449,9 @@ var NEEDS = {
1287
1449
  };
1288
1450
 
1289
1451
  // src/completions.ts
1290
- import { existsSync as existsSync2, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync3, rmSync } from "fs";
1291
- import { join as join5 } from "path";
1292
- import process13 from "process";
1452
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync4, rmSync } from "fs";
1453
+ import { join as join7 } from "path";
1454
+ import process15 from "process";
1293
1455
  var MARKER = "# Generated by `cli completions fish`";
1294
1456
  var FISH_FILE = /\.fish$/;
1295
1457
  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'
@@ -1317,14 +1479,36 @@ var BASH_FUNCTION = `__kaynooo_cli_complete() {
1317
1479
  done
1318
1480
  COMPREPLY+=($(compgen -W "$words" -- "$cur"))
1319
1481
  }`;
1482
+ var ZSH_FUNCTION = `__kaynooo_cli_complete() {
1483
+ local line
1484
+ local -a described plain
1485
+ for line in \${(f)"$("\${words[1]}" __complete "\${(@)words[2,CURRENT]}" 2>/dev/null)"}; do
1486
+ if [[ $line == __files__ ]]; then
1487
+ _files
1488
+ elif [[ $line == *$'\\t'* ]]; then
1489
+ described+=("\${\${line%%$'\\t'*}//:/\\\\:}:\${line#*$'\\t'}")
1490
+ else
1491
+ plain+=("$line")
1492
+ fi
1493
+ done
1494
+ (( \${#described} )) && _describe -V value described
1495
+ (( \${#plain} )) && compadd -- "\${plain[@]}"
1496
+ return 0
1497
+ }`;
1498
+ function zshScript(bins) {
1499
+ return `# Generated by \`cli completions zsh\`
1500
+ ${ZSH_FUNCTION}
1501
+ compdef __kaynooo_cli_complete ${bins.join(" ")}
1502
+ `;
1503
+ }
1320
1504
  function bashScript(bins) {
1321
1505
  return `# Generated by \`cli completions bash\`
1322
1506
  ${BASH_FUNCTION}
1323
1507
  complete -F __kaynooo_cli_complete ${bins.join(" ")}
1324
1508
  `;
1325
1509
  }
1326
- function completionDir(home, env = process13.env) {
1327
- return join5(env.XDG_CACHE_HOME ?? join5(home, ".cache"), "fish", "kaynooo-cli");
1510
+ function completionDir(home, env = process15.env) {
1511
+ return join7(env.XDG_CACHE_HOME ?? join7(home, ".cache"), "fish", "kaynooo-cli");
1328
1512
  }
1329
1513
  function installedBins(host) {
1330
1514
  return Object.values(TOOLS).flat().filter((bin) => host.which(bin) !== null);
@@ -1338,14 +1522,14 @@ complete -c ${bin} -f -a '(__kaynooo_cli_complete ${bin})'
1338
1522
  async function installCompletions(host, dir) {
1339
1523
  const bins = installedBins(host);
1340
1524
  mkdirSync3(dir, { recursive: true });
1341
- const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) && readFileSync3(join5(dir, name), "utf8").startsWith(MARKER));
1525
+ const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) && readFileSync4(join7(dir, name), "utf8").startsWith(MARKER));
1342
1526
  for (const name of removed)
1343
- rmSync(join5(dir, name));
1344
- await Promise.all(bins.map(async (bin) => Bun.write(join5(dir, `${bin}.fish`), completionFile(bin))));
1527
+ rmSync(join7(dir, name));
1528
+ await Promise.all(bins.map(async (bin) => Bun.write(join7(dir, `${bin}.fish`), completionFile(bin))));
1345
1529
  return { written: bins, removed: removed.map((name) => name.replace(FISH_FILE, "")) };
1346
1530
  }
1347
1531
  function missingCompletions(host, dir) {
1348
- return installedBins(host).filter((bin) => !existsSync2(join5(dir, `${bin}.fish`)));
1532
+ return installedBins(host).filter((bin) => !existsSync5(join7(dir, `${bin}.fish`)));
1349
1533
  }
1350
1534
 
1351
1535
  // src/checks.ts
@@ -1389,7 +1573,7 @@ function readJsonText(text) {
1389
1573
  }
1390
1574
  }
1391
1575
  function readJson(path) {
1392
- return existsSync3(path) ? readJsonText(readFileSync4(path, "utf8")) : undefined;
1576
+ return existsSync6(path) ? readJsonText(readFileSync5(path, "utf8")) : undefined;
1393
1577
  }
1394
1578
  function firstLine(text) {
1395
1579
  const trimmed = text.trim();
@@ -1398,7 +1582,7 @@ function firstLine(text) {
1398
1582
  return end === -1 ? trimmed : trimmed.slice(0, end);
1399
1583
  }
1400
1584
  function installed(host, name) {
1401
- return readJson(join6(host.globalModules, name, "package.json"));
1585
+ return readJson(join8(host.globalModules, name, "package.json"));
1402
1586
  }
1403
1587
  function isInstalled(host, name) {
1404
1588
  return installed(host, name)?.version !== undefined;
@@ -1406,7 +1590,7 @@ function isInstalled(host, name) {
1406
1590
  function ownBin(host, name, bin) {
1407
1591
  const declared = installed(host, name)?.bin;
1408
1592
  const file = typeof declared === "string" ? declared : declared?.[bin];
1409
- return file === undefined ? undefined : join6(host.globalModules, name, file);
1593
+ return file === undefined ? undefined : join8(host.globalModules, name, file);
1410
1594
  }
1411
1595
  async function checkTool(host, name, bins) {
1412
1596
  const check = name.slice(name.indexOf("/") + 1);
@@ -1421,17 +1605,29 @@ async function checkTool(host, name, bins) {
1421
1605
  if (latest !== "" && Bun.semver.order(version, latest) < 0)
1422
1606
  return { check, ok: false, detail: `${version}, ${latest} released${off.length > 0 ? `, ${off.join(", ")} not on the PATH` : ""}`, fix: `bun install -g ${name}@${latest}` };
1423
1607
  if (off.length > 0)
1424
- return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${join6(host.globalModules, "..", "..", "..", "bin")} to the PATH` };
1608
+ return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${join8(host.globalModules, "..", "..", "..", "bin")} to the PATH` };
1425
1609
  if (latest === "")
1426
1610
  return { check, ok: true, detail: `${version}, the registry did not answer: ${firstLine(info.stderr) || answered || "no version"}` };
1427
1611
  return { check, ok: true, detail: version };
1428
1612
  }
1613
+ function extraForgeHosts(home) {
1614
+ try {
1615
+ const path = userConfigReadPath("doctor", [], { home, xdg: process.env.XDG_CONFIG_HOME });
1616
+ if (!existsSync6(path))
1617
+ return [];
1618
+ const raw = Bun.JSONC.parse(readFileSync5(path, "utf8"));
1619
+ return Array.isArray(raw?.forgeHosts) ? raw.forgeHosts.filter((each) => typeof each === "string") : [];
1620
+ } catch {
1621
+ return [];
1622
+ }
1623
+ }
1429
1624
  async function checkTea(host) {
1430
1625
  if (host.which("tea") === null)
1431
1626
  return { check: "tea", ok: false, detail: "not installed, and ft goes through it", fix: "install tea from https://gitea.com/gitea/tea/releases" };
1432
1627
  const logins = await host.run(["tea", "login", "list", "-o", "json"]);
1433
1628
  const parsed = logins.code === 0 ? readJsonText(logins.stdout) : undefined;
1434
- const login = parsed?.find((each) => URL.canParse(each.url) && FORGE_HOSTS.has(new URL(each.url).host));
1629
+ const hosts = new Set([...FORGE_HOSTS, ...extraForgeHosts(host.home)]);
1630
+ const login = parsed?.find((each) => URL.canParse(each.url) && hosts.has(new URL(each.url).host));
1435
1631
  if (login === undefined)
1436
1632
  return { check: "tea", ok: false, detail: `no login to ${FORGE}`, fix: `tea login add --url https://${FORGE} --oauth` };
1437
1633
  const version = await host.run(["tea", "api", "--login", login.name, "version"]);
@@ -1442,9 +1638,9 @@ async function checkTea(host) {
1442
1638
  return { check: "tea", ok: true, detail: `logged in to ${forge} as ${login.name}, Forgejo ${served}` };
1443
1639
  }
1444
1640
  function hooksWiring(host) {
1445
- const settings = readJson(join6(host.home, ".claude", "settings.json")) ?? {};
1641
+ const settings = readJson(join8(host.home, ".claude", "settings.json")) ?? {};
1446
1642
  const plugin = settings.enabledPlugins?.[PLUGIN] === true;
1447
- const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" && existsSync3(join6(dir, "hooks", "hooks.json")));
1643
+ const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" && existsSync6(join8(dir, "hooks", "hooks.json")));
1448
1644
  return { plugin, mod };
1449
1645
  }
1450
1646
  function checkHooks(host) {
@@ -1487,7 +1683,7 @@ var FORGEJO = "@kaynooo/cli-forgejo";
1487
1683
  var WORKSPACE = "@kaynooo/cli-workspace";
1488
1684
  function checkWorkspace(host, env = process.env) {
1489
1685
  const folder = workspaceRoot({ home: host.home, env });
1490
- if (existsSync3(folder))
1686
+ if (existsSync6(folder))
1491
1687
  return { check: "workspace", ok: true, detail: folder };
1492
1688
  return { check: "workspace", ok: false, detail: `${folder} does not exist`, fix: `mkdir -p ${folder}, or set "workspace" in ~/.config/kaynooo-cli/config.json to your folder` };
1493
1689
  }
@@ -1549,19 +1745,19 @@ async function applyFixes(host, steps, dry) {
1549
1745
  }
1550
1746
 
1551
1747
  // src/host.ts
1552
- import { homedir as homedir4 } from "os";
1553
- import { join as join7 } from "path";
1554
- import process14 from "process";
1748
+ import { homedir as homedir5 } from "os";
1749
+ import { join as join9 } from "path";
1750
+ import process16 from "process";
1555
1751
  var RUN_TIMEOUT_MS = 20000;
1556
1752
  function hostHere() {
1557
- const home = homedir4();
1753
+ const home = homedir5();
1558
1754
  return {
1559
1755
  home,
1560
- globalModules: join7(process14.env.BUN_INSTALL ?? join7(home, ".bun"), "install", "global", "node_modules"),
1756
+ globalModules: join9(process16.env.BUN_INSTALL ?? join9(home, ".bun"), "install", "global", "node_modules"),
1561
1757
  bunVersion: Bun.version,
1562
1758
  which: (bin) => Bun.which(bin),
1563
1759
  run: async (argv, env) => {
1564
- const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...process14.env, ...env } } });
1760
+ const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...process16.env, ...env } } });
1565
1761
  if (ran.timedOut)
1566
1762
  return { code: 1, stdout: "", stderr: `timed out after ${RUN_TIMEOUT_MS / 1000}s` };
1567
1763
  const of = (stream) => Buffer.concat(ran.chunks.filter((chunk) => chunk.stream === stream).map((chunk) => chunk.data)).toString();
@@ -1571,19 +1767,53 @@ function hostHere() {
1571
1767
  }
1572
1768
 
1573
1769
  // src/install.ts
1574
- import process16 from "process";
1770
+ import process18 from "process";
1575
1771
 
1576
1772
  // ../kit/src/prompt.ts
1577
- import process15 from "process";
1578
- var KEY_SEQUENCES = /\x1B\[[0-9;]*[A-Z~]|\x1BO[A-Z]|[\s\S]/giu;
1579
- var CONTROL = /^[\x00-\x1F\x7F]/;
1580
- var WORDS = /\s+/;
1581
- var MAX_ROWS = 10;
1773
+ import process17 from "process";
1774
+
1775
+ // ../kit/src/picker/score.ts
1776
+ var BOUNDARY_AFTER = new Set([" ", "/", "-", "_", ".", ":", "\\", "(", "[", ",", "\t"]);
1777
+ var NONE = Number.NEGATIVE_INFINITY;
1778
+
1779
+ // ../kit/src/picker/state.ts
1780
+ var IS_CONTROL = /[\x00-\x1F\x7F-\x9F]/;
1582
1781
  var PASTE_START = "\x1B[200~";
1583
1782
  var PASTE_END = "\x1B[201~";
1584
- var KEYS = { "\x1B[A": "up", "\x1BOA": "up", "\x1B[B": "down", "\x1BOB": "down", "\x1B[5~": "pageup", "\x1B[6~": "pagedown", "\x1B[H": "home", "\x1B[1~": "home", "\x1BOH": "home", "\x1B[F": "end", "\x1B[4~": "end", "\x1BOF": "end", "\r": "enter", "\n": "enter", "\x03": "cancel", "\x1B": "cancel", "\x7F": "erase", "\b": "erase" };
1585
- function readKeys(input, paste = { active: false }) {
1783
+ var KEY_SEQUENCES = /\x1B\[[0-9;]*[A-Z~]|\x1BO[A-Z]|\x1B[\s\S]|[\s\S]/gu;
1784
+ var KEYS = {
1785
+ "\x1B[A": "up",
1786
+ "\x1BOA": "up",
1787
+ "\x10": "up",
1788
+ "\x1B[B": "down",
1789
+ "\x1BOB": "down",
1790
+ "\x0E": "down",
1791
+ "\x1B[5~": "pageup",
1792
+ "\x1B[6~": "pagedown",
1793
+ "\x1B[H": "home",
1794
+ "\x1B[1~": "home",
1795
+ "\x1BOH": "home",
1796
+ "\x1B[F": "end",
1797
+ "\x1B[4~": "end",
1798
+ "\x1BOF": "end",
1799
+ "\r": "enter",
1800
+ "\n": "enter",
1801
+ "\x03": "cancel",
1802
+ "\x1B": "cancel",
1803
+ "\x7F": "erase",
1804
+ "\b": "erase",
1805
+ "\x15": "clear",
1806
+ "\x17": "word",
1807
+ "\t": "tab",
1808
+ "\x1F": "help",
1809
+ "\x1BOP": "help",
1810
+ "\x1B[11~": "help"
1811
+ };
1812
+ function parseKeys(input, paste = { active: false }, ctrls = []) {
1813
+ const codes = new Map(ctrls.map((name) => [String.fromCharCode(name.codePointAt(name.length - 1) - 96), name]));
1586
1814
  return (input.match(KEY_SEQUENCES) ?? []).flatMap((sequence) => {
1815
+ const named = codes.get(sequence);
1816
+ const key = named === undefined ? KEYS[sequence] : { ctrl: named };
1587
1817
  if (sequence === PASTE_START || sequence === PASTE_END) {
1588
1818
  paste.active = sequence === PASTE_START;
1589
1819
  return [];
@@ -1591,9 +1821,19 @@ function readKeys(input, paste = { active: false }) {
1591
1821
  if (paste.active && (sequence === "\r" || sequence === `
1592
1822
  `))
1593
1823
  return [];
1594
- return KEYS[sequence] ?? (CONTROL.test(sequence) ? [] : [{ text: sequence }]);
1824
+ if (key !== undefined)
1825
+ return [key];
1826
+ return IS_CONTROL.test(sequence) || sequence.startsWith("\x1B") ? [] : [{ text: sequence }];
1595
1827
  });
1596
1828
  }
1829
+
1830
+ // ../kit/src/prompt.ts
1831
+ var WORDS = /\s+/;
1832
+ var MAX_ROWS = 10;
1833
+ var PROMPT_KEYS = new Set(["up", "down", "pageup", "pagedown", "home", "end", "enter", "cancel", "erase"]);
1834
+ function readKeys(input, paste = { active: false }) {
1835
+ return parseKeys(input, paste).filter((key) => typeof key === "object" ? "text" in key : PROMPT_KEYS.has(key));
1836
+ }
1597
1837
  function flip(checked, value) {
1598
1838
  const next = new Set(checked);
1599
1839
  if (!next.delete(value))
@@ -1733,7 +1973,7 @@ function asking(colors, question, typed, keys) {
1733
1973
  function answer(colors, question, state, picked) {
1734
1974
  return state === "enter" ? `${colors.green("\u2713")} ${question} ${colors.cyan(picked)}` : `${colors.red("\u2717")} ${question} ${colors.dim("cancelled")}`;
1735
1975
  }
1736
- async function ask(question, { hint, terminal = process15 }, render, press) {
1976
+ async function ask(question, { hint, terminal = process17 }, render, press) {
1737
1977
  const { stdin, stderr } = terminal;
1738
1978
  if (!isInteractive(terminal))
1739
1979
  fail(`cannot ask "${question}" off a terminal`, 2, hint);
@@ -1868,7 +2108,7 @@ async function askWorkspace(host) {
1868
2108
  async function install(host, options, recheck, choosing = ask2) {
1869
2109
  const all = candidates2(host);
1870
2110
  const pool = all.filter((each) => !each.installed);
1871
- const { dim, green, red, yellow } = paint(process16.stdout);
2111
+ const { dim, green, red, yellow } = paint(process18.stdout);
1872
2112
  if (options.list) {
1873
2113
  for (const each of pool)
1874
2114
  console.log(`${each.label.padEnd(12)} ${dim(each.hint)}`);
@@ -1976,7 +2216,7 @@ var OPTIONS = {
1976
2216
  function print(results) {
1977
2217
  if (results.length === 0)
1978
2218
  return;
1979
- const { green, red, dim } = paint(process17.stdout);
2219
+ const { green, red, dim } = paint(process19.stdout);
1980
2220
  const width = Math.max(...results.map((result) => result.check.length));
1981
2221
  for (const { check, ok, detail, fix } of results)
1982
2222
  console.log(`${ok ? green("ok ") : red("FAIL")} ${check.padEnd(width)} ${detail}${fix === undefined ? "" : ` ${dim("fix:")} ${fix}`}`);
@@ -1986,7 +2226,7 @@ function print(results) {
1986
2226
  ${dim("fix them all:")} ${INSTALL2}${installs.join(" ")}`);
1987
2227
  }
1988
2228
  function printOutcomes(outcomes, log) {
1989
- const { green, red, dim } = paint(process17.stdout);
2229
+ const { green, red, dim } = paint(process19.stdout);
1990
2230
  const marks = { ran: green("ran "), failed: red("failed "), "dry-run": dim("would "), "not run": dim("not run") };
1991
2231
  for (const { command, status, detail } of outcomes)
1992
2232
  log(`${marks[status]} ${command}${detail === undefined ? "" : ` ${dim(detail)}`}`);
@@ -2026,9 +2266,9 @@ after the fixes:`);
2026
2266
  const absent = Object.keys(TOOLS).filter((name) => !isInstalled(host, name)).length;
2027
2267
  if (!json && only.length === 0 && absent > 0)
2028
2268
  console.log(`
2029
- ${paint(process17.stdout).dim(`${absent} packages not installed: doctor --install`)}`);
2269
+ ${paint(process19.stdout).dim(`${absent} packages not installed: doctor --install`)}`);
2030
2270
  return results.every((result) => result.ok) ? 0 : 1;
2031
2271
  }
2032
2272
 
2033
2273
  // src/cli.ts
2034
- process18.exitCode = await runMain({ name: "doctor", run: async (args) => main(args) });
2274
+ process20.exitCode = await runMain({ name: "doctor", run: async (args) => main(args) });