@kaynooo/cli-doctor 0.5.2 → 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.
package/README.md CHANGED
@@ -38,10 +38,10 @@ Each bin completes itself through `<bin> __complete`. fish gets a file per bin (
38
38
  ## cli stats
39
39
 
40
40
  ```sh
41
- cli stats [--since 7d] [--json] # runs per bin, failures, and the options usage errors did not know
41
+ cli stats [--since 7d] [--json] # runs per bin and per command, failures (exit 1) apart from usage errors (exit 2), and the options usage errors did not know
42
42
  ```
43
43
 
44
- Every bin records each run in `~/.local/state/kaynooo-cli/usage.jsonl`: the bin, its command, the flag names it saw (never values or arguments), the exit code and, on a usage error, the unknown option. `KAYNOOO_CLI_NO_USAGE=1` turns it off; `guard` never records.
44
+ Every bin records each run in `~/.local/state/kaynooo-cli/usage.jsonl`: the bin, its command, the flag names it saw (never values or arguments), the exit code and, on a usage error, the unknown option (never its message). `KAYNOOO_CLI_NO_USAGE=1` turns it off; `guard` never records.
45
45
 
46
46
  ## cli list
47
47
 
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";
@@ -808,26 +808,38 @@ async function readUsage(path = usagePath(), since = 0) {
808
808
  }
809
809
  });
810
810
  }
