@kaynooo/cli-workspace 0.2.0 → 0.3.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/audit-cli.js +279 -113
- package/dist/cli.js +366 -169
- package/dist/repos-cli.js +307 -119
- package/dist/sweep-cli.js +302 -127
- package/package.json +2 -2
package/dist/repos-cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/repos-cli.ts
|
|
5
|
-
import
|
|
5
|
+
import process16 from "process";
|
|
6
6
|
|
|
7
7
|
// ../kit/src/advisory.ts
|
|
8
8
|
var SEVERITIES = ["low", "moderate", "high", "critical"];
|
|
@@ -13,14 +13,14 @@ function isIgnored(advisory, ignore) {
|
|
|
13
13
|
return ignore.includes(advisory.ghsa ?? "") || ignore.includes(String(advisory.id));
|
|
14
14
|
}
|
|
15
15
|
// ../kit/src/args.ts
|
|
16
|
-
import
|
|
16
|
+
import process8 from "process";
|
|
17
17
|
import { parseArgs } from "util";
|
|
18
18
|
|
|
19
19
|
// ../kit/src/format.ts
|
|
20
|
-
import
|
|
20
|
+
import process6 from "process";
|
|
21
21
|
|
|
22
22
|
// ../kit/src/style.ts
|
|
23
|
-
import
|
|
23
|
+
import process5 from "process";
|
|
24
24
|
|
|
25
25
|
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
26
26
|
function x(s) {
|
|
@@ -283,52 +283,236 @@ function le(i = {}) {
|
|
|
283
283
|
}
|
|
284
284
|
var t = le();
|
|
285
285
|
|
|
286
|
-
// ../kit/src/
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
286
|
+
// ../kit/src/theme.ts
|
|
287
|
+
import { existsSync as existsSync3, readFileSync, statSync } from "fs";
|
|
288
|
+
import { homedir as homedir2 } from "os";
|
|
289
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
290
|
+
import process4 from "process";
|
|
291
|
+
|
|
292
|
+
// ../kit/src/config.ts
|
|
293
|
+
import { existsSync } from "fs";
|
|
294
|
+
import { dirname, join, resolve } from "path";
|
|
295
|
+
import process2 from "process";
|
|
296
|
+
function findUp(names, from = process2.cwd(), stop = () => false) {
|
|
297
|
+
const wanted = typeof names === "string" ? [names] : names;
|
|
298
|
+
for (let dir = resolve(from);; dir = dirname(dir)) {
|
|
299
|
+
const found = wanted.map((name) => join(dir, name)).find((path) => existsSync(path));
|
|
300
|
+
if (found !== undefined)
|
|
301
|
+
return found;
|
|
302
|
+
if (stop(dir) || dirname(dir) === dir)
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ../kit/src/user-config.ts
|
|
308
|
+
import { existsSync as existsSync2 } from "fs";
|
|
309
|
+
import { homedir } from "os";
|
|
310
|
+
import { join as join2 } from "path";
|
|
311
|
+
import process3 from "process";
|
|
312
|
+
function configBase(where = {}) {
|
|
313
|
+
const xdg = where.xdg ?? (where.home === undefined ? process3.env.XDG_CONFIG_HOME : undefined);
|
|
314
|
+
return xdg !== undefined && xdg !== "" ? xdg : join2(where.home ?? homedir(), ".config");
|
|
315
|
+
}
|
|
316
|
+
function userConfigPath(bin, where = {}) {
|
|
317
|
+
return join2(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
318
|
+
}
|
|
319
|
+
function userConfigReadPath(bin, legacy = [], where = {}) {
|
|
320
|
+
const current = userConfigPath(bin, where);
|
|
321
|
+
if (existsSync2(current))
|
|
322
|
+
return current;
|
|
323
|
+
const base = configBase(where);
|
|
324
|
+
return legacy.map((parts) => join2(base, ...parts)).find((path) => existsSync2(path)) ?? current;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ../kit/src/theme.ts
|
|
328
|
+
var DEFAULT = {
|
|
329
|
+
colors: { accent: "cyan", id: "yellow", path: "blue", label: "dim", value: "bold", ok: "green", warn: "yellow", problem: "red", note: "dim", passed: "green", failed: "red", running: "cyan", queued: "yellow", skipped: "dim" },
|
|
330
|
+
glyphs: { ok: "\u2713", warn: "\u25B2", problem: "\u2717", note: "\u203A", passed: "\u2713", failed: "\u2717", running: "\u25CF", queued: "\u25CB", skipped: "-", bar: "\u2501" },
|
|
331
|
+
accents: ["cyan", "magenta", "green", "blue", "yellow", "redBright"],
|
|
332
|
+
bins: {}
|
|
333
|
+
};
|
|
334
|
+
var BRIGHT = { accent: "cyanBright", id: "yellowBright", path: "blueBright", label: "white", value: "bold whiteBright", ok: "greenBright", warn: "yellowBright", problem: "redBright", note: "white", passed: "greenBright", failed: "redBright", running: "cyanBright", queued: "yellowBright", skipped: "white" };
|
|
335
|
+
var MONO = { accent: "bold", id: "bold", path: "underline", label: "dim", value: "bold", ok: "bold", warn: "bold", problem: "bold", note: "dim", passed: "bold", failed: "bold", running: "bold", queued: "dim", skipped: "dim" };
|
|
336
|
+
var ASCII = { ok: "+", warn: "!", problem: "x", note: ">", passed: "+", failed: "x", running: "*", queued: "o", skipped: "-", bar: "#" };
|
|
337
|
+
var PRESETS = {
|
|
338
|
+
default: {},
|
|
339
|
+
"high-contrast": { colors: BRIGHT, accents: ["cyanBright", "magentaBright", "greenBright", "blueBright", "yellowBright", "redBright"] },
|
|
340
|
+
mono: { colors: MONO, accents: ["bold"] },
|
|
341
|
+
ascii: { glyphs: ASCII }
|
|
292
342
|
};
|
|
293
|
-
|
|
343
|
+
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"]);
|
|
344
|
+
var HEX = /^#[0-9a-f]{6}$/i;
|
|
345
|
+
var CONTROL = /\p{Cc}/u;
|
|
346
|
+
var MAX_FILE_BYTES = 64 * 1024;
|
|
347
|
+
var SPACES = /\s+/;
|
|
348
|
+
function isColorSpec(spec) {
|
|
349
|
+
if (typeof spec === "number")
|
|
350
|
+
return Number.isInteger(spec) && spec >= 0 && spec <= 255;
|
|
351
|
+
return typeof spec === "string" && spec.trim() !== "" && spec.trim().split(SPACES).every((token) => STYLES.has(token) || HEX.test(token));
|
|
352
|
+
}
|
|
353
|
+
function tinted(colors, spec) {
|
|
354
|
+
if (typeof spec === "number")
|
|
355
|
+
return colors.ansi256(spec);
|
|
356
|
+
return spec.trim().split(SPACES).reduce((chain, token) => HEX.test(token) ? chain.hex(token) : chain[token] ?? chain, colors);
|
|
357
|
+
}
|
|
358
|
+
function isRecord(value) {
|
|
359
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
360
|
+
}
|
|
361
|
+
function readThemeFile(path, warn) {
|
|
362
|
+
try {
|
|
363
|
+
const stat = statSync(path, { throwIfNoEntry: false });
|
|
364
|
+
if (stat === undefined)
|
|
365
|
+
return;
|
|
366
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES) {
|
|
367
|
+
warn(`${path} is not a regular file under ${MAX_FILE_BYTES / 1024} KiB, theme ignored`);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
371
|
+
if (isRecord(parsed))
|
|
372
|
+
return parsed;
|
|
373
|
+
warn(`${path} is not a JSON object, theme ignored`);
|
|
374
|
+
} catch (error) {
|
|
375
|
+
warn(`${path} does not parse (${error instanceof Error ? error.message : String(error)}), theme ignored`);
|
|
376
|
+
}
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
function applyPreset(theme, name, warn, where) {
|
|
380
|
+
if (name === undefined)
|
|
381
|
+
return;
|
|
382
|
+
if (typeof name !== "string" || !Object.hasOwn(PRESETS, name)) {
|
|
383
|
+
warn(`${where}: no preset ${String(name)}, one of ${Object.keys(PRESETS).join(", ")}`);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const preset = PRESETS[name];
|
|
387
|
+
Object.assign(theme.colors, preset.colors);
|
|
388
|
+
Object.assign(theme.glyphs, preset.glyphs);
|
|
389
|
+
if (preset.accents !== undefined)
|
|
390
|
+
theme.accents = [...preset.accents];
|
|
391
|
+
return name;
|
|
392
|
+
}
|
|
393
|
+
function applyFile(theme, file, where, warn) {
|
|
394
|
+
if (isRecord(file.colors)) {
|
|
395
|
+
for (const [key, value] of Object.entries(file.colors)) {
|
|
396
|
+
if (!Object.hasOwn(DEFAULT.colors, key))
|
|
397
|
+
warn(`${where}: no colour ${key}, one of ${Object.keys(DEFAULT.colors).join(", ")}`);
|
|
398
|
+
else if (!isColorSpec(value))
|
|
399
|
+
warn(`${where}: colour ${key} is not an ANSI name, \`#rrggbb\` or a number up to 255`);
|
|
400
|
+
else
|
|
401
|
+
theme.colors[key] = value;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (isRecord(file.glyphs)) {
|
|
405
|
+
for (const [key, value] of Object.entries(file.glyphs)) {
|
|
406
|
+
if (!Object.hasOwn(DEFAULT.glyphs, key))
|
|
407
|
+
warn(`${where}: no glyph ${key}, one of ${Object.keys(DEFAULT.glyphs).join(", ")}`);
|
|
408
|
+
else if (typeof value !== "string" || CONTROL.test(value) || Bun.stringWidth(value) !== 1)
|
|
409
|
+
warn(`${where}: glyph ${key} must be one visible character wide, with no control character`);
|
|
410
|
+
else
|
|
411
|
+
theme.glyphs[key] = value;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (Array.isArray(file.accents) && file.accents.length > 0 && file.accents.every(isColorSpec))
|
|
415
|
+
theme.accents = [...file.accents];
|
|
416
|
+
else if (file.accents !== undefined)
|
|
417
|
+
warn(`${where}: accents must be a non-empty list of colours`);
|
|
418
|
+
if (isRecord(file.bins)) {
|
|
419
|
+
for (const [bin, value] of Object.entries(file.bins)) {
|
|
420
|
+
if (isColorSpec(value))
|
|
421
|
+
theme.bins[bin] = value;
|
|
422
|
+
else
|
|
423
|
+
warn(`${where}: bin ${bin} has no valid colour`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function endsWalk(home) {
|
|
428
|
+
return (dir) => dir === resolve2(home) || existsSync3(join3(dir, ".git"));
|
|
429
|
+
}
|
|
430
|
+
var warned = new Set;
|
|
431
|
+
function warnOnce(message) {
|
|
432
|
+
if (warned.has(message))
|
|
433
|
+
return;
|
|
434
|
+
warned.add(message);
|
|
435
|
+
console.error(`warning: theme ${message}`);
|
|
436
|
+
}
|
|
437
|
+
function isPath(chosen) {
|
|
438
|
+
return chosen.includes("/") || chosen.endsWith(".json");
|
|
439
|
+
}
|
|
440
|
+
function loadTheme({ env = process4.env, from = process4.cwd(), home = homedir2(), warn = warnOnce } = {}) {
|
|
441
|
+
const theme = { colors: { ...DEFAULT.colors }, glyphs: { ...DEFAULT.glyphs }, accents: [...DEFAULT.accents], bins: Object.create(null) };
|
|
442
|
+
const sources = [];
|
|
443
|
+
const chosen = env.KIT_THEME ?? "";
|
|
444
|
+
const wanted = chosen === "" ? [userConfigPath("theme", { home, xdg: env.XDG_CONFIG_HOME }), findUp(join3(".kaynooo", "theme.json"), from, endsWalk(home))] : [];
|
|
445
|
+
if (isPath(chosen))
|
|
446
|
+
wanted.push(resolve2(from, chosen));
|
|
447
|
+
const files = [];
|
|
448
|
+
for (const path of wanted) {
|
|
449
|
+
const file = path === undefined ? undefined : readThemeFile(path, warn);
|
|
450
|
+
if (path !== undefined && file !== undefined)
|
|
451
|
+
files.push({ path, file });
|
|
452
|
+
}
|
|
453
|
+
let preset = "default";
|
|
454
|
+
if (chosen !== "" && !isPath(chosen)) {
|
|
455
|
+
preset = applyPreset(theme, chosen, warn, "KIT_THEME") ?? preset;
|
|
456
|
+
} else {
|
|
457
|
+
const named = files.findLast(({ file }) => file.preset !== undefined);
|
|
458
|
+
if (named !== undefined)
|
|
459
|
+
preset = applyPreset(theme, named.file.preset, warn, named.path) ?? preset;
|
|
460
|
+
}
|
|
461
|
+
for (const { path, file } of files) {
|
|
462
|
+
applyFile(theme, file, path, warn);
|
|
463
|
+
sources.push(path);
|
|
464
|
+
}
|
|
465
|
+
return { theme, sources, preset };
|
|
466
|
+
}
|
|
467
|
+
var current;
|
|
468
|
+
var currentKey = "";
|
|
469
|
+
function activeTheme() {
|
|
470
|
+
const key = `${process4.cwd()}\x00${process4.env.KIT_THEME ?? ""}\x00${process4.env.XDG_CONFIG_HOME ?? ""}`;
|
|
471
|
+
if (current === undefined || key !== currentKey) {
|
|
472
|
+
current = loadTheme();
|
|
473
|
+
currentKey = key;
|
|
474
|
+
}
|
|
475
|
+
return current;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ../kit/src/style.ts
|
|
479
|
+
var MARK_WORDS = { ok: "ok:", warn: "warning:", problem: "error:", note: "note:" };
|
|
480
|
+
function takesControlCodes(stream, env = process5.env) {
|
|
294
481
|
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
295
482
|
}
|
|
296
|
-
function paint(stream, env =
|
|
483
|
+
function paint(stream, env = process5.env) {
|
|
297
484
|
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
298
485
|
}
|
|
299
|
-
function marked(mark, text, stream, detail, env =
|
|
486
|
+
function marked(mark, text, stream, detail, env = process5.env) {
|
|
300
487
|
const colors = paint(stream, env);
|
|
301
|
-
|
|
302
|
-
|
|
488
|
+
let head = MARK_WORDS[mark];
|
|
489
|
+
if (takesControlCodes(stream, env)) {
|
|
490
|
+
const { theme } = activeTheme();
|
|
491
|
+
head = tinted(colors.bold, theme.colors[mark])(theme.glyphs[mark]);
|
|
492
|
+
}
|
|
303
493
|
return `${head} ${text}${detail === undefined ? "" : ` ${colors.dim(detail)}`}`;
|
|
304
494
|
}
|
|
305
495
|
function ok(text, detail) {
|
|
306
|
-
console.log(marked("ok", text,
|
|
496
|
+
console.log(marked("ok", text, process5.stdout, detail));
|
|
307
497
|
}
|
|
308
498
|
function note(text, detail) {
|
|
309
|
-
console.log(marked("note", text,
|
|
499
|
+
console.log(marked("note", text, process5.stdout, detail));
|
|
310
500
|
}
|
|
311
501
|
function problem(text, detail) {
|
|
312
|
-
console.error(marked("problem", text,
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
var STATUSES = {
|
|
325
|
-
passed: { symbol: "\u2713", words: ["passed", "success", "succeeded", "ok"], paint: (colors) => colors.green },
|
|
326
|
-
failed: { symbol: "\u2717", words: ["failed", "failure", "error", "errored"], paint: (colors) => colors.red },
|
|
327
|
-
running: { symbol: "\u25CF", words: ["running", "in_progress", "started"], paint: (colors) => colors.cyan },
|
|
328
|
-
queued: { symbol: "\u25CB", words: ["queued", "waiting", "pending", "created", "blocked", "scheduled"], paint: (colors) => colors.yellow },
|
|
329
|
-
skipped: { symbol: "-", words: ["skipped", "cancelled", "canceled", "manual"], paint: (colors) => colors.dim }
|
|
502
|
+
console.error(marked("problem", text, process5.stderr, detail));
|
|
503
|
+
}
|
|
504
|
+
function role(name, stream, env = process5.env) {
|
|
505
|
+
const colors = paint(stream, env);
|
|
506
|
+
return takesControlCodes(stream, env) ? tinted(colors, activeTheme().theme.colors[name]) : colors;
|
|
507
|
+
}
|
|
508
|
+
var STATUS_WORDS = {
|
|
509
|
+
passed: ["passed", "success", "succeeded", "ok"],
|
|
510
|
+
failed: ["failed", "failure", "error", "errored"],
|
|
511
|
+
running: ["running", "in_progress", "started"],
|
|
512
|
+
queued: ["queued", "waiting", "pending", "created", "blocked", "scheduled"],
|
|
513
|
+
skipped: ["skipped", "cancelled", "canceled", "manual"]
|
|
330
514
|
};
|
|
331
|
-
var STATUS_OF = new Map(Object.entries(
|
|
515
|
+
var STATUS_OF = new Map(Object.entries(STATUS_WORDS).flatMap(([status, words]) => words.map((word) => [word, status])));
|
|
332
516
|
|
|
333
517
|
// ../kit/src/format.ts
|
|
334
518
|
var UNITS = [["d", 86400], ["h", 3600], ["m", 60], ["s", 1]];
|
|
@@ -367,7 +551,7 @@ var ESCAPE = String.fromCharCode(27);
|
|
|
367
551
|
function textWidth(text) {
|
|
368
552
|
return Bun.stringWidth(text);
|
|
369
553
|
}
|
|
370
|
-
function table(rows, { cellWidth, header = false, align = [], fit } = {}) {
|
|
554
|
+
function table(rows, { cellWidth, header = false, align = [], fit, stream = process6.stdout } = {}) {
|
|
371
555
|
const cells = cellWidth === undefined ? rows : rows.map((row) => row.map((cell) => truncate(cell.replaceAll(LINE_BREAKS, " "), cellWidth)));
|
|
372
556
|
const widths = [];
|
|
373
557
|
for (const row of cells) {
|
|
@@ -375,7 +559,7 @@ function table(rows, { cellWidth, header = false, align = [], fit } = {}) {
|
|
|
375
559
|
widths[index] = Math.max(widths[index] ?? 0, textWidth(cell));
|
|
376
560
|
}
|
|
377
561
|
const shown = fit === undefined ? cells : narrow(cells, widths, fit);
|
|
378
|
-
const colors = paint(
|
|
562
|
+
const colors = paint(stream);
|
|
379
563
|
const lines = shown.map((row) => row.map((cell, index) => {
|
|
380
564
|
const width = widths[index] ?? 0;
|
|
381
565
|
const gap = " ".repeat(Math.max(0, width - textWidth(cell)));
|
|
@@ -383,7 +567,8 @@ function table(rows, { cellWidth, header = false, align = [], fit } = {}) {
|
|
|
383
567
|
return `${gap}${cell}`;
|
|
384
568
|
return index === row.length - 1 ? cell : `${cell}${gap}`;
|
|
385
569
|
}).join(" ").trimEnd());
|
|
386
|
-
|
|
570
|
+
const rule = header && takesControlCodes(stream) && lines.length > 1 ? [colors.dim("\u2500".repeat(Math.max(...lines.map(textWidth))))] : [];
|
|
571
|
+
return lines.flatMap((line, index) => header && index === 0 ? [colors.bold(line), ...rule] : [line]).join(`
|
|
387
572
|
`);
|
|
388
573
|
}
|
|
389
574
|
function narrow(rows, widths, limit) {
|
|
@@ -407,27 +592,27 @@ function printJson(value) {
|
|
|
407
592
|
}
|
|
408
593
|
|
|
409
594
|
// ../kit/src/help.ts
|
|
410
|
-
import
|
|
595
|
+
import process7 from "process";
|
|
411
596
|
var OPTIONAL = /\[[^\]]+\]/g;
|
|
412
597
|
var USAGE_PREFIX = /^usage:\s*/i;
|
|
413
598
|
var FULL_STOP = /\.$/;
|
|
414
|
-
function usageLine(usage, colors = paint(
|
|
599
|
+
function usageLine(usage, colors = paint(process7.stdout)) {
|
|
415
600
|
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
416
601
|
}
|
|
417
|
-
function helpText(usage, options, colors = paint(
|
|
602
|
+
function helpText(usage, options, colors = paint(process7.stdout), { examples = [], replaces, exits = [] } = {}) {
|
|
418
603
|
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
|
|
419
604
|
`);
|
|
420
605
|
}
|
|
421
|
-
function exitRows(exits, colors = paint(
|
|
606
|
+
function exitRows(exits, colors = paint(process7.stdout)) {
|
|
422
607
|
if (exits.length === 0)
|
|
423
608
|
return [];
|
|
424
609
|
const width = Math.max(...exits.map(([code]) => String(code).length));
|
|
425
610
|
return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
|
|
426
611
|
}
|
|
427
|
-
function replacesRows(replaces, colors = paint(
|
|
612
|
+
function replacesRows(replaces, colors = paint(process7.stdout)) {
|
|
428
613
|
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
429
614
|
}
|
|
430
|
-
function wantsHelpJson(env =
|
|
615
|
+
function wantsHelpJson(env = process7.env) {
|
|
431
616
|
return env.KIT_HELP === "json";
|
|
432
617
|
}
|
|
433
618
|
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
@@ -446,12 +631,12 @@ function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
|
446
631
|
...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
|
|
447
632
|
};
|
|
448
633
|
}
|
|
449
|
-
function exampleRows(examples, colors = paint(
|
|
634
|
+
function exampleRows(examples, colors = paint(process7.stdout)) {
|
|
450
635
|
if (examples.length === 0)
|
|
451
636
|
return [];
|
|
452
637
|
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
453
638
|
}
|
|
454
|
-
function optionRows(options, colors = paint(
|
|
639
|
+
function optionRows(options, colors = paint(process7.stdout)) {
|
|
455
640
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
456
641
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
457
642
|
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
@@ -544,7 +729,7 @@ var OUTPUT_OPTIONS = {
|
|
|
544
729
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
545
730
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
546
731
|
};
|
|
547
|
-
function applyOutput(color, plain, env =
|
|
732
|
+
function applyOutput(color, plain, env = process8.env) {
|
|
548
733
|
const when = plain === true ? "never" : color ?? "auto";
|
|
549
734
|
if (when === "auto")
|
|
550
735
|
return;
|
|
@@ -715,7 +900,7 @@ function nearestOption(message, options, allowNegative) {
|
|
|
715
900
|
}
|
|
716
901
|
// ../kit/src/process.ts
|
|
717
902
|
import { constants } from "os";
|
|
718
|
-
import
|
|
903
|
+
import process9 from "process";
|
|
719
904
|
var KILL_GRACE_MS = 2000;
|
|
720
905
|
function exitCodeOf(code, signal) {
|
|
721
906
|
if (code !== null)
|
|
@@ -735,7 +920,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
|
|
|
735
920
|
return;
|
|
736
921
|
try {
|
|
737
922
|
if (grouped)
|
|
738
|
-
|
|
923
|
+
process9.kill(-proc.pid, killing);
|
|
739
924
|
else
|
|
740
925
|
proc.kill(killing);
|
|
741
926
|
} catch {}
|
|
@@ -810,10 +995,10 @@ var RESET_STYLE = `${ESC}[0m`;
|
|
|
810
995
|
var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
811
996
|
|
|
812
997
|
// ../kit/src/tool.ts
|
|
813
|
-
import
|
|
998
|
+
import process10 from "process";
|
|
814
999
|
function cwdGone() {
|
|
815
1000
|
try {
|
|
816
|
-
|
|
1001
|
+
process10.cwd();
|
|
817
1002
|
return false;
|
|
818
1003
|
} catch {
|
|
819
1004
|
return true;
|
|
@@ -835,7 +1020,7 @@ function spawnFailure(command, error) {
|
|
|
835
1020
|
async function runTool(label, argv, { timeoutMs, cwd, onStart } = {}) {
|
|
836
1021
|
let ran;
|
|
837
1022
|
try {
|
|
838
|
-
ran = await runCommand(argv, { env:
|
|
1023
|
+
ran = await runCommand(argv, { env: process10.env, ...timeoutMs === undefined ? {} : { timeoutMs }, ...cwd === undefined ? {} : { cwd }, ...onStart === undefined ? {} : { onStart } });
|
|
839
1024
|
} catch (error) {
|
|
840
1025
|
throw spawnFailure(label, error);
|
|
841
1026
|
}
|
|
@@ -850,15 +1035,15 @@ async function runTool(label, argv, { timeoutMs, cwd, onStart } = {}) {
|
|
|
850
1035
|
return { code: ran.code, ...streams };
|
|
851
1036
|
}
|
|
852
1037
|
// ../kit/src/cli.ts
|
|
853
|
-
import { readFileSync, realpathSync } from "fs";
|
|
854
|
-
import { dirname as
|
|
855
|
-
import
|
|
1038
|
+
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
1039
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
1040
|
+
import process12 from "process";
|
|
856
1041
|
|
|
857
1042
|
// ../kit/src/usage.ts
|
|
858
1043
|
import { appendFileSync, mkdirSync } from "fs";
|
|
859
|
-
import { homedir } from "os";
|
|
860
|
-
import { dirname, isAbsolute, join } from "path";
|
|
861
|
-
import
|
|
1044
|
+
import { homedir as homedir3 } from "os";
|
|
1045
|
+
import { dirname as dirname2, isAbsolute, join as join4 } from "path";
|
|
1046
|
+
import process11 from "process";
|
|
862
1047
|
|
|
863
1048
|
// ../kit/src/logs.ts
|
|
864
1049
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -872,14 +1057,14 @@ var usageError;
|
|
|
872
1057
|
function noteUsageError(message) {
|
|
873
1058
|
usageError = message;
|
|
874
1059
|
}
|
|
875
|
-
function stateHome(env =
|
|
1060
|
+
function stateHome(env = process11.env) {
|
|
876
1061
|
const dir = env.XDG_STATE_HOME;
|
|
877
|
-
return dir !== undefined && isAbsolute(dir) ? dir :
|
|
1062
|
+
return dir !== undefined && isAbsolute(dir) ? dir : join4(homedir3(), ".local", "state");
|
|
878
1063
|
}
|
|
879
|
-
function usagePath(env =
|
|
880
|
-
return
|
|
1064
|
+
function usagePath(env = process11.env) {
|
|
1065
|
+
return join4(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
881
1066
|
}
|
|
882
|
-
function usageRecorded(env =
|
|
1067
|
+
function usageRecorded(env = process11.env) {
|
|
883
1068
|
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
884
1069
|
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
885
1070
|
}
|
|
@@ -893,12 +1078,12 @@ function usageEntry(bin, command, argv, code, now = new Date) {
|
|
|
893
1078
|
usageError = undefined;
|
|
894
1079
|
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
895
1080
|
}
|
|
896
|
-
function recordUsage(entry, env =
|
|
1081
|
+
function recordUsage(entry, env = process11.env) {
|
|
897
1082
|
if (!usageRecorded(env))
|
|
898
1083
|
return;
|
|
899
1084
|
try {
|
|
900
1085
|
const path = usagePath(env);
|
|
901
|
-
mkdirSync(
|
|
1086
|
+
mkdirSync(dirname2(path), { recursive: true, mode: 448 });
|
|
902
1087
|
appendFileSync(path, `${JSON.stringify(entry)}
|
|
903
1088
|
`, { mode: 384 });
|
|
904
1089
|
} catch {}
|
|
@@ -984,8 +1169,8 @@ async function help2({ path, header, summary: lazySummary, commands, defaultComm
|
|
|
984
1169
|
`);
|
|
985
1170
|
}
|
|
986
1171
|
function printError(prefix, message, hint, cause) {
|
|
987
|
-
const colors = paint(
|
|
988
|
-
const styled = takesControlCodes(
|
|
1172
|
+
const colors = paint(process12.stderr);
|
|
1173
|
+
const styled = takesControlCodes(process12.stderr);
|
|
989
1174
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
990
1175
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
991
1176
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -1028,11 +1213,11 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
1028
1213
|
}
|
|
1029
1214
|
}
|
|
1030
1215
|
if (name === undefined && level.path.length > 1) {
|
|
1031
|
-
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1216
|
+
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process12.stderr));
|
|
1032
1217
|
return 2;
|
|
1033
1218
|
}
|
|
1034
1219
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
1035
|
-
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1220
|
+
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process12.stdout));
|
|
1036
1221
|
return 0;
|
|
1037
1222
|
}
|
|
1038
1223
|
if (level.path.length === 1 && (name === "--version" || name === "-v")) {
|
|
@@ -1149,17 +1334,17 @@ async function printCandidates(found) {
|
|
|
1149
1334
|
return 0;
|
|
1150
1335
|
}
|
|
1151
1336
|
function packageVersion(entry = Bun.main) {
|
|
1152
|
-
for (let dir =
|
|
1337
|
+
for (let dir = dirname3(realpathSync(entry));; dir = dirname3(dir)) {
|
|
1153
1338
|
try {
|
|
1154
|
-
const { version } = JSON.parse(
|
|
1339
|
+
const { version } = JSON.parse(readFileSync2(join5(dir, "package.json"), "utf8"));
|
|
1155
1340
|
if (typeof version === "string")
|
|
1156
1341
|
return version;
|
|
1157
1342
|
} catch {}
|
|
1158
|
-
if (
|
|
1343
|
+
if (dirname3(dir) === dir)
|
|
1159
1344
|
return "0.0.0";
|
|
1160
1345
|
}
|
|
1161
1346
|
}
|
|
1162
|
-
async function runCli(cli, argv =
|
|
1347
|
+
async function runCli(cli, argv = process12.argv.slice(2)) {
|
|
1163
1348
|
const version = cli.version ?? packageVersion();
|
|
1164
1349
|
if (argv[0] === COMPLETE)
|
|
1165
1350
|
return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
|
|
@@ -1186,7 +1371,7 @@ function commandPath(scope, argv) {
|
|
|
1186
1371
|
}
|
|
1187
1372
|
return path.length === 0 ? undefined : path.join(" ");
|
|
1188
1373
|
}
|
|
1189
|
-
async function runMain({ name, version, run, redact, usage }, argv =
|
|
1374
|
+
async function runMain({ name, version, run, redact, usage }, argv = process12.argv.slice(2)) {
|
|
1190
1375
|
if (argv[0] === COMPLETE)
|
|
1191
1376
|
return printCandidates(leafCandidates(run, argv.slice(1)));
|
|
1192
1377
|
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
@@ -1222,36 +1407,17 @@ function parseSize(text, bareUnit = 1) {
|
|
|
1222
1407
|
const suffix = match[2].toLowerCase();
|
|
1223
1408
|
return Math.round(Number(match[1]) * (suffix === "" ? bareUnit : 1024 ** POWERS[suffix]));
|
|
1224
1409
|
}
|
|
1225
|
-
// ../kit/src/user-config.ts
|
|
1226
|
-
import { existsSync } from "fs";
|
|
1227
|
-
import { homedir as homedir2 } from "os";
|
|
1228
|
-
import { join as join3 } from "path";
|
|
1229
|
-
import process10 from "process";
|
|
1230
|
-
function configBase(where = {}) {
|
|
1231
|
-
const xdg = where.xdg ?? (where.home === undefined ? process10.env.XDG_CONFIG_HOME : undefined);
|
|
1232
|
-
return xdg !== undefined && xdg !== "" ? xdg : join3(where.home ?? homedir2(), ".config");
|
|
1233
|
-
}
|
|
1234
|
-
function userConfigPath(bin, where = {}) {
|
|
1235
|
-
return join3(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
1236
|
-
}
|
|
1237
|
-
function userConfigReadPath(bin, legacy = [], where = {}) {
|
|
1238
|
-
const current = userConfigPath(bin, where);
|
|
1239
|
-
if (existsSync(current))
|
|
1240
|
-
return current;
|
|
1241
|
-
const base = configBase(where);
|
|
1242
|
-
return legacy.map((parts) => join3(base, ...parts)).find((path) => existsSync(path)) ?? current;
|
|
1243
|
-
}
|
|
1244
1410
|
// src/repos.ts
|
|
1245
|
-
import { existsSync as
|
|
1246
|
-
import { homedir as
|
|
1247
|
-
import { join as
|
|
1248
|
-
import
|
|
1411
|
+
import { existsSync as existsSync5, statSync as statSync2 } from "fs";
|
|
1412
|
+
import { homedir as homedir4 } from "os";
|
|
1413
|
+
import { join as join7, relative, resolve as resolve3 } from "path";
|
|
1414
|
+
import process15 from "process";
|
|
1249
1415
|
|
|
1250
1416
|
// src/repos-scan.ts
|
|
1251
|
-
import { existsSync as
|
|
1417
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1252
1418
|
import { readdir } from "fs/promises";
|
|
1253
|
-
import { basename, join as
|
|
1254
|
-
import
|
|
1419
|
+
import { basename, join as join6 } from "path";
|
|
1420
|
+
import process14 from "process";
|
|
1255
1421
|
var MAX_DEPTH = 3;
|
|
1256
1422
|
var CONCURRENCY = 8;
|
|
1257
1423
|
var GIT_MS = 1e4;
|
|
@@ -1272,7 +1438,7 @@ function reasonsOf(repo) {
|
|
|
1272
1438
|
return reasons;
|
|
1273
1439
|
}
|
|
1274
1440
|
async function findRepos(root, skip) {
|
|
1275
|
-
if (
|
|
1441
|
+
if (existsSync4(join6(root, ".git")))
|
|
1276
1442
|
return [root];
|
|
1277
1443
|
const found = [];
|
|
1278
1444
|
async function walk(dir, depth) {
|
|
@@ -1285,8 +1451,8 @@ async function findRepos(root, skip) {
|
|
|
1285
1451
|
for (const entry of entries.toSorted((a, b) => a.name.localeCompare(b.name))) {
|
|
1286
1452
|
if (!entry.isDirectory() || entry.name === "node_modules" || entry.name.startsWith(".") || skip.has(entry.name))
|
|
1287
1453
|
continue;
|
|
1288
|
-
const path =
|
|
1289
|
-
if (
|
|
1454
|
+
const path = join6(dir, entry.name);
|
|
1455
|
+
if (existsSync4(join6(path, ".git")))
|
|
1290
1456
|
found.push(path);
|
|
1291
1457
|
else if (depth < MAX_DEPTH)
|
|
1292
1458
|
await walk(path, depth + 1);
|
|
@@ -1297,7 +1463,7 @@ async function findRepos(root, skip) {
|
|
|
1297
1463
|
}
|
|
1298
1464
|
async function read(path, args, timeoutMs = GIT_MS) {
|
|
1299
1465
|
try {
|
|
1300
|
-
const ran = await runCommand(["git", "--no-optional-locks", ...args], { cwd: path, env: { ...
|
|
1466
|
+
const ran = await runCommand(["git", "--no-optional-locks", ...args], { cwd: path, env: { ...process14.env, GIT_TERMINAL_PROMPT: "0" }, timeoutMs });
|
|
1301
1467
|
return ran.code === 0 && !ran.timedOut ? ran.text.trim() : undefined;
|
|
1302
1468
|
} catch {
|
|
1303
1469
|
return;
|
|
@@ -1317,7 +1483,7 @@ async function packageReleases(path) {
|
|
|
1317
1483
|
}
|
|
1318
1484
|
const releases = [];
|
|
1319
1485
|
for (const name of [...names].toSorted()) {
|
|
1320
|
-
const folder = [
|
|
1486
|
+
const folder = [join6("packages", name), name].find((candidate) => existsSync4(join6(path, candidate)));
|
|
1321
1487
|
const tag = folder === undefined ? undefined : await read(path, ["describe", "--tags", "--abbrev=0", "--match", `${name}-v*`]);
|
|
1322
1488
|
if (folder !== undefined && tag !== undefined && tag !== "")
|
|
1323
1489
|
releases.push({ name, tag, unreleased: await commitsSince(path, tag, folder) });
|
|
@@ -1376,7 +1542,7 @@ function firstLine(text) {
|
|
|
1376
1542
|
}
|
|
1377
1543
|
async function fastForward(path) {
|
|
1378
1544
|
try {
|
|
1379
|
-
const ran = await runCommand(["git", "--no-optional-locks", "merge", "--ff-only", "--quiet", "@{upstream}"], { cwd: path, env: { ...
|
|
1545
|
+
const ran = await runCommand(["git", "--no-optional-locks", "merge", "--ff-only", "--quiet", "@{upstream}"], { cwd: path, env: { ...process14.env, GIT_TERMINAL_PROMPT: "0" }, timeoutMs: GIT_MS });
|
|
1380
1546
|
if (ran.timedOut)
|
|
1381
1547
|
return "timed out";
|
|
1382
1548
|
return ran.code === 0 ? undefined : firstLine(ran.text.trim()) || `exit ${ran.code}`;
|
|
@@ -1416,7 +1582,7 @@ var OPTIONS = {
|
|
|
1416
1582
|
};
|
|
1417
1583
|
async function skipped() {
|
|
1418
1584
|
const file = userConfigReadPath("repos");
|
|
1419
|
-
if (!
|
|
1585
|
+
if (!existsSync5(file))
|
|
1420
1586
|
return new Set;
|
|
1421
1587
|
try {
|
|
1422
1588
|
const config = await Bun.file(file).json();
|
|
@@ -1430,17 +1596,39 @@ function releasedCell(repo) {
|
|
|
1430
1596
|
return repo.packages.filter((release) => release.unreleased > 0).map((release) => `${release.name} ${release.unreleased}`).join(", ") || "-";
|
|
1431
1597
|
return repo.tag === null || repo.unreleased === 0 ? "-" : `${repo.unreleased} since ${repo.tag}`;
|
|
1432
1598
|
}
|
|
1433
|
-
function
|
|
1434
|
-
const
|
|
1599
|
+
function syncCell(repo, stream = process15.stdout) {
|
|
1600
|
+
const colors = paint(stream);
|
|
1435
1601
|
const ahead = repo.ahead ?? 0;
|
|
1436
1602
|
const behind = repo.behind ?? 0;
|
|
1437
|
-
|
|
1438
|
-
|
|
1603
|
+
if (repo.upstream === null)
|
|
1604
|
+
return colors.dim("no upstream");
|
|
1605
|
+
const parts = [ahead > 0 ? colors.green(`+${ahead}`) : "", behind > 0 ? colors.red(`-${behind}`) : ""].filter(Boolean);
|
|
1606
|
+
const diverged = takesControlCodes(stream) && ahead > 0 && behind > 0;
|
|
1607
|
+
return parts.length === 0 ? colors.dim("-") : `${parts.join(" ")}${diverged ? colors.yellow(" diverged") : ""}`;
|
|
1608
|
+
}
|
|
1609
|
+
function branchCell(repo) {
|
|
1610
|
+
const colors = paint(process15.stdout);
|
|
1611
|
+
if (repo.unreadable)
|
|
1612
|
+
return colors.red("? (unreadable)");
|
|
1613
|
+
return repo.branch === "(detached)" ? colors.yellow(repo.branch) : repo.branch;
|
|
1614
|
+
}
|
|
1615
|
+
function row(repo, shown) {
|
|
1616
|
+
const colors = paint(process15.stdout);
|
|
1617
|
+
const tint = role("path", process15.stdout);
|
|
1618
|
+
const unreleased = releasedCell(repo);
|
|
1619
|
+
return [
|
|
1620
|
+
tint(shown),
|
|
1621
|
+
branchCell(repo),
|
|
1622
|
+
repo.dirty === 0 ? colors.dim("-") : colors.yellow(String(repo.dirty)),
|
|
1623
|
+
syncCell(repo),
|
|
1624
|
+
repo.worktrees === 0 ? colors.dim("-") : String(repo.worktrees),
|
|
1625
|
+
unreleased === "-" ? colors.dim("-") : colors.cyan(unreleased)
|
|
1626
|
+
];
|
|
1439
1627
|
}
|
|
1440
1628
|
async function repos(args) {
|
|
1441
1629
|
const { values, positionals } = parse(args, USAGE, OPTIONS, { positionals: ["[root]"], exits: EXITS, replaces: "a cd, git status, git log and git tag loop over each repository of the workspace", examples: ["repos", "repos ~/Workspace --only unreleased --fetch", ["repos --only behind --pull", "fast-forward what is behind and clean"], ["repos --only dirty --path", "the paths, for xargs"]] });
|
|
1442
|
-
const root =
|
|
1443
|
-
if (!
|
|
1630
|
+
const root = resolve3(positionals[0] ?? join7(homedir4(), "Workspace"));
|
|
1631
|
+
if (!existsSync5(root) || !statSync2(root).isDirectory())
|
|
1444
1632
|
fail(`no folder ${root}`);
|
|
1445
1633
|
const only = values.only === undefined ? undefined : oneOf(values.only, "only", REASONS);
|
|
1446
1634
|
const paths = await findRepos(root, await skipped());
|
|
@@ -1458,12 +1646,12 @@ async function repos(args) {
|
|
|
1458
1646
|
const blocker = pullBlocker(repo);
|
|
1459
1647
|
const refused = blocker === undefined ? await fastForward(repo.path) : undefined;
|
|
1460
1648
|
if (blocker !== undefined) {
|
|
1461
|
-
log(marked("note", `${repo.name} skipped`,
|
|
1649
|
+
log(marked("note", `${repo.name} skipped`, process15.stdout, blocker));
|
|
1462
1650
|
} else if (refused !== undefined) {
|
|
1463
1651
|
failedPulls++;
|
|
1464
|
-
log(marked("problem", `${repo.name} not pulled`,
|
|
1652
|
+
log(marked("problem", `${repo.name} not pulled`, process15.stdout, refused));
|
|
1465
1653
|
} else {
|
|
1466
|
-
log(marked("ok", `${repo.name} pulled`,
|
|
1654
|
+
log(marked("ok", `${repo.name} pulled`, process15.stdout, `${repo.behind} ${repo.behind === 1 ? "commit" : "commits"}`));
|
|
1467
1655
|
states[index] = await inspect(repo.path, false);
|
|
1468
1656
|
}
|
|
1469
1657
|
}
|
|
@@ -1478,7 +1666,7 @@ async function repos(args) {
|
|
|
1478
1666
|
printJson(kept.map((repo) => ({ ...repo, reasons: reasonsOf(repo) })));
|
|
1479
1667
|
return failedPulls > 0 ? 1 : 0;
|
|
1480
1668
|
}
|
|
1481
|
-
const label = role("label",
|
|
1669
|
+
const label = role("label", process15.stdout);
|
|
1482
1670
|
if (kept.length === 0) {
|
|
1483
1671
|
console.log(label(`nothing needs attention in ${states.length} repositories`));
|
|
1484
1672
|
return failedPulls > 0 ? 1 : 0;
|
|
@@ -1493,4 +1681,4 @@ async function repos(args) {
|
|
|
1493
1681
|
}
|
|
1494
1682
|
|
|
1495
1683
|
// src/repos-cli.ts
|
|
1496
|
-
|
|
1684
|
+
process16.exitCode = await runMain({ name: "repos", run: repos });
|