@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.
- package/dist/cli-bin.js +111 -11
- package/dist/cli.js +12 -13
- 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
|
|
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
|
|
1405
|
-
const { cyan, dim } = paint(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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/
|
|
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
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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.
|
|
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": {
|