811
+ function tally(counts, code) {
812
+ counts.runs++;
813
+ counts.failed += code === 0 || code === 2 ? 0 : 1;
814
+ counts.usageErrors += code === 2 ? 1 : 0;
815
+ }
811
816
  function summarizeUsage(entries) {
812
817
  const bins = new Map;
813
- const errors = new Map;
818
+ const commands = new Map;
819
+ const unknowns = new Map;
814
820
  for (const entry of entries) {
815
821
  const bin = bins.get(entry.bin) ?? { runs: 0, failed: 0, usageErrors: 0 };
816
- bin.runs++;
817
- bin.failed += entry.code === 0 ? 0 : 1;
818
- bin.usageErrors += entry.code === 2 ? 1 : 0;
822
+ tally(bin, entry.code);
819
823
  bins.set(entry.bin, bin);
820
- if (entry.code === 2 && entry.unknown !== undefined) {
824
+ if (entry.command !== undefined) {
825
+ const command = commands.get(`${entry.bin} ${entry.command}`) ?? { bin: entry.bin, command: entry.command, runs: 0, failed: 0, usageErrors: 0 };
826
+ tally(command, entry.code);
827
+ commands.set(`${entry.bin} ${entry.command}`, command);
828
+ }
829
+ if (entry.code !== 2)
830
+ continue;
831
+ if (entry.unknown !== undefined) {
821
832
  const key = `${entry.bin} ${entry.command ?? ""} ${entry.unknown}`;
822
- const error = errors.get(key) ?? { bin: entry.bin, ...entry.command === undefined ? {} : { command: entry.command }, unknown: entry.unknown, count: 0 };
823
- error.count++;
824
- errors.set(key, error);
833
+ const unknown = unknowns.get(key) ?? { bin: entry.bin, ...entry.command === undefined ? {} : { command: entry.command }, unknown: entry.unknown, count: 0 };
834
+ unknown.count++;
835
+ unknowns.set(key, unknown);
825
836
  }
826
837
  }
827
838
  return {
828
839
  runs: entries.length,
829
840
  bins: [...bins].map(([bin, counts]) => ({ bin, ...counts })).toSorted((a, b) => b.runs - a.runs),
830
- usageErrors: [...errors.values()].toSorted((a, b) => b.count - a.count)
841
+ commands: [...commands.values()].toSorted((a, b) => b.runs - a.runs),
842
+ usageErrors: [...unknowns.values()].toSorted((a, b) => b.count - a.count)
831
843
  };
832
844
  }
833
845
 
@@ -931,7 +943,7 @@ function reportThrown(prefix, error, redact = (text) => text, json = false) {
931
943
  const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
932
944
  const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
933
945
  const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
934
- if (error instanceof UsageError)
946
+ if (error instanceof Exit && error.code === 2)
935
947
  noteUsageError(error.message);
936
948
  const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
937
949
  report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
@@ -1148,11 +1160,10 @@ import process10 from "process";
1148
1160
  import { existsSync, readFileSync as readFileSync2 } from "fs";
1149
1161
  import { basename, join as join3 } from "path";
1150
1162
  var TOOLS = {
1151
- "@kaynooo/cli-audit": ["audit"],
1152
1163
  "@kaynooo/cli-base": ["base", "proof"],
1153
1164
  "@kaynooo/cli-changelog": ["changelog"],
1154
1165
  "@kaynooo/cli-check": ["check", "fix", "errs", "j"],
1155
- "@kaynooo/cli-code": ["peek", "todo-scan", "hotspots"],
1166
+ "@kaynooo/cli-code": ["src", "peek", "todo-scan", "hotspots"],
1156
1167
  "@kaynooo/cli-db": ["db"],
1157
1168
  "@kaynooo/cli-docker": ["dc", "dlog", "dx", "sf"],
1158
1169
  "@kaynooo/cli-doctor": ["doctor", "cli"],
@@ -1167,12 +1178,11 @@ var TOOLS = {
1167
1178
  "@kaynooo/cli-pick": ["pick"],
1168
1179
  "@kaynooo/cli-pkg": ["pkg"],
1169
1180
  "@kaynooo/cli-probe": ["probe"],
1170
- "@kaynooo/cli-proc": ["pid", "ports", "procs"],
1171
- "@kaynooo/cli-repos": ["repos"],
1181
+ "@kaynooo/cli-proc": ["proc", "pid", "ports", "procs"],
1172
1182
  "@kaynooo/cli-stack": ["stack"],
1173
- "@kaynooo/cli-sweep": ["sweep"],
1174
1183
  "@kaynooo/cli-view": ["view"],
1175
- "@kaynooo/cli-wait": ["waitfor", "slot"]
1184
+ "@kaynooo/cli-wait": ["waitfor", "slot"],
1185
+ "@kaynooo/cli-workspace": ["ws", "repos", "sweep", "audit"]
1176
1186
  };
1177
1187
  var FORGE = "git.kaynooo.fr";
1178
1188
  var FORGE_HOSTS = new Set([FORGE, "git.kevyn.fr"]);
@@ -1343,6 +1353,46 @@ function missingCompletions(host, dir) {
1343
1353
  return installedBins(host).filter((bin) => !existsSync2(join4(dir, `${bin}.fish`)));
1344
1354
  }
1345
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
+
1346
1396
  // src/host.ts
1347
1397
  import { homedir as homedir2 } from "os";
1348
1398
  import { join as join5 } from "path";
@@ -1365,6 +1415,67 @@ function hostHere() {
1365
1415
  };
1366
1416
  }
1367
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
+
1368
1479
  // src/list.ts
1369
1480
  var USAGE_WORD = /^Usage:\s*/;
1370
1481
  async function describeBin(host, bin, name) {
@@ -1389,8 +1500,8 @@ Exits 0 when it printed the list, 2 on a usage error.`;
1389
1500
  var LIST_OPTIONS = {
1390
1501
  json: jsonOption("[{bin, package, installed, synopsis?, summary?, replaces?, examples?}]")
1391
1502
  };
1392
- function print(listed) {
1393
- const { cyan, dim } = paint(process12.stdout);
1503
+ function print2(listed) {
1504
+ const { cyan, dim } = paint(process13.stdout);
1394
1505
  const width = Math.max(...listed.map((each) => each.bin.length));
1395
1506
  for (const each of listed) {
1396
1507
  const what = !each.installed ? dim(`not installed: bun install -g ${each.package}`) : `${each.summary ?? ""}${each.replaces === undefined ? "" : dim(`; instead of ${each.replaces}`)}`;
@@ -1403,7 +1514,7 @@ async function list(args, host = hostHere()) {
1403
1514
  if (values.json === true)
1404
1515
  printJson(listed);
1405
1516
  else
1406
- print(listed);
1517
+ print2(listed);
1407
1518
  return 0;
1408
1519
  }
1409
1520
  var COMPLETIONS_USAGE = `cli completions <fish|bash> [--install] [--dir <folder>]: shell completions for every installed bin of the @kaynooo/cli-* packages
@@ -1440,11 +1551,11 @@ async function completions(args, host = hostHere()) {
1440
1551
  }
1441
1552
  var STATS_USAGE = `cli stats [--since 7d] [--json]: how often each bin ran, and the usage errors by the option it did not know
1442
1553
 
1443
- Every bin records each run in ~/.local/state/kaynooo-cli/usage.jsonl (or $XDG_STATE_HOME): the bin, its command, the names of the flags it saw (never a value or an argument), the exit code and, on a usage error, the unknown option. Set KAYNOOO_CLI_NO_USAGE=1 to stop recording; \`guard\` never records.
1554
+ Every bin records each run in ~/.local/state/kaynooo-cli/usage.jsonl (or $XDG_STATE_HOME): the bin, its command, the names of the flags it saw (never a value or an argument), the exit code and and, on a usage error, the unknown option (never the message, which carries the values it refused). failed counts exits other than 0 and 2, usage errors are exit 2 (misuse, or a check that could not be made). Set KAYNOOO_CLI_NO_USAGE=1 to stop recording; \`guard\` never records.
1444
1555
  Exits 0 when it printed the summary, 2 on a usage error.`;
1445
1556
  var STATS_OPTIONS = {
1446
1557
  since: { type: "string", description: "only the runs this recent (7d, 12h)" },
1447
- json: jsonOption("{runs, bins: [{bin, runs, failed, usageErrors}], usageErrors: [{bin, command?, unknown, count}]}")
1558
+ json: jsonOption("{runs, bins: [{bin, runs, failed, usageErrors}], commands: [{bin, command, runs, failed, usageErrors}], usageErrors: [{bin, command?, unknown, count}]}")
1448
1559
  };
1449
1560
  async function stats(args, path = usagePath()) {
1450
1561
  const { values } = parse(args, STATS_USAGE, STATS_OPTIONS, { positionals: [], examples: ["cli stats", ["cli stats --since 7d", "the last week"]] });
@@ -1461,6 +1572,11 @@ async function stats(args, path = usagePath()) {
1461
1572
  console.log(`${summary.runs} runs
1462
1573
 
1463
1574
  ${table(summary.bins.map((each) => [each.bin, String(each.runs), `${each.failed} failed`, `${each.usageErrors} usage errors`]))}`);
1575
+ const busy = summary.commands.filter((each) => each.failed + each.usageErrors > 0).toSorted((a, b) => b.failed + b.usageErrors - (a.failed + a.usageErrors)).slice(0, 15);
1576
+ if (busy.length > 0)
1577
+ console.log(`
1578
+ commands with failures or usage errors
1579
+ ${table(busy.map((each) => [`${each.bin} ${each.command}`, String(each.runs), `${each.failed} failed`, `${each.usageErrors} usage errors`]))}`);
1464
1580
  if (summary.usageErrors.length > 0)
1465
1581
  console.log(`
1466
1582
  unknown options
@@ -1468,12 +1584,13 @@ ${table(summary.usageErrors.map((each) => [`${each.bin}${each.command === undefi
1468
1584
  return 0;
1469
1585
  }
1470
1586
  if (import.meta.main) {
1471
- process12.exitCode = await runCli({
1587
+ process13.exitCode = await runCli({
1472
1588
  name: "cli",
1473
1589
  about: "the bins of the @kaynooo/cli-* packages, described by their own help",
1474
1590
  replaces: "running each bin's --help to find the one that fits",
1475
1591
  examples: ["cli list", ["cli list --json", "with each bin's synopsis and examples"]],
1476
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) },
1477
1594
  list: { summary: "every bin in one line: what it does and what it is reached for instead of", run: async (args) => list(args) },
1478
1595
  stats: { summary: "how often each bin ran and the options usage errors did not know", run: async (args) => stats(args) },
1479
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";
@@ -808,26 +808,38 @@ async function readUsage(path = usagePath(), since = 0) {
808
808
  }
809
809
  });
810
810
  }
811
+ function tally(counts, code) {
812
+ counts.runs++;
813
+ counts.failed += code === 0 || code === 2 ? 0 : 1;
814
+ counts.usageErrors += code === 2 ? 1 : 0;
815
+ }
811
816
  function summarizeUsage(entries) {
812
817
  const bins = new Map;
813
- const errors = new Map;
818
+ const commands = new Map;
819
+ const unknowns = new Map;
814
820
  for (const entry of entries) {
815
821
  const bin = bins.get(entry.bin) ?? { runs: 0, failed: 0, usageErrors: 0 };
816
- bin.runs++;
817
- bin.failed += entry.code === 0 ? 0 : 1;
818
- bin.usageErrors += entry.code === 2 ? 1 : 0;
822
+ tally(bin, entry.code);
819
823
  bins.set(entry.bin, bin);
820
- if (entry.code === 2 && entry.unknown !== undefined) {
824
+ if (entry.command !== undefined) {
825
+ const command = commands.get(`${entry.bin} ${entry.command}`) ?? { bin: entry.bin, command: entry.command, runs: 0, failed: 0, usageErrors: 0 };
826
+ tally(command, entry.code);
827
+ commands.set(`${entry.bin} ${entry.command}`, command);
828
+ }
829
+ if (entry.code !== 2)
830
+ continue;
831
+ if (entry.unknown !== undefined) {
821
832
  const key = `${entry.bin} ${entry.command ?? ""} ${entry.unknown}`;
822
- const error = errors.get(key) ?? { bin: entry.bin, ...entry.command === undefined ? {} : { command: entry.command }, unknown: entry.unknown, count: 0 };
823
- error.count++;
824
- errors.set(key, error);
833
+ const unknown = unknowns.get(key) ?? { bin: entry.bin, ...entry.command === undefined ? {} : { command: entry.command }, unknown: entry.unknown, count: 0 };
834
+ unknown.count++;
835
+ unknowns.set(key, unknown);
825
836
  }
826
837
  }
827
838
  return {
828
839
  runs: entries.length,
829
840
  bins: [...bins].map(([bin, counts]) => ({ bin, ...counts })).toSorted((a, b) => b.runs - a.runs),
830
- usageErrors: [...errors.values()].toSorted((a, b) => b.count - a.count)
841
+ commands: [...commands.values()].toSorted((a, b) => b.runs - a.runs),
842
+ usageErrors: [...unknowns.values()].toSorted((a, b) => b.count - a.count)
831
843
  };
832
844
  }
833
845
 
@@ -931,7 +943,7 @@ function reportThrown(prefix, error, redact = (text) => text, json = false) {
931
943
  const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
932
944
  const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
933
945
  const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
934
- if (error instanceof UsageError)
946
+ if (error instanceof Exit && error.code === 2)
935
947
  noteUsageError(error.message);
936
948
  const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
937
949
  report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
@@ -1139,6 +1151,9 @@ var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "ses
1139
1151
  var {Glob } = globalThis.Bun;
1140
1152
  var SESSION_FILES = new Glob("*.json");
1141
1153
  var ACCOUNT_DIRS = new Glob("*/sessions");
1154
+ // src/doctor.ts
1155
+ import process12 from "process";
1156
+
1142
1157
  // src/checks.ts
1143
1158
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
1144
1159
  import { basename, join as join4 } from "path";
@@ -1207,11 +1222,10 @@ function missingCompletions(host, dir) {
1207
1222
 
1208
1223
  // src/checks.ts
1209
1224
  var TOOLS = {
1210
- "@kaynooo/cli-audit": ["audit"],
1211
1225
  "@kaynooo/cli-base": ["base", "proof"],
1212
1226
  "@kaynooo/cli-changelog": ["changelog"],
1213
1227
  "@kaynooo/cli-check": ["check", "fix", "errs", "j"],
1214
- "@kaynooo/cli-code": ["peek", "todo-scan", "hotspots"],
1228
+ "@kaynooo/cli-code": ["src", "peek", "todo-scan", "hotspots"],
1215
1229
  "@kaynooo/cli-db": ["db"],
1216
1230
  "@kaynooo/cli-docker": ["dc", "dlog", "dx", "sf"],
1217
1231
  "@kaynooo/cli-doctor": ["doctor", "cli"],
@@ -1226,12 +1240,11 @@ var TOOLS = {
1226
1240
  "@kaynooo/cli-pick": ["pick"],
1227
1241
  "@kaynooo/cli-pkg": ["pkg"],
1228
1242
  "@kaynooo/cli-probe": ["probe"],
1229
- "@kaynooo/cli-proc": ["pid", "ports", "procs"],
1230
- "@kaynooo/cli-repos": ["repos"],
1243
+ "@kaynooo/cli-proc": ["proc", "pid", "ports", "procs"],
1231
1244
  "@kaynooo/cli-stack": ["stack"],
1232
- "@kaynooo/cli-sweep": ["sweep"],
1233
1245
  "@kaynooo/cli-view": ["view"],
1234
- "@kaynooo/cli-wait": ["waitfor", "slot"]
1246
+ "@kaynooo/cli-wait": ["waitfor", "slot"],
1247
+ "@kaynooo/cli-workspace": ["ws", "repos", "sweep", "audit"]
1235
1248
  };
1236
1249
  var FORGE = "git.kaynooo.fr";
1237
1250
  var FORGE_HOSTS = new Set([FORGE, "git.kevyn.fr"]);
@@ -1402,7 +1415,7 @@ function hostHere() {
1402
1415
  };
1403
1416
  }
1404
1417
 
1405
- // src/cli.ts
1418
+ // src/doctor.ts
1406
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
1407
1420
 
1408
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.
@@ -1462,8 +1475,6 @@ after the fixes:`);
1462
1475
  print(shown);
1463
1476
  return results.every((result) => result.ok) ? 0 : 1;
1464
1477
  }
1465
- if (import.meta.main)
1466
- process12.exitCode = await runMain({ name: "doctor", run: async (args) => main(args) });
1467
- export {
1468
- main
1469
- };
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.5.2",
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,9 +33,10 @@
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": {
39
- "@kaynooo/cli-kit": "0.21.0"
40
+ "@kaynooo/cli-kit": "0.21.1"
40
41
  }
41
42
  }