@kaynooo/cli-doctor 0.8.0 → 0.9.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 +212 -79
- package/dist/cli.js +211 -78
- package/package.json +2 -2
package/dist/cli-bin.js
CHANGED
|
@@ -2,16 +2,37 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli-bin.ts
|
|
5
|
-
import
|
|
5
|
+
import process18 from "process";
|
|
6
6
|
// ../kit/src/args.ts
|
|
7
|
-
import
|
|
7
|
+
import process7 from "process";
|
|
8
8
|
import { parseArgs } from "util";
|
|
9
9
|
|
|
10
10
|
// ../kit/src/format.ts
|
|
11
|
-
import
|
|
11
|
+
import process5 from "process";
|
|
12
12
|
|
|
13
|
-
// ../kit/src/
|
|
13
|
+
// ../kit/src/mode.ts
|
|
14
14
|
import process2 from "process";
|
|
15
|
+
var MODES = new Set(["terminal", "ci", "agent", "pipe"]);
|
|
16
|
+
var AGENT_VARIABLES = ["CLAUDECODE", "AI_AGENT"];
|
|
17
|
+
function isSet(value) {
|
|
18
|
+
return value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false";
|
|
19
|
+
}
|
|
20
|
+
function outputMode(stream = process2.stdout, env = process2.env) {
|
|
21
|
+
const chosen = env.KIT_MODE;
|
|
22
|
+
if (chosen !== undefined && MODES.has(chosen))
|
|
23
|
+
return chosen;
|
|
24
|
+
if (AGENT_VARIABLES.some((name) => isSet(env[name])))
|
|
25
|
+
return "agent";
|
|
26
|
+
if (stream.isTTY === true)
|
|
27
|
+
return "terminal";
|
|
28
|
+
return isSet(env.CI) ? "ci" : "pipe";
|
|
29
|
+
}
|
|
30
|
+
function isInteractive(streams = process2) {
|
|
31
|
+
return streams.stdin?.isTTY === true && streams.stderr?.isTTY === true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ../kit/src/style.ts
|
|
35
|
+
import process4 from "process";
|
|
15
36
|
|
|
16
37
|
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
17
38
|
function x(s) {
|
|
@@ -274,22 +295,34 @@ function le(i = {}) {
|
|
|
274
295
|
}
|
|
275
296
|
var t = le();
|
|
276
297
|
|
|
298
|
+
// ../kit/src/user-config.ts
|
|
299
|
+
import { homedir } from "os";
|
|
300
|
+
import { join } from "path";
|
|
301
|
+
import process3 from "process";
|
|
302
|
+
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");
|
|
305
|
+
}
|
|
306
|
+
function userConfigPath(bin, where = {}) {
|
|
307
|
+
return join(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
308
|
+
}
|
|
309
|
+
|
|
277
310
|
// ../kit/src/theme.ts
|
|
278
311
|
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"]);
|
|
279
312
|
var MAX_FILE_BYTES = 64 * 1024;
|
|
280
313
|
var warned = new Set;
|
|
281
314
|
|
|
282
315
|
// ../kit/src/style.ts
|
|
283
|
-
function takesControlCodes(stream, env =
|
|
284
|
-
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
316
|
+
function takesControlCodes(stream, env = process4.env) {
|
|
317
|
+
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb" && outputMode(stream, env) === "terminal";
|
|
285
318
|
}
|
|
286
|
-
function paint(stream, env =
|
|
319
|
+
function paint(stream, env = process4.env) {
|
|
287
320
|
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
288
321
|
}
|
|
289
322
|
var STATUS_WORDS = {
|
|
290
323
|
passed: ["passed", "success", "succeeded", "ok"],
|
|
291
324
|
failed: ["failed", "failure", "error", "errored"],
|
|
292
|
-
running: ["running", "in_progress", "started"],
|
|
325
|
+
running: ["running", "in_progress", "started", "holding"],
|
|
293
326
|
queued: ["queued", "waiting", "pending", "created", "blocked", "scheduled"],
|
|
294
327
|
skipped: ["skipped", "cancelled", "canceled", "manual"]
|
|
295
328
|
};
|
|
@@ -308,8 +341,11 @@ var ESCAPE = String.fromCharCode(27);
|
|
|
308
341
|
function textWidth(text) {
|
|
309
342
|
return Bun.stringWidth(text);
|
|
310
343
|
}
|
|
311
|
-
function table(rows, { cellWidth, header = false, align = [], fit, stream =
|
|
344
|
+
function table(rows, { cellWidth, header = false, align = [], fit, stream = process5.stdout, env = process5.env } = {}) {
|
|
312
345
|
const cells = cellWidth === undefined ? rows : rows.map((row) => row.map((cell) => truncate(cell.replaceAll(LINE_BREAKS, " "), cellWidth)));
|
|
346
|
+
if (outputMode(stream, env) === "agent")
|
|
347
|
+
return cells.map((row) => row.map((cell) => Bun.stripANSI(cell).replaceAll(/[\t\r\n]+/g, " ")).join("\t")).join(`
|
|
348
|
+
`);
|
|
313
349
|
const widths = [];
|
|
314
350
|
for (const row of cells) {
|
|
315
351
|
for (const [index, cell] of row.entries())
|
|
@@ -344,32 +380,35 @@ function narrow(rows, widths, limit) {
|
|
|
344
380
|
}
|
|
345
381
|
return rows.map((row) => row.map((cell, index) => textWidth(cell) > (widths[index] ?? 0) ? truncate(cell, widths[index] ?? 0) : cell));
|
|
346
382
|
}
|
|
383
|
+
function jsonText(value, replacer, { stream = process5.stdout, env = process5.env } = {}) {
|
|
384
|
+
return JSON.stringify(value, replacer, outputMode(stream, env) === "agent" ? undefined : 2);
|
|
385
|
+
}
|
|
347
386
|
function printJson(value) {
|
|
348
|
-
console.log(
|
|
387
|
+
console.log(jsonText(value));
|
|
349
388
|
}
|
|
350
389
|
|
|
351
390
|
// ../kit/src/help.ts
|
|
352
|
-
import
|
|
391
|
+
import process6 from "process";
|
|
353
392
|
var OPTIONAL = /\[[^\]]+\]/g;
|
|
354
393
|
var USAGE_PREFIX = /^usage:\s*/i;
|
|
355
394
|
var FULL_STOP = /\.$/;
|
|
356
|
-
function usageLine(usage, colors = paint(
|
|
395
|
+
function usageLine(usage, colors = paint(process6.stdout)) {
|
|
357
396
|
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
358
397
|
}
|
|
359
|
-
function helpText(usage, options, colors = paint(
|
|
398
|
+
function helpText(usage, options, colors = paint(process6.stdout), { examples = [], replaces, exits = [] } = {}) {
|
|
360
399
|
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
|
|
361
400
|
`);
|
|
362
401
|
}
|
|
363
|
-
function exitRows(exits, colors = paint(
|
|
402
|
+
function exitRows(exits, colors = paint(process6.stdout)) {
|
|
364
403
|
if (exits.length === 0)
|
|
365
404
|
return [];
|
|
366
405
|
const width = Math.max(...exits.map(([code]) => String(code).length));
|
|
367
406
|
return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
|
|
368
407
|
}
|
|
369
|
-
function replacesRows(replaces, colors = paint(
|
|
370
|
-
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
408
|
+
function replacesRows(replaces, colors = paint(process6.stdout)) {
|
|
409
|
+
return replaces === undefined || outputMode() === "agent" ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
371
410
|
}
|
|
372
|
-
function wantsHelpJson(env =
|
|
411
|
+
function wantsHelpJson(env = process6.env) {
|
|
373
412
|
return env.KIT_HELP === "json";
|
|
374
413
|
}
|
|
375
414
|
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
@@ -388,12 +427,12 @@ function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
|
388
427
|
...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
|
|
389
428
|
};
|
|
390
429
|
}
|
|
391
|
-
function exampleRows(examples, colors = paint(
|
|
392
|
-
if (examples.length === 0)
|
|
430
|
+
function exampleRows(examples, colors = paint(process6.stdout)) {
|
|
431
|
+
if (examples.length === 0 || outputMode() === "agent")
|
|
393
432
|
return [];
|
|
394
433
|
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
395
434
|
}
|
|
396
|
-
function optionRows(options, colors = paint(
|
|
435
|
+
function optionRows(options, colors = paint(process6.stdout)) {
|
|
397
436
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
398
437
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
399
438
|
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
@@ -486,7 +525,7 @@ var OUTPUT_OPTIONS = {
|
|
|
486
525
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
487
526
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
488
527
|
};
|
|
489
|
-
function applyOutput(color, plain, env =
|
|
528
|
+
function applyOutput(color, plain, env = process7.env) {
|
|
490
529
|
const when = plain === true ? "never" : color ?? "auto";
|
|
491
530
|
if (when === "auto")
|
|
492
531
|
return;
|
|
@@ -657,7 +696,7 @@ function nearestOption(message, options, allowNegative) {
|
|
|
657
696
|
}
|
|
658
697
|
// ../kit/src/process.ts
|
|
659
698
|
import { constants } from "os";
|
|
660
|
-
import
|
|
699
|
+
import process8 from "process";
|
|
661
700
|
var KILL_GRACE_MS = 2000;
|
|
662
701
|
function exitCodeOf(code, signal) {
|
|
663
702
|
if (code !== null)
|
|
@@ -677,7 +716,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
|
|
|
677
716
|
return;
|
|
678
717
|
try {
|
|
679
718
|
if (grouped)
|
|
680
|
-
|
|
719
|
+
process8.kill(-proc.pid, killing);
|
|
681
720
|
else
|
|
682
721
|
proc.kill(killing);
|
|
683
722
|
} catch {}
|
|
@@ -752,14 +791,14 @@ var RESET_STYLE = `${ESC}[0m`;
|
|
|
752
791
|
var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
753
792
|
// ../kit/src/cli.ts
|
|
754
793
|
import { readFileSync, realpathSync } from "fs";
|
|
755
|
-
import { dirname as dirname2, join as
|
|
756
|
-
import
|
|
794
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
795
|
+
import process10 from "process";
|
|
757
796
|
|
|
758
797
|
// ../kit/src/usage.ts
|
|
759
798
|
import { appendFileSync, mkdirSync } from "fs";
|
|
760
|
-
import { homedir } from "os";
|
|
761
|
-
import { dirname, isAbsolute, join } from "path";
|
|
762
|
-
import
|
|
799
|
+
import { homedir as homedir2 } from "os";
|
|
800
|
+
import { dirname, isAbsolute, join as join2 } from "path";
|
|
801
|
+
import process9 from "process";
|
|
763
802
|
|
|
764
803
|
// ../kit/src/logs.ts
|
|
765
804
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -773,14 +812,14 @@ var usageError;
|
|
|
773
812
|
function noteUsageError(message) {
|
|
774
813
|
usageError = message;
|
|
775
814
|
}
|
|
776
|
-
function stateHome(env =
|
|
815
|
+
function stateHome(env = process9.env) {
|
|
777
816
|
const dir = env.XDG_STATE_HOME;
|
|
778
|
-
return dir !== undefined && isAbsolute(dir) ? dir :
|
|
817
|
+
return dir !== undefined && isAbsolute(dir) ? dir : join2(homedir2(), ".local", "state");
|
|
779
818
|
}
|
|
780
|
-
function usagePath(env =
|
|
781
|
-
return
|
|
819
|
+
function usagePath(env = process9.env) {
|
|
820
|
+
return join2(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
782
821
|
}
|
|
783
|
-
function usageRecorded(env =
|
|
822
|
+
function usageRecorded(env = process9.env) {
|
|
784
823
|
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
785
824
|
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
786
825
|
}
|
|
@@ -794,7 +833,7 @@ function usageEntry(bin, command, argv, code, now = new Date) {
|
|
|
794
833
|
usageError = undefined;
|
|
795
834
|
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
796
835
|
}
|
|
797
|
-
function recordUsage(entry, env =
|
|
836
|
+
function recordUsage(entry, env = process9.env) {
|
|
798
837
|
if (!usageRecorded(env))
|
|
799
838
|
return;
|
|
800
839
|
try {
|
|
@@ -933,8 +972,8 @@ async function help2({ path, header, summary: lazySummary, commands, defaultComm
|
|
|
933
972
|
`);
|
|
934
973
|
}
|
|
935
974
|
function printError(prefix, message, hint, cause) {
|
|
936
|
-
const colors = paint(
|
|
937
|
-
const styled = takesControlCodes(
|
|
975
|
+
const colors = paint(process10.stderr);
|
|
976
|
+
const styled = takesControlCodes(process10.stderr);
|
|
938
977
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
939
978
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
940
979
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -977,11 +1016,11 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
977
1016
|
}
|
|
978
1017
|
}
|
|
979
1018
|
if (name === undefined && level.path.length > 1) {
|
|
980
|
-
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1019
|
+
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stderr));
|
|
981
1020
|
return 2;
|
|
982
1021
|
}
|
|
983
1022
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
984
|
-
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1023
|
+
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stdout));
|
|
985
1024
|
return 0;
|
|
986
1025
|
}
|
|
987
1026
|
if (level.path.length === 1 && (name === "--version" || name === "-v")) {
|
|
@@ -1100,7 +1139,7 @@ async function printCandidates(found) {
|
|
|
1100
1139
|
function packageVersion(entry = Bun.main) {
|
|
1101
1140
|
for (let dir = dirname2(realpathSync(entry));; dir = dirname2(dir)) {
|
|
1102
1141
|
try {
|
|
1103
|
-
const { version } = JSON.parse(readFileSync(
|
|
1142
|
+
const { version } = JSON.parse(readFileSync(join3(dir, "package.json"), "utf8"));
|
|
1104
1143
|
if (typeof version === "string")
|
|
1105
1144
|
return version;
|
|
1106
1145
|
} catch {}
|
|
@@ -1108,7 +1147,7 @@ function packageVersion(entry = Bun.main) {
|
|
|
1108
1147
|
return "0.0.0";
|
|
1109
1148
|
}
|
|
1110
1149
|
}
|
|
1111
|
-
async function runCli(cli, argv =
|
|
1150
|
+
async function runCli(cli, argv = process10.argv.slice(2)) {
|
|
1112
1151
|
const version = cli.version ?? packageVersion();
|
|
1113
1152
|
if (argv[0] === COMPLETE)
|
|
1114
1153
|
return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
|
|
@@ -1135,7 +1174,7 @@ function commandPath(scope, argv) {
|
|
|
1135
1174
|
}
|
|
1136
1175
|
return path.length === 0 ? undefined : path.join(" ");
|
|
1137
1176
|
}
|
|
1138
|
-
async function runMain({ name, version, run, redact, usage }, argv =
|
|
1177
|
+
async function runMain({ name, version, run, redact, usage }, argv = process10.argv.slice(2)) {
|
|
1139
1178
|
if (argv[0] === COMPLETE)
|
|
1140
1179
|
return printCandidates(leafCandidates(run, argv.slice(1)));
|
|
1141
1180
|
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
@@ -1161,14 +1200,61 @@ var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "ses
|
|
|
1161
1200
|
var {Glob } = globalThis.Bun;
|
|
1162
1201
|
var SESSION_FILES = new Glob("*.json");
|
|
1163
1202
|
var ACCOUNT_DIRS = new Glob("*/sessions");
|
|
1203
|
+
// ../kit/src/workspace-root.ts
|
|
1204
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
1205
|
+
import { homedir as homedir3 } from "os";
|
|
1206
|
+
import { dirname as dirname3, join as join4, resolve } from "path";
|
|
1207
|
+
import process11 from "process";
|
|
1208
|
+
function expandHome(path, home) {
|
|
1209
|
+
if (path === "~")
|
|
1210
|
+
return home;
|
|
1211
|
+
return path.startsWith("~/") ? join4(home, path.slice(2)) : path;
|
|
1212
|
+
}
|
|
1213
|
+
function configured(env, home) {
|
|
1214
|
+
const path = userConfigPath("config", { home, xdg: env.XDG_CONFIG_HOME });
|
|
1215
|
+
if (!existsSync(path))
|
|
1216
|
+
return;
|
|
1217
|
+
try {
|
|
1218
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
1219
|
+
const folder = typeof parsed === "object" && parsed !== null ? parsed.workspace : undefined;
|
|
1220
|
+
return typeof folder === "string" && folder !== "" ? folder : undefined;
|
|
1221
|
+
} catch {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
function workspaceRoot({ given, env = process11.env, home = homedir3() } = {}) {
|
|
1226
|
+
const fromEnv = env.KAYNOOO_WORKSPACE === "" ? undefined : env.KAYNOOO_WORKSPACE;
|
|
1227
|
+
return resolve(expandHome(given ?? fromEnv ?? configured(env, home) ?? join4(home, "Workspace"), home));
|
|
1228
|
+
}
|
|
1229
|
+
function workspaceChosen({ env = process11.env, home = homedir3() } = {}) {
|
|
1230
|
+
return (env.KAYNOOO_WORKSPACE ?? "") !== "" || configured(env, home) !== undefined;
|
|
1231
|
+
}
|
|
1232
|
+
function saveWorkspace(folder, { env = process11.env, home = homedir3() } = {}) {
|
|
1233
|
+
const path = userConfigPath("config", { home, xdg: env.XDG_CONFIG_HOME });
|
|
1234
|
+
let current = {};
|
|
1235
|
+
if (existsSync(path)) {
|
|
1236
|
+
try {
|
|
1237
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
1238
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
1239
|
+
return false;
|
|
1240
|
+
current = parsed;
|
|
1241
|
+
} catch {
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
mkdirSync2(dirname3(path), { recursive: true });
|
|
1246
|
+
writeFileSync(path, `${JSON.stringify({ ...current, workspace: folder }, undefined, 2)}
|
|
1247
|
+
`);
|
|
1248
|
+
return true;
|
|
1249
|
+
}
|
|
1164
1250
|
// src/completions.ts
|
|
1165
|
-
import { existsSync as
|
|
1166
|
-
import { join as
|
|
1167
|
-
import
|
|
1251
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync4, rmSync } from "fs";
|
|
1252
|
+
import { join as join6 } from "path";
|
|
1253
|
+
import process13 from "process";
|
|
1168
1254
|
|
|
1169
1255
|
// src/checks.ts
|
|
1170
|
-
import { existsSync, readFileSync as
|
|
1171
|
-
import { basename, join as
|
|
1256
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
1257
|
+
import { basename, join as join5 } from "path";
|
|
1172
1258
|
|
|
1173
1259
|
// src/catalog.ts
|
|
1174
1260
|
var HOOKS_REQUIRES = "@kaynooo/cli-guard";
|
|
@@ -1244,7 +1330,7 @@ function readJsonText(text) {
|
|
|
1244
1330
|
}
|
|
1245
1331
|
}
|
|
1246
1332
|
function readJson(path) {
|
|
1247
|
-
return
|
|
1333
|
+
return existsSync2(path) ? readJsonText(readFileSync3(path, "utf8")) : undefined;
|
|
1248
1334
|
}
|
|
1249
1335
|
function firstLine(text) {
|
|
1250
1336
|
const trimmed = text.trim();
|
|
@@ -1253,7 +1339,7 @@ function firstLine(text) {
|
|
|
1253
1339
|
return end === -1 ? trimmed : trimmed.slice(0, end);
|
|
1254
1340
|
}
|
|
1255
1341
|
function installed(host, name) {
|
|
1256
|
-
return readJson(
|
|
1342
|
+
return readJson(join5(host.globalModules, name, "package.json"));
|
|
1257
1343
|
}
|
|
1258
1344
|
function isInstalled(host, name) {
|
|
1259
1345
|
return installed(host, name)?.version !== undefined;
|
|
@@ -1261,7 +1347,7 @@ function isInstalled(host, name) {
|
|
|
1261
1347
|
function ownBin(host, name, bin) {
|
|
1262
1348
|
const declared = installed(host, name)?.bin;
|
|
1263
1349
|
const file = typeof declared === "string" ? declared : declared?.[bin];
|
|
1264
|
-
return file === undefined ? undefined :
|
|
1350
|
+
return file === undefined ? undefined : join5(host.globalModules, name, file);
|
|
1265
1351
|
}
|
|
1266
1352
|
async function checkTool(host, name, bins) {
|
|
1267
1353
|
const check = name.slice(name.indexOf("/") + 1);
|
|
@@ -1276,7 +1362,7 @@ async function checkTool(host, name, bins) {
|
|
|
1276
1362
|
if (latest !== "" && Bun.semver.order(version, latest) < 0)
|
|
1277
1363
|
return { check, ok: false, detail: `${version}, ${latest} released${off.length > 0 ? `, ${off.join(", ")} not on the PATH` : ""}`, fix: `bun install -g ${name}@${latest}` };
|
|
1278
1364
|
if (off.length > 0)
|
|
1279
|
-
return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${
|
|
1365
|
+
return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${join5(host.globalModules, "..", "..", "..", "bin")} to the PATH` };
|
|
1280
1366
|
if (latest === "")
|
|
1281
1367
|
return { check, ok: true, detail: `${version}, the registry did not answer: ${firstLine(info.stderr) || answered || "no version"}` };
|
|
1282
1368
|
return { check, ok: true, detail: version };
|
|
@@ -1297,9 +1383,9 @@ async function checkTea(host) {
|
|
|
1297
1383
|
return { check: "tea", ok: true, detail: `logged in to ${forge} as ${login.name}, Forgejo ${served}` };
|
|
1298
1384
|
}
|
|
1299
1385
|
function hooksWiring(host) {
|
|
1300
|
-
const settings = readJson(
|
|
1386
|
+
const settings = readJson(join5(host.home, ".claude", "settings.json")) ?? {};
|
|
1301
1387
|
const plugin = settings.enabledPlugins?.[PLUGIN] === true;
|
|
1302
|
-
const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" &&
|
|
1388
|
+
const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" && existsSync2(join5(dir, "hooks", "hooks.json")));
|
|
1303
1389
|
return { plugin, mod };
|
|
1304
1390
|
}
|
|
1305
1391
|
function checkHooks(host) {
|
|
@@ -1337,8 +1423,15 @@ function checkNeeds(host) {
|
|
|
1337
1423
|
return { check: "needs", ok: true, detail: "every tool the installed packages need is on the PATH" };
|
|
1338
1424
|
}
|
|
1339
1425
|
var toolCheck = (name) => name.slice(name.indexOf("/") + 1);
|
|
1340
|
-
var OTHER_CHECKS = ["tea", "hooks", "needs", "bun", "completions"];
|
|
1426
|
+
var OTHER_CHECKS = ["tea", "hooks", "needs", "bun", "completions", "workspace"];
|
|
1341
1427
|
var FORGEJO = "@kaynooo/cli-forgejo";
|
|
1428
|
+
var WORKSPACE = "@kaynooo/cli-workspace";
|
|
1429
|
+
function checkWorkspace(host, env = process.env) {
|
|
1430
|
+
const folder = workspaceRoot({ home: host.home, env });
|
|
1431
|
+
if (existsSync2(folder))
|
|
1432
|
+
return { check: "workspace", ok: true, detail: folder };
|
|
1433
|
+
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` };
|
|
1434
|
+
}
|
|
1342
1435
|
var CHECK_NAMES = [...Object.keys(TOOLS).map(toolCheck), ...OTHER_CHECKS];
|
|
1343
1436
|
async function runChecks(host, only = []) {
|
|
1344
1437
|
const wanted = (check) => only.length === 0 || only.includes(check);
|
|
@@ -1354,7 +1447,8 @@ async function runChecks(host, only = []) {
|
|
|
1354
1447
|
...wanted("hooks") && hooks ? [checkHooks(host)] : [],
|
|
1355
1448
|
...wanted("needs") ? [checkNeeds(host)] : [],
|
|
1356
1449
|
...wanted("bun") ? [checkBun(host)] : [],
|
|
1357
|
-
...wanted("completions") ? [checkCompletions(host)] : []
|
|
1450
|
+
...wanted("completions") ? [checkCompletions(host)] : [],
|
|
1451
|
+
...wanted("workspace") && (only.length > 0 || isInstalled(host, WORKSPACE) || isInstalled(host, "@kaynooo/cli-pkg")) ? [checkWorkspace(host)] : []
|
|
1358
1452
|
];
|
|
1359
1453
|
}
|
|
1360
1454
|
|
|
@@ -1392,8 +1486,8 @@ ${BASH_FUNCTION}
|
|
|
1392
1486
|
complete -F __kaynooo_cli_complete ${bins.join(" ")}
|
|
1393
1487
|
`;
|
|
1394
1488
|
}
|
|
1395
|
-
function completionDir(home, env =
|
|
1396
|
-
return
|
|
1489
|
+
function completionDir(home, env = process13.env) {
|
|
1490
|
+
return join6(env.XDG_CACHE_HOME ?? join6(home, ".cache"), "fish", "kaynooo-cli");
|
|
1397
1491
|
}
|
|
1398
1492
|
function installedBins(host) {
|
|
1399
1493
|
return Object.values(TOOLS).flat().filter((bin) => host.which(bin) !== null);
|
|
@@ -1406,19 +1500,19 @@ complete -c ${bin} -f -a '(__kaynooo_cli_complete ${bin})'
|
|
|
1406
1500
|
}
|
|
1407
1501
|
async function installCompletions(host, dir) {
|
|
1408
1502
|
const bins = installedBins(host);
|
|
1409
|
-
|
|
1410
|
-
const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) &&
|
|
1503
|
+
mkdirSync3(dir, { recursive: true });
|
|
1504
|
+
const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) && readFileSync4(join6(dir, name), "utf8").startsWith(MARKER));
|
|
1411
1505
|
for (const name of removed)
|
|
1412
|
-
rmSync(
|
|
1413
|
-
await Promise.all(bins.map(async (bin) => Bun.write(
|
|
1506
|
+
rmSync(join6(dir, name));
|
|
1507
|
+
await Promise.all(bins.map(async (bin) => Bun.write(join6(dir, `${bin}.fish`), completionFile(bin))));
|
|
1414
1508
|
return { written: bins, removed: removed.map((name) => name.replace(FISH_FILE, "")) };
|
|
1415
1509
|
}
|
|
1416
1510
|
function missingCompletions(host, dir) {
|
|
1417
|
-
return installedBins(host).filter((bin) => !
|
|
1511
|
+
return installedBins(host).filter((bin) => !existsSync3(join6(dir, `${bin}.fish`)));
|
|
1418
1512
|
}
|
|
1419
1513
|
|
|
1420
1514
|
// src/doctor.ts
|
|
1421
|
-
import
|
|
1515
|
+
import process17 from "process";
|
|
1422
1516
|
|
|
1423
1517
|
// src/fix.ts
|
|
1424
1518
|
var INSTALL = /^bun install -g (\S+)$/;
|
|
@@ -1458,19 +1552,19 @@ async function applyFixes(host, steps, dry) {
|
|
|
1458
1552
|
}
|
|
1459
1553
|
|
|
1460
1554
|
// src/host.ts
|
|
1461
|
-
import { homedir as
|
|
1462
|
-
import { join as
|
|
1463
|
-
import
|
|
1555
|
+
import { homedir as homedir4 } from "os";
|
|
1556
|
+
import { join as join7 } from "path";
|
|
1557
|
+
import process14 from "process";
|
|
1464
1558
|
var RUN_TIMEOUT_MS = 20000;
|
|
1465
1559
|
function hostHere() {
|
|
1466
|
-
const home =
|
|
1560
|
+
const home = homedir4();
|
|
1467
1561
|
return {
|
|
1468
1562
|
home,
|
|
1469
|
-
globalModules:
|
|
1563
|
+
globalModules: join7(process14.env.BUN_INSTALL ?? join7(home, ".bun"), "install", "global", "node_modules"),
|
|
1470
1564
|
bunVersion: Bun.version,
|
|
1471
1565
|
which: (bin) => Bun.which(bin),
|
|
1472
1566
|
run: async (argv, env) => {
|
|
1473
|
-
const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...
|
|
1567
|
+
const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...process14.env, ...env } } });
|
|
1474
1568
|
if (ran.timedOut)
|
|
1475
1569
|
return { code: 1, stdout: "", stderr: `timed out after ${RUN_TIMEOUT_MS / 1000}s` };
|
|
1476
1570
|
const of = (stream) => Buffer.concat(ran.chunks.filter((chunk) => chunk.stream === stream).map((chunk) => chunk.data)).toString();
|
|
@@ -1480,10 +1574,10 @@ function hostHere() {
|
|
|
1480
1574
|
}
|
|
1481
1575
|
|
|
1482
1576
|
// src/install.ts
|
|
1483
|
-
import
|
|
1577
|
+
import process16 from "process";
|
|
1484
1578
|
|
|
1485
1579
|
// ../kit/src/prompt.ts
|
|
1486
|
-
import
|
|
1580
|
+
import process15 from "process";
|
|
1487
1581
|
var KEY_SEQUENCES = /\x1B\[[0-9;]*[A-Z~]|\x1BO[A-Z]|[\s\S]/giu;
|
|
1488
1582
|
var CONTROL = /^[\x00-\x1F\x7F]/;
|
|
1489
1583
|
var WORDS = /\s+/;
|
|
@@ -1521,6 +1615,36 @@ async function checklist(question, choices, { initial = new Set, min = 0, toggle
|
|
|
1521
1615
|
});
|
|
1522
1616
|
return accepted ? checked : undefined;
|
|
1523
1617
|
}
|
|
1618
|
+
async function input2(question, { default: fallback, mask = false, validate, ...settings } = {}) {
|
|
1619
|
+
let value = "";
|
|
1620
|
+
let invalid;
|
|
1621
|
+
const taken = () => value === "" ? fallback ?? "" : value;
|
|
1622
|
+
const shown = () => mask ? "*".repeat([...taken()].length) : taken();
|
|
1623
|
+
const accepted = await ask(question, settings, (colors, state, { columns }) => {
|
|
1624
|
+
if (state !== "asking")
|
|
1625
|
+
return [answer(colors, question, state, shown())];
|
|
1626
|
+
const characters = [...shown()];
|
|
1627
|
+
const room = Math.max(columns - question.length - 5, 1);
|
|
1628
|
+
const tail = characters.length > room ? `\u2026${characters.slice(1 - room).join("")}` : shown();
|
|
1629
|
+
const typed = value === "" ? colors.dim(tail) : tail;
|
|
1630
|
+
return [`${colors.cyan("?")} ${question} ${typed}${colors.dim("\u2588")}`, ...invalid === undefined ? [] : [` ${colors.red(invalid)}`]];
|
|
1631
|
+
}, (key) => {
|
|
1632
|
+
if (key === "cancel")
|
|
1633
|
+
return "cancel";
|
|
1634
|
+
invalid = undefined;
|
|
1635
|
+
if (key === "enter") {
|
|
1636
|
+
invalid = validate?.(taken());
|
|
1637
|
+
return invalid === undefined ? "enter" : undefined;
|
|
1638
|
+
}
|
|
1639
|
+
if (key === "erase")
|
|
1640
|
+
value = [...value].slice(0, -1).join("");
|
|
1641
|
+
else if (typeof key === "object")
|
|
1642
|
+
value += key.text;
|
|
1643
|
+
return;
|
|
1644
|
+
});
|
|
1645
|
+
return accepted ? taken() : undefined;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1524
1648
|
class List {
|
|
1525
1649
|
choices;
|
|
1526
1650
|
query = "";
|
|
@@ -1579,9 +1703,9 @@ function asking(colors, question, typed, keys) {
|
|
|
1579
1703
|
function answer(colors, question, state, picked) {
|
|
1580
1704
|
return state === "enter" ? `${colors.green("\u2713")} ${question} ${colors.cyan(picked)}` : `${colors.red("\u2717")} ${question} ${colors.dim("cancelled")}`;
|
|
1581
1705
|
}
|
|
1582
|
-
async function ask(question, { hint, terminal =
|
|
1706
|
+
async function ask(question, { hint, terminal = process15 }, render, press) {
|
|
1583
1707
|
const { stdin, stderr } = terminal;
|
|
1584
|
-
if (
|
|
1708
|
+
if (!isInteractive(terminal))
|
|
1585
1709
|
fail(`cannot ask "${question}" off a terminal`, 2, hint);
|
|
1586
1710
|
const colors = paint(stderr);
|
|
1587
1711
|
let drawn = 0;
|
|
@@ -1680,15 +1804,22 @@ function checksFor(packages, plugin) {
|
|
|
1680
1804
|
return [...packages.map((name) => name.slice(name.indexOf("/") + 1)), ...plugin ? ["hooks"] : [], "needs", "completions", ...packages.includes("@kaynooo/cli-forgejo") ? ["tea"] : []];
|
|
1681
1805
|
}
|
|
1682
1806
|
async function ask2(pool) {
|
|
1683
|
-
if (
|
|
1807
|
+
if (!isInteractive())
|
|
1684
1808
|
badUsage("name what to install, or all: doctor --install forgejo check hooks (doctor --install --list shows the choices)");
|
|
1685
1809
|
const choices = pool.map((each) => ({ value: each, label: each.label, hint: each.hint }));
|
|
1686
1810
|
const picked = await checklist("install which?", choices, { hint: "name them instead: doctor --install forgejo check" });
|
|
1687
1811
|
return picked === undefined ? [] : [...picked];
|
|
1688
1812
|
}
|
|
1813
|
+
async function askWorkspace(host) {
|
|
1814
|
+
if (!isInteractive() || workspaceChosen({ home: host.home }))
|
|
1815
|
+
return;
|
|
1816
|
+
const folder = await input2("folder holding your repositories (repos, sweep and pkg bump look there)", { default: "~/Workspace" });
|
|
1817
|
+
if (folder !== undefined && folder !== "" && !saveWorkspace(folder, { home: host.home }))
|
|
1818
|
+
console.error(`could not write the workspace into ${userConfigPath("config", { home: host.home })}: it does not parse, fix it by hand`);
|
|
1819
|
+
}
|
|
1689
1820
|
async function install(host, options, recheck) {
|
|
1690
1821
|
const pool = candidates2(host);
|
|
1691
|
-
const { dim, green, red, yellow } = paint(
|
|
1822
|
+
const { dim, green, red, yellow } = paint(process16.stdout);
|
|
1692
1823
|
if (options.list) {
|
|
1693
1824
|
for (const each of pool)
|
|
1694
1825
|
console.log(`${each.label.padEnd(12)} ${dim(each.hint)}`);
|
|
@@ -1719,6 +1850,8 @@ async function install(host, options, recheck) {
|
|
|
1719
1850
|
console.log(`${yellow("warn ")} ${each.package}: ${each.need} is missing, ${each.why}`);
|
|
1720
1851
|
if (planned.packages.length === 0 && !planned.plugin)
|
|
1721
1852
|
return 1;
|
|
1853
|
+
if (!options.dryRun && planned.packages.some((name) => name === "@kaynooo/cli-workspace" || name === "@kaynooo/cli-pkg"))
|
|
1854
|
+
await askWorkspace(host);
|
|
1722
1855
|
const command = ["bun", "install", "-g", ...planned.packages];
|
|
1723
1856
|
if (planned.packages.length > 0)
|
|
1724
1857
|
console.log(`${options.dryRun ? dim("would ") : green("install")} ${command.join(" ")}`);
|
|
@@ -1775,7 +1908,7 @@ var OPTIONS = {
|
|
|
1775
1908
|
function print(results) {
|
|
1776
1909
|
if (results.length === 0)
|
|
1777
1910
|
return;
|
|
1778
|
-
const { green, red, dim } = paint(
|
|
1911
|
+
const { green, red, dim } = paint(process17.stdout);
|
|
1779
1912
|
const width = Math.max(...results.map((result) => result.check.length));
|
|
1780
1913
|
for (const { check, ok, detail, fix } of results)
|
|
1781
1914
|
console.log(`${ok ? green("ok ") : red("FAIL")} ${check.padEnd(width)} ${detail}${fix === undefined ? "" : ` ${dim("fix:")} ${fix}`}`);
|
|
@@ -1785,7 +1918,7 @@ function print(results) {
|
|
|
1785
1918
|
${dim("fix them all:")} ${INSTALL2}${installs.join(" ")}`);
|
|
1786
1919
|
}
|
|
1787
1920
|
function printOutcomes(outcomes, log) {
|
|
1788
|
-
const { green, red, dim } = paint(
|
|
1921
|
+
const { green, red, dim } = paint(process17.stdout);
|
|
1789
1922
|
const marks = { ran: green("ran "), failed: red("failed "), "dry-run": dim("would "), "not run": dim("not run") };
|
|
1790
1923
|
for (const { command, status, detail } of outcomes)
|
|
1791
1924
|
log(`${marks[status]} ${command}${detail === undefined ? "" : ` ${dim(detail)}`}`);
|
|
@@ -1825,7 +1958,7 @@ after the fixes:`);
|
|
|
1825
1958
|
const absent = Object.keys(TOOLS).filter((name) => !isInstalled(host, name)).length;
|
|
1826
1959
|
if (!json && only.length === 0 && absent > 0)
|
|
1827
1960
|
console.log(`
|
|
1828
|
-
${paint(
|
|
1961
|
+
${paint(process17.stdout).dim(`${absent} packages not installed: doctor --install`)}`);
|
|
1829
1962
|
return results.every((result) => result.ok) ? 0 : 1;
|
|
1830
1963
|
}
|
|
1831
1964
|
|
|
@@ -1854,7 +1987,7 @@ var LIST_OPTIONS = {
|
|
|
1854
1987
|
json: jsonOption("[{bin, package, installed, synopsis?, summary?, replaces?, examples?}]")
|
|
1855
1988
|
};
|
|
1856
1989
|
function print2(listed) {
|
|
1857
|
-
const { cyan, dim } = paint(
|
|
1990
|
+
const { cyan, dim } = paint(process18.stdout);
|
|
1858
1991
|
const width = Math.max(...listed.map((each) => each.bin.length));
|
|
1859
1992
|
for (const each of listed) {
|
|
1860
1993
|
const what = !each.installed ? dim(`not installed: bun install -g ${each.package}`) : `${each.summary ?? ""}${each.replaces === undefined ? "" : dim(`; instead of ${each.replaces}`)}`;
|
|
@@ -1937,7 +2070,7 @@ ${table(summary.usageErrors.map((each) => [`${each.bin}${each.command === undefi
|
|
|
1937
2070
|
return 0;
|
|
1938
2071
|
}
|
|
1939
2072
|
if (import.meta.main) {
|
|
1940
|
-
|
|
2073
|
+
process18.exitCode = await runCli({
|
|
1941
2074
|
name: "cli",
|
|
1942
2075
|
about: "the bins of the @kaynooo/cli-* packages, described by their own help",
|
|
1943
2076
|
replaces: "running each bin's --help to find the one that fits",
|
package/dist/cli.js
CHANGED
|
@@ -2,16 +2,37 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
|
-
import
|
|
5
|
+
import process18 from "process";
|
|
6
6
|
// ../kit/src/args.ts
|
|
7
|
-
import
|
|
7
|
+
import process7 from "process";
|
|
8
8
|
import { parseArgs } from "util";
|
|
9
9
|
|
|
10
10
|
// ../kit/src/format.ts
|
|
11
|
-
import
|
|
11
|
+
import process5 from "process";
|
|
12
12
|
|
|
13
|
-
// ../kit/src/
|
|
13
|
+
// ../kit/src/mode.ts
|
|
14
14
|
import process2 from "process";
|
|
15
|
+
var MODES = new Set(["terminal", "ci", "agent", "pipe"]);
|
|
16
|
+
var AGENT_VARIABLES = ["CLAUDECODE", "AI_AGENT"];
|
|
17
|
+
function isSet(value) {
|
|
18
|
+
return value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false";
|
|
19
|
+
}
|
|
20
|
+
function outputMode(stream = process2.stdout, env = process2.env) {
|
|
21
|
+
const chosen = env.KIT_MODE;
|
|
22
|
+
if (chosen !== undefined && MODES.has(chosen))
|
|
23
|
+
return chosen;
|
|
24
|
+
if (AGENT_VARIABLES.some((name) => isSet(env[name])))
|
|
25
|
+
return "agent";
|
|
26
|
+
if (stream.isTTY === true)
|
|
27
|
+
return "terminal";
|
|
28
|
+
return isSet(env.CI) ? "ci" : "pipe";
|
|
29
|
+
}
|
|
30
|
+
function isInteractive(streams = process2) {
|
|
31
|
+
return streams.stdin?.isTTY === true && streams.stderr?.isTTY === true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ../kit/src/style.ts
|
|
35
|
+
import process4 from "process";
|
|
15
36
|
|
|
16
37
|
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
17
38
|
function x(s) {
|
|
@@ -274,22 +295,34 @@ function le(i = {}) {
|
|
|
274
295
|
}
|
|
275
296
|
var t = le();
|
|
276
297
|
|
|
298
|
+
// ../kit/src/user-config.ts
|
|
299
|
+
import { homedir } from "os";
|
|
300
|
+
import { join } from "path";
|
|
301
|
+
import process3 from "process";
|
|
302
|
+
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");
|
|
305
|
+
}
|
|
306
|
+
function userConfigPath(bin, where = {}) {
|
|
307
|
+
return join(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
308
|
+
}
|
|
309
|
+
|
|
277
310
|
// ../kit/src/theme.ts
|
|
278
311
|
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"]);
|
|
279
312
|
var MAX_FILE_BYTES = 64 * 1024;
|
|
280
313
|
var warned = new Set;
|
|
281
314
|
|
|
282
315
|
// ../kit/src/style.ts
|
|
283
|
-
function takesControlCodes(stream, env =
|
|
284
|
-
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
316
|
+
function takesControlCodes(stream, env = process4.env) {
|
|
317
|
+
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb" && outputMode(stream, env) === "terminal";
|
|
285
318
|
}
|
|
286
|
-
function paint(stream, env =
|
|
319
|
+
function paint(stream, env = process4.env) {
|
|
287
320
|
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
288
321
|
}
|
|
289
322
|
var STATUS_WORDS = {
|
|
290
323
|
passed: ["passed", "success", "succeeded", "ok"],
|
|
291
324
|
failed: ["failed", "failure", "error", "errored"],
|
|
292
|
-
running: ["running", "in_progress", "started"],
|
|
325
|
+
running: ["running", "in_progress", "started", "holding"],
|
|
293
326
|
queued: ["queued", "waiting", "pending", "created", "blocked", "scheduled"],
|
|
294
327
|
skipped: ["skipped", "cancelled", "canceled", "manual"]
|
|
295
328
|
};
|
|
@@ -308,8 +341,11 @@ var ESCAPE = String.fromCharCode(27);
|
|
|
308
341
|
function textWidth(text) {
|
|
309
342
|
return Bun.stringWidth(text);
|
|
310
343
|
}
|
|
311
|
-
function table(rows, { cellWidth, header = false, align = [], fit, stream =
|
|
344
|
+
function table(rows, { cellWidth, header = false, align = [], fit, stream = process5.stdout, env = process5.env } = {}) {
|
|
312
345
|
const cells = cellWidth === undefined ? rows : rows.map((row) => row.map((cell) => truncate(cell.replaceAll(LINE_BREAKS, " "), cellWidth)));
|
|
346
|
+
if (outputMode(stream, env) === "agent")
|
|
347
|
+
return cells.map((row) => row.map((cell) => Bun.stripANSI(cell).replaceAll(/[\t\r\n]+/g, " ")).join("\t")).join(`
|
|
348
|
+
`);
|
|
313
349
|
const widths = [];
|
|
314
350
|
for (const row of cells) {
|
|
315
351
|
for (const [index, cell] of row.entries())
|
|
@@ -344,32 +380,35 @@ function narrow(rows, widths, limit) {
|
|
|
344
380
|
}
|
|
345
381
|
return rows.map((row) => row.map((cell, index) => textWidth(cell) > (widths[index] ?? 0) ? truncate(cell, widths[index] ?? 0) : cell));
|
|
346
382
|
}
|
|
383
|
+
function jsonText(value, replacer, { stream = process5.stdout, env = process5.env } = {}) {
|
|
384
|
+
return JSON.stringify(value, replacer, outputMode(stream, env) === "agent" ? undefined : 2);
|
|
385
|
+
}
|
|
347
386
|
function printJson(value) {
|
|
348
|
-
console.log(
|
|
387
|
+
console.log(jsonText(value));
|
|
349
388
|
}
|
|
350
389
|
|
|
351
390
|
// ../kit/src/help.ts
|
|
352
|
-
import
|
|
391
|
+
import process6 from "process";
|
|
353
392
|
var OPTIONAL = /\[[^\]]+\]/g;
|
|
354
393
|
var USAGE_PREFIX = /^usage:\s*/i;
|
|
355
394
|
var FULL_STOP = /\.$/;
|
|
356
|
-
function usageLine(usage, colors = paint(
|
|
395
|
+
function usageLine(usage, colors = paint(process6.stdout)) {
|
|
357
396
|
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
358
397
|
}
|
|
359
|
-
function helpText(usage, options, colors = paint(
|
|
398
|
+
function helpText(usage, options, colors = paint(process6.stdout), { examples = [], replaces, exits = [] } = {}) {
|
|
360
399
|
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
|
|
361
400
|
`);
|
|
362
401
|
}
|
|
363
|
-
function exitRows(exits, colors = paint(
|
|
402
|
+
function exitRows(exits, colors = paint(process6.stdout)) {
|
|
364
403
|
if (exits.length === 0)
|
|
365
404
|
return [];
|
|
366
405
|
const width = Math.max(...exits.map(([code]) => String(code).length));
|
|
367
406
|
return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
|
|
368
407
|
}
|
|
369
|
-
function replacesRows(replaces, colors = paint(
|
|
370
|
-
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
408
|
+
function replacesRows(replaces, colors = paint(process6.stdout)) {
|
|
409
|
+
return replaces === undefined || outputMode() === "agent" ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
371
410
|
}
|
|
372
|
-
function wantsHelpJson(env =
|
|
411
|
+
function wantsHelpJson(env = process6.env) {
|
|
373
412
|
return env.KIT_HELP === "json";
|
|
374
413
|
}
|
|
375
414
|
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
@@ -388,12 +427,12 @@ function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
|
388
427
|
...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
|
|
389
428
|
};
|
|
390
429
|
}
|
|
391
|
-
function exampleRows(examples, colors = paint(
|
|
392
|
-
if (examples.length === 0)
|
|
430
|
+
function exampleRows(examples, colors = paint(process6.stdout)) {
|
|
431
|
+
if (examples.length === 0 || outputMode() === "agent")
|
|
393
432
|
return [];
|
|
394
433
|
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
395
434
|
}
|
|
396
|
-
function optionRows(options, colors = paint(
|
|
435
|
+
function optionRows(options, colors = paint(process6.stdout)) {
|
|
397
436
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
398
437
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
399
438
|
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
@@ -486,7 +525,7 @@ var OUTPUT_OPTIONS = {
|
|
|
486
525
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
487
526
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
488
527
|
};
|
|
489
|
-
function applyOutput(color, plain, env =
|
|
528
|
+
function applyOutput(color, plain, env = process7.env) {
|
|
490
529
|
const when = plain === true ? "never" : color ?? "auto";
|
|
491
530
|
if (when === "auto")
|
|
492
531
|
return;
|
|
@@ -657,7 +696,7 @@ function nearestOption(message, options, allowNegative) {
|
|
|
657
696
|
}
|
|
658
697
|
// ../kit/src/process.ts
|
|
659
698
|
import { constants } from "os";
|
|
660
|
-
import
|
|
699
|
+
import process8 from "process";
|
|
661
700
|
var KILL_GRACE_MS = 2000;
|
|
662
701
|
function exitCodeOf(code, signal) {
|
|
663
702
|
if (code !== null)
|
|
@@ -677,7 +716,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
|
|
|
677
716
|
return;
|
|
678
717
|
try {
|
|
679
718
|
if (grouped)
|
|
680
|
-
|
|
719
|
+
process8.kill(-proc.pid, killing);
|
|
681
720
|
else
|
|
682
721
|
proc.kill(killing);
|
|
683
722
|
} catch {}
|
|
@@ -752,14 +791,14 @@ var RESET_STYLE = `${ESC}[0m`;
|
|
|
752
791
|
var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
753
792
|
// ../kit/src/cli.ts
|
|
754
793
|
import { readFileSync, realpathSync } from "fs";
|
|
755
|
-
import { dirname as dirname2, join as
|
|
756
|
-
import
|
|
794
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
795
|
+
import process10 from "process";
|
|
757
796
|
|
|
758
797
|
// ../kit/src/usage.ts
|
|
759
798
|
import { appendFileSync, mkdirSync } from "fs";
|
|
760
|
-
import { homedir } from "os";
|
|
761
|
-
import { dirname, isAbsolute, join } from "path";
|
|
762
|
-
import
|
|
799
|
+
import { homedir as homedir2 } from "os";
|
|
800
|
+
import { dirname, isAbsolute, join as join2 } from "path";
|
|
801
|
+
import process9 from "process";
|
|
763
802
|
|
|
764
803
|
// ../kit/src/logs.ts
|
|
765
804
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -773,14 +812,14 @@ var usageError;
|
|
|
773
812
|
function noteUsageError(message) {
|
|
774
813
|
usageError = message;
|
|
775
814
|
}
|
|
776
|
-
function stateHome(env =
|
|
815
|
+
function stateHome(env = process9.env) {
|
|
777
816
|
const dir = env.XDG_STATE_HOME;
|
|
778
|
-
return dir !== undefined && isAbsolute(dir) ? dir :
|
|
817
|
+
return dir !== undefined && isAbsolute(dir) ? dir : join2(homedir2(), ".local", "state");
|
|
779
818
|
}
|
|
780
|
-
function usagePath(env =
|
|
781
|
-
return
|
|
819
|
+
function usagePath(env = process9.env) {
|
|
820
|
+
return join2(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
782
821
|
}
|
|
783
|
-
function usageRecorded(env =
|
|
822
|
+
function usageRecorded(env = process9.env) {
|
|
784
823
|
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
785
824
|
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
786
825
|
}
|
|
@@ -794,7 +833,7 @@ function usageEntry(bin, command, argv, code, now = new Date) {
|
|
|
794
833
|
usageError = undefined;
|
|
795
834
|
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
796
835
|
}
|
|
797
|
-
function recordUsage(entry, env =
|
|
836
|
+
function recordUsage(entry, env = process9.env) {
|
|
798
837
|
if (!usageRecorded(env))
|
|
799
838
|
return;
|
|
800
839
|
try {
|
|
@@ -933,8 +972,8 @@ async function help2({ path, header, summary: lazySummary, commands, defaultComm
|
|
|
933
972
|
`);
|
|
934
973
|
}
|
|
935
974
|
function printError(prefix, message, hint, cause) {
|
|
936
|
-
const colors = paint(
|
|
937
|
-
const styled = takesControlCodes(
|
|
975
|
+
const colors = paint(process10.stderr);
|
|
976
|
+
const styled = takesControlCodes(process10.stderr);
|
|
938
977
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
939
978
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
940
979
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -977,11 +1016,11 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
977
1016
|
}
|
|
978
1017
|
}
|
|
979
1018
|
if (name === undefined && level.path.length > 1) {
|
|
980
|
-
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1019
|
+
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stderr));
|
|
981
1020
|
return 2;
|
|
982
1021
|
}
|
|
983
1022
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
984
|
-
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1023
|
+
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stdout));
|
|
985
1024
|
return 0;
|
|
986
1025
|
}
|
|
987
1026
|
if (level.path.length === 1 && (name === "--version" || name === "-v")) {
|
|
@@ -1100,7 +1139,7 @@ async function printCandidates(found) {
|
|
|
1100
1139
|
function packageVersion(entry = Bun.main) {
|
|
1101
1140
|
for (let dir = dirname2(realpathSync(entry));; dir = dirname2(dir)) {
|
|
1102
1141
|
try {
|
|
1103
|
-
const { version } = JSON.parse(readFileSync(
|
|
1142
|
+
const { version } = JSON.parse(readFileSync(join3(dir, "package.json"), "utf8"));
|
|
1104
1143
|
if (typeof version === "string")
|
|
1105
1144
|
return version;
|
|
1106
1145
|
} catch {}
|
|
@@ -1108,7 +1147,7 @@ function packageVersion(entry = Bun.main) {
|
|
|
1108
1147
|
return "0.0.0";
|
|
1109
1148
|
}
|
|
1110
1149
|
}
|
|
1111
|
-
async function runCli(cli, argv =
|
|
1150
|
+
async function runCli(cli, argv = process10.argv.slice(2)) {
|
|
1112
1151
|
const version = cli.version ?? packageVersion();
|
|
1113
1152
|
if (argv[0] === COMPLETE)
|
|
1114
1153
|
return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
|
|
@@ -1135,7 +1174,7 @@ function commandPath(scope, argv) {
|
|
|
1135
1174
|
}
|
|
1136
1175
|
return path.length === 0 ? undefined : path.join(" ");
|
|
1137
1176
|
}
|
|
1138
|
-
async function runMain({ name, version, run, redact, usage }, argv =
|
|
1177
|
+
async function runMain({ name, version, run, redact, usage }, argv = process10.argv.slice(2)) {
|
|
1139
1178
|
if (argv[0] === COMPLETE)
|
|
1140
1179
|
return printCandidates(leafCandidates(run, argv.slice(1)));
|
|
1141
1180
|
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
@@ -1161,12 +1200,59 @@ var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "ses
|
|
|
1161
1200
|
var {Glob } = globalThis.Bun;
|
|
1162
1201
|
var SESSION_FILES = new Glob("*.json");
|
|
1163
1202
|
var ACCOUNT_DIRS = new Glob("*/sessions");
|
|
1203
|
+
// ../kit/src/workspace-root.ts
|
|
1204
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
1205
|
+
import { homedir as homedir3 } from "os";
|
|
1206
|
+
import { dirname as dirname3, join as join4, resolve } from "path";
|
|
1207
|
+
import process11 from "process";
|
|
1208
|
+
function expandHome(path, home) {
|
|
1209
|
+
if (path === "~")
|
|
1210
|
+
return home;
|
|
1211
|
+
return path.startsWith("~/") ? join4(home, path.slice(2)) : path;
|
|
1212
|
+
}
|
|
1213
|
+
function configured(env, home) {
|
|
1214
|
+
const path = userConfigPath("config", { home, xdg: env.XDG_CONFIG_HOME });
|
|
1215
|
+
if (!existsSync(path))
|
|
1216
|
+
return;
|
|
1217
|
+
try {
|
|
1218
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
1219
|
+
const folder = typeof parsed === "object" && parsed !== null ? parsed.workspace : undefined;
|
|
1220
|
+
return typeof folder === "string" && folder !== "" ? folder : undefined;
|
|
1221
|
+
} catch {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
function workspaceRoot({ given, env = process11.env, home = homedir3() } = {}) {
|
|
1226
|
+
const fromEnv = env.KAYNOOO_WORKSPACE === "" ? undefined : env.KAYNOOO_WORKSPACE;
|
|
1227
|
+
return resolve(expandHome(given ?? fromEnv ?? configured(env, home) ?? join4(home, "Workspace"), home));
|
|
1228
|
+
}
|
|
1229
|
+
function workspaceChosen({ env = process11.env, home = homedir3() } = {}) {
|
|
1230
|
+
return (env.KAYNOOO_WORKSPACE ?? "") !== "" || configured(env, home) !== undefined;
|
|
1231
|
+
}
|
|
1232
|
+
function saveWorkspace(folder, { env = process11.env, home = homedir3() } = {}) {
|
|
1233
|
+
const path = userConfigPath("config", { home, xdg: env.XDG_CONFIG_HOME });
|
|
1234
|
+
let current = {};
|
|
1235
|
+
if (existsSync(path)) {
|
|
1236
|
+
try {
|
|
1237
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
1238
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
1239
|
+
return false;
|
|
1240
|
+
current = parsed;
|
|
1241
|
+
} catch {
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
mkdirSync2(dirname3(path), { recursive: true });
|
|
1246
|
+
writeFileSync(path, `${JSON.stringify({ ...current, workspace: folder }, undefined, 2)}
|
|
1247
|
+
`);
|
|
1248
|
+
return true;
|
|
1249
|
+
}
|
|
1164
1250
|
// src/doctor.ts
|
|
1165
|
-
import
|
|
1251
|
+
import process17 from "process";
|
|
1166
1252
|
|
|
1167
1253
|
// src/checks.ts
|
|
1168
|
-
import { existsSync as
|
|
1169
|
-
import { basename, join as
|
|
1254
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
1255
|
+
import { basename, join as join6 } from "path";
|
|
1170
1256
|
|
|
1171
1257
|
// src/catalog.ts
|
|
1172
1258
|
var HOOKS_REQUIRES = "@kaynooo/cli-guard";
|
|
@@ -1202,9 +1288,9 @@ var NEEDS = {
|
|
|
1202
1288
|
};
|
|
1203
1289
|
|
|
1204
1290
|
// src/completions.ts
|
|
1205
|
-
import { existsSync, mkdirSync as
|
|
1206
|
-
import { join as
|
|
1207
|
-
import
|
|
1291
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync3, rmSync } from "fs";
|
|
1292
|
+
import { join as join5 } from "path";
|
|
1293
|
+
import process13 from "process";
|
|
1208
1294
|
var MARKER = "# Generated by `cli completions fish`";
|
|
1209
1295
|
var FISH_FILE = /\.fish$/;
|
|
1210
1296
|
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'
|
|
@@ -1238,8 +1324,8 @@ ${BASH_FUNCTION}
|
|
|
1238
1324
|
complete -F __kaynooo_cli_complete ${bins.join(" ")}
|
|
1239
1325
|
`;
|
|
1240
1326
|
}
|
|
1241
|
-
function completionDir(home, env =
|
|
1242
|
-
return
|
|
1327
|
+
function completionDir(home, env = process13.env) {
|
|
1328
|
+
return join5(env.XDG_CACHE_HOME ?? join5(home, ".cache"), "fish", "kaynooo-cli");
|
|
1243
1329
|
}
|
|
1244
1330
|
function installedBins(host) {
|
|
1245
1331
|
return Object.values(TOOLS).flat().filter((bin) => host.which(bin) !== null);
|
|
@@ -1252,15 +1338,15 @@ complete -c ${bin} -f -a '(__kaynooo_cli_complete ${bin})'
|
|
|
1252
1338
|
}
|
|
1253
1339
|
async function installCompletions(host, dir) {
|
|
1254
1340
|
const bins = installedBins(host);
|
|
1255
|
-
|
|
1256
|
-
const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) &&
|
|
1341
|
+
mkdirSync3(dir, { recursive: true });
|
|
1342
|
+
const removed = readdirSync(dir).filter((name) => FISH_FILE.test(name) && !bins.includes(name.replace(FISH_FILE, "")) && readFileSync3(join5(dir, name), "utf8").startsWith(MARKER));
|
|
1257
1343
|
for (const name of removed)
|
|
1258
|
-
rmSync(
|
|
1259
|
-
await Promise.all(bins.map(async (bin) => Bun.write(
|
|
1344
|
+
rmSync(join5(dir, name));
|
|
1345
|
+
await Promise.all(bins.map(async (bin) => Bun.write(join5(dir, `${bin}.fish`), completionFile(bin))));
|
|
1260
1346
|
return { written: bins, removed: removed.map((name) => name.replace(FISH_FILE, "")) };
|
|
1261
1347
|
}
|
|
1262
1348
|
function missingCompletions(host, dir) {
|
|
1263
|
-
return installedBins(host).filter((bin) => !
|
|
1349
|
+
return installedBins(host).filter((bin) => !existsSync2(join5(dir, `${bin}.fish`)));
|
|
1264
1350
|
}
|
|
1265
1351
|
|
|
1266
1352
|
// src/checks.ts
|
|
@@ -1304,7 +1390,7 @@ function readJsonText(text) {
|
|
|
1304
1390
|
}
|
|
1305
1391
|
}
|
|
1306
1392
|
function readJson(path) {
|
|
1307
|
-
return
|
|
1393
|
+
return existsSync3(path) ? readJsonText(readFileSync4(path, "utf8")) : undefined;
|
|
1308
1394
|
}
|
|
1309
1395
|
function firstLine(text) {
|
|
1310
1396
|
const trimmed = text.trim();
|
|
@@ -1313,7 +1399,7 @@ function firstLine(text) {
|
|
|
1313
1399
|
return end === -1 ? trimmed : trimmed.slice(0, end);
|
|
1314
1400
|
}
|
|
1315
1401
|
function installed(host, name) {
|
|
1316
|
-
return readJson(
|
|
1402
|
+
return readJson(join6(host.globalModules, name, "package.json"));
|
|
1317
1403
|
}
|
|
1318
1404
|
function isInstalled(host, name) {
|
|
1319
1405
|
return installed(host, name)?.version !== undefined;
|
|
@@ -1321,7 +1407,7 @@ function isInstalled(host, name) {
|
|
|
1321
1407
|
function ownBin(host, name, bin) {
|
|
1322
1408
|
const declared = installed(host, name)?.bin;
|
|
1323
1409
|
const file = typeof declared === "string" ? declared : declared?.[bin];
|
|
1324
|
-
return file === undefined ? undefined :
|
|
1410
|
+
return file === undefined ? undefined : join6(host.globalModules, name, file);
|
|
1325
1411
|
}
|
|
1326
1412
|
async function checkTool(host, name, bins) {
|
|
1327
1413
|
const check = name.slice(name.indexOf("/") + 1);
|
|
@@ -1336,7 +1422,7 @@ async function checkTool(host, name, bins) {
|
|
|
1336
1422
|
if (latest !== "" && Bun.semver.order(version, latest) < 0)
|
|
1337
1423
|
return { check, ok: false, detail: `${version}, ${latest} released${off.length > 0 ? `, ${off.join(", ")} not on the PATH` : ""}`, fix: `bun install -g ${name}@${latest}` };
|
|
1338
1424
|
if (off.length > 0)
|
|
1339
|
-
return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${
|
|
1425
|
+
return { check, ok: false, detail: `${version}, ${off.join(", ")} not on the PATH`, fix: `add ${join6(host.globalModules, "..", "..", "..", "bin")} to the PATH` };
|
|
1340
1426
|
if (latest === "")
|
|
1341
1427
|
return { check, ok: true, detail: `${version}, the registry did not answer: ${firstLine(info.stderr) || answered || "no version"}` };
|
|
1342
1428
|
return { check, ok: true, detail: version };
|
|
@@ -1357,9 +1443,9 @@ async function checkTea(host) {
|
|
|
1357
1443
|
return { check: "tea", ok: true, detail: `logged in to ${forge} as ${login.name}, Forgejo ${served}` };
|
|
1358
1444
|
}
|
|
1359
1445
|
function hooksWiring(host) {
|
|
1360
|
-
const settings = readJson(
|
|
1446
|
+
const settings = readJson(join6(host.home, ".claude", "settings.json")) ?? {};
|
|
1361
1447
|
const plugin = settings.enabledPlugins?.[PLUGIN] === true;
|
|
1362
|
-
const mod = (settings.env?.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(":").map((dir) => dir.replace(LEADING_TILDE, host.home)).find((dir) => basename(dir) === "cli" &&
|
|
1448
|
+
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")));
|
|
1363
1449
|
return { plugin, mod };
|
|
1364
1450
|
}
|
|
1365
1451
|
function checkHooks(host) {
|
|
@@ -1397,8 +1483,15 @@ function checkNeeds(host) {
|
|
|
1397
1483
|
return { check: "needs", ok: true, detail: "every tool the installed packages need is on the PATH" };
|
|
1398
1484
|
}
|
|
1399
1485
|
var toolCheck = (name) => name.slice(name.indexOf("/") + 1);
|
|
1400
|
-
var OTHER_CHECKS = ["tea", "hooks", "needs", "bun", "completions"];
|
|
1486
|
+
var OTHER_CHECKS = ["tea", "hooks", "needs", "bun", "completions", "workspace"];
|
|
1401
1487
|
var FORGEJO = "@kaynooo/cli-forgejo";
|
|
1488
|
+
var WORKSPACE = "@kaynooo/cli-workspace";
|
|
1489
|
+
function checkWorkspace(host, env = process.env) {
|
|
1490
|
+
const folder = workspaceRoot({ home: host.home, env });
|
|
1491
|
+
if (existsSync3(folder))
|
|
1492
|
+
return { check: "workspace", ok: true, detail: folder };
|
|
1493
|
+
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` };
|
|
1494
|
+
}
|
|
1402
1495
|
var CHECK_NAMES = [...Object.keys(TOOLS).map(toolCheck), ...OTHER_CHECKS];
|
|
1403
1496
|
async function runChecks(host, only = []) {
|
|
1404
1497
|
const wanted = (check) => only.length === 0 || only.includes(check);
|
|
@@ -1414,7 +1507,8 @@ async function runChecks(host, only = []) {
|
|
|
1414
1507
|
...wanted("hooks") && hooks ? [checkHooks(host)] : [],
|
|
1415
1508
|
...wanted("needs") ? [checkNeeds(host)] : [],
|
|
1416
1509
|
...wanted("bun") ? [checkBun(host)] : [],
|
|
1417
|
-
...wanted("completions") ? [checkCompletions(host)] : []
|
|
1510
|
+
...wanted("completions") ? [checkCompletions(host)] : [],
|
|
1511
|
+
...wanted("workspace") && (only.length > 0 || isInstalled(host, WORKSPACE) || isInstalled(host, "@kaynooo/cli-pkg")) ? [checkWorkspace(host)] : []
|
|
1418
1512
|
];
|
|
1419
1513
|
}
|
|
1420
1514
|
|
|
@@ -1456,19 +1550,19 @@ async function applyFixes(host, steps, dry) {
|
|
|
1456
1550
|
}
|
|
1457
1551
|
|
|
1458
1552
|
// src/host.ts
|
|
1459
|
-
import { homedir as
|
|
1460
|
-
import { join as
|
|
1461
|
-
import
|
|
1553
|
+
import { homedir as homedir4 } from "os";
|
|
1554
|
+
import { join as join7 } from "path";
|
|
1555
|
+
import process14 from "process";
|
|
1462
1556
|
var RUN_TIMEOUT_MS = 20000;
|
|
1463
1557
|
function hostHere() {
|
|
1464
|
-
const home =
|
|
1558
|
+
const home = homedir4();
|
|
1465
1559
|
return {
|
|
1466
1560
|
home,
|
|
1467
|
-
globalModules:
|
|
1561
|
+
globalModules: join7(process14.env.BUN_INSTALL ?? join7(home, ".bun"), "install", "global", "node_modules"),
|
|
1468
1562
|
bunVersion: Bun.version,
|
|
1469
1563
|
which: (bin) => Bun.which(bin),
|
|
1470
1564
|
run: async (argv, env) => {
|
|
1471
|
-
const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...
|
|
1565
|
+
const ran = await runCommand(argv, { timeoutMs: RUN_TIMEOUT_MS, ...env === undefined ? {} : { env: { ...process14.env, ...env } } });
|
|
1472
1566
|
if (ran.timedOut)
|
|
1473
1567
|
return { code: 1, stdout: "", stderr: `timed out after ${RUN_TIMEOUT_MS / 1000}s` };
|
|
1474
1568
|
const of = (stream) => Buffer.concat(ran.chunks.filter((chunk) => chunk.stream === stream).map((chunk) => chunk.data)).toString();
|
|
@@ -1478,10 +1572,10 @@ function hostHere() {
|
|
|
1478
1572
|
}
|
|
1479
1573
|
|
|
1480
1574
|
// src/install.ts
|
|
1481
|
-
import
|
|
1575
|
+
import process16 from "process";
|
|
1482
1576
|
|
|
1483
1577
|
// ../kit/src/prompt.ts
|
|
1484
|
-
import
|
|
1578
|
+
import process15 from "process";
|
|
1485
1579
|
var KEY_SEQUENCES = /\x1B\[[0-9;]*[A-Z~]|\x1BO[A-Z]|[\s\S]/giu;
|
|
1486
1580
|
var CONTROL = /^[\x00-\x1F\x7F]/;
|
|
1487
1581
|
var WORDS = /\s+/;
|
|
@@ -1519,6 +1613,36 @@ async function checklist(question, choices, { initial = new Set, min = 0, toggle
|
|
|
1519
1613
|
});
|
|
1520
1614
|
return accepted ? checked : undefined;
|
|
1521
1615
|
}
|
|
1616
|
+
async function input2(question, { default: fallback, mask = false, validate, ...settings } = {}) {
|
|
1617
|
+
let value = "";
|
|
1618
|
+
let invalid;
|
|
1619
|
+
const taken = () => value === "" ? fallback ?? "" : value;
|
|
1620
|
+
const shown = () => mask ? "*".repeat([...taken()].length) : taken();
|
|
1621
|
+
const accepted = await ask(question, settings, (colors, state, { columns }) => {
|
|
1622
|
+
if (state !== "asking")
|
|
1623
|
+
return [answer(colors, question, state, shown())];
|
|
1624
|
+
const characters = [...shown()];
|
|
1625
|
+
const room = Math.max(columns - question.length - 5, 1);
|
|
1626
|
+
const tail = characters.length > room ? `\u2026${characters.slice(1 - room).join("")}` : shown();
|
|
1627
|
+
const typed = value === "" ? colors.dim(tail) : tail;
|
|
1628
|
+
return [`${colors.cyan("?")} ${question} ${typed}${colors.dim("\u2588")}`, ...invalid === undefined ? [] : [` ${colors.red(invalid)}`]];
|
|
1629
|
+
}, (key) => {
|
|
1630
|
+
if (key === "cancel")
|
|
1631
|
+
return "cancel";
|
|
1632
|
+
invalid = undefined;
|
|
1633
|
+
if (key === "enter") {
|
|
1634
|
+
invalid = validate?.(taken());
|
|
1635
|
+
return invalid === undefined ? "enter" : undefined;
|
|
1636
|
+
}
|
|
1637
|
+
if (key === "erase")
|
|
1638
|
+
value = [...value].slice(0, -1).join("");
|
|
1639
|
+
else if (typeof key === "object")
|
|
1640
|
+
value += key.text;
|
|
1641
|
+
return;
|
|
1642
|
+
});
|
|
1643
|
+
return accepted ? taken() : undefined;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1522
1646
|
class List {
|
|
1523
1647
|
choices;
|
|
1524
1648
|
query = "";
|
|
@@ -1577,9 +1701,9 @@ function asking(colors, question, typed, keys) {
|
|
|
1577
1701
|
function answer(colors, question, state, picked) {
|
|
1578
1702
|
return state === "enter" ? `${colors.green("\u2713")} ${question} ${colors.cyan(picked)}` : `${colors.red("\u2717")} ${question} ${colors.dim("cancelled")}`;
|
|
1579
1703
|
}
|
|
1580
|
-
async function ask(question, { hint, terminal =
|
|
1704
|
+
async function ask(question, { hint, terminal = process15 }, render, press) {
|
|
1581
1705
|
const { stdin, stderr } = terminal;
|
|
1582
|
-
if (
|
|
1706
|
+
if (!isInteractive(terminal))
|
|
1583
1707
|
fail(`cannot ask "${question}" off a terminal`, 2, hint);
|
|
1584
1708
|
const colors = paint(stderr);
|
|
1585
1709
|
let drawn = 0;
|
|
@@ -1678,15 +1802,22 @@ function checksFor(packages, plugin) {
|
|
|
1678
1802
|
return [...packages.map((name) => name.slice(name.indexOf("/") + 1)), ...plugin ? ["hooks"] : [], "needs", "completions", ...packages.includes("@kaynooo/cli-forgejo") ? ["tea"] : []];
|
|
1679
1803
|
}
|
|
1680
1804
|
async function ask2(pool) {
|
|
1681
|
-
if (
|
|
1805
|
+
if (!isInteractive())
|
|
1682
1806
|
badUsage("name what to install, or all: doctor --install forgejo check hooks (doctor --install --list shows the choices)");
|
|
1683
1807
|
const choices = pool.map((each) => ({ value: each, label: each.label, hint: each.hint }));
|
|
1684
1808
|
const picked = await checklist("install which?", choices, { hint: "name them instead: doctor --install forgejo check" });
|
|
1685
1809
|
return picked === undefined ? [] : [...picked];
|
|
1686
1810
|
}
|
|
1811
|
+
async function askWorkspace(host) {
|
|
1812
|
+
if (!isInteractive() || workspaceChosen({ home: host.home }))
|
|
1813
|
+
return;
|
|
1814
|
+
const folder = await input2("folder holding your repositories (repos, sweep and pkg bump look there)", { default: "~/Workspace" });
|
|
1815
|
+
if (folder !== undefined && folder !== "" && !saveWorkspace(folder, { home: host.home }))
|
|
1816
|
+
console.error(`could not write the workspace into ${userConfigPath("config", { home: host.home })}: it does not parse, fix it by hand`);
|
|
1817
|
+
}
|
|
1687
1818
|
async function install(host, options, recheck) {
|
|
1688
1819
|
const pool = candidates2(host);
|
|
1689
|
-
const { dim, green, red, yellow } = paint(
|
|
1820
|
+
const { dim, green, red, yellow } = paint(process16.stdout);
|
|
1690
1821
|
if (options.list) {
|
|
1691
1822
|
for (const each of pool)
|
|
1692
1823
|
console.log(`${each.label.padEnd(12)} ${dim(each.hint)}`);
|
|
@@ -1717,6 +1848,8 @@ async function install(host, options, recheck) {
|
|
|
1717
1848
|
console.log(`${yellow("warn ")} ${each.package}: ${each.need} is missing, ${each.why}`);
|
|
1718
1849
|
if (planned.packages.length === 0 && !planned.plugin)
|
|
1719
1850
|
return 1;
|
|
1851
|
+
if (!options.dryRun && planned.packages.some((name) => name === "@kaynooo/cli-workspace" || name === "@kaynooo/cli-pkg"))
|
|
1852
|
+
await askWorkspace(host);
|
|
1720
1853
|
const command = ["bun", "install", "-g", ...planned.packages];
|
|
1721
1854
|
if (planned.packages.length > 0)
|
|
1722
1855
|
console.log(`${options.dryRun ? dim("would ") : green("install")} ${command.join(" ")}`);
|
|
@@ -1773,7 +1906,7 @@ var OPTIONS = {
|
|
|
1773
1906
|
function print(results) {
|
|
1774
1907
|
if (results.length === 0)
|
|
1775
1908
|
return;
|
|
1776
|
-
const { green, red, dim } = paint(
|
|
1909
|
+
const { green, red, dim } = paint(process17.stdout);
|
|
1777
1910
|
const width = Math.max(...results.map((result) => result.check.length));
|
|
1778
1911
|
for (const { check, ok, detail, fix } of results)
|
|
1779
1912
|
console.log(`${ok ? green("ok ") : red("FAIL")} ${check.padEnd(width)} ${detail}${fix === undefined ? "" : ` ${dim("fix:")} ${fix}`}`);
|
|
@@ -1783,7 +1916,7 @@ function print(results) {
|
|
|
1783
1916
|
${dim("fix them all:")} ${INSTALL2}${installs.join(" ")}`);
|
|
1784
1917
|
}
|
|
1785
1918
|
function printOutcomes(outcomes, log) {
|
|
1786
|
-
const { green, red, dim } = paint(
|
|
1919
|
+
const { green, red, dim } = paint(process17.stdout);
|
|
1787
1920
|
const marks = { ran: green("ran "), failed: red("failed "), "dry-run": dim("would "), "not run": dim("not run") };
|
|
1788
1921
|
for (const { command, status, detail } of outcomes)
|
|
1789
1922
|
log(`${marks[status]} ${command}${detail === undefined ? "" : ` ${dim(detail)}`}`);
|
|
@@ -1823,9 +1956,9 @@ after the fixes:`);
|
|
|
1823
1956
|
const absent = Object.keys(TOOLS).filter((name) => !isInstalled(host, name)).length;
|
|
1824
1957
|
if (!json && only.length === 0 && absent > 0)
|
|
1825
1958
|
console.log(`
|
|
1826
|
-
${paint(
|
|
1959
|
+
${paint(process17.stdout).dim(`${absent} packages not installed: doctor --install`)}`);
|
|
1827
1960
|
return results.every((result) => result.ok) ? 0 : 1;
|
|
1828
1961
|
}
|
|
1829
1962
|
|
|
1830
1963
|
// src/cli.ts
|
|
1831
|
-
|
|
1964
|
+
process18.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.9.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",
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
"doctor": "$npm_execpath src/cli.ts"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@kaynooo/cli-kit": "0.
|
|
40
|
+
"@kaynooo/cli-kit": "0.22.0"
|
|
41
41
|
}
|
|
42
42
|
}
|