@kaynooo/cli-docker 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/dc-cli.js +246 -58
- package/dist/dlog-cli.js +246 -58
- package/dist/dx-cli.js +903 -128
- package/dist/sf-cli.js +910 -136
- package/package.json +3 -3
- package/src/dx.ts +5 -8
- package/src/picker.ts +5 -5
- package/src/sf.ts +13 -17
package/README.md
CHANGED
|
@@ -12,12 +12,12 @@ bun install -g @kaynooo/cli-docker
|
|
|
12
12
|
| --- | --- |
|
|
13
13
|
| `dc <compose args>` | `docker compose` on the nearest compose file (or `.env` setting `COMPOSE_FILE`) up to the repository root |
|
|
14
14
|
| `dc <project> <compose args>` | the same on a stack that came up from other files (`-f docker-compose.prod.yaml --env-file .env.prod`), found through the labels compose put on its containers |
|
|
15
|
-
| `dx` | without a terminal
|
|
15
|
+
| `dx` | without a terminal (a script, a pipe, an agent) it lists the services with their state, ports and image, `--json` for the full record: that is the form to use there. On a terminal it picks one instead: enter opens its shell (or brings it up), ctrl-l follows its logs, ctrl-r restarts, ctrl-x stops, ctrl-b rebuilds; the ones acted on last come first |
|
|
16
16
|
| `dx -` | the last action again |
|
|
17
17
|
| `dx <service> [action]` | `shell` (the default, `up` for a stopped service), `logs`, `restart`, `up`, `stop` or `build` |
|
|
18
18
|
| `dx <service> logs --tail 50 --no-follow` | `--tail N` sets the lines (200), `--no-follow` prints them once and exits instead of following, so a script or an agent gets them without hanging; both are refused for any other action |
|
|
19
19
|
| `dlog [service...]` | one line per service with its state and health, then the last distinct error lines of its logs (`-n` per service, `--since 1h`), a repeated message once with `×N` and secrets masked as `redact` does; `--all` adds the last lines of a quiet service. `--level warn` keeps warnings too and `--grep <regex>` keeps the lines matching a case insensitive regex instead of the error words. Exits 1 when a service is down or unhealthy or logged a line; `--fail-on down|unhealthy|errors` (repeatable, all three by default) picks what counts, so `--fail-on down --fail-on unhealthy` gates on health and ignores an old error still inside `--since` |
|
|
20
|
-
| `sf` | without a terminal
|
|
20
|
+
| `sf` | without a terminal (a script, a pipe, an agent) it lists the Symfony console commands with their description, `sf --list --json` adding arguments and options: that is the form to use there. On a terminal it picks a command and runs it, asking for each required argument; the commands run last come first, and the picker opens on the list cached from the last run. It runs in the php service of the nearest compose stack, else with the local php |
|
|
21
21
|
| `sf --list --json` | every command with its console folder, signature, arguments and options as JSON |
|
|
22
22
|
| `sf -` | the last command again, with the arguments it ran with |
|
|
23
23
|
| `sf <command> [args...]` | runs without the picker; a name the list does not hold goes to the console as is, which resolves `c:c` to `cache:clear` itself |
|
package/dist/dc-cli.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/dc-cli.ts
|
|
5
|
-
import
|
|
5
|
+
import process12 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/style.ts
|
|
11
|
-
import
|
|
11
|
+
import process5 from "process";
|
|
12
12
|
|
|
13
13
|
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
14
14
|
function x(s) {
|
|
@@ -271,21 +271,209 @@ function le(i = {}) {
|
|
|
271
271
|
}
|
|
272
272
|
var t = le();
|
|
273
273
|
|
|
274
|
+
// ../kit/src/theme.ts
|
|
275
|
+
import { existsSync as existsSync2, readFileSync, statSync } from "fs";
|
|
276
|
+
import { homedir as homedir2 } from "os";
|
|
277
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
278
|
+
import process4 from "process";
|
|
279
|
+
|
|
280
|
+
// ../kit/src/config.ts
|
|
281
|
+
import { existsSync } from "fs";
|
|
282
|
+
import { dirname, join, resolve } from "path";
|
|
283
|
+
import process2 from "process";
|
|
284
|
+
function findUp(names, from = process2.cwd(), stop = () => false) {
|
|
285
|
+
const wanted = typeof names === "string" ? [names] : names;
|
|
286
|
+
for (let dir = resolve(from);; dir = dirname(dir)) {
|
|
287
|
+
const found = wanted.map((name) => join(dir, name)).find((path) => existsSync(path));
|
|
288
|
+
if (found !== undefined)
|
|
289
|
+
return found;
|
|
290
|
+
if (stop(dir) || dirname(dir) === dir)
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ../kit/src/user-config.ts
|
|
296
|
+
import { homedir } from "os";
|
|
297
|
+
import { join as join2 } from "path";
|
|
298
|
+
import process3 from "process";
|
|
299
|
+
function configBase(where = {}) {
|
|
300
|
+
const xdg = where.xdg ?? (where.home === undefined ? process3.env.XDG_CONFIG_HOME : undefined);
|
|
301
|
+
return xdg !== undefined && xdg !== "" ? xdg : join2(where.home ?? homedir(), ".config");
|
|
302
|
+
}
|
|
303
|
+
function userConfigPath(bin, where = {}) {
|
|
304
|
+
return join2(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ../kit/src/theme.ts
|
|
308
|
+
var DEFAULT = {
|
|
309
|
+
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" },
|
|
310
|
+
glyphs: { ok: "\u2713", warn: "\u25B2", problem: "\u2717", note: "\u203A", passed: "\u2713", failed: "\u2717", running: "\u25CF", queued: "\u25CB", skipped: "-", bar: "\u2501" },
|
|
311
|
+
accents: ["cyan", "magenta", "green", "blue", "yellow", "redBright"],
|
|
312
|
+
bins: {}
|
|
313
|
+
};
|
|
314
|
+
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" };
|
|
315
|
+
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" };
|
|
316
|
+
var ASCII = { ok: "+", warn: "!", problem: "x", note: ">", passed: "+", failed: "x", running: "*", queued: "o", skipped: "-", bar: "#" };
|
|
317
|
+
var PRESETS = {
|
|
318
|
+
default: {},
|
|
319
|
+
"high-contrast": { colors: BRIGHT, accents: ["cyanBright", "magentaBright", "greenBright", "blueBright", "yellowBright", "redBright"] },
|
|
320
|
+
mono: { colors: MONO, accents: ["bold"] },
|
|
321
|
+
ascii: { glyphs: ASCII }
|
|
322
|
+
};
|
|
323
|
+
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"]);
|
|
324
|
+
var HEX = /^#[0-9a-f]{6}$/i;
|
|
325
|
+
var CONTROL = /\p{Cc}/u;
|
|
326
|
+
var MAX_FILE_BYTES = 64 * 1024;
|
|
327
|
+
var SPACES = /\s+/;
|
|
328
|
+
function isColorSpec(spec) {
|
|
329
|
+
if (typeof spec === "number")
|
|
330
|
+
return Number.isInteger(spec) && spec >= 0 && spec <= 255;
|
|
331
|
+
return typeof spec === "string" && spec.trim() !== "" && spec.trim().split(SPACES).every((token) => STYLES.has(token) || HEX.test(token));
|
|
332
|
+
}
|
|
333
|
+
function tinted(colors, spec) {
|
|
334
|
+
if (typeof spec === "number")
|
|
335
|
+
return colors.ansi256(spec);
|
|
336
|
+
return spec.trim().split(SPACES).reduce((chain, token) => HEX.test(token) ? chain.hex(token) : chain[token] ?? chain, colors);
|
|
337
|
+
}
|
|
338
|
+
function isRecord(value) {
|
|
339
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
340
|
+
}
|
|
341
|
+
function readThemeFile(path, warn) {
|
|
342
|
+
try {
|
|
343
|
+
const stat = statSync(path, { throwIfNoEntry: false });
|
|
344
|
+
if (stat === undefined)
|
|
345
|
+
return;
|
|
346
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES) {
|
|
347
|
+
warn(`${path} is not a regular file under ${MAX_FILE_BYTES / 1024} KiB, theme ignored`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
351
|
+
if (isRecord(parsed))
|
|
352
|
+
return parsed;
|
|
353
|
+
warn(`${path} is not a JSON object, theme ignored`);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
warn(`${path} does not parse (${error instanceof Error ? error.message : String(error)}), theme ignored`);
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
function applyPreset(theme, name, warn, where) {
|
|
360
|
+
if (name === undefined)
|
|
361
|
+
return;
|
|
362
|
+
if (typeof name !== "string" || !Object.hasOwn(PRESETS, name)) {
|
|
363
|
+
warn(`${where}: no preset ${String(name)}, one of ${Object.keys(PRESETS).join(", ")}`);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const preset = PRESETS[name];
|
|
367
|
+
Object.assign(theme.colors, preset.colors);
|
|
368
|
+
Object.assign(theme.glyphs, preset.glyphs);
|
|
369
|
+
if (preset.accents !== undefined)
|
|
370
|
+
theme.accents = [...preset.accents];
|
|
371
|
+
return name;
|
|
372
|
+
}
|
|
373
|
+
function applyFile(theme, file, where, warn) {
|
|
374
|
+
if (isRecord(file.colors)) {
|
|
375
|
+
for (const [key, value] of Object.entries(file.colors)) {
|
|
376
|
+
if (!Object.hasOwn(DEFAULT.colors, key))
|
|
377
|
+
warn(`${where}: no colour ${key}, one of ${Object.keys(DEFAULT.colors).join(", ")}`);
|
|
378
|
+
else if (!isColorSpec(value))
|
|
379
|
+
warn(`${where}: colour ${key} is not an ANSI name, \`#rrggbb\` or a number up to 255`);
|
|
380
|
+
else
|
|
381
|
+
theme.colors[key] = value;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (isRecord(file.glyphs)) {
|
|
385
|
+
for (const [key, value] of Object.entries(file.glyphs)) {
|
|
386
|
+
if (!Object.hasOwn(DEFAULT.glyphs, key))
|
|
387
|
+
warn(`${where}: no glyph ${key}, one of ${Object.keys(DEFAULT.glyphs).join(", ")}`);
|
|
388
|
+
else if (typeof value !== "string" || CONTROL.test(value) || Bun.stringWidth(value) !== 1)
|
|
389
|
+
warn(`${where}: glyph ${key} must be one visible character wide, with no control character`);
|
|
390
|
+
else
|
|
391
|
+
theme.glyphs[key] = value;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (Array.isArray(file.accents) && file.accents.length > 0 && file.accents.every(isColorSpec))
|
|
395
|
+
theme.accents = [...file.accents];
|
|
396
|
+
else if (file.accents !== undefined)
|
|
397
|
+
warn(`${where}: accents must be a non-empty list of colours`);
|
|
398
|
+
if (isRecord(file.bins)) {
|
|
399
|
+
for (const [bin, value] of Object.entries(file.bins)) {
|
|
400
|
+
if (isColorSpec(value))
|
|
401
|
+
theme.bins[bin] = value;
|
|
402
|
+
else
|
|
403
|
+
warn(`${where}: bin ${bin} has no valid colour`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function endsWalk(home) {
|
|
408
|
+
return (dir) => dir === resolve2(home) || existsSync2(join3(dir, ".git"));
|
|
409
|
+
}
|
|
410
|
+
var warned = new Set;
|
|
411
|
+
function warnOnce(message) {
|
|
412
|
+
if (warned.has(message))
|
|
413
|
+
return;
|
|
414
|
+
warned.add(message);
|
|
415
|
+
console.error(`warning: theme ${message}`);
|
|
416
|
+
}
|
|
417
|
+
function isPath(chosen) {
|
|
418
|
+
return chosen.includes("/") || chosen.endsWith(".json");
|
|
419
|
+
}
|
|
420
|
+
function loadTheme({ env = process4.env, from = process4.cwd(), home = homedir2(), warn = warnOnce } = {}) {
|
|
421
|
+
const theme = { colors: { ...DEFAULT.colors }, glyphs: { ...DEFAULT.glyphs }, accents: [...DEFAULT.accents], bins: Object.create(null) };
|
|
422
|
+
const sources = [];
|
|
423
|
+
const chosen = env.KIT_THEME ?? "";
|
|
424
|
+
const wanted = chosen === "" ? [userConfigPath("theme", { home, xdg: env.XDG_CONFIG_HOME }), findUp(join3(".kaynooo", "theme.json"), from, endsWalk(home))] : [];
|
|
425
|
+
if (isPath(chosen))
|
|
426
|
+
wanted.push(resolve2(from, chosen));
|
|
427
|
+
const files = [];
|
|
428
|
+
for (const path of wanted) {
|
|
429
|
+
const file = path === undefined ? undefined : readThemeFile(path, warn);
|
|
430
|
+
if (path !== undefined && file !== undefined)
|
|
431
|
+
files.push({ path, file });
|
|
432
|
+
}
|
|
433
|
+
let preset = "default";
|
|
434
|
+
if (chosen !== "" && !isPath(chosen)) {
|
|
435
|
+
preset = applyPreset(theme, chosen, warn, "KIT_THEME") ?? preset;
|
|
436
|
+
} else {
|
|
437
|
+
const named = files.findLast(({ file }) => file.preset !== undefined);
|
|
438
|
+
if (named !== undefined)
|
|
439
|
+
preset = applyPreset(theme, named.file.preset, warn, named.path) ?? preset;
|
|
440
|
+
}
|
|
441
|
+
for (const { path, file } of files) {
|
|
442
|
+
applyFile(theme, file, path, warn);
|
|
443
|
+
sources.push(path);
|
|
444
|
+
}
|
|
445
|
+
return { theme, sources, preset };
|
|
446
|
+
}
|
|
447
|
+
var current;
|
|
448
|
+
var currentKey = "";
|
|
449
|
+
function activeTheme() {
|
|
450
|
+
const key = `${process4.cwd()}\x00${process4.env.KIT_THEME ?? ""}\x00${process4.env.XDG_CONFIG_HOME ?? ""}`;
|
|
451
|
+
if (current === undefined || key !== currentKey) {
|
|
452
|
+
current = loadTheme();
|
|
453
|
+
currentKey = key;
|
|
454
|
+
}
|
|
455
|
+
return current;
|
|
456
|
+
}
|
|
457
|
+
|
|
274
458
|
// ../kit/src/style.ts
|
|
275
|
-
function takesControlCodes(stream, env =
|
|
459
|
+
function takesControlCodes(stream, env = process5.env) {
|
|
276
460
|
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
277
461
|
}
|
|
278
|
-
function paint(stream, env =
|
|
462
|
+
function paint(stream, env = process5.env) {
|
|
279
463
|
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
280
464
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
465
|
+
function role(name, stream, env = process5.env) {
|
|
466
|
+
const colors = paint(stream, env);
|
|
467
|
+
return takesControlCodes(stream, env) ? tinted(colors, activeTheme().theme.colors[name]) : colors;
|
|
468
|
+
}
|
|
469
|
+
var STATUS_WORDS = {
|
|
470
|
+
passed: ["passed", "success", "succeeded", "ok"],
|
|
471
|
+
failed: ["failed", "failure", "error", "errored"],
|
|
472
|
+
running: ["running", "in_progress", "started"],
|
|
473
|
+
queued: ["queued", "waiting", "pending", "created", "blocked", "scheduled"],
|
|
474
|
+
skipped: ["skipped", "cancelled", "canceled", "manual"]
|
|
287
475
|
};
|
|
288
|
-
var STATUS_OF = new Map(Object.entries(
|
|
476
|
+
var STATUS_OF = new Map(Object.entries(STATUS_WORDS).flatMap(([status, words]) => words.map((word) => [word, status])));
|
|
289
477
|
|
|
290
478
|
// ../kit/src/format.ts
|
|
291
479
|
function upTo(text, separator) {
|
|
@@ -298,27 +486,27 @@ function printJson(value) {
|
|
|
298
486
|
}
|
|
299
487
|
|
|
300
488
|
// ../kit/src/help.ts
|
|
301
|
-
import
|
|
489
|
+
import process6 from "process";
|
|
302
490
|
var OPTIONAL = /\[[^\]]+\]/g;
|
|
303
491
|
var USAGE_PREFIX = /^usage:\s*/i;
|
|
304
492
|
var FULL_STOP = /\.$/;
|
|
305
|
-
function usageLine(usage, colors = paint(
|
|
493
|
+
function usageLine(usage, colors = paint(process6.stdout)) {
|
|
306
494
|
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
307
495
|
}
|
|
308
|
-
function helpText(usage, options, colors = paint(
|
|
496
|
+
function helpText(usage, options, colors = paint(process6.stdout), { examples = [], replaces, exits = [] } = {}) {
|
|
309
497
|
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
|
|
310
498
|
`);
|
|
311
499
|
}
|
|
312
|
-
function exitRows(exits, colors = paint(
|
|
500
|
+
function exitRows(exits, colors = paint(process6.stdout)) {
|
|
313
501
|
if (exits.length === 0)
|
|
314
502
|
return [];
|
|
315
503
|
const width = Math.max(...exits.map(([code]) => String(code).length));
|
|
316
504
|
return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
|
|
317
505
|
}
|
|
318
|
-
function replacesRows(replaces, colors = paint(
|
|
506
|
+
function replacesRows(replaces, colors = paint(process6.stdout)) {
|
|
319
507
|
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
320
508
|
}
|
|
321
|
-
function wantsHelpJson(env =
|
|
509
|
+
function wantsHelpJson(env = process6.env) {
|
|
322
510
|
return env.KIT_HELP === "json";
|
|
323
511
|
}
|
|
324
512
|
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
@@ -337,12 +525,12 @@ function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
|
337
525
|
...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
|
|
338
526
|
};
|
|
339
527
|
}
|
|
340
|
-
function exampleRows(examples, colors = paint(
|
|
528
|
+
function exampleRows(examples, colors = paint(process6.stdout)) {
|
|
341
529
|
if (examples.length === 0)
|
|
342
530
|
return [];
|
|
343
531
|
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
344
532
|
}
|
|
345
|
-
function optionRows(options, colors = paint(
|
|
533
|
+
function optionRows(options, colors = paint(process6.stdout)) {
|
|
346
534
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
347
535
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
348
536
|
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
@@ -436,7 +624,7 @@ var OUTPUT_OPTIONS = {
|
|
|
436
624
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
437
625
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
438
626
|
};
|
|
439
|
-
function applyOutput(color, plain, env =
|
|
627
|
+
function applyOutput(color, plain, env = process7.env) {
|
|
440
628
|
const when = plain === true ? "never" : color ?? "auto";
|
|
441
629
|
if (when === "auto")
|
|
442
630
|
return;
|
|
@@ -611,15 +799,15 @@ var ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x
|
|
|
611
799
|
var RESET_STYLE = `${ESC}[0m`;
|
|
612
800
|
var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
613
801
|
// ../kit/src/cli.ts
|
|
614
|
-
import { readFileSync, realpathSync } from "fs";
|
|
615
|
-
import { dirname as
|
|
616
|
-
import
|
|
802
|
+
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
803
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
804
|
+
import process9 from "process";
|
|
617
805
|
|
|
618
806
|
// ../kit/src/usage.ts
|
|
619
807
|
import { appendFileSync, mkdirSync } from "fs";
|
|
620
|
-
import { homedir } from "os";
|
|
621
|
-
import { dirname, isAbsolute, join } from "path";
|
|
622
|
-
import
|
|
808
|
+
import { homedir as homedir3 } from "os";
|
|
809
|
+
import { dirname as dirname2, isAbsolute, join as join4 } from "path";
|
|
810
|
+
import process8 from "process";
|
|
623
811
|
|
|
624
812
|
// ../kit/src/logs.ts
|
|
625
813
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -633,14 +821,14 @@ var usageError;
|
|
|
633
821
|
function noteUsageError(message) {
|
|
634
822
|
usageError = message;
|
|
635
823
|
}
|
|
636
|
-
function stateHome(env =
|
|
824
|
+
function stateHome(env = process8.env) {
|
|
637
825
|
const dir = env.XDG_STATE_HOME;
|
|
638
|
-
return dir !== undefined && isAbsolute(dir) ? dir :
|
|
826
|
+
return dir !== undefined && isAbsolute(dir) ? dir : join4(homedir3(), ".local", "state");
|
|
639
827
|
}
|
|
640
|
-
function usagePath(env =
|
|
641
|
-
return
|
|
828
|
+
function usagePath(env = process8.env) {
|
|
829
|
+
return join4(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
642
830
|
}
|
|
643
|
-
function usageRecorded(env =
|
|
831
|
+
function usageRecorded(env = process8.env) {
|
|
644
832
|
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
645
833
|
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
646
834
|
}
|
|
@@ -654,12 +842,12 @@ function usageEntry(bin, command, argv, code, now = new Date) {
|
|
|
654
842
|
usageError = undefined;
|
|
655
843
|
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
656
844
|
}
|
|
657
|
-
function recordUsage(entry, env =
|
|
845
|
+
function recordUsage(entry, env = process8.env) {
|
|
658
846
|
if (!usageRecorded(env))
|
|
659
847
|
return;
|
|
660
848
|
try {
|
|
661
849
|
const path = usagePath(env);
|
|
662
|
-
mkdirSync(
|
|
850
|
+
mkdirSync(dirname2(path), { recursive: true, mode: 448 });
|
|
663
851
|
appendFileSync(path, `${JSON.stringify(entry)}
|
|
664
852
|
`, { mode: 384 });
|
|
665
853
|
} catch {}
|
|
@@ -672,8 +860,8 @@ var LEVEL_OPTIONS = {
|
|
|
672
860
|
};
|
|
673
861
|
var TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
|
|
674
862
|
function printError(prefix, message, hint, cause) {
|
|
675
|
-
const colors = paint(
|
|
676
|
-
const styled = takesControlCodes(
|
|
863
|
+
const colors = paint(process9.stderr);
|
|
864
|
+
const styled = takesControlCodes(process9.stderr);
|
|
677
865
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
678
866
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
679
867
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -692,7 +880,7 @@ function reportThrown(prefix, error, redact = (text) => text, json = false) {
|
|
|
692
880
|
const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
|
|
693
881
|
const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
|
|
694
882
|
const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
|
|
695
|
-
if (error instanceof
|
|
883
|
+
if (error instanceof Exit && error.code === 2)
|
|
696
884
|
noteUsageError(error.message);
|
|
697
885
|
const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
|
|
698
886
|
report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
|
|
@@ -756,17 +944,17 @@ async function printCandidates(found) {
|
|
|
756
944
|
return 0;
|
|
757
945
|
}
|
|
758
946
|
function packageVersion(entry = Bun.main) {
|
|
759
|
-
for (let dir =
|
|
947
|
+
for (let dir = dirname3(realpathSync(entry));; dir = dirname3(dir)) {
|
|
760
948
|
try {
|
|
761
|
-
const { version } = JSON.parse(
|
|
949
|
+
const { version } = JSON.parse(readFileSync2(join5(dir, "package.json"), "utf8"));
|
|
762
950
|
if (typeof version === "string")
|
|
763
951
|
return version;
|
|
764
952
|
} catch {}
|
|
765
|
-
if (
|
|
953
|
+
if (dirname3(dir) === dir)
|
|
766
954
|
return "0.0.0";
|
|
767
955
|
}
|
|
768
956
|
}
|
|
769
|
-
async function runMain({ name, version, run, redact, usage }, argv =
|
|
957
|
+
async function runMain({ name, version, run, redact, usage }, argv = process9.argv.slice(2)) {
|
|
770
958
|
if (argv[0] === COMPLETE)
|
|
771
959
|
return printCandidates(leafCandidates(run, argv.slice(1)));
|
|
772
960
|
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
@@ -809,15 +997,15 @@ var {Glob } = globalThis.Bun;
|
|
|
809
997
|
var SESSION_FILES = new Glob("*.json");
|
|
810
998
|
var ACCOUNT_DIRS = new Glob("*/sessions");
|
|
811
999
|
// src/dc.ts
|
|
812
|
-
import
|
|
1000
|
+
import process11 from "process";
|
|
813
1001
|
|
|
814
1002
|
// src/stack.ts
|
|
815
|
-
import { existsSync, readdirSync, readFileSync as
|
|
816
|
-
import { dirname as
|
|
1003
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
1004
|
+
import { dirname as dirname5, join as join7, relative, resolve as resolve3 } from "path";
|
|
817
1005
|
|
|
818
1006
|
// ../env/src/files.ts
|
|
819
1007
|
import { chmod, chown, readdir, realpath, rename, rm, stat, writeFile } from "fs/promises";
|
|
820
|
-
import { basename, dirname as
|
|
1008
|
+
import { basename, dirname as dirname4, join as join6 } from "path";
|
|
821
1009
|
|
|
822
1010
|
// ../env/src/dotenv.ts
|
|
823
1011
|
var ASSIGNMENT = /^\s*(?:export\s+)?([A-Z_][\w.-]*)\s*=(.*)$/i;
|
|
@@ -1088,7 +1276,7 @@ async function envFilesBelow(folder, depth = 0) {
|
|
|
1088
1276
|
return found;
|
|
1089
1277
|
}
|
|
1090
1278
|
for (const entry of children) {
|
|
1091
|
-
const path =
|
|
1279
|
+
const path = join6(folder, entry.name);
|
|
1092
1280
|
if (entry.isDirectory() && depth < KNOWN_DEPTH && !SKIPPED.has(entry.name))
|
|
1093
1281
|
found.push(...await envFilesBelow(path, depth + 1));
|
|
1094
1282
|
else if (ENV_FILE.test(entry.name) && await isFileEntry(entry, path))
|
|
@@ -1179,21 +1367,21 @@ function children(dir = ".") {
|
|
|
1179
1367
|
}
|
|
1180
1368
|
function up(dir) {
|
|
1181
1369
|
const dirs = [];
|
|
1182
|
-
for (let current = dir;; current =
|
|
1370
|
+
for (let current = dir;; current = join7(current, "..")) {
|
|
1183
1371
|
dirs.push(current);
|
|
1184
|
-
const absolute =
|
|
1185
|
-
if (
|
|
1372
|
+
const absolute = resolve3(current);
|
|
1373
|
+
if (existsSync3(join7(current, ".git")) || dirname5(absolute) === absolute)
|
|
1186
1374
|
return dirs;
|
|
1187
1375
|
}
|
|
1188
1376
|
}
|
|
1189
1377
|
function stackAt(dir) {
|
|
1190
|
-
return { dir, run: from(dir, ["docker", "compose"]), list: { argv: ["docker", "compose"], cwd:
|
|
1378
|
+
return { dir, run: from(dir, ["docker", "compose"]), list: { argv: ["docker", "compose"], cwd: resolve3(dir), env: process.env } };
|
|
1191
1379
|
}
|
|
1192
1380
|
function holdsStack(dir) {
|
|
1193
|
-
if (COMPOSE_FILES.some((name) =>
|
|
1381
|
+
if (COMPOSE_FILES.some((name) => existsSync3(join7(dir, name))))
|
|
1194
1382
|
return true;
|
|
1195
1383
|
try {
|
|
1196
|
-
return COMPOSE_FILE_VAR.test(
|
|
1384
|
+
return COMPOSE_FILE_VAR.test(readFileSync3(join7(dir, ".env"), "utf-8"));
|
|
1197
1385
|
} catch {
|
|
1198
1386
|
return false;
|
|
1199
1387
|
}
|
|
@@ -1222,7 +1410,7 @@ async function labels(project) {
|
|
|
1222
1410
|
const proc = Bun.spawn(["docker", "ps", "--all", ...filter, "--format", LABEL_FORMAT], { stdout: "pipe", stderr: "ignore" });
|
|
1223
1411
|
if (await proc.exited !== 0)
|
|
1224
1412
|
return [];
|
|
1225
|
-
return labelled(await new Response(proc.stdout).text()).filter((stack) => [...stack.files, ...stack.envFiles].every((file) =>
|
|
1413
|
+
return labelled(await new Response(proc.stdout).text()).filter((stack) => [...stack.files, ...stack.envFiles].every((file) => existsSync3(file)));
|
|
1226
1414
|
}
|
|
1227
1415
|
function labelledStack(dir, { project, files, envFiles, workdir }) {
|
|
1228
1416
|
const options = (paths) => ["-p", project, ...files.flatMap((file) => ["-f", paths(file)]), ...envFiles.flatMap((file) => ["--env-file", paths(file)])];
|
|
@@ -1237,7 +1425,7 @@ function stackOf(recorded) {
|
|
|
1237
1425
|
return labelledStack(relative(".", recorded.workdir) || ".", recorded);
|
|
1238
1426
|
}
|
|
1239
1427
|
async function recordedNearby() {
|
|
1240
|
-
const dirs = new Set([...up("."), ...children()].map((dir) =>
|
|
1428
|
+
const dirs = new Set([...up("."), ...children()].map((dir) => resolve3(dir)));
|
|
1241
1429
|
return (await labels()).filter((stack) => dirs.has(stack.workdir));
|
|
1242
1430
|
}
|
|
1243
1431
|
async function attempt(stack, args) {
|
|
@@ -1347,7 +1535,7 @@ async function target(args) {
|
|
|
1347
1535
|
}
|
|
1348
1536
|
async function choose(recorded) {
|
|
1349
1537
|
const picker = Bun.which("pick");
|
|
1350
|
-
if (picker === null || !
|
|
1538
|
+
if (picker === null || !process11.stdin.isTTY)
|
|
1351
1539
|
return;
|
|
1352
1540
|
const proc = Bun.spawn([picker, "--prompt", "dc> "], { stdin: new Blob([recorded.map((stack) => stack.project).join(`
|
|
1353
1541
|
`)]), stdout: "pipe", stderr: "inherit" });
|
|
@@ -1355,8 +1543,8 @@ async function choose(recorded) {
|
|
|
1355
1543
|
return recorded.find((stack) => stack.project === picked);
|
|
1356
1544
|
}
|
|
1357
1545
|
async function run(stack, args, announce) {
|
|
1358
|
-
if (announce &&
|
|
1359
|
-
console.error(paint(
|
|
1546
|
+
if (announce && process11.stderr.isTTY)
|
|
1547
|
+
console.error(paint(process11.stderr).dim([...stack.run, ...args].join(" ")));
|
|
1360
1548
|
return Bun.spawn([...stack.list.argv, ...args], { cwd: stack.list.cwd, env: stack.list.env, stdio: ["inherit", "inherit", "inherit"] }).exited;
|
|
1361
1549
|
}
|
|
1362
1550
|
async function dc(args) {
|
|
@@ -1386,4 +1574,4 @@ async function main(args) {
|
|
|
1386
1574
|
}
|
|
1387
1575
|
return dc(args);
|
|
1388
1576
|
}
|
|
1389
|
-
|
|
1577
|
+
process12.exitCode = await runMain({ name: "dc", run: main });
|