@kaynooo/cli-docker 0.0.0-stage → 0.2.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/dx-cli.js ADDED
@@ -0,0 +1,1123 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // src/dx-cli.ts
5
+ import process11 from "process";
6
+
7
+ // ../kit/src/args.ts
8
+ import process4 from "process";
9
+ import { parseArgs } from "util";
10
+
11
+ // ../kit/src/style.ts
12
+ import process2 from "process";
13
+
14
+ // ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
15
+ function x(s) {
16
+ let r = s.startsWith("#") ? s.slice(1).toLowerCase() : s.toLowerCase();
17
+ if (!/^[a-f0-9]+$/.test(r))
18
+ return [0, 0, 0];
19
+ let t = r.length, n = (c) => Number.parseInt(c, 16);
20
+ if (t === 3 || t === 4) {
21
+ let c = n(r[0] + r[0]), u = n(r[1] + r[1]), h = n(r[2] + r[2]), g = t === 4 ? n(r[3] + r[3]) : undefined;
22
+ return g !== undefined ? [c, u, h, g] : [c, u, h];
23
+ }
24
+ if (t !== 6 && t !== 8)
25
+ throw Error(`Invalid hex color length: ${t}`);
26
+ let a = n(r.slice(0, 2)), b = n(r.slice(2, 4)), o = n(r.slice(4, 6)), y = t === 8 ? n(r.slice(6, 8)) : undefined;
27
+ if ([a, b, o].some(Number.isNaN) || y !== undefined && Number.isNaN(y))
28
+ throw Error(`Invalid hex color value: ${s}`);
29
+ return y !== undefined ? [a, b, o, y] : [a, b, o];
30
+ }
31
+ function A(s) {
32
+ let [r, t, n, a] = s;
33
+ if (a)
34
+ return `#${(r << 24 | t << 16 | n << 8 | Math.round((a ?? 1) * 255)).toString(16).padStart(8, "0").toUpperCase()}`;
35
+ return `#${(r << 16 | t << 8 | n).toString(16).padStart(6, "0").toUpperCase()}`;
36
+ }
37
+ function R(s, r, t) {
38
+ s = (s % 360 + 360) % 360, t /= 100;
39
+ let n = r * Math.min(t, 1 - t) / 100, a = (b) => {
40
+ let o = (b + s / 30) % 12, y = t - n * Math.max(Math.min(o - 3, 9 - o, 1), -1);
41
+ return Math.round(255 * y);
42
+ };
43
+ return [a(0), a(8), a(4)];
44
+ }
45
+ function k(s) {
46
+ let [r, t, n] = s;
47
+ r /= 255, t /= 255, n /= 255;
48
+ let a = Math.max(r, t, n), b = Math.min(r, t, n), o = 0, y = 0, c = (a + b) / 2;
49
+ if (a !== b) {
50
+ let u = a - b;
51
+ if (y = c > 0 && c < 1 ? u / (1 - Math.abs(2 * c - 1)) : 0, a === r)
52
+ o = (t - n) / u + (t < n ? 6 : 0);
53
+ else if (a === t)
54
+ o = (n - r) / u + 2;
55
+ else
56
+ o = (r - t) / u + 4;
57
+ o /= 6;
58
+ }
59
+ return [Math.round(o * 360), Math.round(y * 100), Math.round(c * 100)];
60
+ }
61
+ function H(s, r, t) {
62
+ s = (s % 360 + 360) % 360, r /= 100, t /= 100;
63
+ let n = (a) => {
64
+ let b = (a + s / 60) % 6, o = t - t * r * Math.max(Math.min(b, 4 - b, 1), 0);
65
+ return Math.round(255 * o);
66
+ };
67
+ return [n(5), n(3), n(1)];
68
+ }
69
+ function f(s) {
70
+ let [r, t, n] = s;
71
+ r /= 255, t /= 255, n /= 255;
72
+ let a = Math.max(r, t, n), b = Math.min(r, t, n), o = a - b, y = 0, c = a === 0 ? 0 : o / a, u = a;
73
+ if (o !== 0) {
74
+ if (a === r)
75
+ y = (t - n) / o + (t < n ? 6 : 0);
76
+ else if (a === t)
77
+ y = (n - r) / o + 2;
78
+ else
79
+ y = (r - t) / o + 4;
80
+ y /= 6;
81
+ }
82
+ return [Math.round(y * 360), Math.round(c * 100), Math.round(u * 100)];
83
+ }
84
+ function O(s) {
85
+ let r = s[0] / 255, t = s[1] / 255, n = s[2] / 255, a = 1 - Math.max(r, t, n);
86
+ if (a === 1)
87
+ return [0, 0, 0, 100];
88
+ let b = (1 - r - a) / (1 - a), o = (1 - t - a) / (1 - a), y = (1 - n - a) / (1 - a);
89
+ return [Math.round(b * 100), Math.round(o * 100), Math.round(y * 100), Math.round(a * 100)];
90
+ }
91
+ function v(s, r, t, n) {
92
+ return s /= 100, r /= 100, t /= 100, n /= 100, [Math.round(255 * (1 - s) * (1 - n)), Math.round(255 * (1 - r) * (1 - n)), Math.round(255 * (1 - t) * (1 - n))];
93
+ }
94
+ var m = (s) => s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
95
+ var p = (s) => s <= 0.0031308 ? 12.92 * s : 1.055 * s ** 0.4166666666666667 - 0.055;
96
+ var i = (s, r) => Math.round(s * 10 ** r) / 10 ** r;
97
+ function T(s) {
98
+ let r = m(s[0] / 255), t = m(s[1] / 255), n = m(s[2] / 255), a = Math.cbrt(0.4122214708 * r + 0.5363325363 * t + 0.0514459929 * n), b = Math.cbrt(0.2119034982 * r + 0.6806995451 * t + 0.1073969566 * n), o = Math.cbrt(0.0883024619 * r + 0.2817188376 * t + 0.6299787005 * n);
99
+ return [i(0.2104542553 * a + 0.793617785 * b - 0.0040720468 * o, 4), i(1.9779984951 * a - 2.428592205 * b + 0.4505937099 * o, 4), i(0.0259040371 * a + 0.7827717662 * b - 0.808675766 * o, 4)];
100
+ }
101
+ function M(s, r, t) {
102
+ let n = (s + 0.3963377774 * r + 0.2158037573 * t) ** 3, a = (s - 0.1055613458 * r - 0.0638541728 * t) ** 3, b = (s - 0.0894841775 * r - 1.291485548 * t) ** 3, o = p(4.0767416621 * n - 3.3077115913 * a + 0.2309699292 * b), y = p(-1.2684380046 * n + 2.6097574011 * a - 0.3413193965 * b), c = p(-0.0041960863 * n - 0.7034186147 * a + 1.707614701 * b), u = (h) => Math.min(255, Math.max(0, Math.round(h * 255)));
103
+ return [u(o), u(y), u(c)];
104
+ }
105
+ function d(s) {
106
+ let [r, t, n] = T(s), a = Math.sqrt(t * t + n * n), b = (Math.atan2(n, t) * 180 / Math.PI + 360) % 360;
107
+ return [i(r, 4), i(a, 4), i(b, 2)];
108
+ }
109
+ function C(s, r, t) {
110
+ let n = t * Math.PI / 180;
111
+ return M(s, r * Math.cos(n), r * Math.sin(n));
112
+ }
113
+ function l(s) {
114
+ let r = s / 255;
115
+ return r <= 0.03928 ? r / 12.92 : ((r + 0.055) / 1.055) ** 2.4;
116
+ }
117
+
118
+ class e {
119
+ r;
120
+ g;
121
+ b;
122
+ a;
123
+ constructor(s, r, t, n = 1) {
124
+ this.r = s, this.g = r, this.b = t, this.a = n;
125
+ }
126
+ static from(s, r) {
127
+ if (s === "hex") {
128
+ let [t, n, a, b] = x(r);
129
+ return new e(t, n, a, b);
130
+ }
131
+ if (s === "rgb") {
132
+ if (Array.isArray(r)) {
133
+ let [o, y, c, u] = r;
134
+ return new e(o, y, c, u);
135
+ }
136
+ let { r: t, g: n, b: a, a: b } = r;
137
+ return new e(t, n, a, b);
138
+ }
139
+ if (s === "hsl") {
140
+ let t, n, a, b;
141
+ if (Array.isArray(r))
142
+ [t, n, a, b] = r;
143
+ else
144
+ ({ h: t, s: n, l: a, a: b } = r);
145
+ let [o, y, c] = R(t, n, a);
146
+ return new e(o, y, c, b);
147
+ }
148
+ if (s === "hsv") {
149
+ let t, n, a, b;
150
+ if (Array.isArray(r))
151
+ [t, n, a, b] = r;
152
+ else
153
+ ({ h: t, s: n, v: a, a: b } = r);
154
+ let [o, y, c] = H(t, n, a);
155
+ return new e(o, y, c, b);
156
+ }
157
+ if (s === "cmyk") {
158
+ let t, n, a, b, o;
159
+ if (Array.isArray(r))
160
+ [t, n, a, b, o] = r;
161
+ else
162
+ ({ c: t, m: n, y: a, k: b, a: o } = r);
163
+ let [y, c, u] = v(t, n, a, b);
164
+ return new e(y, c, u, o);
165
+ }
166
+ if (s === "oklch") {
167
+ let t, n, a, b;
168
+ if (Array.isArray(r))
169
+ [t, n, a, b] = r;
170
+ else
171
+ ({ l: t, c: n, h: a, a: b } = r);
172
+ let [o, y, c] = C(t, n, a);
173
+ return new e(o, y, c, b);
174
+ }
175
+ if (s === "oklab") {
176
+ let t, n, a, b;
177
+ if (Array.isArray(r))
178
+ [t, n, a, b] = r;
179
+ else
180
+ ({ l: t, a: n, b: a, alpha: b } = r);
181
+ let [o, y, c] = M(t, n, a);
182
+ return new e(o, y, c, b);
183
+ }
184
+ throw Error("Invalid input");
185
+ }
186
+ to(s) {
187
+ switch (s) {
188
+ case "rgb":
189
+ return [this.r, this.g, this.b];
190
+ case "rgba":
191
+ return [this.r, this.g, this.b, this.a];
192
+ case "hex":
193
+ return A([this.r, this.g, this.b]);
194
+ case "hexa":
195
+ return A([this.r, this.g, this.b, this.a]);
196
+ case "hsl":
197
+ return k([this.r, this.g, this.b]);
198
+ case "hsla":
199
+ return [...k([this.r, this.g, this.b]), this.a];
200
+ case "hsv":
201
+ return f([this.r, this.g, this.b]);
202
+ case "hsva":
203
+ return [...f([this.r, this.g, this.b]), this.a];
204
+ case "cmyk":
205
+ return O([this.r, this.g, this.b]);
206
+ case "cmyka":
207
+ return [...O([this.r, this.g, this.b]), this.a];
208
+ case "oklch":
209
+ return d([this.r, this.g, this.b]);
210
+ case "oklcha":
211
+ return [...d([this.r, this.g, this.b]), this.a];
212
+ case "oklab":
213
+ return T([this.r, this.g, this.b]);
214
+ case "oklaba":
215
+ return [...T([this.r, this.g, this.b]), this.a];
216
+ default:
217
+ return [this.r, this.g, this.b];
218
+ }
219
+ }
220
+ getLuminance() {
221
+ let s = l(this.r), r = l(this.g), t = l(this.b);
222
+ return 0.2126 * s + 0.7152 * r + 0.0722 * t;
223
+ }
224
+ contrastRatio(s) {
225
+ let r = this.getLuminance(), t = s.getLuminance(), [n, a] = r >= t ? [r, t] : [t, r];
226
+ return (n + 0.05) / (a + 0.05);
227
+ }
228
+ bestContrastForeground() {
229
+ let s = new e(255, 255, 255, 1), r = new e(0, 0, 0, 1), t = this.contrastRatio(s), n = this.contrastRatio(r);
230
+ return t >= n ? s : r;
231
+ }
232
+ }
233
+
234
+ // ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-y1msbssb.js
235
+ var r = 39;
236
+ var o = 49;
237
+ var f2 = "\x1B[";
238
+ var C2 = { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29], black: [30, r], red: [31, r], green: [32, r], yellow: [33, r], blue: [34, r], magenta: [35, r], cyan: [36, r], white: [37, r], gray: [90, r], grey: [90, r], blackBright: [90, r], redBright: [91, r], greenBright: [92, r], yellowBright: [93, r], blueBright: [94, r], magentaBright: [95, r], cyanBright: [96, r], whiteBright: [97, r], bgBlack: [40, o], bgRed: [41, o], bgGreen: [42, o], bgYellow: [43, o], bgBlue: [44, o], bgMagenta: [45, o], bgCyan: [46, o], bgWhite: [47, o], bgBlackBright: [100, o], bgRedBright: [101, o], bgGreenBright: [102, o], bgYellowBright: [103, o], bgBlueBright: [104, o], bgMagentaBright: [105, o], bgCyanBright: [106, o], bgWhiteBright: [107, o], rgb: (i, n, a, l = "fg") => [`${l === "fg" ? 38 : 48};2;${i};${n};${a}`, l === "fg" ? r : o], hex: (i, n = "fg") => {
239
+ let [a, l, s] = e.from("hex", i).to("rgb");
240
+ return [`${n === "fg" ? 38 : 48};2;${a};${l};${s}`, n === "fg" ? r : o];
241
+ }, ansi256: (i, n = "fg") => [`${n === "fg" ? 38 : 48};5;${i}`, n === "fg" ? r : o] };
242
+ var b = new Set(["", "1", "2", "3", "true"]);
243
+ function h(i, n = globalThis.process?.env ?? {}) {
244
+ if (n.FORCE_COLOR !== undefined)
245
+ return b.has(n.FORCE_COLOR);
246
+ if (n.NO_COLOR !== undefined || n.NODE_DISABLE_COLORS !== undefined || n.TERM === "dumb")
247
+ return false;
248
+ return i?.isTTY === true;
249
+ }
250
+ function d2(i, n, a) {
251
+ if (!h(a.stream ?? globalThis.process?.stdout, a.env))
252
+ return n;
253
+ let l = "", s = "";
254
+ for (let g = 0, y = i.length;g < y; g++) {
255
+ let [c, p] = i[g];
256
+ l += `${f2}${c}m`, s = `${f2}${p}m${s}`;
257
+ }
258
+ return l + n + s;
259
+ }
260
+ function u(i, n = []) {
261
+ return new Proxy((l) => d2(n, l, i), { get(l, s) {
262
+ let g = C2[s];
263
+ if (Array.isArray(g))
264
+ return u(i, [...n, g]);
265
+ if (typeof g === "function")
266
+ return (...y) => u(i, [...n, g(...y)]);
267
+ throw Error(`Unknown style: ${String(s)}`);
268
+ } });
269
+ }
270
+ function le(i = {}) {
271
+ return u(i);
272
+ }
273
+ var t = le();
274
+
275
+ // ../kit/src/style.ts
276
+ function takesControlCodes(stream, env = process2.env) {
277
+ return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
278
+ }
279
+ function paint(stream, env = process2.env) {
280
+ return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
281
+ }
282
+ var STATUSES = {
283
+ passed: { symbol: "\u2713", words: ["passed", "success", "succeeded", "ok"], paint: (colors) => colors.green },
284
+ failed: { symbol: "\u2717", words: ["failed", "failure", "error", "errored"], paint: (colors) => colors.red },
285
+ running: { symbol: "\u25CF", words: ["running", "in_progress", "started"], paint: (colors) => colors.cyan },
286
+ queued: { symbol: "\u25CB", words: ["queued", "waiting", "pending", "created", "blocked", "scheduled"], paint: (colors) => colors.yellow },
287
+ skipped: { symbol: "-", words: ["skipped", "cancelled", "canceled", "manual"], paint: (colors) => colors.dim }
288
+ };
289
+ var STATUS_OF = new Map(Object.entries(STATUSES).flatMap(([status, { words }]) => words.map((word) => [word, status])));
290
+
291
+ // ../kit/src/format.ts
292
+ function upTo(text, separator) {
293
+ const end = text.indexOf(separator);
294
+ return end === -1 ? text : text.slice(0, end);
295
+ }
296
+ var ESCAPE = String.fromCharCode(27);
297
+ function printJson(value) {
298
+ console.log(JSON.stringify(value, undefined, 2));
299
+ }
300
+
301
+ // ../kit/src/help.ts
302
+ import process3 from "process";
303
+ var OPTIONAL = /\[[^\]]+\]/g;
304
+ var USAGE_PREFIX = /^usage:\s*/i;
305
+ var FULL_STOP = /\.$/;
306
+ function usageLine(usage, colors = paint(process3.stdout)) {
307
+ return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
308
+ }
309
+ function helpText(usage, options, colors = paint(process3.stdout), { examples = [], replaces } = {}) {
310
+ return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exampleRows(examples, colors)].join(`
311
+ `);
312
+ }
313
+ function replacesRows(replaces, colors = paint(process3.stdout)) {
314
+ return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
315
+ }
316
+ function wantsHelpJson(env = process3.env) {
317
+ return env.KIT_HELP === "json";
318
+ }
319
+ function description(usage, { examples = [], replaces } = {}) {
320
+ const lines = usage.replace(USAGE_PREFIX, "").split(`
321
+ `);
322
+ const first = lines[0];
323
+ const colon = first.indexOf(": ");
324
+ const prose = lines[lines.indexOf("") + 1] ?? "";
325
+ const fallback = lines.includes("") ? `${prose.charAt(0).toLowerCase()}${prose.slice(1)}`.replace(FULL_STOP, "") : "";
326
+ return {
327
+ synopsis: colon === -1 ? first : first.slice(0, colon),
328
+ summary: colon === -1 ? fallback : first.slice(colon + 2),
329
+ ...replaces === undefined ? {} : { replaces },
330
+ examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] })
331
+ };
332
+ }
333
+ function exampleRows(examples, colors = paint(process3.stdout)) {
334
+ if (examples.length === 0)
335
+ return [];
336
+ return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
337
+ }
338
+ function optionRows(options, colors = paint(process3.stdout)) {
339
+ const rows = Object.entries(options).map(([name, option]) => {
340
+ const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
341
+ const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
342
+ const placeholder = option.optional === undefined ? named : `[${named}]`;
343
+ const value = option.type === "string" ? ` ${colors.dim(placeholder)}` : "";
344
+ return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? placeholder.length + 1 : 0), description: option.description ?? "" };
345
+ });
346
+ const width = Math.max(0, ...rows.map((row) => row.width));
347
+ return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
348
+ }
349
+
350
+ // ../kit/src/text.ts
351
+ var ANSI = new RegExp(`${String.fromCharCode(27)}\\[[\\d;?]*[a-z]`, "gi");
352
+ function distance(a, b) {
353
+ let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
354
+ for (const [i, left] of [...a].entries()) {
355
+ const current = [i + 1];
356
+ for (const [j, right] of [...b].entries())
357
+ current.push(Math.min((previous[j + 1] ?? 0) + 1, (current[j] ?? 0) + 1, (previous[j] ?? 0) + (left === right ? 0 : 1)));
358
+ previous = current;
359
+ }
360
+ return previous[b.length] ?? 0;
361
+ }
362
+ function closest(name, names) {
363
+ const started = names.find((known) => known.startsWith(name));
364
+ if (started !== undefined)
365
+ return started;
366
+ const [best] = names.map((known) => ({ known, far: distance(name, known) })).sort((a, b) => a.far - b.far);
367
+ return best !== undefined && best.far <= (name.length < 4 ? 1 : 2) ? best.known : undefined;
368
+ }
369
+
370
+ // ../kit/src/args.ts
371
+ var DASHES = /^-+/;
372
+ function jsonOption(holds) {
373
+ return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
374
+ }
375
+
376
+ class Exit extends Error {
377
+ code;
378
+ hint;
379
+ constructor(message, code, hint) {
380
+ super(message);
381
+ this.code = code;
382
+ this.hint = hint;
383
+ }
384
+ }
385
+ function fail(message, code = 2, hint) {
386
+ throw new Exit(message, code, hint);
387
+ }
388
+
389
+ class UsageError extends Exit {
390
+ constructor(message, hint) {
391
+ super(message, 2, hint);
392
+ }
393
+ }
394
+ function badUsage(message) {
395
+ throw new UsageError(message);
396
+ }
397
+
398
+ class HelpShown extends Exit {
399
+ constructor() {
400
+ super("help shown", 0);
401
+ }
402
+ }
403
+
404
+ class Completing {
405
+ options;
406
+ positionals;
407
+ candidates;
408
+ constructor(options, positionals = [], candidates = {}) {
409
+ this.options = options;
410
+ this.positionals = positionals;
411
+ this.candidates = candidates;
412
+ }
413
+ }
414
+ var completion = { active: false };
415
+ var OUTPUT_OPTIONS = {
416
+ color: { type: "string", description: "auto (on a terminal alone), always or never" },
417
+ plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
418
+ };
419
+ function applyOutput(color, plain, env = process4.env) {
420
+ const when = plain === true ? "never" : color ?? "auto";
421
+ if (when === "auto")
422
+ return;
423
+ if (when !== "always" && when !== "never")
424
+ badUsage(`--color takes auto, always or never, not ${when}`);
425
+ if (when === "always") {
426
+ env.FORCE_COLOR = "1";
427
+ delete env.NO_COLOR;
428
+ } else {
429
+ env.NO_COLOR = "1";
430
+ delete env.FORCE_COLOR;
431
+ }
432
+ }
433
+ function parse(args, usage, options, settings = {}) {
434
+ const output = Object.fromEntries(Object.entries(OUTPUT_OPTIONS).filter(([name]) => !(name in options)));
435
+ const all = { ...options, ...output, help: { type: "boolean", short: "h", description: "show this help" } };
436
+ const listing = listed(all, settings.allowNegative === true);
437
+ if (completion.active)
438
+ throw new Completing(listing, settings.positionals, settings.candidates);
439
+ const { own, rest } = settings.trailing === true ? splitTrailing(args, all, settings.positionals?.length ?? 0) : splitRest(args, settings.rest === true);
440
+ let parsed;
441
+ try {
442
+ parsed = parseArgs({ args: joinDashValues(withBare(own, all), all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
443
+ } catch (error) {
444
+ const message = parseError(error);
445
+ throw new UsageError(message, nearestOption(message, all, settings.allowNegative === true));
446
+ }
447
+ const values = parsed.values;
448
+ applyOutput("color" in output ? values.color : undefined, "plain" in output ? values.plain : undefined);
449
+ if (values.help === true) {
450
+ console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings)) : helpText(usage, listing, undefined, settings));
451
+ throw new HelpShown;
452
+ }
453
+ checkChoices(parsed.values, all);
454
+ checkConflicts(parsed.values, all);
455
+ if (settings.positionals !== undefined)
456
+ checkPositionals(parsed.positionals, settings.positionals);
457
+ return { ...parsed, values: parsed.values, positionals: parsed.positionals, rest };
458
+ }
459
+ function splitRest(args, passes) {
460
+ const separator = passes ? args.indexOf("--") : -1;
461
+ return { own: separator === -1 ? args : args.slice(0, separator), rest: separator === -1 ? undefined : args.slice(separator + 1) };
462
+ }
463
+ function splitTrailing(args, options, count) {
464
+ const takesValue = (word) => !word.includes("=") && Object.entries(options).some(([name, { short, type }]) => type === "string" && (word === `--${name}` || word === `-${short}`));
465
+ let seen = 0;
466
+ if (count === 0)
467
+ return { own: args, rest: undefined };
468
+ for (let at = 0;at < args.length; at++) {
469
+ const word = args[at];
470
+ if (word === "--")
471
+ break;
472
+ if (word.startsWith("-")) {
473
+ if (takesValue(word))
474
+ at++;
475
+ continue;
476
+ }
477
+ seen++;
478
+ if (seen === count)
479
+ return { own: args.slice(0, at + 1), rest: args.slice(at + 1) };
480
+ }
481
+ return { own: args, rest: undefined };
482
+ }
483
+ function listed(options, allowNegative) {
484
+ if (!allowNegative)
485
+ return options;
486
+ return Object.fromEntries(Object.entries(options).flatMap(([name, option]) => {
487
+ if (option.type !== "boolean" || option.negative === undefined)
488
+ return [[name, option]];
489
+ return [...option.description === undefined ? [] : [[name, option]], [`no-${name}`, { type: "boolean", description: option.negative }]];
490
+ }));
491
+ }
492
+ function withBare(args, options) {
493
+ const bare = new Map(Object.entries(options).flatMap(([name, { short, optional }]) => optional === undefined ? [] : [[`--${name}`, optional], ...short === undefined ? [] : [[`-${short}`, optional]]]));
494
+ if (bare.size === 0)
495
+ return args;
496
+ const separator = args.indexOf("--");
497
+ const own = separator === -1 ? args : args.slice(0, separator);
498
+ return [...own.flatMap((arg, index) => {
499
+ const optional = bare.get(arg);
500
+ const next = own[index + 1];
501
+ const value = next !== undefined && (optional?.accepts === undefined ? !next.startsWith("-") : optional.accepts.test(next));
502
+ return optional === undefined || value ? [arg] : [arg, optional.bare];
503
+ }), ...separator === -1 ? [] : args.slice(separator)];
504
+ }
505
+ function checkConflicts(values, options) {
506
+ const given = (name) => values[name] !== undefined && values[name] !== false;
507
+ for (const [name, { conflicts = [] }] of Object.entries(options)) {
508
+ const other = given(name) ? conflicts.find(given) : undefined;
509
+ if (other !== undefined)
510
+ badUsage(`--${name} cannot be used with --${other}`);
511
+ }
512
+ }
513
+ function checkChoices(values, options) {
514
+ for (const [name, option] of Object.entries(options)) {
515
+ if (option.choices === undefined)
516
+ continue;
517
+ const given = values[name];
518
+ for (const value of Array.isArray(given) ? given : [given]) {
519
+ if (typeof value === "string")
520
+ oneOf(value, name, option.choices);
521
+ }
522
+ }
523
+ }
524
+ function oneOf(value, name, choices) {
525
+ if (!choices.includes(value))
526
+ badUsage(`${name.startsWith("<") ? name : `--${name}`} takes one of ${choices.join(", ")}, not ${value}`);
527
+ return value;
528
+ }
529
+ function checkPositionals(given, names) {
530
+ const variadic = names.at(-1)?.replace("]", "").endsWith("...") === true;
531
+ const required = names.filter((name) => !name.startsWith("[")).length;
532
+ if (given.length < required)
533
+ badUsage(`missing ${names[given.length]}`);
534
+ if (!variadic && given.length > names.length)
535
+ badUsage(`unexpected argument ${given[names.length]}`);
536
+ }
537
+ function joinDashValues(args, options) {
538
+ const longOf = new Map(Object.entries(options).flatMap(([name, option]) => option.short === undefined ? [[`--${name}`, name]] : [[`--${name}`, name], [`-${option.short}`, name]]));
539
+ const isOption = (arg) => arg === "--" || longOf.has(arg.includes("=") ? arg.slice(0, arg.indexOf("=")) : arg);
540
+ const joined = [];
541
+ for (let i = 0;i < args.length; i++) {
542
+ const arg = args[i] ?? "";
543
+ if (arg === "--")
544
+ return [...joined, ...args.slice(i)];
545
+ const name = longOf.get(arg);
546
+ const next = args[i + 1];
547
+ if (name !== undefined && options[name]?.type === "string" && next !== undefined && next.startsWith("-") && next !== "-" && !isOption(next)) {
548
+ joined.push(`--${name}=${next}`);
549
+ i++;
550
+ } else {
551
+ joined.push(arg);
552
+ }
553
+ }
554
+ return joined;
555
+ }
556
+ function parseError(error) {
557
+ const message = upTo(error instanceof Error ? error.message : String(error), ". ");
558
+ return `${message.charAt(0).toLowerCase()}${message.slice(1)}`;
559
+ }
560
+ var UNKNOWN_OPTION = /^unknown option '(-[^']+)'/;
561
+ function nearestOption(message, options, allowNegative) {
562
+ const typed = UNKNOWN_OPTION.exec(message)?.[1];
563
+ if (typed === undefined)
564
+ return;
565
+ const word = typed.replace(DASHES, "");
566
+ if (word.length < 2 && !typed.startsWith("--"))
567
+ return;
568
+ const known = Object.entries(options).flatMap(([name, option]) => [
569
+ ...option.short === undefined ? [] : [`-${option.short}`],
570
+ `--${name}`,
571
+ ...allowNegative && option.type === "boolean" ? [`--no-${name}`] : []
572
+ ]);
573
+ const meant = closest(word, known.map((flag) => flag.replace(DASHES, "")));
574
+ return meant === undefined ? undefined : `did you mean ${known.find((flag) => flag.replace(DASHES, "") === meant)}?`;
575
+ }
576
+ // ../kit/src/progress.ts
577
+ var ESC = String.fromCharCode(27);
578
+ var ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x7E]|\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\))`, "y");
579
+ var RESET_STYLE = `${ESC}[0m`;
580
+ var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
581
+ // ../kit/src/cli.ts
582
+ import process6 from "process";
583
+
584
+ // ../kit/src/usage.ts
585
+ import { appendFileSync, mkdirSync } from "fs";
586
+ import { homedir } from "os";
587
+ import { dirname, isAbsolute, join } from "path";
588
+ import process5 from "process";
589
+
590
+ // ../kit/src/logs.ts
591
+ var DAY_MS = 24 * 60 * 60 * 1000;
592
+ var CLI_FOLDER = "kaynooo-cli";
593
+
594
+ // ../kit/src/usage.ts
595
+ var UNKNOWN_OPTION2 = /unknown option '(--[a-z][a-z0-9-]*)[=']/;
596
+ var FLAG_NAME = /^(?:--[a-z][a-z0-9-]*|-[a-zA-Z])$/;
597
+ var LONGEST_NAME = 40;
598
+ var usageError;
599
+ function noteUsageError(message) {
600
+ usageError = message;
601
+ }
602
+ function stateHome(env = process5.env) {
603
+ const dir = env.XDG_STATE_HOME;
604
+ return dir !== undefined && isAbsolute(dir) ? dir : join(homedir(), ".local", "state");
605
+ }
606
+ function usagePath(env = process5.env) {
607
+ return join(stateHome(env), CLI_FOLDER, "usage.jsonl");
608
+ }
609
+ function usageRecorded(env = process5.env) {
610
+ const off = env.KAYNOOO_CLI_NO_USAGE;
611
+ return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
612
+ }
613
+ function flagNames(argv) {
614
+ const end = argv.indexOf("--");
615
+ const names = (end === -1 ? argv : argv.slice(0, end)).filter((word) => word.startsWith("-") && word !== "-").map((word) => word.includes("=") ? word.slice(0, word.indexOf("=")) : word);
616
+ return [...new Set(names)].filter((name) => name.length <= LONGEST_NAME && FLAG_NAME.test(name));
617
+ }
618
+ function usageEntry(bin, command, argv, code, now = new Date) {
619
+ const unknown = code === 2 && usageError !== undefined ? UNKNOWN_OPTION2.exec(usageError)?.[1] : undefined;
620
+ usageError = undefined;
621
+ return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
622
+ }
623
+ function recordUsage(entry, env = process5.env) {
624
+ if (!usageRecorded(env))
625
+ return;
626
+ try {
627
+ const path = usagePath(env);
628
+ mkdirSync(dirname(path), { recursive: true, mode: 448 });
629
+ appendFileSync(path, `${JSON.stringify(entry)}
630
+ `, { mode: 384 });
631
+ } catch {}
632
+ }
633
+
634
+ // ../kit/src/cli.ts
635
+ var LEVEL_OPTIONS = {
636
+ ...OUTPUT_OPTIONS,
637
+ help: { type: "boolean", short: "h", description: "show this help" }
638
+ };
639
+ var TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
640
+ function printError(prefix, message, hint, cause) {
641
+ const colors = paint(process6.stderr);
642
+ const styled = takesControlCodes(process6.stderr);
643
+ const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
644
+ const under = (label, text, tint) => text === undefined ? "" : `
645
+ ${styled ? tint(label) : `${label}:`} ${text}`;
646
+ console.error(`${head} ${message}${under("cause", cause, colors.dim)}${under("hint", hint, colors.yellow)}`);
647
+ }
648
+ function printJsonError(message, hint, cause) {
649
+ console.error(JSON.stringify({ error: message, ...hint === undefined ? {} : { hint }, ...cause === undefined ? {} : { cause } }));
650
+ }
651
+ function wantsJson(argv) {
652
+ const end = argv.indexOf("--");
653
+ return (end === -1 ? argv : argv.slice(0, end)).includes("--json");
654
+ }
655
+ function reportThrown(prefix, error, redact = (text) => text, json = false) {
656
+ if (error instanceof HelpShown)
657
+ return 0;
658
+ const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
659
+ const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
660
+ const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
661
+ if (error instanceof UsageError)
662
+ noteUsageError(error.message);
663
+ const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
664
+ report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
665
+ return error instanceof Exit ? error.code : 1;
666
+ }
667
+ var COMPLETE = "__complete";
668
+ var FILES = "__files__";
669
+ async function completingOf(run) {
670
+ completion.active = true;
671
+ try {
672
+ await run([]);
673
+ } catch (error) {
674
+ if (error instanceof Completing)
675
+ return error;
676
+ } finally {
677
+ completion.active = false;
678
+ }
679
+ return new Completing({});
680
+ }
681
+ function candidateLine(candidate) {
682
+ return typeof candidate === "string" ? candidate : candidate.join("\t");
683
+ }
684
+ function positionalBeingTyped(before, { options, positionals }) {
685
+ const takesValue = (word) => !word.includes("=") && Object.entries(options).some(([name, { short, type }]) => type === "string" && (word === `--${name}` || word === `-${short}`));
686
+ let index = 0;
687
+ let at = 0;
688
+ while (at < before.length) {
689
+ const word = before[at];
690
+ if (word === "--") {
691
+ index += before.length - at - 1;
692
+ break;
693
+ }
694
+ if (!word.startsWith("-"))
695
+ index++;
696
+ else if (takesValue(word))
697
+ at++;
698
+ at++;
699
+ }
700
+ const last = positionals.at(-1);
701
+ if (index < positionals.length)
702
+ return positionals[index];
703
+ return last?.replace("]", "").endsWith("...") === true ? last : undefined;
704
+ }
705
+ async function leafCandidates(run, words) {
706
+ const completing = await completingOf(run);
707
+ if ((words.at(-1) ?? "").startsWith("-"))
708
+ return Object.entries(completing.options).map(([name, option]) => option.description === undefined ? `--${name}` : `--${name} ${option.description}`);
709
+ const flag = words.at(-2);
710
+ const option = flag?.startsWith("-") === true ? Object.entries(completing.options).find(([name, { short }]) => flag === `--${name}` || flag === `-${short}`)?.[1] : undefined;
711
+ if (option?.type === "string") {
712
+ const values = option.choices === undefined ? await option.candidates?.() : option.choices;
713
+ return values === undefined ? [FILES] : values.map(candidateLine);
714
+ }
715
+ const name = positionalBeingTyped(words.slice(0, -1), completing);
716
+ const values = name === undefined ? undefined : await completing.candidates[name]?.();
717
+ return values === undefined ? [FILES] : values.map(candidateLine);
718
+ }
719
+ async function printCandidates(found) {
720
+ for (const line of await found)
721
+ console.log(line);
722
+ return 0;
723
+ }
724
+ async function runMain({ name, version, run, redact, usage }, argv = process6.argv.slice(2)) {
725
+ if (argv[0] === COMPLETE)
726
+ return printCandidates(leafCandidates(run, argv.slice(1)));
727
+ if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
728
+ console.log(version);
729
+ return 0;
730
+ }
731
+ let code;
732
+ try {
733
+ code = await run(argv);
734
+ } catch (error) {
735
+ code = reportThrown(name, error, redact, wantsJson(argv));
736
+ }
737
+ if (usage !== false)
738
+ recordUsage(usageEntry(name, undefined, argv, code));
739
+ return code;
740
+ }
741
+ // ../kit/src/secrets.ts
742
+ var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
743
+ // ../kit/src/sessions.ts
744
+ var {Glob } = globalThis.Bun;
745
+ var SESSION_FILES = new Glob("*.json");
746
+ var ACCOUNT_DIRS = new Glob("*/sessions");
747
+ // package.json
748
+ var version = "0.2.0";
749
+
750
+ // src/dx.ts
751
+ import process10 from "process";
752
+
753
+ // src/history.ts
754
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
755
+ import { homedir as homedir2 } from "os";
756
+ import { dirname as dirname2, join as join2 } from "path";
757
+ import process8 from "process";
758
+ var REMEMBERED = 20;
759
+ function historyFile() {
760
+ return join2(process8.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache"), "dx", "history.json");
761
+ }
762
+ function history() {
763
+ try {
764
+ const file = historyFile();
765
+ return existsSync(file) ? JSON.parse(readFileSync(file, "utf-8")) : {};
766
+ } catch {
767
+ return {};
768
+ }
769
+ }
770
+ function runs() {
771
+ return history()[process8.cwd()] ?? [];
772
+ }
773
+ function record(run) {
774
+ const all = history();
775
+ const file = historyFile();
776
+ all[process8.cwd()] = [run, ...(all[process8.cwd()] ?? []).filter((earlier) => earlier.id !== run.id)].slice(0, REMEMBERED);
777
+ mkdirSync2(dirname2(file), { recursive: true });
778
+ writeFileSync(file, JSON.stringify(all));
779
+ }
780
+ function byRecency(items, previous, idOf) {
781
+ const rank = new Map(previous.map((run, index) => [run.id, index]));
782
+ const recent = items.filter((item) => rank.has(idOf(item))).sort((a, b) => rank.get(idOf(a)) - rank.get(idOf(b)));
783
+ return [...recent, ...items.filter((item) => !rank.has(idOf(item)))];
784
+ }
785
+
786
+ // src/picker.ts
787
+ import process9 from "process";
788
+
789
+ // src/stack.ts
790
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
791
+ import { dirname as dirname3, join as join3, relative, resolve } from "path";
792
+ var LABEL_FORMAT = ["project", "project.config_files", "project.environment_file", "project.working_dir"].map((label) => `{{.Label "com.docker.compose.${label}"}}`).join("\t");
793
+ var COMPOSE_FILE_VAR = /^\s*(?:export\s+)?COMPOSE_FILE\s*=\s*\S/m;
794
+ var COMPOSE_FILES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
795
+ var SKIPPED = new Set(["node_modules", "vendor", "dist", "build", "target", "venv", "__pycache__"]);
796
+ var ACTIONS = ["shell", "logs", "restart", "up", "stop", "build"];
797
+ function from(dir, command) {
798
+ return dir === "." ? command : ["env", "-C", dir, ...command];
799
+ }
800
+ function children(dir = ".") {
801
+ return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !SKIPPED.has(child.name)).map((child) => child.name).sort();
802
+ }
803
+ function up(dir) {
804
+ const dirs = [];
805
+ for (let current = dir;; current = join3(current, "..")) {
806
+ dirs.push(current);
807
+ const absolute = resolve(current);
808
+ if (existsSync2(join3(current, ".git")) || dirname3(absolute) === absolute)
809
+ return dirs;
810
+ }
811
+ }
812
+ function stackAt(dir) {
813
+ return { dir, run: from(dir, ["docker", "compose"]), list: { argv: ["docker", "compose"], cwd: resolve(dir), env: process.env } };
814
+ }
815
+ function holdsStack(dir) {
816
+ if (COMPOSE_FILES.some((name) => existsSync2(join3(dir, name))))
817
+ return true;
818
+ try {
819
+ return COMPOSE_FILE_VAR.test(readFileSync2(join3(dir, ".env"), "utf-8"));
820
+ } catch {
821
+ return false;
822
+ }
823
+ }
824
+ function nearestStack(dir) {
825
+ const found = up(dir).find(holdsStack);
826
+ return found === undefined ? undefined : stackAt(found);
827
+ }
828
+ function stacks() {
829
+ const here = nearestStack(".");
830
+ const below = children().filter(holdsStack);
831
+ return [...here ? [here] : [], ...below.filter((dir) => dir !== here?.dir).map(stackAt)];
832
+ }
833
+ function labelled(text) {
834
+ const projects = new Map;
835
+ for (const line of text.split(`
836
+ `)) {
837
+ const [project, files, envFiles = "", workdir = ""] = line.split("\t");
838
+ if (project !== undefined && project !== "" && files !== undefined && files !== "" && workdir !== "" && !projects.has(project))
839
+ projects.set(project, { project, files: files.split(","), envFiles: envFiles.split(",").filter(Boolean), workdir });
840
+ }
841
+ return [...projects.values()];
842
+ }
843
+ async function labels(project) {
844
+ const filter = project === undefined ? [] : ["--filter", `label=com.docker.compose.project=${project}`];
845
+ const proc = Bun.spawn(["docker", "ps", "--all", ...filter, "--format", LABEL_FORMAT], { stdout: "pipe", stderr: "ignore" });
846
+ if (await proc.exited !== 0)
847
+ return [];
848
+ return labelled(await new Response(proc.stdout).text()).filter((stack) => [...stack.files, ...stack.envFiles].every((file) => existsSync2(file)));
849
+ }
850
+ function labelledStack(dir, { project, files, envFiles, workdir }) {
851
+ const options = (paths) => ["-p", project, ...files.flatMap((file) => ["-f", paths(file)]), ...envFiles.flatMap((file) => ["--env-file", paths(file)])];
852
+ return {
853
+ dir,
854
+ project,
855
+ run: from(dir, ["docker", "compose", ...options((file) => relative(workdir, file))]),
856
+ list: { argv: ["docker", "compose", ...options((file) => file)], cwd: workdir, env: process.env }
857
+ };
858
+ }
859
+ function stackOf(recorded) {
860
+ return labelledStack(relative(".", recorded.workdir) || ".", recorded);
861
+ }
862
+ async function recordedNearby() {
863
+ const dirs = new Set([...up("."), ...children()].map((dir) => resolve(dir)));
864
+ return (await labels()).filter((stack) => dirs.has(stack.workdir));
865
+ }
866
+ async function output(stack, args) {
867
+ const proc = Bun.spawn([...stack.list.argv, ...args], { cwd: stack.list.cwd, env: stack.list.env, stdout: "pipe", stderr: "pipe" });
868
+ return await proc.exited === 0 ? new Response(proc.stdout).text() : "";
869
+ }
870
+ function containers(text) {
871
+ const trimmed = text.trim();
872
+ if (!trimmed)
873
+ return [];
874
+ return trimmed.startsWith("[") ? JSON.parse(trimmed) : trimmed.split(`
875
+ `).map((line) => JSON.parse(line));
876
+ }
877
+ async function services(stack) {
878
+ const [config, ps] = await Promise.all([output(stack, ["config", "--format", "json"]), output(stack, ["ps", "--all", "--format", "json"])]);
879
+ const parsed = config ? JSON.parse(config) : {};
880
+ const declared = parsed.services ?? {};
881
+ const project = stack.project ?? parsed.name ?? "";
882
+ const running = new Map(containers(ps).map((container) => [container.Service, container]));
883
+ return Object.entries(declared).map(([name, service]) => ({
884
+ stack,
885
+ project,
886
+ name,
887
+ state: running.get(name)?.State ?? "none",
888
+ status: running.get(name)?.Status ?? "",
889
+ ports: (service.ports ?? []).filter((port) => (port.published ?? "") !== "").map((port) => `${port.published}->${port.target}`).join(" "),
890
+ image: service.image ?? "built"
891
+ }));
892
+ }
893
+ async function allServices() {
894
+ const [listed, recorded] = await Promise.all([Promise.all(stacks().map(services)), recordedNearby()]);
895
+ const found = listed.flat();
896
+ const known = new Set(found.map((service) => service.project));
897
+ const others = recorded.filter((stack) => !known.has(stack.project));
898
+ return [...found, ...(await Promise.all(others.map(async (stack) => services(stackOf(stack))))).flat()];
899
+ }
900
+ function named(service) {
901
+ return service.stack.project === undefined ? service.name : `${service.stack.project}:${service.name}`;
902
+ }
903
+ function key(service) {
904
+ return service.stack.dir === "." ? named(service) : `${service.stack.dir}/${named(service)}`;
905
+ }
906
+ async function shellOf(service) {
907
+ return await output(service.stack, ["exec", "-T", service.name, "sh", "-c", "command -v bash"]) ? "bash" : "sh";
908
+ }
909
+ async function commandFor(service, action) {
910
+ const run = service.stack.run;
911
+ switch (action) {
912
+ case "shell":
913
+ return [...run, "exec", service.name, await shellOf(service)];
914
+ case "logs":
915
+ return [...run, "logs", "-f", "--tail=200", service.name];
916
+ case "restart":
917
+ return [...run, "restart", service.name];
918
+ case "up":
919
+ return [...run, "up", "-d", service.name];
920
+ case "stop":
921
+ return [...run, "stop", service.name];
922
+ case "build":
923
+ return [...run, "up", "-d", "--build", service.name];
924
+ }
925
+ }
926
+ function defaultAction(service) {
927
+ return service.state === "running" ? "shell" : "up";
928
+ }
929
+ function stateColor(state) {
930
+ if (state === "running")
931
+ return "green";
932
+ if (state === "exited" || state === "dead")
933
+ return "red";
934
+ return state === "none" ? "dim" : "yellow";
935
+ }
936
+ async function serviceNamed(dir, name, project) {
937
+ const [recorded] = project === "" ? [] : await labels(project);
938
+ const stack = recorded === undefined ? stackAt(dir) : labelledStack(dir, recorded);
939
+ return (await services(stack)).find((candidate) => candidate.name === name);
940
+ }
941
+ async function logsOf(stack, name) {
942
+ return output(stack, ["logs", "--tail=30", "--no-log-prefix", name]);
943
+ }
944
+
945
+ // src/picker.ts
946
+ var KEYS = { "ctrl-l": "logs", "ctrl-r": "restart", "ctrl-x": "stop", "ctrl-b": "build" };
947
+ var KEY_LABELS = { "ctrl-l": "Logs", "ctrl-r": "Restart", "ctrl-x": "Stop", "ctrl-b": "Rebuild" };
948
+ function row(service) {
949
+ const colors = paint(process9.stderr);
950
+ const dir = service.stack.dir;
951
+ const project = service.stack.project;
952
+ const name = project === undefined ? service.name : `${colors.dim(`${project}:`)}${service.name}`;
953
+ return {
954
+ hidden: [dir, service.name, key(service), project ?? ""],
955
+ cells: [dir === "." ? name : `${colors.dim(`${dir}/`)}${name}`, colors[stateColor(service.state)](service.state), colors.cyan(service.ports), colors.dim(service.image)]
956
+ };
957
+ }
958
+ function table(rows) {
959
+ const widths = rows[0]?.cells.map((_, index) => Math.max(...rows.map((each) => Bun.stringWidth(each.cells[index])))) ?? [];
960
+ return rows.map((each) => [
961
+ ...each.hidden,
962
+ ...each.cells.map((cell, index) => index === each.cells.length - 1 ? cell.trimEnd() : `${cell}${" ".repeat(widths[index] + 1 - Bun.stringWidth(cell))}`)
963
+ ].join("\t")).join(`
964
+ `);
965
+ }
966
+ function pickService(services) {
967
+ const proc = Bun.spawnSync([
968
+ "fzf",
969
+ "--prompt",
970
+ "dx> ",
971
+ "--header",
972
+ "enter shell or up, ctrl-l logs, ctrl-r restart, ctrl-x stop, ctrl-b rebuild",
973
+ "--expect",
974
+ Object.keys(KEYS).join(","),
975
+ "--ansi",
976
+ "--reverse",
977
+ "--height",
978
+ String(Math.max(15, Math.ceil((services.length + 4) / 0.6))),
979
+ "--delimiter",
980
+ "\t",
981
+ "--with-nth",
982
+ "5..",
983
+ "--nth",
984
+ "1",
985
+ "--tabstop",
986
+ "1",
987
+ "--tiebreak",
988
+ "chunk,index",
989
+ "--preview",
990
+ `${process9.execPath} ${process9.argv[1]} --show {1} {2} {4}`,
991
+ "--preview-window",
992
+ "down,40%"
993
+ ], { stdin: new TextEncoder().encode(table(services.map(row))), stdout: "pipe", stderr: "inherit" });
994
+ const [pressed = "", line] = proc.stdout.toString().split(`
995
+ `);
996
+ const keyed = line?.split("\t")[2];
997
+ const service = services.find((candidate) => key(candidate) === keyed);
998
+ return service === undefined ? undefined : { service, key: pressed };
999
+ }
1000
+
1001
+ // src/dx.ts
1002
+ var usage2 = `dx [service] [action]
1003
+ dx -
1004
+
1005
+ Without a service, picks one with fzf when it is installed and a terminal is attached: enter opens its shell (or brings a stopped service up), ctrl-l follows its logs, ctrl-r restarts, ctrl-x stops and ctrl-b rebuilds it. The services last acted on come first, per folder. Without fzf or a terminal it lists them instead.
1006
+ \`dx -\` does the last action again, \`dx <service> [action]\` acts without the picker: \`shell\` (bash when the container has it), \`logs\` (follows the last 200 lines), \`restart\`, \`up\`, \`stop\` or \`build\` (up with a rebuild).
1007
+ The services are the stack of this folder or its nearest parent, the ones of the child folders (keyed \`api/php\`), and stacks found only through their containers (keyed \`<project>:php\`).
1008
+
1009
+ Exits with the code of the command it ran, 1 when there is no compose service here or none by that name.`;
1010
+ var options = {
1011
+ json: jsonOption("[{ key, project, name, state, status, ports, image }]")
1012
+ };
1013
+ function table2(services) {
1014
+ const colors = paint(process10.stdout);
1015
+ const keys = services.map(key);
1016
+ const width = Math.max(...keys.map((name) => name.length));
1017
+ const states = Math.max(...services.map((service) => service.state.length));
1018
+ return services.map((service, index) => [
1019
+ keys[index].padEnd(width),
1020
+ colors[stateColor(service.state)](service.state.padEnd(states)),
1021
+ colors.cyan(service.ports),
1022
+ colors.dim(service.image)
1023
+ ].join(" ").trimEnd()).join(`
1024
+ `);
1025
+ }
1026
+ function find(services, named) {
1027
+ const found = services.find((service) => key(service) === named) ?? services.find((service) => service.name === named);
1028
+ if (found !== undefined)
1029
+ return found;
1030
+ const nearest = closest(named, services.map(key));
1031
+ return fail(`no service named ${named}${nearest === undefined ? "" : `, did you mean ${nearest}?`}`, 1);
1032
+ }
1033
+ function listed2(services) {
1034
+ return byRecency(services, runs(), key).map((service) => ({
1035
+ label: key(service),
1036
+ hint: [service.state, service.ports, service.image].filter(Boolean).join(" \xB7 "),
1037
+ typed: key(service),
1038
+ preview: ["--show", service.stack.dir, service.name, service.stack.project ?? ""],
1039
+ actions: Object.entries(KEYS).map(([pressed, action]) => ({ label: KEY_LABELS[pressed] ?? action, key: pressed, typed: `${key(service)} ${action}` }))
1040
+ }));
1041
+ }
1042
+ async function hidden(flag, rest, services) {
1043
+ if (flag === "--list") {
1044
+ console.log(JSON.stringify(listed2(services)));
1045
+ return 0;
1046
+ }
1047
+ if (flag === "--names") {
1048
+ console.log(services.map((service) => `${key(service)} ${service.state}`).join(`
1049
+ `));
1050
+ return 0;
1051
+ }
1052
+ if (flag === "--show") {
1053
+ const [dir = ".", name = "", project = ""] = rest;
1054
+ const service = await serviceNamed(dir, name, project);
1055
+ if (service === undefined)
1056
+ return 0;
1057
+ const colors = paint(process10.stdout);
1058
+ console.log(`${colors[stateColor(service.state)](service.status || service.state)} ${colors.dim(service.image)}${service.ports ? ` ${colors.cyan(service.ports)}` : ""}
1059
+ `);
1060
+ console.log(await logsOf(service.stack, name));
1061
+ return 0;
1062
+ }
1063
+ return;
1064
+ }
1065
+ async function dx(args) {
1066
+ const [flag = ""] = args;
1067
+ if (flag === "--show" || flag === "--list" || flag === "--names") {
1068
+ const services = flag === "--show" ? [] : await allServices();
1069
+ if (services.length === 0 && flag !== "--show")
1070
+ fail("no compose service here", 1);
1071
+ return await hidden(flag, args.slice(1), services) ?? 0;
1072
+ }
1073
+ const emit = flag === "--emit";
1074
+ const parsed = parse(emit ? args.slice(1) : args, usage2, options, { replaces: "docker compose exec <service> bash, logs -f and restart typed per service", examples: ["dx", ["dx php", "a shell in php, or php brought up when stopped"], ["dx php logs", "follow its logs"], ["dx -", "the last action again"]] });
1075
+ const [named, asked] = parsed.positionals;
1076
+ const services = await allServices();
1077
+ if (services.length === 0)
1078
+ fail("no compose service here", 1);
1079
+ let service;
1080
+ let action;
1081
+ if (named === undefined) {
1082
+ const interactive = process10.stdin.isTTY && process10.stderr.isTTY && parsed.values.json !== true;
1083
+ if (!interactive || Bun.which("fzf") === null) {
1084
+ if (emit)
1085
+ fail("the picker needs a terminal and fzf", 1);
1086
+ if (interactive)
1087
+ console.error("fzf is not installed, listing the services instead");
1088
+ if (parsed.values.json === true)
1089
+ printJson(services.map((each) => ({ key: key(each), project: each.project, name: each.name, state: each.state, status: each.status, ports: each.ports, image: each.image })));
1090
+ else
1091
+ console.log(table2(services));
1092
+ return 0;
1093
+ }
1094
+ const picked = pickService(byRecency(services, runs(), key));
1095
+ if (picked === undefined)
1096
+ return 1;
1097
+ service = picked.service;
1098
+ action = KEYS[picked.key];
1099
+ } else if (named === "-") {
1100
+ const last = runs()[0];
1101
+ service = last && services.find((candidate) => key(candidate) === last.id);
1102
+ if (service === undefined)
1103
+ fail(last ? `${last.id} is gone` : "nothing done here yet", 1);
1104
+ action = last.args[0];
1105
+ } else {
1106
+ service = find(services, named);
1107
+ if (asked !== undefined && !ACTIONS.includes(asked))
1108
+ fail(`no action ${asked}, one of ${ACTIONS.join(", ")}`);
1109
+ action = asked;
1110
+ }
1111
+ const chosen = action ?? defaultAction(service);
1112
+ const command = await commandFor(service, chosen);
1113
+ record({ id: key(service), args: [chosen] });
1114
+ if (emit) {
1115
+ console.log(["run", action === undefined ? key(service) : `${key(service)} ${action}`, "", ...command.map((word) => `=${word}`)].join(`
1116
+ `));
1117
+ return 0;
1118
+ }
1119
+ return Bun.spawn(command, { stdio: ["inherit", "inherit", "inherit"] }).exited;
1120
+ }
1121
+
1122
+ // src/dx-cli.ts
1123
+ process11.exitCode = await runMain({ name: "dx", version, run: dx });