@kaynooo/cli-doctor 0.6.0 → 0.7.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.
Files changed (3) hide show
  1. package/dist/cli-bin.js +111 -11
  2. package/dist/cli.js +12 -13
  3. package/package.json +2 -1
package/dist/cli-bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // @bun
3
3
 
4
4
  // src/cli-bin.ts
5
- import process12 from "process";
5
+ import process13 from "process";
6
6
  // ../kit/src/args.ts
7
7
  import process5 from "process";
8
8
  import { parseArgs } from "util";
@@ -1160,11 +1160,10 @@ import process10 from "process";
1160
1160
  import { existsSync, readFileSync as readFileSync2 } from "fs";
1161
1161
  import { basename, join as join3 } from "path";
1162
1162
  var TOOLS = {
1163
- "@kaynooo/cli-audit": ["audit"],
1164
1163
  "@kaynooo/cli-base": ["base", "proof"],
1165
1164
  "@kaynooo/cli-changelog": ["changelog"],
1166
1165
  "@kaynooo/cli-check": ["check", "fix", "errs", "j"],
1167
- "@kaynooo/cli-code": ["peek", "todo-scan", "hotspots"],
1166
+ "@kaynooo/cli-code": ["src", "peek", "todo-scan", "hotspots"],
1168
1167
  "@kaynooo/cli-db": ["db"],
1169
1168
  "@kaynooo/cli-docker": ["dc", "dlog", "dx", "sf"],
1170
1169
  "@kaynooo/cli-doctor": ["doctor", "cli"],
@@ -1179,12 +1178,11 @@ var TOOLS = {
1179
1178
  "@kaynooo/cli-pick": ["pick"],
1180
1179
  "@kaynooo/cli-pkg": ["pkg"],
1181
1180
  "@kaynooo/cli-probe": ["probe"],
1182
- "@kaynooo/cli-proc": ["pid", "ports", "procs"],
1183
- "@kaynooo/cli-repos": ["repos"],
1181
+ "@kaynooo/cli-proc": ["proc", "pid", "ports", "procs"],
1184
1182
  "@kaynooo/cli-stack": ["stack"],
1185
- "@kaynooo/cli-sweep": ["sweep"],
1186
1183
  "@kaynooo/cli-view": ["view"],
1187
- "@kaynooo/cli-wait": ["waitfor", "slot"]
1184
+ "@kaynooo/cli-wait": ["waitfor", "slot"],
1185
+ "@kaynooo/cli-workspace": ["ws", "repos", "sweep", "audit"]
1188
1186
  };
1189
1187
  var FORGE = "git.kaynooo.fr";
1190
1188
  var FORGE_HOSTS = new Set([FORGE, "git.kevyn.fr"]);
@@ -1355,6 +1353,46 @@ function missingCompletions(host, dir) {
1355
1353
  return installedBins(host).filter((bin) => !existsSync2(join4(dir, `${bin}.fish`)));
1356
1354
  }
1357
1355
 
1356
+ // src/doctor.ts
1357
+ import process12 from "process";
1358
+
1359
+ // src/fix.ts
1360
+ var INSTALL = /^bun install -g (\S+)$/;
1361
+ var RUNNABLE = /^(?:cli completions fish --install|claude plugin (?:install \S+ --marketplace \S+|disable \S+))$/;
1362
+ function planFixes(results) {
1363
+ const steps = [];
1364
+ const installs = [];
1365
+ for (const { ok, fix } of results) {
1366
+ if (ok || fix === undefined)
1367
+ continue;
1368
+ const install = INSTALL.exec(fix);
1369
+ if (install !== null)
1370
+ installs.push(install[1] ?? "");
1371
+ else
1372
+ steps.push({ command: fix, argv: RUNNABLE.test(fix) ? fix.split(" ") : undefined });
1373
+ }
1374
+ if (installs.length === 0)
1375
+ return steps;
1376
+ const command = `bun install -g ${installs.join(" ")}`;
1377
+ return [{ command, argv: command.split(" ") }, ...steps];
1378
+ }
1379
+ async function applyFixes(host, steps, dry) {
1380
+ const outcomes = [];
1381
+ for (const { command, argv } of steps) {
1382
+ if (argv === undefined) {
1383
+ outcomes.push({ command, status: "not run", detail: "not a command doctor runs: do it by hand" });
1384
+ continue;
1385
+ }
1386
+ if (dry) {
1387
+ outcomes.push({ command, status: "dry-run" });
1388
+ continue;
1389
+ }
1390
+ const ran = await host.run(argv);
1391
+ outcomes.push(ran.code === 0 ? { command, status: "ran" } : { command, status: "failed", detail: `exit ${ran.code}: ${firstLine(ran.stderr || ran.stdout)}` });
1392
+ }
1393
+ return outcomes;
1394
+ }
1395
+
1358
1396
  // src/host.ts
1359
1397
  import { homedir as homedir2 } from "os";
1360
1398
  import { join as join5 } from "path";
@@ -1377,6 +1415,67 @@ function hostHere() {
1377
1415
  };
1378
1416
  }
