@kaynooo/cli-docker 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/dc-cli.js +297 -62
- package/dist/dlog-cli.js +297 -62
- package/dist/dx-cli.js +954 -132
- package/dist/sf-cli.js +962 -141
- package/package.json +3 -3
- package/src/dc.ts +2 -2
- package/src/dx.ts +7 -10
- package/src/picker.ts +5 -5
- package/src/sf.ts +15 -19
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,37 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/dc-cli.ts
|
|
5
|
-
import
|
|
5
|
+
import process14 from "process";
|
|
6
6
|
// ../kit/src/args.ts
|
|
7
|
-
import
|
|
7
|
+
import process9 from "process";
|
|
8
8
|
import { parseArgs } from "util";
|
|
9
9
|
|
|
10
|
-
// ../kit/src/
|
|
10
|
+
// ../kit/src/format.ts
|
|
11
|
+
import process7 from "process";
|
|
12
|
+
|
|
13
|
+
// ../kit/src/mode.ts
|
|
11
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 process6 from "process";
|
|
12
36
|
|
|
13
37
|
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
14
38
|
function x(s) {
|
|
@@ -271,21 +295,229 @@ function le(i = {}) {
|
|
|
271
295
|
}
|
|
272
296
|
var t = le();
|
|
273
297
|
|
|
298
|
+
// ../kit/src/theme.ts
|
|
299
|
+
import { existsSync as existsSync2, readFileSync, statSync } from "fs";
|
|
300
|
+
import { homedir as homedir2 } from "os";
|
|
301
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
302
|
+
import process5 from "process";
|
|
303
|
+
|
|
304
|
+
// ../kit/src/config.ts
|
|
305
|
+
import { existsSync } from "fs";
|
|
306
|
+
import { dirname, join, resolve } from "path";
|
|
307
|
+
import process3 from "process";
|
|
308
|
+
function findUp(names, from = process3.cwd(), stop = () => false) {
|
|
309
|
+
const wanted = typeof names === "string" ? [names] : names;
|
|
310
|
+
for (let dir = resolve(from);; dir = dirname(dir)) {
|
|
311
|
+
const found = wanted.map((name) => join(dir, name)).find((path) => existsSync(path));
|
|
312
|
+
if (found !== undefined)
|
|
313
|
+
return found;
|
|
314
|
+
if (stop(dir) || dirname(dir) === dir)
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ../kit/src/user-config.ts
|
|
320
|
+
import { homedir } from "os";
|
|
321
|
+
import { join as join2 } from "path";
|
|
322
|
+
import process4 from "process";
|
|
323
|
+
function configBase(where = {}) {
|
|
324
|
+
const xdg = where.xdg ?? (where.home === undefined ? process4.env.XDG_CONFIG_HOME : undefined);
|
|
325
|
+
return xdg !== undefined && xdg !== "" ? xdg : join2(where.home ?? homedir(), ".config");
|
|
326
|
+
}
|
|
327
|
+
function userConfigPath(bin, where = {}) {
|
|
328
|
+
return join2(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ../kit/src/theme.ts
|
|
332
|
+
var DEFAULT = {
|
|
333
|
+
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" },
|
|
334
|
+
glyphs: { ok: "\u2713", warn: "\u25B2", problem: "\u2717", note: "\u203A", passed: "\u2713", failed: "\u2717", running: "\u25CF", queued: "\u25CB", skipped: "-", bar: "\u2501" },
|
|
335
|
+
accents: ["cyan", "magenta", "green", "blue", "yellow", "redBright"],
|
|
336
|
+
bins: {}
|
|
337
|
+
};
|
|
338
|
+
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" };
|
|
339
|
+
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" };
|
|
340
|
+
var ASCII = { ok: "+", warn: "!", problem: "x", note: ">", passed: "+", failed: "x", running: "*", queued: "o", skipped: "-", bar: "#" };
|
|
341
|
+
var PRESETS = {
|
|
342
|
+
default: {},
|
|
343
|
+
"high-contrast": { colors: BRIGHT, accents: ["cyanBright", "magentaBright", "greenBright", "blueBright", "yellowBright", "redBright"] },
|
|
344
|
+
mono: { colors: MONO, accents: ["bold"] },
|
|
345
|
+
ascii: { glyphs: ASCII }
|
|
346
|
+
};
|
|
347
|
+
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"]);
|
|
348
|
+
var HEX = /^#[0-9a-f]{6}$/i;
|
|
349
|
+
var CONTROL = /\p{Cc}/u;
|
|
350
|
+
var MAX_FILE_BYTES = 64 * 1024;
|
|
351
|
+
var SPACES = /\s+/;
|
|
352
|
+
function isColorSpec(spec) {
|
|
353
|
+
if (typeof spec === "number")
|
|
354
|
+
return Number.isInteger(spec) && spec >= 0 && spec <= 255;
|
|
355
|
+
return typeof spec === "string" && spec.trim() !== "" && spec.trim().split(SPACES).every((token) => STYLES.has(token) || HEX.test(token));
|
|
356
|
+
}
|
|
357
|
+
var CUBE = [0, 95, 135, 175, 215, 255];
|
|
358
|
+
function cubeLevel(channel) {
|
|
359
|
+
return CUBE.reduce((best, value, level) => Math.abs(value - channel) < Math.abs(CUBE[best] - channel) ? level : best, 0);
|
|
360
|
+
}
|
|
361
|
+
function nearest256(hex) {
|
|
362
|
+
const rgb = [1, 3, 5].map((at) => Number.parseInt(hex.slice(at, at + 2), 16));
|
|
363
|
+
const levels = rgb.map(cubeLevel);
|
|
364
|
+
const cube = levels.map((level) => CUBE[level]);
|
|
365
|
+
const grey = Math.min(23, Math.max(0, Math.round((rgb.reduce((sum, channel) => sum + channel, 0) / 3 - 8) / 10)));
|
|
366
|
+
const greyValue = 8 + grey * 10;
|
|
367
|
+
const distance = (colour) => colour.reduce((sum, channel, at) => sum + (channel - rgb[at]) ** 2, 0);
|
|
368
|
+
return distance([greyValue, greyValue, greyValue]) < distance(cube) ? 232 + grey : 16 + 36 * levels[0] + 6 * levels[1] + levels[2];
|
|
369
|
+
}
|
|
370
|
+
function hasTrueColor(env) {
|
|
371
|
+
return env.COLORTERM === "truecolor" || env.COLORTERM === "24bit";
|
|
372
|
+
}
|
|
373
|
+
function tinted(colors, spec, env = process5.env) {
|
|
374
|
+
if (typeof spec === "number")
|
|
375
|
+
return colors.ansi256(spec);
|
|
376
|
+
return spec.trim().split(SPACES).reduce((chain, token) => {
|
|
377
|
+
if (HEX.test(token))
|
|
378
|
+
return hasTrueColor(env) ? chain.hex(token) : chain.ansi256(nearest256(token));
|
|
379
|
+
return chain[token] ?? chain;
|
|
380
|
+
}, colors);
|
|
381
|
+
}
|
|
382
|
+
function isRecord(value) {
|
|
383
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
384
|
+
}
|
|
385
|
+
function readThemeFile(path, warn) {
|
|
386
|
+
try {
|
|
387
|
+
const stat = statSync(path, { throwIfNoEntry: false });
|
|
388
|
+
if (stat === undefined)
|
|
389
|
+
return;
|
|
390
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES) {
|
|
391
|
+
warn(`${path} is not a regular file under ${MAX_FILE_BYTES / 1024} KiB, theme ignored`);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
395
|
+
if (isRecord(parsed))
|
|
396
|
+
return parsed;
|
|
397
|
+
warn(`${path} is not a JSON object, theme ignored`);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
warn(`${path} does not parse (${error instanceof Error ? error.message : String(error)}), theme ignored`);
|
|
400
|
+
}
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
function applyPreset(theme, name, warn, where) {
|
|
404
|
+
if (name === undefined)
|
|
405
|
+
return;
|
|
406
|
+
if (typeof name !== "string" || !Object.hasOwn(PRESETS, name)) {
|
|
407
|
+
warn(`${where}: no preset ${String(name)}, one of ${Object.keys(PRESETS).join(", ")}`);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const preset = PRESETS[name];
|
|
411
|
+
Object.assign(theme.colors, preset.colors);
|
|
412
|
+
Object.assign(theme.glyphs, preset.glyphs);
|
|
413
|
+
if (preset.accents !== undefined)
|
|
414
|
+
theme.accents = [...preset.accents];
|
|
415
|
+
return name;
|
|
416
|
+
}
|
|
417
|
+
function applyFile(theme, file, where, warn) {
|
|
418
|
+
if (isRecord(file.colors)) {
|
|
419
|
+
for (const [key, value] of Object.entries(file.colors)) {
|
|
420
|
+
if (!Object.hasOwn(DEFAULT.colors, key))
|
|
421
|
+
warn(`${where}: no colour ${key}, one of ${Object.keys(DEFAULT.colors).join(", ")}`);
|
|
422
|
+
else if (!isColorSpec(value))
|
|
423
|
+
warn(`${where}: colour ${key} is not an ANSI name, \`#rrggbb\` or a number up to 255`);
|
|
424
|
+
else
|
|
425
|
+
theme.colors[key] = value;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (isRecord(file.glyphs)) {
|
|
429
|
+
for (const [key, value] of Object.entries(file.glyphs)) {
|
|
430
|
+
if (!Object.hasOwn(DEFAULT.glyphs, key))
|
|
431
|
+
warn(`${where}: no glyph ${key}, one of ${Object.keys(DEFAULT.glyphs).join(", ")}`);
|
|
432
|
+
else if (typeof value !== "string" || CONTROL.test(value) || Bun.stringWidth(value) !== 1)
|
|
433
|
+
warn(`${where}: glyph ${key} must be one visible character wide, with no control character`);
|
|
434
|
+
else
|
|
435
|
+
theme.glyphs[key] = value;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (Array.isArray(file.accents) && file.accents.length > 0 && file.accents.every(isColorSpec))
|
|
439
|
+
theme.accents = [...file.accents];
|
|
440
|
+
else if (file.accents !== undefined)
|
|
441
|
+
warn(`${where}: accents must be a non-empty list of colours`);
|
|
442
|
+
if (isRecord(file.bins)) {
|
|
443
|
+
for (const [bin, value] of Object.entries(file.bins)) {
|
|
444
|
+
if (isColorSpec(value))
|
|
445
|
+
theme.bins[bin] = value;
|
|
446
|
+
else
|
|
447
|
+
warn(`${where}: bin ${bin} has no valid colour`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function endsWalk(home) {
|
|
452
|
+
return (dir) => dir === resolve2(home) || existsSync2(join3(dir, ".git"));
|
|
453
|
+
}
|
|
454
|
+
var warned = new Set;
|
|
455
|
+
function warnOnce(message) {
|
|
456
|
+
if (warned.has(message))
|
|
457
|
+
return;
|
|
458
|
+
warned.add(message);
|
|
459
|
+
console.error(`warning: theme ${message}`);
|
|
460
|
+
}
|
|
461
|
+
function isPath(chosen) {
|
|
462
|
+
return chosen.includes("/") || chosen.endsWith(".json");
|
|
463
|
+
}
|
|
464
|
+
function loadTheme({ env = process5.env, from = process5.cwd(), home = homedir2(), warn = warnOnce } = {}) {
|
|
465
|
+
const theme = { colors: { ...DEFAULT.colors }, glyphs: { ...DEFAULT.glyphs }, accents: [...DEFAULT.accents], bins: Object.create(null) };
|
|
466
|
+
const sources = [];
|
|
467
|
+
const chosen = env.KIT_THEME ?? "";
|
|
468
|
+
const wanted = chosen === "" ? [userConfigPath("theme", { home, xdg: env.XDG_CONFIG_HOME }), findUp(join3(".kaynooo", "theme.json"), from, endsWalk(home))] : [];
|
|
469
|
+
if (isPath(chosen))
|
|
470
|
+
wanted.push(resolve2(from, chosen));
|
|
471
|
+
const files = [];
|
|
472
|
+
for (const path of wanted) {
|
|
473
|
+
const file = path === undefined ? undefined : readThemeFile(path, warn);
|
|
474
|
+
if (path !== undefined && file !== undefined)
|
|
475
|
+
files.push({ path, file });
|
|
476
|
+
}
|
|
477
|
+
let preset = "default";
|
|
478
|
+
if (chosen !== "" && !isPath(chosen)) {
|
|
479
|
+
preset = applyPreset(theme, chosen, warn, "KIT_THEME") ?? preset;
|
|
480
|
+
} else {
|
|
481
|
+
const named = files.findLast(({ file }) => file.preset !== undefined);
|
|
482
|
+
if (named !== undefined)
|
|
483
|
+
preset = applyPreset(theme, named.file.preset, warn, named.path) ?? preset;
|
|
484
|
+
}
|
|
485
|
+
for (const { path, file } of files) {
|
|
486
|
+
applyFile(theme, file, path, warn);
|
|
487
|
+
sources.push(path);
|
|
488
|
+
}
|
|
489
|
+
return { theme, sources, preset };
|
|
490
|
+
}
|
|
491
|
+
var current;
|
|
492
|
+
var currentKey = "";
|
|
493
|
+
function activeTheme() {
|
|
494
|
+
const key = `${process5.cwd()}\x00${process5.env.KIT_THEME ?? ""}\x00${process5.env.XDG_CONFIG_HOME ?? ""}`;
|
|
495
|
+
if (current === undefined || key !== currentKey) {
|
|
496
|
+
current = loadTheme();
|
|
497
|
+
currentKey = key;
|
|
498
|
+
}
|
|
499
|
+
return current;
|
|
500
|
+
}
|
|
501
|
+
|
|
274
502
|
// ../kit/src/style.ts
|
|
275
|
-
function takesControlCodes(stream, env =
|
|
276
|
-
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
503
|
+
function takesControlCodes(stream, env = process6.env) {
|
|
504
|
+
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb" && outputMode(stream, env) === "terminal";
|
|
277
505
|
}
|
|
278
|
-
function paint(stream, env =
|
|
506
|
+
function paint(stream, env = process6.env) {
|
|
279
507
|
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
280
508
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
509
|
+
function role(name, stream, env = process6.env) {
|
|
510
|
+
const colors = paint(stream, env);
|
|
511
|
+
return takesControlCodes(stream, env) ? tinted(colors, activeTheme().theme.colors[name], env) : colors;
|
|
512
|
+
}
|
|
513
|
+
var STATUS_WORDS = {
|
|
514
|
+
passed: ["passed", "success", "succeeded", "ok"],
|
|
515
|
+
failed: ["failed", "failure", "error", "errored"],
|
|
516
|
+
running: ["running", "in_progress", "started", "holding"],
|
|
517
|
+
queued: ["queued", "waiting", "pending", "created", "blocked", "scheduled"],
|
|
518
|
+
skipped: ["skipped", "cancelled", "canceled", "manual"]
|
|
287
519
|
};
|
|
288
|
-
var STATUS_OF = new Map(Object.entries(
|
|
520
|
+
var STATUS_OF = new Map(Object.entries(STATUS_WORDS).flatMap(([status, words]) => words.map((word) => [word, status])));
|
|
289
521
|
|
|
290
522
|
// ../kit/src/format.ts
|
|
291
523
|
function upTo(text, separator) {
|
|
@@ -293,32 +525,35 @@ function upTo(text, separator) {
|
|
|
293
525
|
return end === -1 ? text : text.slice(0, end);
|
|
294
526
|
}
|
|
295
527
|
var ESCAPE = String.fromCharCode(27);
|
|
528
|
+
function jsonText(value, replacer, { stream = process7.stdout, env = process7.env } = {}) {
|
|
529
|
+
return JSON.stringify(value, replacer, outputMode(stream, env) === "agent" ? undefined : 2);
|
|
530
|
+
}
|
|
296
531
|
function printJson(value) {
|
|
297
|
-
console.log(
|
|
532
|
+
console.log(jsonText(value));
|
|
298
533
|
}
|
|
299
534
|
|
|
300
535
|
// ../kit/src/help.ts
|
|
301
|
-
import
|
|
536
|
+
import process8 from "process";
|
|
302
537
|
var OPTIONAL = /\[[^\]]+\]/g;
|
|
303
538
|
var USAGE_PREFIX = /^usage:\s*/i;
|
|
304
539
|
var FULL_STOP = /\.$/;
|
|
305
|
-
function usageLine(usage, colors = paint(
|
|
540
|
+
function usageLine(usage, colors = paint(process8.stdout)) {
|
|
306
541
|
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
307
542
|
}
|
|
308
|
-
function helpText(usage, options, colors = paint(
|
|
543
|
+
function helpText(usage, options, colors = paint(process8.stdout), { examples = [], replaces, exits = [] } = {}) {
|
|
309
544
|
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
|
|
310
545
|
`);
|
|
311
546
|
}
|
|
312
|
-
function exitRows(exits, colors = paint(
|
|
547
|
+
function exitRows(exits, colors = paint(process8.stdout)) {
|
|
313
548
|
if (exits.length === 0)
|
|
314
549
|
return [];
|
|
315
550
|
const width = Math.max(...exits.map(([code]) => String(code).length));
|
|
316
551
|
return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
|
|
317
552
|
}
|
|
318
|
-
function replacesRows(replaces, colors = paint(
|
|
319
|
-
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
553
|
+
function replacesRows(replaces, colors = paint(process8.stdout)) {
|
|
554
|
+
return replaces === undefined || outputMode() === "agent" ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
320
555
|
}
|
|
321
|
-
function wantsHelpJson(env =
|
|
556
|
+
function wantsHelpJson(env = process8.env) {
|
|
322
557
|
return env.KIT_HELP === "json";
|
|
323
558
|
}
|
|
324
559
|
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
@@ -337,12 +572,12 @@ function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
|
337
572
|
...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
|
|
338
573
|
};
|
|
339
574
|
}
|
|
340
|
-
function exampleRows(examples, colors = paint(
|
|
341
|
-
if (examples.length === 0)
|
|
575
|
+
function exampleRows(examples, colors = paint(process8.stdout)) {
|
|
576
|
+
if (examples.length === 0 || outputMode() === "agent")
|
|
342
577
|
return [];
|
|
343
578
|
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
344
579
|
}
|
|
345
|
-
function optionRows(options, colors = paint(
|
|
580
|
+
function optionRows(options, colors = paint(process8.stdout)) {
|
|
346
581
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
347
582
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
348
583
|
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
@@ -436,7 +671,7 @@ var OUTPUT_OPTIONS = {
|
|
|
436
671
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
437
672
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
438
673
|
};
|
|
439
|
-
function applyOutput(color, plain, env =
|
|
674
|
+
function applyOutput(color, plain, env = process9.env) {
|
|
440
675
|
const when = plain === true ? "never" : color ?? "auto";
|
|
441
676
|
if (when === "auto")
|
|
442
677
|
return;
|
|
@@ -611,15 +846,15 @@ var ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x
|
|
|
611
846
|
var RESET_STYLE = `${ESC}[0m`;
|
|
612
847
|
var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
613
848
|
// ../kit/src/cli.ts
|
|
614
|
-
import { readFileSync, realpathSync } from "fs";
|
|
615
|
-
import { dirname as
|
|
616
|
-
import
|
|
849
|
+
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
850
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
851
|
+
import process11 from "process";
|
|
617
852
|
|
|
618
853
|
// ../kit/src/usage.ts
|
|
619
854
|
import { appendFileSync, mkdirSync } from "fs";
|
|
620
|
-
import { homedir } from "os";
|
|
621
|
-
import { dirname, isAbsolute, join } from "path";
|
|
622
|
-
import
|
|
855
|
+
import { homedir as homedir3 } from "os";
|
|
856
|
+
import { dirname as dirname2, isAbsolute, join as join4 } from "path";
|
|
857
|
+
import process10 from "process";
|
|
623
858
|
|
|
624
859
|
// ../kit/src/logs.ts
|
|
625
860
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -633,14 +868,14 @@ var usageError;
|
|
|
633
868
|
function noteUsageError(message) {
|
|
634
869
|
usageError = message;
|
|
635
870
|
}
|
|
636
|
-
function stateHome(env =
|
|
871
|
+
function stateHome(env = process10.env) {
|
|
637
872
|
const dir = env.XDG_STATE_HOME;
|
|
638
|
-
return dir !== undefined && isAbsolute(dir) ? dir :
|
|
873
|
+
return dir !== undefined && isAbsolute(dir) ? dir : join4(homedir3(), ".local", "state");
|
|
639
874
|
}
|
|
640
|
-
function usagePath(env =
|
|
641
|
-
return
|
|
875
|
+
function usagePath(env = process10.env) {
|
|
876
|
+
return join4(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
642
877
|
}
|
|
643
|
-
function usageRecorded(env =
|
|
878
|
+
function usageRecorded(env = process10.env) {
|
|
644
879
|
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
645
880
|
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
646
881
|
}
|
|
@@ -654,12 +889,12 @@ function usageEntry(bin, command, argv, code, now = new Date) {
|
|
|
654
889
|
usageError = undefined;
|
|
655
890
|
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
656
891
|
}
|
|
657
|
-
function recordUsage(entry, env =
|
|
892
|
+
function recordUsage(entry, env = process10.env) {
|
|
658
893
|
if (!usageRecorded(env))
|
|
659
894
|
return;
|
|
660
895
|
try {
|
|
661
896
|
const path = usagePath(env);
|
|
662
|
-
mkdirSync(
|
|
897
|
+
mkdirSync(dirname2(path), { recursive: true, mode: 448 });
|
|
663
898
|
appendFileSync(path, `${JSON.stringify(entry)}
|
|
664
899
|
`, { mode: 384 });
|
|
665
900
|
} catch {}
|
|
@@ -672,8 +907,8 @@ var LEVEL_OPTIONS = {
|
|
|
672
907
|
};
|
|
673
908
|
var TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
|
|
674
909
|
function printError(prefix, message, hint, cause) {
|
|
675
|
-
const colors = paint(
|
|
676
|
-
const styled = takesControlCodes(
|
|
910
|
+
const colors = paint(process11.stderr);
|
|
911
|
+
const styled = takesControlCodes(process11.stderr);
|
|
677
912
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
678
913
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
679
914
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -692,7 +927,7 @@ function reportThrown(prefix, error, redact = (text) => text, json = false) {
|
|
|
692
927
|
const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
|
|
693
928
|
const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
|
|
694
929
|
const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
|
|
695
|
-
if (error instanceof
|
|
930
|
+
if (error instanceof Exit && error.code === 2)
|
|
696
931
|
noteUsageError(error.message);
|
|
697
932
|
const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
|
|
698
933
|
report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
|
|
@@ -756,17 +991,17 @@ async function printCandidates(found) {
|
|
|
756
991
|
return 0;
|
|
757
992
|
}
|
|
758
993
|
function packageVersion(entry = Bun.main) {
|
|
759
|
-
for (let dir =
|
|
994
|
+
for (let dir = dirname3(realpathSync(entry));; dir = dirname3(dir)) {
|
|
760
995
|
try {
|
|
761
|
-
const { version } = JSON.parse(
|
|
996
|
+
const { version } = JSON.parse(readFileSync2(join5(dir, "package.json"), "utf8"));
|
|
762
997
|
if (typeof version === "string")
|
|
763
998
|
return version;
|
|
764
999
|
} catch {}
|
|
765
|
-
if (
|
|
1000
|
+
if (dirname3(dir) === dir)
|
|
766
1001
|
return "0.0.0";
|
|
767
1002
|
}
|
|
768
1003
|
}
|
|
769
|
-
async function runMain({ name, version, run, redact, usage }, argv =
|
|
1004
|
+
async function runMain({ name, version, run, redact, usage }, argv = process11.argv.slice(2)) {
|
|
770
1005
|
if (argv[0] === COMPLETE)
|
|
771
1006
|
return printCandidates(leafCandidates(run, argv.slice(1)));
|
|
772
1007
|
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
@@ -809,15 +1044,15 @@ var {Glob } = globalThis.Bun;
|
|
|
809
1044
|
var SESSION_FILES = new Glob("*.json");
|
|
810
1045
|
var ACCOUNT_DIRS = new Glob("*/sessions");
|
|
811
1046
|
// src/dc.ts
|
|
812
|
-
import
|
|
1047
|
+
import process13 from "process";
|
|
813
1048
|
|
|
814
1049
|
// src/stack.ts
|
|
815
|
-
import { existsSync, readdirSync, readFileSync as
|
|
816
|
-
import { dirname as
|
|
1050
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
1051
|
+
import { dirname as dirname5, join as join7, relative, resolve as resolve3 } from "path";
|
|
817
1052
|
|
|
818
1053
|
// ../env/src/files.ts
|
|
819
1054
|
import { chmod, chown, readdir, realpath, rename, rm, stat, writeFile } from "fs/promises";
|
|
820
|
-
import { basename, dirname as
|
|
1055
|
+
import { basename, dirname as dirname4, join as join6 } from "path";
|
|
821
1056
|
|
|
822
1057
|
// ../env/src/dotenv.ts
|
|
823
1058
|
var ASSIGNMENT = /^\s*(?:export\s+)?([A-Z_][\w.-]*)\s*=(.*)$/i;
|
|
@@ -1088,7 +1323,7 @@ async function envFilesBelow(folder, depth = 0) {
|
|
|
1088
1323
|
return found;
|
|
1089
1324
|
}
|
|
1090
1325
|
for (const entry of children) {
|
|
1091
|
-
const path =
|
|
1326
|
+
const path = join6(folder, entry.name);
|
|
1092
1327
|
if (entry.isDirectory() && depth < KNOWN_DEPTH && !SKIPPED.has(entry.name))
|
|
1093
1328
|
found.push(...await envFilesBelow(path, depth + 1));
|
|
1094
1329
|
else if (ENV_FILE.test(entry.name) && await isFileEntry(entry, path))
|
|
@@ -1179,21 +1414,21 @@ function children(dir = ".") {
|
|
|
1179
1414
|
}
|
|
1180
1415
|
function up(dir) {
|
|
1181
1416
|
const dirs = [];
|
|
1182
|
-
for (let current = dir;; current =
|
|
1417
|
+
for (let current = dir;; current = join7(current, "..")) {
|
|
1183
1418
|
dirs.push(current);
|
|
1184
|
-
const absolute =
|
|
1185
|
-
if (
|
|
1419
|
+
const absolute = resolve3(current);
|
|
1420
|
+
if (existsSync3(join7(current, ".git")) || dirname5(absolute) === absolute)
|
|
1186
1421
|
return dirs;
|
|
1187
1422
|
}
|
|
1188
1423
|
}
|
|
1189
1424
|
function stackAt(dir) {
|
|
1190
|
-
return { dir, run: from(dir, ["docker", "compose"]), list: { argv: ["docker", "compose"], cwd:
|
|
1425
|
+
return { dir, run: from(dir, ["docker", "compose"]), list: { argv: ["docker", "compose"], cwd: resolve3(dir), env: process.env } };
|
|
1191
1426
|
}
|
|
1192
1427
|
function holdsStack(dir) {
|
|
1193
|
-
if (COMPOSE_FILES.some((name) =>
|
|
1428
|
+
if (COMPOSE_FILES.some((name) => existsSync3(join7(dir, name))))
|
|
1194
1429
|
return true;
|
|
1195
1430
|
try {
|
|
1196
|
-
return COMPOSE_FILE_VAR.test(
|
|
1431
|
+
return COMPOSE_FILE_VAR.test(readFileSync3(join7(dir, ".env"), "utf-8"));
|
|
1197
1432
|
} catch {
|
|
1198
1433
|
return false;
|
|
1199
1434
|
}
|
|
@@ -1222,7 +1457,7 @@ async function labels(project) {
|
|
|
1222
1457
|
const proc = Bun.spawn(["docker", "ps", "--all", ...filter, "--format", LABEL_FORMAT], { stdout: "pipe", stderr: "ignore" });
|
|
1223
1458
|
if (await proc.exited !== 0)
|
|
1224
1459
|
return [];
|
|
1225
|
-
return labelled(await new Response(proc.stdout).text()).filter((stack) => [...stack.files, ...stack.envFiles].every((file) =>
|
|
1460
|
+
return labelled(await new Response(proc.stdout).text()).filter((stack) => [...stack.files, ...stack.envFiles].every((file) => existsSync3(file)));
|
|
1226
1461
|
}
|
|
1227
1462
|
function labelledStack(dir, { project, files, envFiles, workdir }) {
|
|
1228
1463
|
const options = (paths) => ["-p", project, ...files.flatMap((file) => ["-f", paths(file)]), ...envFiles.flatMap((file) => ["--env-file", paths(file)])];
|
|
@@ -1237,7 +1472,7 @@ function stackOf(recorded) {
|
|
|
1237
1472
|
return labelledStack(relative(".", recorded.workdir) || ".", recorded);
|
|
1238
1473
|
}
|
|
1239
1474
|
async function recordedNearby() {
|
|
1240
|
-
const dirs = new Set([...up("."), ...children()].map((dir) =>
|
|
1475
|
+
const dirs = new Set([...up("."), ...children()].map((dir) => resolve3(dir)));
|
|
1241
1476
|
return (await labels()).filter((stack) => dirs.has(stack.workdir));
|
|
1242
1477
|
}
|
|
1243
1478
|
async function attempt(stack, args) {
|
|
@@ -1347,7 +1582,7 @@ async function target(args) {
|
|
|
1347
1582
|
}
|
|
1348
1583
|
async function choose(recorded) {
|
|
1349
1584
|
const picker = Bun.which("pick");
|
|
1350
|
-
if (picker === null || !
|
|
1585
|
+
if (picker === null || !isInteractive())
|
|
1351
1586
|
return;
|
|
1352
1587
|
const proc = Bun.spawn([picker, "--prompt", "dc> "], { stdin: new Blob([recorded.map((stack) => stack.project).join(`
|
|
1353
1588
|
`)]), stdout: "pipe", stderr: "inherit" });
|
|
@@ -1355,8 +1590,8 @@ async function choose(recorded) {
|
|
|
1355
1590
|
return recorded.find((stack) => stack.project === picked);
|
|
1356
1591
|
}
|
|
1357
1592
|
async function run(stack, args, announce) {
|
|
1358
|
-
if (announce &&
|
|
1359
|
-
console.error(paint(
|
|
1593
|
+
if (announce && process13.stderr.isTTY)
|
|
1594
|
+
console.error(paint(process13.stderr).dim([...stack.run, ...args].join(" ")));
|
|
1360
1595
|
return Bun.spawn([...stack.list.argv, ...args], { cwd: stack.list.cwd, env: stack.list.env, stdio: ["inherit", "inherit", "inherit"] }).exited;
|
|
1361
1596
|
}
|
|
1362
1597
|
async function dc(args) {
|
|
@@ -1386,4 +1621,4 @@ async function main(args) {
|
|
|
1386
1621
|
}
|
|
1387
1622
|
return dc(args);
|
|
1388
1623
|
}
|
|
1389
|
-
|
|
1624
|
+
process14.exitCode = await runMain({ name: "dc", run: main });
|