1379
1417
 
1418
+ // src/doctor.ts
1419
+ var USAGE = `doctor [--only <check>] [--quiet] [--fix [--dry-run]] [--json]: checks this host's @kaynooo/cli-* install, one line per check, the command that fixes a failing one beside it
1420
+
1421
+ Each @kaynooo/cli-* package installed globally with its bins on the PATH and no older than the registry's latest; tea logged in to git.kaynooo.fr and reaching it; the Claude Code hooks wired through the cli-hooks plugin or the cli mod, not both; Bun at least the version the tools ask for; fish completions for every bin.
1422
+ --fix runs the printed fix: lines it may (global installs of the packages, the completions, the hooks plugin), the installs in one call, then checks again; a line that installs a system package or only describes a step is printed as not run. --dry-run shows what --fix would run.
1423
+ --quiet prints only the failing checks, nothing when all pass. --only limits the run to the checks named, e.g. --only tea --only bun.`;
1424
+ var EXITS = [[0, "every check passes (after --fix, the ones it fixed too)"], [1, "a check fails"], [2, "a usage error"]];
1425
+ var INSTALL2 = "bun install -g ";
1426
+ var OPTIONS = {
1427
+ json: jsonOption("[{check, ok, detail, fix?}], as the checks stand after --fix; the fixes it ran go to stderr"),
1428
+ only: { type: "string", multiple: true, choices: CHECK_NAMES, description: "run only this check (a package such as cli-forgejo, tea, hooks, bun or completions), repeatable" },
1429
+ quiet: { type: "boolean", short: "q", description: "print only the failing checks" },
1430
+ fix: { type: "boolean", description: "run the fix: lines doctor may run, then check again" },
1431
+ "dry-run": { type: "boolean", description: "with --fix, show what would run without running it (alone, it implies --fix)" }
1432
+ };
1433
+ function print(results) {
1434
+ if (results.length === 0)
1435
+ return;
1436
+ const { green, red, dim } = paint(process12.stdout);
1437
+ const width = Math.max(...results.map((result) => result.check.length));
1438
+ for (const { check, ok, detail, fix } of results)
1439
+ console.log(`${ok ? green("ok ") : red("FAIL")} ${check.padEnd(width)} ${detail}${fix === undefined ? "" : ` ${dim("fix:")} ${fix}`}`);
1440
+ const installs = results.flatMap((result) => result.fix?.startsWith(INSTALL2) === true ? [result.fix.slice(INSTALL2.length)] : []);
1441
+ if (installs.length > 1)
1442
+ console.log(`
1443
+ ${dim("fix them all:")} ${INSTALL2}${installs.join(" ")}`);
1444
+ }
1445
+ function printOutcomes(outcomes, log) {
1446
+ const { green, red, dim } = paint(process12.stdout);
1447
+ const marks = { ran: green("ran "), failed: red("failed "), "dry-run": dim("would "), "not run": dim("not run") };
1448
+ for (const { command, status, detail } of outcomes)
1449
+ log(`${marks[status]} ${command}${detail === undefined ? "" : ` ${dim(detail)}`}`);
1450
+ }
1451
+ async function main(args, host = hostHere()) {
1452
+ const { values } = parse(args, USAGE, OPTIONS, { positionals: [], exits: EXITS, replaces: "checking each bin's version, tea's login and the hooks by hand", examples: ["doctor", ["doctor --json", "the checks for a script"], ["doctor -q", "silent unless something fails"], ["doctor --fix --dry-run", "what --fix would run"]] });
1453
+ const only = values.only ?? [];
1454
+ const dry = values["dry-run"] === true;
1455
+ const json = values.json === true;
1456
+ let results = await runChecks(host, only);
1457
+ let fixed = false;
1458
+ if ((values.fix === true || dry) && results.some((result) => !result.ok)) {
1459
+ if (!json)
1460
+ print(values.quiet === true ? results.filter((result) => !result.ok) : results);
1461
+ const steps = planFixes(results);
1462
+ printOutcomes(await applyFixes(host, steps, dry), json ? console.error : console.log);
1463
+ if (dry)
1464
+ return 1;
1465
+ results = await runChecks(host, only);
1466
+ fixed = true;
1467
+ }
1468
+ const shown = values.quiet === true ? results.filter((result) => !result.ok) : results;
1469
+ if (fixed && !json && shown.length > 0)
1470
+ console.log(`
1471
+ after the fixes:`);
1472
+ if (json)
1473
+ printJson(shown);
1474
+ else
1475
+ print(shown);
1476
+ return results.every((result) => result.ok) ? 0 : 1;
1477
+ }
1478
+
1380
1479
  // src/list.ts
1381
1480
  var USAGE_WORD = /^Usage:\s*/;
1382
1481
  async function describeBin(host, bin, name) {
@@ -1401,8 +1500,8 @@ Exits 0 when it printed the list, 2 on a usage error.`;
1401
1500
  var LIST_OPTIONS = {
1402
1501
  json: jsonOption("[{bin, package, installed, synopsis?, summary?, replaces?, examples?}]")
1403
1502
  };
1404
- function print(listed) {
1405
- const { cyan, dim } = paint(process12.stdout);
1503
+ function print2(listed) {
1504
+ const { cyan, dim } = paint(process13.stdout);
1406
1505
  const width = Math.max(...listed.map((each) => each.bin.length));
1407
1506
  for (const each of listed) {
1408
1507
  const what = !each.installed ? dim(`not installed: bun install -g ${each.package}`) : `${each.summary ?? ""}${each.replaces === undefined ? "" : dim(`; instead of ${each.replaces}`)}`;
@@ -1415,7 +1514,7 @@ async function list(args, host = hostHere()) {
1415
1514
  if (values.json === true)
1416
1515
  printJson(listed);
1417
1516
  else
1418
- print(listed);
1517
+ print2(listed);
1419
1518
  return 0;
1420
1519
  }
1421
1520
  var COMPLETIONS_USAGE = `cli completions <fish|bash> [--install] [--dir <folder>]: shell completions for every installed bin of the @kaynooo/cli-* packages
@@ -1485,12 +1584,13 @@ ${table(summary.usageErrors.map((each) => [`${each.bin}${each.command === undefi
1485
1584
  return 0;
1486
1585
  }
1487
1586
  if (import.meta.main) {
1488
- process12.exitCode = await runCli({
1587
+ process13.exitCode = await runCli({
1489
1588
  name: "cli",
1490
1589
  about: "the bins of the @kaynooo/cli-* packages, described by their own help",
1491
1590
  replaces: "running each bin's --help to find the one that fits",
1492
1591
  examples: ["cli list", ["cli list --json", "with each bin's synopsis and examples"]],
1493
1592
  commands: {
1593
+ doctor: { summary: "checks this host's install of the bins, one line per check, the command that fixes a failing one beside it", run: async (args) => main(args) },
1494
1594
  list: { summary: "every bin in one line: what it does and what it is reached for instead of", run: async (args) => list(args) },
1495
1595
  stats: { summary: "how often each bin ran and the options usage errors did not know", run: async (args) => stats(args) },
1496
1596
  completions: { summary: "fish completions for every installed bin, printed or written to the folder fish reads", run: async (args) => completions(args) }
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // @bun
3
3
 
4
4
  // src/cli.ts
5
- import process12 from "process";
5
+ import process13 from "process";
6
6
  // ../kit/src/args.ts
7
7
  import process5 from "process";
8
8
  import { parseArgs } from "util";
@@ -1151,6 +1151,9 @@ var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "ses
1151
1151
  var {Glob } = globalThis.Bun;
1152
1152
  var SESSION_FILES = new Glob("*.json");
1153
1153
  var ACCOUNT_DIRS = new Glob("*/sessions");
1154
+ // src/doctor.ts
1155
+ import process12 from "process";
1156
+
1154
1157
  // src/checks.ts
1155
1158
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
1156
1159
  import { basename, join as join4 } from "path";
@@ -1219,11 +1222,10 @@ function missingCompletions(host, dir) {
1219
1222
 
1220
1223
  // src/checks.ts
1221
1224
  var TOOLS = {
1222
- "@kaynooo/cli-audit": ["audit"],
1223
1225
  "@kaynooo/cli-base": ["base", "proof"],
1224
1226
  "@kaynooo/cli-changelog": ["changelog"],
1225
1227
  "@kaynooo/cli-check": ["check", "fix", "errs", "j"],
1226
- "@kaynooo/cli-code": ["peek", "todo-scan", "hotspots"],
1228
+ "@kaynooo/cli-code": ["src", "peek", "todo-scan", "hotspots"],
1227
1229
  "@kaynooo/cli-db": ["db"],
1228
1230
  "@kaynooo/cli-docker": ["dc", "dlog", "dx", "sf"],
1229
1231
  "@kaynooo/cli-doctor": ["doctor", "cli"],
@@ -1238,12 +1240,11 @@ var TOOLS = {
1238
1240
  "@kaynooo/cli-pick": ["pick"],
1239
1241
  "@kaynooo/cli-pkg": ["pkg"],
1240
1242
  "@kaynooo/cli-probe": ["probe"],
1241
- "@kaynooo/cli-proc": ["pid", "ports", "procs"],
1242
- "@kaynooo/cli-repos": ["repos"],
1243
+ "@kaynooo/cli-proc": ["proc", "pid", "ports", "procs"],
1243
1244
  "@kaynooo/cli-stack": ["stack"],
1244
- "@kaynooo/cli-sweep": ["sweep"],
1245
1245
  "@kaynooo/cli-view": ["view"],
1246
- "@kaynooo/cli-wait": ["waitfor", "slot"]
1246
+ "@kaynooo/cli-wait": ["waitfor", "slot"],
1247
+ "@kaynooo/cli-workspace": ["ws", "repos", "sweep", "audit"]
1247
1248
  };
1248
1249
  var FORGE = "git.kaynooo.fr";
1249
1250
  var FORGE_HOSTS = new Set([FORGE, "git.kevyn.fr"]);
@@ -1414,7 +1415,7 @@ function hostHere() {
1414
1415
  };
1415
1416
  }
1416
1417
 
1417
- // src/cli.ts
1418
+ // src/doctor.ts
1418
1419
  var USAGE = `doctor [--only <check>] [--quiet] [--fix [--dry-run]] [--json]: checks this host's @kaynooo/cli-* install, one line per check, the command that fixes a failing one beside it
1419
1420
 
1420
1421
  Each @kaynooo/cli-* package installed globally with its bins on the PATH and no older than the registry's latest; tea logged in to git.kaynooo.fr and reaching it; the Claude Code hooks wired through the cli-hooks plugin or the cli mod, not both; Bun at least the version the tools ask for; fish completions for every bin.
@@ -1474,8 +1475,6 @@ after the fixes:`);
1474
1475
  print(shown);
1475
1476
  return results.every((result) => result.ok) ? 0 : 1;
1476
1477
  }
1477
- if (import.meta.main)
1478
- process12.exitCode = await runMain({ name: "doctor", run: async (args) => main(args) });
1479
- export {
1480
- main
1481
- };
1478
+
1479
+ // src/cli.ts
1480
+ process13.exitCode = await runMain({ name: "doctor", run: async (args) => main(args) });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kaynooo/cli-doctor",
3
3
  "type": "module",
4
- "version": "0.6.0",
4
+ "version": "0.7.0",
5
5
  "description": "doctor: checks the @kaynooo/cli-* install of a host: each bin's version against the registry, tea's login to Forgejo, the Claude Code hooks and the Bun floor; cli list: every bin in one line, read from its own help.",
6
6
  "author": "Kaynooo <contact@kaynooo.fr>",
7
7
  "license": "MIT",
@@ -33,6 +33,7 @@
33
33
  },
34
34
  "scripts": {
35
35
  "build": "$npm_execpath build src/cli.ts src/cli-bin.ts --target bun --outdir dist",
36
+ "cli": "$npm_execpath src/cli-bin.ts",
36
37
  "doctor": "$npm_execpath src/cli.ts"
37
38
  },
38
39
  "devDependencies": {