@kaynooo/cli-out 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +32 -2
- package/dist/cli.js +1523 -0
- package/package.json +31 -4
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1523 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/cli.ts
|
|
5
|
+
import process11 from "process";
|
|
6
|
+
|
|
7
|
+
// ../kit/src/args.ts
|
|
8
|
+
import { fstatSync } from "fs";
|
|
9
|
+
import process3 from "process";
|
|
10
|
+
import { parseArgs } from "util";
|
|
11
|
+
|
|
12
|
+
// ../kit/src/format.ts
|
|
13
|
+
import process2 from "process";
|
|
14
|
+
|
|
15
|
+
// ../kit/src/style.ts
|
|
16
|
+
import process from "process";
|
|
17
|
+
|
|
18
|
+
// ../../node_modules/.bun/@kaynooo+utils@2.31.0+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
19
|
+
function x(s) {
|
|
20
|
+
let r = s.startsWith("#") ? s.slice(1).toLowerCase() : s.toLowerCase();
|
|
21
|
+
if (!/^[a-f0-9]+$/.test(r))
|
|
22
|
+
return [0, 0, 0];
|
|
23
|
+
let t = r.length, n = (c) => Number.parseInt(c, 16);
|
|
24
|
+
if (t === 3 || t === 4) {
|
|
25
|
+
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;
|
|
26
|
+
return g !== undefined ? [c, u, h, g] : [c, u, h];
|
|
27
|
+
}
|
|
28
|
+
if (t !== 6 && t !== 8)
|
|
29
|
+
throw Error(`Invalid hex color length: ${t}`);
|
|
30
|
+
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;
|
|
31
|
+
if ([a, b, o].some(Number.isNaN) || y !== undefined && Number.isNaN(y))
|
|
32
|
+
throw Error(`Invalid hex color value: ${s}`);
|
|
33
|
+
return y !== undefined ? [a, b, o, y] : [a, b, o];
|
|
34
|
+
}
|
|
35
|
+
function A(s) {
|
|
36
|
+
let [r, t, n, a] = s;
|
|
37
|
+
if (a)
|
|
38
|
+
return `#${(r << 24 | t << 16 | n << 8 | Math.round((a ?? 1) * 255)).toString(16).padStart(8, "0").toUpperCase()}`;
|
|
39
|
+
return `#${(r << 16 | t << 8 | n).toString(16).padStart(6, "0").toUpperCase()}`;
|
|
40
|
+
}
|
|
41
|
+
function R(s, r, t) {
|
|
42
|
+
s = (s % 360 + 360) % 360, t /= 100;
|
|
43
|
+
let n = r * Math.min(t, 1 - t) / 100, a = (b) => {
|
|
44
|
+
let o = (b + s / 30) % 12, y = t - n * Math.max(Math.min(o - 3, 9 - o, 1), -1);
|
|
45
|
+
return Math.round(255 * y);
|
|
46
|
+
};
|
|
47
|
+
return [a(0), a(8), a(4)];
|
|
48
|
+
}
|
|
49
|
+
function k(s) {
|
|
50
|
+
let [r, t, n] = s;
|
|
51
|
+
r /= 255, t /= 255, n /= 255;
|
|
52
|
+
let a = Math.max(r, t, n), b = Math.min(r, t, n), o = 0, y = 0, c = (a + b) / 2;
|
|
53
|
+
if (a !== b) {
|
|
54
|
+
let u = a - b;
|
|
55
|
+
if (y = c > 0 && c < 1 ? u / (1 - Math.abs(2 * c - 1)) : 0, a === r)
|
|
56
|
+
o = (t - n) / u + (t < n ? 6 : 0);
|
|
57
|
+
else if (a === t)
|
|
58
|
+
o = (n - r) / u + 2;
|
|
59
|
+
else
|
|
60
|
+
o = (r - t) / u + 4;
|
|
61
|
+
o /= 6;
|
|
62
|
+
}
|
|
63
|
+
return [Math.round(o * 360), Math.round(y * 100), Math.round(c * 100)];
|
|
64
|
+
}
|
|
65
|
+
function H(s, r, t) {
|
|
66
|
+
s = (s % 360 + 360) % 360, r /= 100, t /= 100;
|
|
67
|
+
let n = (a) => {
|
|
68
|
+
let b = (a + s / 60) % 6, o = t - t * r * Math.max(Math.min(b, 4 - b, 1), 0);
|
|
69
|
+
return Math.round(255 * o);
|
|
70
|
+
};
|
|
71
|
+
return [n(5), n(3), n(1)];
|
|
72
|
+
}
|
|
73
|
+
function f(s) {
|
|
74
|
+
let [r, t, n] = s;
|
|
75
|
+
r /= 255, t /= 255, n /= 255;
|
|
76
|
+
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;
|
|
77
|
+
if (o !== 0) {
|
|
78
|
+
if (a === r)
|
|
79
|
+
y = (t - n) / o + (t < n ? 6 : 0);
|
|
80
|
+
else if (a === t)
|
|
81
|
+
y = (n - r) / o + 2;
|
|
82
|
+
else
|
|
83
|
+
y = (r - t) / o + 4;
|
|
84
|
+
y /= 6;
|
|
85
|
+
}
|
|
86
|
+
return [Math.round(y * 360), Math.round(c * 100), Math.round(u * 100)];
|
|
87
|
+
}
|
|
88
|
+
function O(s) {
|
|
89
|
+
let r = s[0] / 255, t = s[1] / 255, n = s[2] / 255, a = 1 - Math.max(r, t, n);
|
|
90
|
+
if (a === 1)
|
|
91
|
+
return [0, 0, 0, 100];
|
|
92
|
+
let b = (1 - r - a) / (1 - a), o = (1 - t - a) / (1 - a), y = (1 - n - a) / (1 - a);
|
|
93
|
+
return [Math.round(b * 100), Math.round(o * 100), Math.round(y * 100), Math.round(a * 100)];
|
|
94
|
+
}
|
|
95
|
+
function v(s, r, t, n) {
|
|
96
|
+
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))];
|
|
97
|
+
}
|
|
98
|
+
var m = (s) => s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
99
|
+
var p = (s) => s <= 0.0031308 ? 12.92 * s : 1.055 * s ** 0.4166666666666667 - 0.055;
|
|
100
|
+
var i = (s, r) => Math.round(s * 10 ** r) / 10 ** r;
|
|
101
|
+
function T(s) {
|
|
102
|
+
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);
|
|
103
|
+
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)];
|
|
104
|
+
}
|
|
105
|
+
function M(s, r, t) {
|
|
106
|
+
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)));
|
|
107
|
+
return [u(o), u(y), u(c)];
|
|
108
|
+
}
|
|
109
|
+
function d(s) {
|
|
110
|
+
let [r, t, n] = T(s), a = Math.sqrt(t * t + n * n), b = (Math.atan2(n, t) * 180 / Math.PI + 360) % 360;
|
|
111
|
+
return [i(r, 4), i(a, 4), i(b, 2)];
|
|
112
|
+
}
|
|
113
|
+
function C(s, r, t) {
|
|
114
|
+
let n = t * Math.PI / 180;
|
|
115
|
+
return M(s, r * Math.cos(n), r * Math.sin(n));
|
|
116
|
+
}
|
|
117
|
+
function l(s) {
|
|
118
|
+
let r = s / 255;
|
|
119
|
+
return r <= 0.03928 ? r / 12.92 : ((r + 0.055) / 1.055) ** 2.4;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class e {
|
|
123
|
+
r;
|
|
124
|
+
g;
|
|
125
|
+
b;
|
|
126
|
+
a;
|
|
127
|
+
constructor(s, r, t, n = 1) {
|
|
128
|
+
this.r = s, this.g = r, this.b = t, this.a = n;
|
|
129
|
+
}
|
|
130
|
+
static from(s, r) {
|
|
131
|
+
if (s === "hex") {
|
|
132
|
+
let [t, n, a, b] = x(r);
|
|
133
|
+
return new e(t, n, a, b);
|
|
134
|
+
}
|
|
135
|
+
if (s === "rgb") {
|
|
136
|
+
if (Array.isArray(r)) {
|
|
137
|
+
let [o, y, c, u] = r;
|
|
138
|
+
return new e(o, y, c, u);
|
|
139
|
+
}
|
|
140
|
+
let { r: t, g: n, b: a, a: b } = r;
|
|
141
|
+
return new e(t, n, a, b);
|
|
142
|
+
}
|
|
143
|
+
if (s === "hsl") {
|
|
144
|
+
let t, n, a, b;
|
|
145
|
+
if (Array.isArray(r))
|
|
146
|
+
[t, n, a, b] = r;
|
|
147
|
+
else
|
|
148
|
+
({ h: t, s: n, l: a, a: b } = r);
|
|
149
|
+
let [o, y, c] = R(t, n, a);
|
|
150
|
+
return new e(o, y, c, b);
|
|
151
|
+
}
|
|
152
|
+
if (s === "hsv") {
|
|
153
|
+
let t, n, a, b;
|
|
154
|
+
if (Array.isArray(r))
|
|
155
|
+
[t, n, a, b] = r;
|
|
156
|
+
else
|
|
157
|
+
({ h: t, s: n, v: a, a: b } = r);
|
|
158
|
+
let [o, y, c] = H(t, n, a);
|
|
159
|
+
return new e(o, y, c, b);
|
|
160
|
+
}
|
|
161
|
+
if (s === "cmyk") {
|
|
162
|
+
let t, n, a, b, o;
|
|
163
|
+
if (Array.isArray(r))
|
|
164
|
+
[t, n, a, b, o] = r;
|
|
165
|
+
else
|
|
166
|
+
({ c: t, m: n, y: a, k: b, a: o } = r);
|
|
167
|
+
let [y, c, u] = v(t, n, a, b);
|
|
168
|
+
return new e(y, c, u, o);
|
|
169
|
+
}
|
|
170
|
+
if (s === "oklch") {
|
|
171
|
+
let t, n, a, b;
|
|
172
|
+
if (Array.isArray(r))
|
|
173
|
+
[t, n, a, b] = r;
|
|
174
|
+
else
|
|
175
|
+
({ l: t, c: n, h: a, a: b } = r);
|
|
176
|
+
let [o, y, c] = C(t, n, a);
|
|
177
|
+
return new e(o, y, c, b);
|
|
178
|
+
}
|
|
179
|
+
if (s === "oklab") {
|
|
180
|
+
let t, n, a, b;
|
|
181
|
+
if (Array.isArray(r))
|
|
182
|
+
[t, n, a, b] = r;
|
|
183
|
+
else
|
|
184
|
+
({ l: t, a: n, b: a, alpha: b } = r);
|
|
185
|
+
let [o, y, c] = M(t, n, a);
|
|
186
|
+
return new e(o, y, c, b);
|
|
187
|
+
}
|
|
188
|
+
throw Error("Invalid input");
|
|
189
|
+
}
|
|
190
|
+
to(s) {
|
|
191
|
+
switch (s) {
|
|
192
|
+
case "rgb":
|
|
193
|
+
return [this.r, this.g, this.b];
|
|
194
|
+
case "rgba":
|
|
195
|
+
return [this.r, this.g, this.b, this.a];
|
|
196
|
+
case "hex":
|
|
197
|
+
return A([this.r, this.g, this.b]);
|
|
198
|
+
case "hexa":
|
|
199
|
+
return A([this.r, this.g, this.b, this.a]);
|
|
200
|
+
case "hsl":
|
|
201
|
+
return k([this.r, this.g, this.b]);
|
|
202
|
+
case "hsla":
|
|
203
|
+
return [...k([this.r, this.g, this.b]), this.a];
|
|
204
|
+
case "hsv":
|
|
205
|
+
return f([this.r, this.g, this.b]);
|
|
206
|
+
case "hsva":
|
|
207
|
+
return [...f([this.r, this.g, this.b]), this.a];
|
|
208
|
+
case "cmyk":
|
|
209
|
+
return O([this.r, this.g, this.b]);
|
|
210
|
+
case "cmyka":
|
|
211
|
+
return [...O([this.r, this.g, this.b]), this.a];
|
|
212
|
+
case "oklch":
|
|
213
|
+
return d([this.r, this.g, this.b]);
|
|
214
|
+
case "oklcha":
|
|
215
|
+
return [...d([this.r, this.g, this.b]), this.a];
|
|
216
|
+
case "oklab":
|
|
217
|
+
return T([this.r, this.g, this.b]);
|
|
218
|
+
case "oklaba":
|
|
219
|
+
return [...T([this.r, this.g, this.b]), this.a];
|
|
220
|
+
default:
|
|
221
|
+
return [this.r, this.g, this.b];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
getLuminance() {
|
|
225
|
+
let s = l(this.r), r = l(this.g), t = l(this.b);
|
|
226
|
+
return 0.2126 * s + 0.7152 * r + 0.0722 * t;
|
|
227
|
+
}
|
|
228
|
+
contrastRatio(s) {
|
|
229
|
+
let r = this.getLuminance(), t = s.getLuminance(), [n, a] = r >= t ? [r, t] : [t, r];
|
|
230
|
+
return (n + 0.05) / (a + 0.05);
|
|
231
|
+
}
|
|
232
|
+
bestContrastForeground() {
|
|
233
|
+
let s = new e(255, 255, 255, 1), r = new e(0, 0, 0, 1), t = this.contrastRatio(s), n = this.contrastRatio(r);
|
|
234
|
+
return t >= n ? s : r;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ../../node_modules/.bun/@kaynooo+utils@2.31.0+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-y1msbssb.js
|
|
239
|
+
var r = 39;
|
|
240
|
+
var o = 49;
|
|
241
|
+
var f2 = "\x1B[";
|
|
242
|
+
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") => {
|
|
243
|
+
let [a, l, s] = e.from("hex", i).to("rgb");
|
|
244
|
+
return [`${n === "fg" ? 38 : 48};2;${a};${l};${s}`, n === "fg" ? r : o];
|
|
245
|
+
}, ansi256: (i, n = "fg") => [`${n === "fg" ? 38 : 48};5;${i}`, n === "fg" ? r : o] };
|
|
246
|
+
var b = new Set(["", "1", "2", "3", "true"]);
|
|
247
|
+
function h(i, n = globalThis.process?.env ?? {}) {
|
|
248
|
+
if (n.FORCE_COLOR !== undefined)
|
|
249
|
+
return b.has(n.FORCE_COLOR);
|
|
250
|
+
if (n.NO_COLOR !== undefined || n.NODE_DISABLE_COLORS !== undefined || n.TERM === "dumb")
|
|
251
|
+
return false;
|
|
252
|
+
return i?.isTTY === true;
|
|
253
|
+
}
|
|
254
|
+
function d2(i, n, a) {
|
|
255
|
+
if (!h(a.stream ?? globalThis.process?.stdout, a.env))
|
|
256
|
+
return n;
|
|
257
|
+
let l = "", s = "";
|
|
258
|
+
for (let g = 0, y = i.length;g < y; g++) {
|
|
259
|
+
let [c, p] = i[g];
|
|
260
|
+
l += `${f2}${c}m`, s = `${f2}${p}m${s}`;
|
|
261
|
+
}
|
|
262
|
+
return l + n + s;
|
|
263
|
+
}
|
|
264
|
+
function u(i, n = []) {
|
|
265
|
+
return new Proxy((l) => d2(n, l, i), { get(l, s) {
|
|
266
|
+
let g = C2[s];
|
|
267
|
+
if (Array.isArray(g))
|
|
268
|
+
return u(i, [...n, g]);
|
|
269
|
+
if (typeof g === "function")
|
|
270
|
+
return (...y) => u(i, [...n, g(...y)]);
|
|
271
|
+
throw Error(`Unknown style: ${String(s)}`);
|
|
272
|
+
} });
|
|
273
|
+
}
|
|
274
|
+
function le(i = {}) {
|
|
275
|
+
return u(i);
|
|
276
|
+
}
|
|
277
|
+
var t = le();
|
|
278
|
+
|
|
279
|
+
// ../kit/src/style.ts
|
|
280
|
+
function takesControlCodes(stream, env = process.env) {
|
|
281
|
+
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
282
|
+
}
|
|
283
|
+
function paint(stream, env = process.env) {
|
|
284
|
+
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
285
|
+
}
|
|
286
|
+
var STATUSES = {
|
|
287
|
+
passed: { symbol: "\u2713", words: ["passed", "success", "succeeded", "ok"], paint: (colors) => colors.green },
|
|
288
|
+
failed: { symbol: "\u2717", words: ["failed", "failure", "error", "errored"], paint: (colors) => colors.red },
|
|
289
|
+
running: { symbol: "\u25CF", words: ["running", "in_progress", "started"], paint: (colors) => colors.cyan },
|
|
290
|
+
queued: { symbol: "\u25CB", words: ["queued", "waiting", "pending", "created", "blocked", "scheduled"], paint: (colors) => colors.yellow },
|
|
291
|
+
skipped: { symbol: "-", words: ["skipped", "cancelled", "canceled", "manual"], paint: (colors) => colors.dim }
|
|
292
|
+
};
|
|
293
|
+
var STATUS_OF = new Map(Object.entries(STATUSES).flatMap(([status, { words }]) => words.map((word) => [word, status])));
|
|
294
|
+
|
|
295
|
+
// ../kit/src/format.ts
|
|
296
|
+
function upTo(text, separator) {
|
|
297
|
+
const end = text.indexOf(separator);
|
|
298
|
+
return end === -1 ? text : text.slice(0, end);
|
|
299
|
+
}
|
|
300
|
+
function truncate(text, width) {
|
|
301
|
+
return text.length <= width ? text : `${text.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
302
|
+
}
|
|
303
|
+
var LINE_BREAKS = /\s*\n\s*/g;
|
|
304
|
+
var ESCAPE = String.fromCharCode(27);
|
|
305
|
+
function textWidth(text) {
|
|
306
|
+
return Bun.stringWidth(text);
|
|
307
|
+
}
|
|
308
|
+
function table(rows, { cellWidth, header = false, align = [], fit } = {}) {
|
|
309
|
+
const cells = cellWidth === undefined ? rows : rows.map((row) => row.map((cell) => truncate(cell.replaceAll(LINE_BREAKS, " "), cellWidth)));
|
|
310
|
+
const widths = [];
|
|
311
|
+
for (const row of cells) {
|
|
312
|
+
for (const [index, cell] of row.entries())
|
|
313
|
+
widths[index] = Math.max(widths[index] ?? 0, textWidth(cell));
|
|
314
|
+
}
|
|
315
|
+
const shown = fit === undefined ? cells : narrow(cells, widths, fit);
|
|
316
|
+
const colors = paint(process2.stdout);
|
|
317
|
+
const lines = shown.map((row) => row.map((cell, index) => {
|
|
318
|
+
const width = widths[index] ?? 0;
|
|
319
|
+
const gap = " ".repeat(Math.max(0, width - textWidth(cell)));
|
|
320
|
+
if (align[index] === "right")
|
|
321
|
+
return `${gap}${cell}`;
|
|
322
|
+
return index === row.length - 1 ? cell : `${cell}${gap}`;
|
|
323
|
+
}).join(" ").trimEnd());
|
|
324
|
+
return lines.map((line, index) => header && index === 0 ? colors.bold(line) : line).join(`
|
|
325
|
+
`);
|
|
326
|
+
}
|
|
327
|
+
function narrow(rows, widths, limit) {
|
|
328
|
+
const used = () => widths.reduce((sum, width) => sum + width, 0) + 2 * Math.max(0, widths.length - 1);
|
|
329
|
+
const cuttable = (index) => rows.every((row) => !(row[index] ?? "").includes(ESCAPE));
|
|
330
|
+
const floor = 8;
|
|
331
|
+
while (used() > limit) {
|
|
332
|
+
let widest = -1;
|
|
333
|
+
for (const [index, width] of widths.entries()) {
|
|
334
|
+
if (cuttable(index) && width > floor && width > (widths[widest] ?? 0))
|
|
335
|
+
widest = index;
|
|
336
|
+
}
|
|
337
|
+
if (widest === -1)
|
|
338
|
+
break;
|
|
339
|
+
widths[widest] = Math.max(floor, (widths[widest] ?? 0) - (used() - limit));
|
|
340
|
+
}
|
|
341
|
+
return rows.map((row) => row.map((cell, index) => textWidth(cell) > (widths[index] ?? 0) ? truncate(cell, widths[index] ?? 0) : cell));
|
|
342
|
+
}
|
|
343
|
+
function printJson(value) {
|
|
344
|
+
console.log(JSON.stringify(value, undefined, 2));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// ../kit/src/text.ts
|
|
348
|
+
var ANSI = new RegExp(`${String.fromCharCode(27)}\\[[\\d;?]*[a-z]`, "gi");
|
|
349
|
+
function stripAnsi(text) {
|
|
350
|
+
return text.replace(ANSI, "");
|
|
351
|
+
}
|
|
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
|
+
function jsonOption(holds) {
|
|
372
|
+
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
class Exit extends Error {
|
|
376
|
+
code;
|
|
377
|
+
hint;
|
|
378
|
+
constructor(message, code, hint) {
|
|
379
|
+
super(message);
|
|
380
|
+
this.code = code;
|
|
381
|
+
this.hint = hint;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function fail(message, code = 2, hint) {
|
|
385
|
+
throw new Exit(message, code, hint);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
class UsageError extends Exit {
|
|
389
|
+
constructor(message, hint) {
|
|
390
|
+
super(message, 2, hint);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function badUsage(message) {
|
|
394
|
+
throw new UsageError(message);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
class HelpShown extends Exit {
|
|
398
|
+
constructor() {
|
|
399
|
+
super("help shown", 0);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
class Completing {
|
|
404
|
+
options;
|
|
405
|
+
constructor(options) {
|
|
406
|
+
this.options = options;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
var completion = { active: false };
|
|
410
|
+
var OPTIONAL = /\[[^\]]+\]/g;
|
|
411
|
+
var USAGE_PREFIX = /^usage:\s*/i;
|
|
412
|
+
var FULL_STOP = /\.$/;
|
|
413
|
+
var DASHES = /^-+/;
|
|
414
|
+
function usageLine(usage, colors = paint(process3.stdout)) {
|
|
415
|
+
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
416
|
+
}
|
|
417
|
+
function helpText(usage, options, colors = paint(process3.stdout), { examples = [], replaces } = {}) {
|
|
418
|
+
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exampleRows(examples, colors)].join(`
|
|
419
|
+
`);
|
|
420
|
+
}
|
|
421
|
+
function replacesRows(replaces, colors = paint(process3.stdout)) {
|
|
422
|
+
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
423
|
+
}
|
|
424
|
+
function wantsHelpJson(env = process3.env) {
|
|
425
|
+
return env.KIT_HELP === "json";
|
|
426
|
+
}
|
|
427
|
+
function description(usage, { examples = [], replaces } = {}) {
|
|
428
|
+
const lines = usage.replace(USAGE_PREFIX, "").split(`
|
|
429
|
+
`);
|
|
430
|
+
const first = lines[0];
|
|
431
|
+
const colon = first.indexOf(": ");
|
|
432
|
+
const prose = lines[lines.indexOf("") + 1] ?? "";
|
|
433
|
+
const fallback = lines.includes("") ? `${prose.charAt(0).toLowerCase()}${prose.slice(1)}`.replace(FULL_STOP, "") : "";
|
|
434
|
+
return {
|
|
435
|
+
synopsis: colon === -1 ? first : first.slice(0, colon),
|
|
436
|
+
summary: colon === -1 ? fallback : first.slice(colon + 2),
|
|
437
|
+
...replaces === undefined ? {} : { replaces },
|
|
438
|
+
examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] })
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
function exampleRows(examples, colors = paint(process3.stdout)) {
|
|
442
|
+
if (examples.length === 0)
|
|
443
|
+
return [];
|
|
444
|
+
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
445
|
+
}
|
|
446
|
+
function optionRows(options, colors = paint(process3.stdout)) {
|
|
447
|
+
const rows = Object.entries(options).map(([name, option]) => {
|
|
448
|
+
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
449
|
+
const value = option.type === "string" ? ` ${colors.dim("<value>")}` : "";
|
|
450
|
+
return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? " <value>".length : 0), description: option.description ?? "" };
|
|
451
|
+
});
|
|
452
|
+
const width = Math.max(0, ...rows.map((row) => row.width));
|
|
453
|
+
return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
|
|
454
|
+
}
|
|
455
|
+
var OUTPUT_OPTIONS = {
|
|
456
|
+
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
457
|
+
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
458
|
+
};
|
|
459
|
+
function applyOutput(color, plain, env = process3.env) {
|
|
460
|
+
const when = plain === true ? "never" : color ?? "auto";
|
|
461
|
+
if (when === "auto")
|
|
462
|
+
return;
|
|
463
|
+
if (when !== "always" && when !== "never")
|
|
464
|
+
badUsage(`--color takes auto, always or never, not ${when}`);
|
|
465
|
+
if (when === "always") {
|
|
466
|
+
env.FORCE_COLOR = "1";
|
|
467
|
+
delete env.NO_COLOR;
|
|
468
|
+
} else {
|
|
469
|
+
env.NO_COLOR = "1";
|
|
470
|
+
delete env.FORCE_COLOR;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function parse(args, usage, options, settings = {}) {
|
|
474
|
+
const output = Object.fromEntries(Object.entries(OUTPUT_OPTIONS).filter(([name]) => !(name in options)));
|
|
475
|
+
const all = { ...options, ...output, help: { type: "boolean", short: "h", description: "show this help" } };
|
|
476
|
+
if (completion.active)
|
|
477
|
+
throw new Completing(all);
|
|
478
|
+
const separator = settings.rest === true ? args.indexOf("--") : -1;
|
|
479
|
+
const own = separator === -1 ? args : args.slice(0, separator);
|
|
480
|
+
const rest = separator === -1 ? undefined : args.slice(separator + 1);
|
|
481
|
+
let parsed;
|
|
482
|
+
try {
|
|
483
|
+
parsed = parseArgs({ args: joinDashValues(own, all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
|
|
484
|
+
} catch (error) {
|
|
485
|
+
const message = parseError(error);
|
|
486
|
+
throw new UsageError(message, nearestOption(message, all, settings.allowNegative === true));
|
|
487
|
+
}
|
|
488
|
+
const values = parsed.values;
|
|
489
|
+
applyOutput("color" in output ? values.color : undefined, "plain" in output ? values.plain : undefined);
|
|
490
|
+
if (values.help === true) {
|
|
491
|
+
console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings)) : helpText(usage, all, undefined, settings));
|
|
492
|
+
throw new HelpShown;
|
|
493
|
+
}
|
|
494
|
+
if (settings.positionals !== undefined)
|
|
495
|
+
checkPositionals(parsed.positionals, settings.positionals);
|
|
496
|
+
return { ...parsed, positionals: parsed.positionals, rest };
|
|
497
|
+
}
|
|
498
|
+
function checkPositionals(given, names) {
|
|
499
|
+
const variadic = names.at(-1)?.replace("]", "").endsWith("...") === true;
|
|
500
|
+
const required = names.filter((name) => !name.startsWith("[")).length;
|
|
501
|
+
if (given.length < required)
|
|
502
|
+
badUsage(`missing ${names[given.length]}`);
|
|
503
|
+
if (!variadic && given.length > names.length)
|
|
504
|
+
badUsage(`unexpected argument ${given[names.length]}`);
|
|
505
|
+
}
|
|
506
|
+
function joinDashValues(args, options) {
|
|
507
|
+
const longOf = new Map(Object.entries(options).flatMap(([name, option]) => option.short === undefined ? [[`--${name}`, name]] : [[`--${name}`, name], [`-${option.short}`, name]]));
|
|
508
|
+
const isOption = (arg) => arg === "--" || longOf.has(arg.includes("=") ? arg.slice(0, arg.indexOf("=")) : arg);
|
|
509
|
+
const joined = [];
|
|
510
|
+
for (let i = 0;i < args.length; i++) {
|
|
511
|
+
const arg = args[i] ?? "";
|
|
512
|
+
if (arg === "--")
|
|
513
|
+
return [...joined, ...args.slice(i)];
|
|
514
|
+
const name = longOf.get(arg);
|
|
515
|
+
const next = args[i + 1];
|
|
516
|
+
if (name !== undefined && options[name]?.type === "string" && next !== undefined && next.startsWith("-") && next !== "-" && !isOption(next)) {
|
|
517
|
+
joined.push(`--${name}=${next}`);
|
|
518
|
+
i++;
|
|
519
|
+
} else {
|
|
520
|
+
joined.push(arg);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return joined;
|
|
524
|
+
}
|
|
525
|
+
function parseError(error) {
|
|
526
|
+
const message = upTo(error instanceof Error ? error.message : String(error), ". ");
|
|
527
|
+
return `${message.charAt(0).toLowerCase()}${message.slice(1)}`;
|
|
528
|
+
}
|
|
529
|
+
var UNKNOWN_OPTION = /^unknown option '(-[^']+)'/;
|
|
530
|
+
function nearestOption(message, options, allowNegative) {
|
|
531
|
+
const typed = UNKNOWN_OPTION.exec(message)?.[1];
|
|
532
|
+
if (typed === undefined)
|
|
533
|
+
return;
|
|
534
|
+
const word = typed.replace(DASHES, "");
|
|
535
|
+
if (word.length < 2 && !typed.startsWith("--"))
|
|
536
|
+
return;
|
|
537
|
+
const known = Object.entries(options).flatMap(([name, option]) => [
|
|
538
|
+
...option.short === undefined ? [] : [`-${option.short}`],
|
|
539
|
+
`--${name}`,
|
|
540
|
+
...allowNegative && option.type === "boolean" ? [`--no-${name}`] : []
|
|
541
|
+
]);
|
|
542
|
+
const meant = closest(word, known.map((flag) => flag.replace(DASHES, "")));
|
|
543
|
+
return meant === undefined ? undefined : `did you mean ${known.find((flag) => flag.replace(DASHES, "") === meant)}?`;
|
|
544
|
+
}
|
|
545
|
+
var WHOLE = /^\d+$/;
|
|
546
|
+
function wholeNumber(value, name, fallback, min = 1) {
|
|
547
|
+
if (value === undefined)
|
|
548
|
+
return fallback;
|
|
549
|
+
const number = Number(value);
|
|
550
|
+
if (!WHOLE.test(value) || !Number.isSafeInteger(number) || number < min)
|
|
551
|
+
badUsage(`${name.startsWith("<") ? name : `--${name}`} takes a whole number from ${min}, not ${value}`);
|
|
552
|
+
return number;
|
|
553
|
+
}
|
|
554
|
+
var DURATION = /^(\d+(?:\.\d+)?)(ms|[smhd])?$/;
|
|
555
|
+
var UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
|
|
556
|
+
function duration(value, name, fallback, unit = "s") {
|
|
557
|
+
if (value === undefined)
|
|
558
|
+
return fallback;
|
|
559
|
+
const match = DURATION.exec(value.trim());
|
|
560
|
+
const ms = match === null ? 0 : Number(match[1]) * UNIT_MS[match[2] ?? unit];
|
|
561
|
+
if (ms < 1)
|
|
562
|
+
badUsage(`--${name} takes a duration such as 30s, 5m, 1h or 7d, not ${value}`);
|
|
563
|
+
return ms;
|
|
564
|
+
}
|
|
565
|
+
function isStdinPiped() {
|
|
566
|
+
const stat = fstatSync(0);
|
|
567
|
+
return stat.isFIFO() || stat.isFile();
|
|
568
|
+
}
|
|
569
|
+
// ../kit/src/process.ts
|
|
570
|
+
import { constants } from "os";
|
|
571
|
+
import process4 from "process";
|
|
572
|
+
var KILL_GRACE_MS = 2000;
|
|
573
|
+
var SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
574
|
+
function exitCodeOf(code, signal) {
|
|
575
|
+
if (code !== null)
|
|
576
|
+
return code;
|
|
577
|
+
if (typeof signal === "number")
|
|
578
|
+
return 128 + signal;
|
|
579
|
+
return signal === null ? 129 : 128 + constants.signals[signal];
|
|
580
|
+
}
|
|
581
|
+
function holdSignals(cleanup) {
|
|
582
|
+
let received;
|
|
583
|
+
let child;
|
|
584
|
+
const held = {
|
|
585
|
+
get signal() {
|
|
586
|
+
return received;
|
|
587
|
+
},
|
|
588
|
+
forward: (to) => {
|
|
589
|
+
child = to;
|
|
590
|
+
},
|
|
591
|
+
release: () => {
|
|
592
|
+
for (const signal of SIGNALS)
|
|
593
|
+
process4.off(signal, onSignal);
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
function onSignal(signal) {
|
|
597
|
+
received = signal;
|
|
598
|
+
if (child !== undefined) {
|
|
599
|
+
child.kill(signal);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
if (cleanup === undefined)
|
|
603
|
+
return;
|
|
604
|
+
held.release();
|
|
605
|
+
cleanup(signal);
|
|
606
|
+
process4.kill(process4.pid, signal);
|
|
607
|
+
}
|
|
608
|
+
for (const signal of SIGNALS)
|
|
609
|
+
process4.on(signal, onSignal);
|
|
610
|
+
return held;
|
|
611
|
+
}
|
|
612
|
+
async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal, maxBytes = Infinity, onChunk, onStart } = {}) {
|
|
613
|
+
const chunks = [];
|
|
614
|
+
const grouped = timeoutMs !== undefined || signal !== undefined || onStart !== undefined || onChunk !== undefined;
|
|
615
|
+
const proc = Bun.spawn(argv, { ...cwd === undefined ? {} : { cwd }, ...env === undefined ? {} : { env }, stdin, stdout: "pipe", stderr: "pipe", ...grouped ? { detached: true } : {} });
|
|
616
|
+
const state = { kept: 0, truncated: false, timedOut: false, failure: undefined, done: false };
|
|
617
|
+
const timers = [];
|
|
618
|
+
const killGroup = (killing) => {
|
|
619
|
+
if (state.done)
|
|
620
|
+
return;
|
|
621
|
+
try {
|
|
622
|
+
if (grouped)
|
|
623
|
+
process4.kill(-proc.pid, killing);
|
|
624
|
+
else
|
|
625
|
+
proc.kill(killing);
|
|
626
|
+
} catch {}
|
|
627
|
+
};
|
|
628
|
+
const stop = () => {
|
|
629
|
+
killGroup("SIGTERM");
|
|
630
|
+
timers.push(setTimeout(killGroup, KILL_GRACE_MS, "SIGKILL"));
|
|
631
|
+
};
|
|
632
|
+
const onAbort = () => stop();
|
|
633
|
+
if (timeoutMs !== undefined) {
|
|
634
|
+
timers.push(setTimeout(() => {
|
|
635
|
+
state.timedOut = true;
|
|
636
|
+
stop();
|
|
637
|
+
}, timeoutMs));
|
|
638
|
+
}
|
|
639
|
+
if (signal?.aborted === true)
|
|
640
|
+
onAbort();
|
|
641
|
+
else
|
|
642
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
643
|
+
onStart?.({ kill: (killing) => killGroup(killing) });
|
|
644
|
+
const drain = async (stream, name) => {
|
|
645
|
+
for await (const data of stream) {
|
|
646
|
+
if (state.failure !== undefined)
|
|
647
|
+
continue;
|
|
648
|
+
try {
|
|
649
|
+
onChunk?.({ stream: name, data });
|
|
650
|
+
} catch (error) {
|
|
651
|
+
state.failure = error;
|
|
652
|
+
stop();
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
if (state.kept + data.length > maxBytes) {
|
|
656
|
+
state.truncated = true;
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
state.kept += data.length;
|
|
660
|
+
chunks.push({ stream: name, data });
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
try {
|
|
664
|
+
await Promise.all([drain(proc.stdout, "stdout"), drain(proc.stderr, "stderr")]);
|
|
665
|
+
await proc.exited;
|
|
666
|
+
} finally {
|
|
667
|
+
state.done = true;
|
|
668
|
+
for (const timer of timers)
|
|
669
|
+
clearTimeout(timer);
|
|
670
|
+
signal?.removeEventListener("abort", onAbort);
|
|
671
|
+
}
|
|
672
|
+
if (state.failure !== undefined)
|
|
673
|
+
throw state.failure;
|
|
674
|
+
const joined = () => Buffer.concat(chunks.map(({ data }) => data));
|
|
675
|
+
let output;
|
|
676
|
+
let text;
|
|
677
|
+
return {
|
|
678
|
+
code: exitCodeOf(proc.exitCode, proc.signalCode),
|
|
679
|
+
chunks,
|
|
680
|
+
timedOut: state.timedOut,
|
|
681
|
+
truncated: state.truncated,
|
|
682
|
+
get output() {
|
|
683
|
+
return output ??= joined();
|
|
684
|
+
},
|
|
685
|
+
get text() {
|
|
686
|
+
return text ??= (output ??= joined()).toString();
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// ../kit/src/progress.ts
|
|
692
|
+
var ESC = String.fromCharCode(27);
|
|
693
|
+
var ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x7E]|\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\))`, "y");
|
|
694
|
+
var RESET_STYLE = `${ESC}[0m`;
|
|
695
|
+
var CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
696
|
+
// ../kit/src/cli.ts
|
|
697
|
+
import process5 from "process";
|
|
698
|
+
var LEVEL_OPTIONS = {
|
|
699
|
+
...OUTPUT_OPTIONS,
|
|
700
|
+
help: { type: "boolean", short: "h", description: "show this help" }
|
|
701
|
+
};
|
|
702
|
+
var TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
|
|
703
|
+
function printError(prefix, message, hint, cause) {
|
|
704
|
+
const colors = paint(process5.stderr);
|
|
705
|
+
const styled = takesControlCodes(process5.stderr);
|
|
706
|
+
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
707
|
+
const under = (label, text, tint) => text === undefined ? "" : `
|
|
708
|
+
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
709
|
+
console.error(`${head} ${message}${under("cause", cause, colors.dim)}${under("hint", hint, colors.yellow)}`);
|
|
710
|
+
}
|
|
711
|
+
function printJsonError(message, hint, cause) {
|
|
712
|
+
console.error(JSON.stringify({ error: message, ...hint === undefined ? {} : { hint }, ...cause === undefined ? {} : { cause } }));
|
|
713
|
+
}
|
|
714
|
+
function wantsJson(argv) {
|
|
715
|
+
const end = argv.indexOf("--");
|
|
716
|
+
return (end === -1 ? argv : argv.slice(0, end)).includes("--json");
|
|
717
|
+
}
|
|
718
|
+
function reportThrown(prefix, error, redact = (text) => text, json = false) {
|
|
719
|
+
if (error instanceof HelpShown)
|
|
720
|
+
return 0;
|
|
721
|
+
const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
|
|
722
|
+
const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
|
|
723
|
+
const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
|
|
724
|
+
const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
|
|
725
|
+
report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
|
|
726
|
+
return error instanceof Exit ? error.code : 1;
|
|
727
|
+
}
|
|
728
|
+
var COMPLETE = "__complete";
|
|
729
|
+
var FILES = "__files__";
|
|
730
|
+
async function optionsOf(run) {
|
|
731
|
+
completion.active = true;
|
|
732
|
+
try {
|
|
733
|
+
await run([]);
|
|
734
|
+
} catch (error) {
|
|
735
|
+
if (error instanceof Completing)
|
|
736
|
+
return error.options;
|
|
737
|
+
} finally {
|
|
738
|
+
completion.active = false;
|
|
739
|
+
}
|
|
740
|
+
return {};
|
|
741
|
+
}
|
|
742
|
+
async function leafCandidates(run, words) {
|
|
743
|
+
if (!(words.at(-1) ?? "").startsWith("-"))
|
|
744
|
+
return [FILES];
|
|
745
|
+
return Object.entries(await optionsOf(run)).map(([name, option]) => option.description === undefined ? `--${name}` : `--${name} ${option.description}`);
|
|
746
|
+
}
|
|
747
|
+
async function printCandidates(found) {
|
|
748
|
+
for (const line of await found)
|
|
749
|
+
console.log(line);
|
|
750
|
+
return 0;
|
|
751
|
+
}
|
|
752
|
+
async function runMain({ name, version, run, redact }, argv = process5.argv.slice(2)) {
|
|
753
|
+
if (argv[0] === COMPLETE)
|
|
754
|
+
return printCandidates(leafCandidates(run, argv.slice(1)));
|
|
755
|
+
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
756
|
+
console.log(version);
|
|
757
|
+
return 0;
|
|
758
|
+
}
|
|
759
|
+
try {
|
|
760
|
+
return await run(argv);
|
|
761
|
+
} catch (error) {
|
|
762
|
+
return reportThrown(name, error, redact, wantsJson(argv));
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
// ../kit/src/logs.ts
|
|
766
|
+
import { lstatSync, openSync } from "fs";
|
|
767
|
+
import { mkdir, mkdtemp, readdir, rm, stat } from "fs/promises";
|
|
768
|
+
import { homedir, tmpdir } from "os";
|
|
769
|
+
import { join } from "path";
|
|
770
|
+
import process6 from "process";
|
|
771
|
+
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
772
|
+
var CLI_FOLDER = "kaynooo-cli";
|
|
773
|
+
function isPrivateDirectory(path) {
|
|
774
|
+
try {
|
|
775
|
+
const info = lstatSync(path, { throwIfNoEntry: false });
|
|
776
|
+
return info !== undefined && info.isDirectory() && info.uid === (process6.getuid?.() ?? info.uid) && (info.mode & 63) === 0;
|
|
777
|
+
} catch {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
async function privateLogDirectory(name, env = process6.env) {
|
|
782
|
+
const runtime = env.XDG_RUNTIME_DIR;
|
|
783
|
+
const base = runtime === undefined || runtime === "" ? join(homedir(), ".cache", CLI_FOLDER) : join(runtime, CLI_FOLDER);
|
|
784
|
+
const path = join(base, name);
|
|
785
|
+
try {
|
|
786
|
+
await mkdir(path, { recursive: true, mode: 448 });
|
|
787
|
+
if (isPrivateDirectory(path))
|
|
788
|
+
return path;
|
|
789
|
+
} catch {}
|
|
790
|
+
return mkdtemp(join(tmpdir(), `${name.replaceAll("/", "-")}-`));
|
|
791
|
+
}
|
|
792
|
+
async function sweepLogs(dir, maxAgeMs = DAY_MS, now = Date.now()) {
|
|
793
|
+
let names;
|
|
794
|
+
try {
|
|
795
|
+
names = await readdir(dir);
|
|
796
|
+
} catch {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
for (const name of names) {
|
|
800
|
+
const path = join(dir, name);
|
|
801
|
+
try {
|
|
802
|
+
const info = await stat(path);
|
|
803
|
+
if (info.isDirectory())
|
|
804
|
+
await sweepLogs(path, maxAgeMs, now);
|
|
805
|
+
if (now - info.mtimeMs > maxAgeMs)
|
|
806
|
+
await rm(path, { force: true, recursive: info.isDirectory() });
|
|
807
|
+
} catch {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function createLog(path) {
|
|
813
|
+
return openSync(path, "wx", 384);
|
|
814
|
+
}
|
|
815
|
+
// ../kit/src/secrets.ts
|
|
816
|
+
var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
|
|
817
|
+
// ../kit/src/sessions.ts
|
|
818
|
+
var {Glob } = globalThis.Bun;
|
|
819
|
+
var SESSION_FILES = new Glob("*.json");
|
|
820
|
+
var ACCOUNT_DIRS = new Glob("*/sessions");
|
|
821
|
+
// package.json
|
|
822
|
+
var version = "0.6.0";
|
|
823
|
+
|
|
824
|
+
// src/shape.ts
|
|
825
|
+
var HEX_LITERAL = /\b0x[0-9a-f]+\b/gi;
|
|
826
|
+
var PATH = /(?:\.{1,2}\/|\/)?[\w.@~-]+(?:\/[\w.@~-]+)+/g;
|
|
827
|
+
var FILE = /\b[\w@~-]+(?:\.[\w-]+)*\.[a-z]\w{0,5}\b/gi;
|
|
828
|
+
var HASH = /\b(?=[0-9a-f]*\d)(?=[0-9a-f]*[a-f])[0-9a-f]{7,}\b/gi;
|
|
829
|
+
var DURATION2 = /\b\d+(?:\.\d+)?\s?(?:ms|\u00B5s|ns|[smh])\b/g;
|
|
830
|
+
var PERCENT = /\b\d+(?:\.\d+)?%/g;
|
|
831
|
+
var NUMBER = /\d+(?:\.\d+)?/g;
|
|
832
|
+
var MAX_SHAPED = 2000;
|
|
833
|
+
var IMPORTANT = /error|fail|warn|panic|exception|fatal|\u2717|\u2718|^\s+at\s+\S|^\s*File ".*", line \d+|^\s*\d+: .+ at /i;
|
|
834
|
+
function isImportant(line) {
|
|
835
|
+
return IMPORTANT.test(stripAnsi(line.slice(0, MAX_SHAPED)));
|
|
836
|
+
}
|
|
837
|
+
function shape(line) {
|
|
838
|
+
return stripAnsi(line.slice(0, MAX_SHAPED)).replaceAll(HEX_LITERAL, "<hex>").replaceAll(PATH, "<path>").replaceAll(FILE, "<file>").replaceAll(HASH, "<hex>").replaceAll(DURATION2, "<time>").replaceAll(PERCENT, "<pct>").replaceAll(NUMBER, "<n>").trimEnd();
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// src/fold.ts
|
|
842
|
+
var FOLD_LINES = 150;
|
|
843
|
+
var HEAD = 40;
|
|
844
|
+
var TAIL = 60;
|
|
845
|
+
var MAX_BLOCK = 20;
|
|
846
|
+
var MIN_REFERENCED = 20;
|
|
847
|
+
var TOP_REPEATED = 3;
|
|
848
|
+
var LINE_BREAK = /\r\n|\r|\n/;
|
|
849
|
+
var LINE_END = /(?:\r\n|\r|\n)$/;
|
|
850
|
+
function lineCount(text) {
|
|
851
|
+
if (text === "")
|
|
852
|
+
return 0;
|
|
853
|
+
const count = text.split(LINE_BREAK).length;
|
|
854
|
+
return LINE_END.test(text) ? count - 1 : count;
|
|
855
|
+
}
|
|
856
|
+
function shouldFold(text, threshold) {
|
|
857
|
+
return lineCount(text) > threshold;
|
|
858
|
+
}
|
|
859
|
+
function finalState(line) {
|
|
860
|
+
const segments = line.split("\r").filter((segment) => segment !== "");
|
|
861
|
+
return segments.at(-1) ?? "";
|
|
862
|
+
}
|
|
863
|
+
function splitLines(text) {
|
|
864
|
+
const lines = text.replaceAll(`\r
|
|
865
|
+
`, `
|
|
866
|
+
`).split(`
|
|
867
|
+
`).map((line) => line.includes("\r") ? finalState(line) : line);
|
|
868
|
+
return text.endsWith(`
|
|
869
|
+
`) ? lines.slice(0, -1) : lines;
|
|
870
|
+
}
|
|
871
|
+
function repeats(keys, at, size) {
|
|
872
|
+
if (keys[at] !== keys[at + size])
|
|
873
|
+
return false;
|
|
874
|
+
for (let offset = 1;offset < size; offset++) {
|
|
875
|
+
if (keys[at + offset] !== keys[at + size + offset])
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
return true;
|
|
879
|
+
}
|
|
880
|
+
function toUnits(lines, keys) {
|
|
881
|
+
const units = [];
|
|
882
|
+
for (let at = 0;at < lines.length; ) {
|
|
883
|
+
let size = 1;
|
|
884
|
+
let reps = 1;
|
|
885
|
+
for (let candidate = 1;candidate <= MAX_BLOCK && at + candidate * 2 <= lines.length; candidate++) {
|
|
886
|
+
let count = 1;
|
|
887
|
+
while (at + (count + 1) * candidate <= lines.length && repeats(keys, at + (count - 1) * candidate, candidate))
|
|
888
|
+
count++;
|
|
889
|
+
if (count > 1 && candidate * count > size * reps) {
|
|
890
|
+
size = candidate;
|
|
891
|
+
reps = count;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
const slice = lines.slice(at, at + size);
|
|
895
|
+
units.push({
|
|
896
|
+
start: at,
|
|
897
|
+
size,
|
|
898
|
+
reps,
|
|
899
|
+
lines: slice,
|
|
900
|
+
last: lines[at + size * reps - 1] ?? "",
|
|
901
|
+
key: keys.slice(at, at + size).join(`
|
|
902
|
+
`),
|
|
903
|
+
important: slice.some((line) => isImportant(line))
|
|
904
|
+
});
|
|
905
|
+
at += size * reps;
|
|
906
|
+
}
|
|
907
|
+
return units;
|
|
908
|
+
}
|
|
909
|
+
function clip(line, width = 100) {
|
|
910
|
+
const trimmed = line.trim();
|
|
911
|
+
return trimmed.length > width ? `${trimmed.slice(0, width)}...` : trimmed;
|
|
912
|
+
}
|
|
913
|
+
function toEntries(units) {
|
|
914
|
+
const entries = [];
|
|
915
|
+
const firstSeen = new Map;
|
|
916
|
+
const counts = new Map;
|
|
917
|
+
let references = false;
|
|
918
|
+
for (const unit of units) {
|
|
919
|
+
const seen = counts.get(unit.key);
|
|
920
|
+
counts.set(unit.key, { count: (seen?.count ?? 0) + unit.reps, sample: seen?.sample ?? clip(unit.lines[0] ?? "") });
|
|
921
|
+
const earlier = firstSeen.get(unit.key);
|
|
922
|
+
const covers = unit.size * unit.reps;
|
|
923
|
+
if (earlier !== undefined && (unit.size > 1 || unit.key.length >= MIN_REFERENCED)) {
|
|
924
|
+
references = true;
|
|
925
|
+
const where = unit.size > 1 ? `block same as line ${earlier}` : `same as line ${earlier}`;
|
|
926
|
+
const times = unit.reps > 1 ? `, repeated ${unit.reps} times` : "";
|
|
927
|
+
const prefix = unit.important ? `${clip(unit.lines[0] ?? "")} ` : "";
|
|
928
|
+
entries.push({ text: `${prefix}(${where}${times})`, important: unit.important, covers });
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
firstSeen.set(unit.key, unit.start + 1);
|
|
932
|
+
if (unit.reps === 1) {
|
|
933
|
+
entries.push(...unit.lines.map((text) => ({ text, important: unit.important, covers: 1 })));
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (unit.size === 1) {
|
|
937
|
+
const first = unit.lines[0] ?? "";
|
|
938
|
+
const ending = unit.last === first ? "" : `, last: ${clip(unit.last)}`;
|
|
939
|
+
entries.push({ text: `${first} (x${unit.reps}${ending})`, important: unit.important, covers });
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
entries.push(...unit.lines.map((text) => ({ text, important: unit.important, covers: unit.reps })));
|
|
943
|
+
entries.push({ text: `(block repeated ${unit.reps} times)`, important: unit.important, covers: 0 });
|
|
944
|
+
}
|
|
945
|
+
const repeated = [...counts.values()].filter(({ count }) => count >= 2).sort((a, b) => b.count - a.count).slice(0, TOP_REPEATED).map(({ count, sample }) => `${count}x ${sample}`);
|
|
946
|
+
return { entries, references, repeated };
|
|
947
|
+
}
|
|
948
|
+
function fold(text, { threshold, logPath }) {
|
|
949
|
+
const lines = splitLines(text);
|
|
950
|
+
const { entries, references, repeated } = toEntries(toUnits(lines, lines.map((line) => shape(line))));
|
|
951
|
+
const head = Math.min(HEAD, Math.floor(threshold / 3));
|
|
952
|
+
const tail = Math.min(TAIL, Math.floor(threshold / 2));
|
|
953
|
+
const out = [];
|
|
954
|
+
let dropped = 0;
|
|
955
|
+
if (entries.length <= threshold) {
|
|
956
|
+
out.push(...entries.map(({ text }) => text));
|
|
957
|
+
} else {
|
|
958
|
+
const middleEnd = entries.length - tail;
|
|
959
|
+
let gap = 0;
|
|
960
|
+
const closeGap = () => {
|
|
961
|
+
if (gap > 0)
|
|
962
|
+
out.push(`[out: ${gap} lines left out]`);
|
|
963
|
+
dropped += gap;
|
|
964
|
+
gap = 0;
|
|
965
|
+
};
|
|
966
|
+
for (const [index, entry] of entries.entries()) {
|
|
967
|
+
if (index < head || index >= middleEnd) {
|
|
968
|
+
closeGap();
|
|
969
|
+
out.push(entry.text);
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (entry.important) {
|
|
973
|
+
closeGap();
|
|
974
|
+
out.push(entry.text);
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
gap += entry.covers;
|
|
978
|
+
}
|
|
979
|
+
closeGap();
|
|
980
|
+
}
|
|
981
|
+
const note = references ? ' (line numbers in "same as line N" refer to it)' : "";
|
|
982
|
+
const header = [`[out: ${lines.length} lines, ${dropped} left out, full log: ${logPath}${note}]`];
|
|
983
|
+
if (repeated.length > 0)
|
|
984
|
+
header.push(`[out: most repeated: ${repeated.join(", ")}]`);
|
|
985
|
+
return `${[...header, ...out].join(`
|
|
986
|
+
`)}
|
|
987
|
+
`;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// src/run.ts
|
|
991
|
+
import { closeSync, rmSync, writeSync } from "fs";
|
|
992
|
+
import process10 from "process";
|
|
993
|
+
|
|
994
|
+
// src/logs.ts
|
|
995
|
+
import { join as join2 } from "path";
|
|
996
|
+
import process8 from "process";
|
|
997
|
+
var MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
998
|
+
async function logDir() {
|
|
999
|
+
return privateLogDirectory("out");
|
|
1000
|
+
}
|
|
1001
|
+
async function cleanLogs(dir, now = Date.now()) {
|
|
1002
|
+
await sweepLogs(dir, MAX_AGE_MS, now);
|
|
1003
|
+
}
|
|
1004
|
+
function newLog(dir) {
|
|
1005
|
+
const path = join2(dir, `${new Date().toISOString().replaceAll(/[:.]/g, "-")}-${process8.pid}.log`);
|
|
1006
|
+
return { path, fd: createLog(path) };
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// ../kit/src/shell.ts
|
|
1010
|
+
var SEPARATORS = new Set([`
|
|
1011
|
+
`, ";", "|"]);
|
|
1012
|
+
var PLAIN_BREAKERS = new Set(["<", ">", "(", ")", "&", "|"]);
|
|
1013
|
+
var GLOB_CHARS = new Set(["*", "?", "["]);
|
|
1014
|
+
var COMMENT_PREFIXES = new Set([";", "&", "|", "(", ")"]);
|
|
1015
|
+
var WHITESPACE = /\s/;
|
|
1016
|
+
var LEADING_HEX = /^[\da-f]*/i;
|
|
1017
|
+
var DOUBLE_QUOTED_ESCAPES = new Set(["$", "`", '"', "\\"]);
|
|
1018
|
+
var ANSI_QUOTE = "$'";
|
|
1019
|
+
var ANSI_ESCAPES = { n: `
|
|
1020
|
+
`, t: "\t", r: "\r", a: "\x07", b: "\b", f: "\f", v: "\v", e: "\x1B", E: "\x1B", "\\": "\\", "'": "'", '"': '"', "?": "?" };
|
|
1021
|
+
var ANSI_DIGITS = { x: 2, u: 4, U: 8 };
|
|
1022
|
+
var OCTAL = /^[0-7]{1,3}/;
|
|
1023
|
+
var KEYWORDS = new Set(["then", "do", "else", "if", "elif", "while", "until", "!", "{", "}"]);
|
|
1024
|
+
var SHELLS = new Set(["sh", "bash", "zsh", "dash", "ash", "ksh"]);
|
|
1025
|
+
var COMMAND_STRING_PROGRAMS = new Set([...SHELLS, "su", "runuser"]);
|
|
1026
|
+
var SHELL_VALUE_OPTIONS = new Set(["-o", "-O", "--rcfile", "--init-file"]);
|
|
1027
|
+
var PRINTERS = new Set(["echo", "printf"]);
|
|
1028
|
+
var FIND_EXEC = new Set(["-exec", "-execdir", "-ok", "-okdir"]);
|
|
1029
|
+
function wrapper(short = "", long = [], operands = 0) {
|
|
1030
|
+
return { short, long, operands };
|
|
1031
|
+
}
|
|
1032
|
+
var WRAPPERS = new Map([
|
|
1033
|
+
["command", wrapper()],
|
|
1034
|
+
["builtin", wrapper()],
|
|
1035
|
+
["nohup", wrapper()],
|
|
1036
|
+
["setsid", wrapper()],
|
|
1037
|
+
["busybox", wrapper()],
|
|
1038
|
+
["exec", wrapper("a")],
|
|
1039
|
+
["time", wrapper("fo", ["--format", "--output"])],
|
|
1040
|
+
["env", wrapper("uCS", ["--unset", "--chdir", "--split-string", "--argv0"])],
|
|
1041
|
+
["sudo", wrapper("ughpCTrtUDR", ["--user", "--group", "--host", "--prompt", "--close-from", "--command-timeout", "--role", "--type", "--other-user", "--chdir", "--chroot"])],
|
|
1042
|
+
["doas", wrapper("uC")],
|
|
1043
|
+
["timeout", wrapper("sk", ["--signal", "--kill-after"], 1)],
|
|
1044
|
+
["nice", wrapper("n", ["--adjustment"])],
|
|
1045
|
+
["ionice", wrapper("cnpPu", ["--class", "--classdata", "--pid", "--pgid", "--uid"])],
|
|
1046
|
+
["stdbuf", wrapper("ioe", ["--input", "--output", "--error"])],
|
|
1047
|
+
["chroot", wrapper("", ["--userspec", "--groups"], 1)],
|
|
1048
|
+
["xargs", wrapper("IndsEaPL", ["--max-args", "--max-procs", "--max-chars", "--delimiter", "--arg-file", "--eof", "--max-lines", "--process-slot-var"])]
|
|
1049
|
+
]);
|
|
1050
|
+
function closerOf(quote) {
|
|
1051
|
+
return quote === ANSI_QUOTE ? "'" : quote;
|
|
1052
|
+
}
|
|
1053
|
+
function ansiEscape(text, at) {
|
|
1054
|
+
const letter = text[at + 1] ?? "";
|
|
1055
|
+
const simple = ANSI_ESCAPES[letter];
|
|
1056
|
+
if (simple !== undefined)
|
|
1057
|
+
return [simple, at + 1];
|
|
1058
|
+
const hex = LEADING_HEX.exec(text.slice(at + 2, at + 2 + (ANSI_DIGITS[letter] ?? 0)))?.[0] ?? "";
|
|
1059
|
+
if (hex !== "")
|
|
1060
|
+
return [String.fromCodePoint(Number.parseInt(hex, 16)), at + 1 + hex.length];
|
|
1061
|
+
const octal = OCTAL.exec(text.slice(at + 1))?.[0];
|
|
1062
|
+
if (octal !== undefined)
|
|
1063
|
+
return [String.fromCodePoint(Number.parseInt(octal, 8)), at + octal.length];
|
|
1064
|
+
return [`\\${letter}`, at + 1];
|
|
1065
|
+
}
|
|
1066
|
+
function words(text) {
|
|
1067
|
+
const found = [];
|
|
1068
|
+
let current = "";
|
|
1069
|
+
let isStarted = false;
|
|
1070
|
+
let isProse = false;
|
|
1071
|
+
let hasGlob = false;
|
|
1072
|
+
let hasBrace = false;
|
|
1073
|
+
let quote = null;
|
|
1074
|
+
for (let i = 0;i < text.length; i++) {
|
|
1075
|
+
const char = text[i] ?? "";
|
|
1076
|
+
const isContinuation = char === "\\" && quote !== "'" && text[i + 1] === `
|
|
1077
|
+
`;
|
|
1078
|
+
if (isContinuation)
|
|
1079
|
+
i++;
|
|
1080
|
+
if (quote === null && (isContinuation || WHITESPACE.test(char))) {
|
|
1081
|
+
if (isStarted)
|
|
1082
|
+
found.push({ text: current, isProse, hasGlob, hasBrace });
|
|
1083
|
+
current = "";
|
|
1084
|
+
isStarted = false;
|
|
1085
|
+
isProse = false;
|
|
1086
|
+
hasGlob = false;
|
|
1087
|
+
hasBrace = false;
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
if (isContinuation)
|
|
1091
|
+
continue;
|
|
1092
|
+
isStarted = true;
|
|
1093
|
+
if (char === "\\" && quote === ANSI_QUOTE) {
|
|
1094
|
+
const [decoded, last] = ansiEscape(text, i);
|
|
1095
|
+
current += decoded;
|
|
1096
|
+
i = last;
|
|
1097
|
+
} else if (char === "\\" && quote === '"' && !DOUBLE_QUOTED_ESCAPES.has(text[i + 1] ?? "")) {
|
|
1098
|
+
current += char;
|
|
1099
|
+
} else if (char === "\\" && quote !== "'") {
|
|
1100
|
+
current += text[++i] ?? "";
|
|
1101
|
+
} else if (quote !== null && char === closerOf(quote)) {
|
|
1102
|
+
quote = null;
|
|
1103
|
+
} else if (quote === null && char === "$" && text[i + 1] === "'") {
|
|
1104
|
+
quote = ANSI_QUOTE;
|
|
1105
|
+
i++;
|
|
1106
|
+
} else if (quote === null && (char === '"' || char === "'")) {
|
|
1107
|
+
quote = char;
|
|
1108
|
+
} else {
|
|
1109
|
+
current += char;
|
|
1110
|
+
hasGlob ||= quote === null && GLOB_CHARS.has(char);
|
|
1111
|
+
hasBrace ||= quote === null && char === "{";
|
|
1112
|
+
}
|
|
1113
|
+
isProse ||= quote !== null && WHITESPACE.test(char);
|
|
1114
|
+
}
|
|
1115
|
+
if (isStarted)
|
|
1116
|
+
found.push({ text: current, isProse, hasGlob, hasBrace });
|
|
1117
|
+
return found;
|
|
1118
|
+
}
|
|
1119
|
+
function tokenize(text) {
|
|
1120
|
+
return words(text).map((word) => word.text);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// src/stages.ts
|
|
1124
|
+
var DIGITS = /^\d+$/;
|
|
1125
|
+
var SIGNED = /^[+-]?\d+$/;
|
|
1126
|
+
var SHORT_COUNT = /^-(\d+)$/;
|
|
1127
|
+
var GREP_FLAGS = new Set(["i", "v", "E", "F", "w", "x", "n", "H", "h", "s", "a", "I", "P", "G"]);
|
|
1128
|
+
var GREP_VALUES = new Set(["e", "m", "A", "B", "C"]);
|
|
1129
|
+
var LONG_VALUE = /^--(lines|regexp|max-count|after-context|before-context|context)=(.*)$/;
|
|
1130
|
+
var LONG_NAMES = { lines: "n", regexp: "e", "max-count": "m", "after-context": "A", "before-context": "B", context: "C" };
|
|
1131
|
+
var LONG_FLAGS = { "--ignore-case": "i", "--invert-match": "v", "--extended-regexp": "E", "--fixed-strings": "F", "--word-regexp": "w", "--line-regexp": "x", "--line-number": "n" };
|
|
1132
|
+
var REGEX_SPECIAL = /[.*+?^${}()|[\]\\]/g;
|
|
1133
|
+
var BASIC_SWAPPED = new Set(["(", ")", "|", "+", "?", "{", "}"]);
|
|
1134
|
+
var DEFAULT_LINES = 10;
|
|
1135
|
+
function options(args, flags, valued) {
|
|
1136
|
+
const read = { flags: new Set, values: new Map, operands: [] };
|
|
1137
|
+
const add = (name, value) => read.values.set(name, [...read.values.get(name) ?? [], value]);
|
|
1138
|
+
for (let i = 0;i < args.length; i++) {
|
|
1139
|
+
const arg = args[i] ?? "";
|
|
1140
|
+
const long = LONG_VALUE.exec(arg);
|
|
1141
|
+
const count = SHORT_COUNT.exec(arg);
|
|
1142
|
+
if (long !== null) {
|
|
1143
|
+
add(LONG_NAMES[long[1] ?? ""] ?? "", long[2] ?? "");
|
|
1144
|
+
} else if (LONG_FLAGS[arg] !== undefined) {
|
|
1145
|
+
read.flags.add(LONG_FLAGS[arg]);
|
|
1146
|
+
} else if (count !== null) {
|
|
1147
|
+
add("count", count[1] ?? "");
|
|
1148
|
+
} else if (arg.startsWith("-") && arg.length > 1 && !arg.startsWith("--")) {
|
|
1149
|
+
for (const [at, letter] of [...arg.slice(1)].entries()) {
|
|
1150
|
+
if (valued.has(letter)) {
|
|
1151
|
+
const glued = arg.slice(at + 2);
|
|
1152
|
+
add(letter, glued === "" ? args[++i] ?? "" : glued);
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
if (!flags.has(letter))
|
|
1156
|
+
return;
|
|
1157
|
+
read.flags.add(letter);
|
|
1158
|
+
}
|
|
1159
|
+
} else if (arg.startsWith("--")) {
|
|
1160
|
+
return;
|
|
1161
|
+
} else {
|
|
1162
|
+
read.operands.push(arg);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return read;
|
|
1166
|
+
}
|
|
1167
|
+
function cut(lines, bin, args) {
|
|
1168
|
+
const read = options(args, new Set(["q", "v"]), new Set(["n"]));
|
|
1169
|
+
const value = read?.values.get("n")?.at(-1) ?? read?.values.get("count")?.at(-1) ?? String(DEFAULT_LINES);
|
|
1170
|
+
if (read === undefined || read.operands.length > 0 || !SIGNED.test(value))
|
|
1171
|
+
return;
|
|
1172
|
+
const n = Math.abs(Number(value));
|
|
1173
|
+
if (bin === "tail")
|
|
1174
|
+
return value.startsWith("+") ? lines.slice(Math.max(0, n - 1)) : lines.slice(Math.max(0, lines.length - n));
|
|
1175
|
+
return value.startsWith("-") ? lines.slice(0, Math.max(0, lines.length - n)) : lines.slice(0, n);
|
|
1176
|
+
}
|
|
1177
|
+
function patternSource(pattern, read) {
|
|
1178
|
+
if (read.flags.has("F"))
|
|
1179
|
+
return pattern.replaceAll(REGEX_SPECIAL, "\\$&");
|
|
1180
|
+
if (read.flags.has("E") || read.flags.has("P"))
|
|
1181
|
+
return pattern;
|
|
1182
|
+
let source = "";
|
|
1183
|
+
for (let i = 0;i < pattern.length; i++) {
|
|
1184
|
+
const char = pattern[i] ?? "";
|
|
1185
|
+
const next = pattern[i + 1] ?? "";
|
|
1186
|
+
if (char === "\\" && BASIC_SWAPPED.has(next)) {
|
|
1187
|
+
source += next;
|
|
1188
|
+
i++;
|
|
1189
|
+
} else if (char === "\\") {
|
|
1190
|
+
source += `${char}${next}`;
|
|
1191
|
+
i++;
|
|
1192
|
+
} else {
|
|
1193
|
+
source += BASIC_SWAPPED.has(char) ? `\\${char}` : char;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return source;
|
|
1197
|
+
}
|
|
1198
|
+
function anchoredSource(source, flags) {
|
|
1199
|
+
if (flags.has("x"))
|
|
1200
|
+
return `^(?:${source})$`;
|
|
1201
|
+
return flags.has("w") ? `\\b(?:${source})\\b` : source;
|
|
1202
|
+
}
|
|
1203
|
+
function search(lines, args) {
|
|
1204
|
+
const read = options(args, GREP_FLAGS, GREP_VALUES);
|
|
1205
|
+
if (read === undefined)
|
|
1206
|
+
return;
|
|
1207
|
+
const patterns = read.values.get("e") ?? read.operands.splice(0, 1);
|
|
1208
|
+
const numbers = ["A", "B", "C", "m", "count"].map((name) => read.values.get(name)?.at(-1));
|
|
1209
|
+
if (patterns.length === 0 || read.operands.length > 0 || numbers.some((each) => each !== undefined && !DIGITS.test(each)))
|
|
1210
|
+
return;
|
|
1211
|
+
const [after, before, context, max, count] = numbers.map((each) => each === undefined ? undefined : Number(each));
|
|
1212
|
+
let regex;
|
|
1213
|
+
try {
|
|
1214
|
+
const source = patterns.map((pattern) => `(?:${patternSource(pattern, read)})`).join("|");
|
|
1215
|
+
regex = new RegExp(anchoredSource(source, read.flags), read.flags.has("i") ? "i" : "");
|
|
1216
|
+
} catch {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
const matched = [];
|
|
1220
|
+
for (const [index, line] of lines.entries()) {
|
|
1221
|
+
if (regex.test(line) !== read.flags.has("v"))
|
|
1222
|
+
matched.push(index);
|
|
1223
|
+
if (max !== undefined && matched.length >= max)
|
|
1224
|
+
break;
|
|
1225
|
+
}
|
|
1226
|
+
const ahead = before ?? context ?? count ?? 0;
|
|
1227
|
+
const behind = after ?? context ?? count ?? 0;
|
|
1228
|
+
const kept = [];
|
|
1229
|
+
let last = -1;
|
|
1230
|
+
for (const index of matched) {
|
|
1231
|
+
const from = Math.max(last + 1, index - ahead);
|
|
1232
|
+
if (last >= 0 && from > last + 1 && ahead + behind > 0)
|
|
1233
|
+
kept.push("--");
|
|
1234
|
+
for (let at = from;at <= Math.min(lines.length - 1, index + behind); at++)
|
|
1235
|
+
kept.push(lines[at] ?? "");
|
|
1236
|
+
last = Math.max(last, Math.min(lines.length - 1, index + behind));
|
|
1237
|
+
}
|
|
1238
|
+
return kept;
|
|
1239
|
+
}
|
|
1240
|
+
function filtered(text, stages) {
|
|
1241
|
+
const ended = text.endsWith(`
|
|
1242
|
+
`);
|
|
1243
|
+
let lines = (ended ? text.slice(0, -1) : text).split(`
|
|
1244
|
+
`);
|
|
1245
|
+
for (const stage of stages) {
|
|
1246
|
+
const [bin = "", ...args] = tokenize(stage);
|
|
1247
|
+
if (bin === "grep")
|
|
1248
|
+
lines = search(lines, args);
|
|
1249
|
+
else
|
|
1250
|
+
lines = bin === "tail" || bin === "head" ? cut(lines, bin, args) : undefined;
|
|
1251
|
+
if (lines === undefined)
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
return lines.length === 0 ? "" : `${lines.join(`
|
|
1255
|
+
`)}${ended ? `
|
|
1256
|
+
` : ""}`;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// src/stats.ts
|
|
1260
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
1261
|
+
import { homedir as homedir2 } from "os";
|
|
1262
|
+
import { basename, dirname, join as join3 } from "path";
|
|
1263
|
+
import process9 from "process";
|
|
1264
|
+
var BYTES_PER_TOKEN = 4;
|
|
1265
|
+
var KEY_WORD = /^[a-z][a-z:_-]*$/;
|
|
1266
|
+
var KEY_WORDS = 3;
|
|
1267
|
+
var BLANKS = /\s+/;
|
|
1268
|
+
var ASSIGNMENT = /^\w+=/;
|
|
1269
|
+
var CHAIN = /&&|\|\||;/;
|
|
1270
|
+
var SHELLS2 = new Set(["sh", "bash", "zsh"]);
|
|
1271
|
+
var TOP = 10;
|
|
1272
|
+
function statsPath(env = process9.env) {
|
|
1273
|
+
return join3(env.XDG_STATE_HOME ?? join3(homedir2(), ".local", "state"), CLI_FOLDER, "out", "stats.jsonl");
|
|
1274
|
+
}
|
|
1275
|
+
function commandKey(command) {
|
|
1276
|
+
const [program = "", ...rest] = command.slice(Math.max(0, command.findIndex((word) => !ASSIGNMENT.test(word))));
|
|
1277
|
+
if (SHELLS2.has(basename(program)) && rest[0] === "-c" && rest[1] !== undefined) {
|
|
1278
|
+
const chain = rest[1].split(CHAIN).map((segment) => segment.trim()).filter((segment) => segment !== "" && segment !== "cd" && !segment.startsWith("cd "));
|
|
1279
|
+
return commandKey((chain.at(-1) ?? "").split(BLANKS));
|
|
1280
|
+
}
|
|
1281
|
+
const words = [basename(program)];
|
|
1282
|
+
for (const word of rest) {
|
|
1283
|
+
if (words.length === KEY_WORDS || !KEY_WORD.test(word))
|
|
1284
|
+
break;
|
|
1285
|
+
words.push(word);
|
|
1286
|
+
}
|
|
1287
|
+
return words.join(" ");
|
|
1288
|
+
}
|
|
1289
|
+
function record(entry, path = statsPath()) {
|
|
1290
|
+
try {
|
|
1291
|
+
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
1292
|
+
appendFileSync(path, `${JSON.stringify(entry)}
|
|
1293
|
+
`, { mode: 384 });
|
|
1294
|
+
} catch {}
|
|
1295
|
+
}
|
|
1296
|
+
async function readEntries(path = statsPath(), since = 0) {
|
|
1297
|
+
const file = Bun.file(path);
|
|
1298
|
+
if (!await file.exists())
|
|
1299
|
+
return [];
|
|
1300
|
+
return (await file.text()).split(`
|
|
1301
|
+
`).flatMap((line) => {
|
|
1302
|
+
try {
|
|
1303
|
+
const entry = JSON.parse(line);
|
|
1304
|
+
return Date.parse(entry.at) >= since ? [entry] : [];
|
|
1305
|
+
} catch {
|
|
1306
|
+
return [];
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
function tokens(bytes) {
|
|
1311
|
+
return Math.round(bytes / BYTES_PER_TOKEN);
|
|
1312
|
+
}
|
|
1313
|
+
function formatNumber(value) {
|
|
1314
|
+
return value.toLocaleString("en-US");
|
|
1315
|
+
}
|
|
1316
|
+
function summarize(entries) {
|
|
1317
|
+
const commands = Map.groupBy(entries, (entry) => entry.command).entries().map(([command, runs]) => ({
|
|
1318
|
+
command,
|
|
1319
|
+
runs: runs.length,
|
|
1320
|
+
folded: runs.filter((run) => run.folded).length,
|
|
1321
|
+
tokensSaved: tokens(runs.reduce((sum, run) => sum + run.baseline - run.shown, 0))
|
|
1322
|
+
}));
|
|
1323
|
+
const sum = (field) => entries.reduce((total, entry) => total + entry[field], 0);
|
|
1324
|
+
return { runs: entries.length, folded: entries.filter((entry) => entry.folded).length, bytes: sum("bytes"), shown: sum("shown"), tokensSaved: tokens(sum("baseline") - sum("shown")), commands: [...commands].sort((a, b) => b.tokensSaved - a.tokensSaved) };
|
|
1325
|
+
}
|
|
1326
|
+
function renderSummary(summary, period) {
|
|
1327
|
+
if (summary.runs === 0)
|
|
1328
|
+
return `no run of out recorded ${period}`;
|
|
1329
|
+
const top = summary.commands.slice(0, TOP).filter((each) => each.tokensSaved !== 0);
|
|
1330
|
+
return [
|
|
1331
|
+
`${formatNumber(summary.runs)} runs ${period}, ${formatNumber(summary.folded)} folded: ${formatNumber(summary.bytes)} bytes printed, ${formatNumber(summary.shown)} shown, about ${formatNumber(summary.tokensSaved)} tokens saved (bytes / ${BYTES_PER_TOKEN})`,
|
|
1332
|
+
...top.length === 0 ? [] : ["", table([["command", "runs", "folded", "tokens saved"], ...top.map((each) => [each.command, formatNumber(each.runs), formatNumber(each.folded), formatNumber(each.tokensSaved)])])]
|
|
1333
|
+
].join(`
|
|
1334
|
+
`);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// src/run.ts
|
|
1338
|
+
var HEAD_BYTES = 2 * 1024 * 1024;
|
|
1339
|
+
var TAIL_BYTES = 2 * 1024 * 1024;
|
|
1340
|
+
var FALLBACK_LINES = 100;
|
|
1341
|
+
|
|
1342
|
+
class Recorder {
|
|
1343
|
+
dir;
|
|
1344
|
+
head = [];
|
|
1345
|
+
tail = [];
|
|
1346
|
+
headBytes = 0;
|
|
1347
|
+
tailBytes = 0;
|
|
1348
|
+
dropped = 0;
|
|
1349
|
+
log;
|
|
1350
|
+
constructor(dir) {
|
|
1351
|
+
this.dir = dir;
|
|
1352
|
+
}
|
|
1353
|
+
add(chunk) {
|
|
1354
|
+
if (this.headBytes < HEAD_BYTES) {
|
|
1355
|
+
this.head.push(chunk);
|
|
1356
|
+
this.headBytes += chunk.data.length;
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
writeSync(this.startLog().fd, chunk.data);
|
|
1360
|
+
this.tail.push(chunk);
|
|
1361
|
+
this.tailBytes += chunk.data.length;
|
|
1362
|
+
while (this.tail.length > 1 && this.tailBytes - (this.tail[0]?.data.length ?? 0) >= TAIL_BYTES) {
|
|
1363
|
+
const gone = this.tail.shift();
|
|
1364
|
+
this.tailBytes -= gone?.data.length ?? 0;
|
|
1365
|
+
this.dropped += gone?.data.length ?? 0;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
startLog() {
|
|
1369
|
+
if (this.log !== undefined)
|
|
1370
|
+
return this.log;
|
|
1371
|
+
this.log = newLog(this.dir);
|
|
1372
|
+
for (const chunk of [...this.head, ...this.tail])
|
|
1373
|
+
writeSync(this.log.fd, chunk.data);
|
|
1374
|
+
return this.log;
|
|
1375
|
+
}
|
|
1376
|
+
get overflowing() {
|
|
1377
|
+
return this.dropped > 0;
|
|
1378
|
+
}
|
|
1379
|
+
get bytes() {
|
|
1380
|
+
return this.headBytes + this.tailBytes + this.dropped;
|
|
1381
|
+
}
|
|
1382
|
+
get chunks() {
|
|
1383
|
+
return [...this.head, ...this.tail];
|
|
1384
|
+
}
|
|
1385
|
+
save() {
|
|
1386
|
+
return this.startLog().path;
|
|
1387
|
+
}
|
|
1388
|
+
discard() {
|
|
1389
|
+
if (this.log === undefined)
|
|
1390
|
+
return;
|
|
1391
|
+
closeSync(this.log.fd);
|
|
1392
|
+
rmSync(this.log.path, { force: true });
|
|
1393
|
+
this.log = undefined;
|
|
1394
|
+
}
|
|
1395
|
+
get text() {
|
|
1396
|
+
const decode = (chunks) => Buffer.concat(chunks.map(({ data }) => data)).toString();
|
|
1397
|
+
if (this.dropped === 0)
|
|
1398
|
+
return decode(this.chunks);
|
|
1399
|
+
return `${decode(this.head)}
|
|
1400
|
+
[out: ${this.dropped} bytes left out of memory, all of it is in the log]
|
|
1401
|
+
${decode(this.tail)}`;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
function replay(chunks) {
|
|
1405
|
+
for (const { stream, data } of chunks)
|
|
1406
|
+
process10[stream].write(data);
|
|
1407
|
+
}
|
|
1408
|
+
function count(recorder, shown, recorded) {
|
|
1409
|
+
const baseline = recorded.was.length === 0 || recorder.overflowing ? undefined : filtered(recorder.text, recorded.was);
|
|
1410
|
+
record({ at: new Date().toISOString(), dir: process10.cwd(), command: recorded.command, bytes: recorder.bytes, baseline: baseline === undefined ? recorder.bytes : Buffer.byteLength(baseline), shown, folded: shown !== recorder.bytes });
|
|
1411
|
+
}
|
|
1412
|
+
async function run(command, threshold, was = []) {
|
|
1413
|
+
const dir = await logDir();
|
|
1414
|
+
await cleanLogs(dir);
|
|
1415
|
+
const recorder = new Recorder(dir);
|
|
1416
|
+
const held = holdSignals();
|
|
1417
|
+
let started = false;
|
|
1418
|
+
let code;
|
|
1419
|
+
try {
|
|
1420
|
+
const ran = await runCommand(command, {
|
|
1421
|
+
stdin: "inherit",
|
|
1422
|
+
maxBytes: 0,
|
|
1423
|
+
onStart: (child) => {
|
|
1424
|
+
started = true;
|
|
1425
|
+
held.forward(child);
|
|
1426
|
+
},
|
|
1427
|
+
onChunk: (chunk) => {
|
|
1428
|
+
recorder.add(chunk);
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
code = ran.code;
|
|
1432
|
+
} catch (error) {
|
|
1433
|
+
if (!started) {
|
|
1434
|
+
console.error(`out: cannot run ${command[0]}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1435
|
+
return 127;
|
|
1436
|
+
}
|
|
1437
|
+
console.error(`out: ${error instanceof Error ? error.message : String(error)}`);
|
|
1438
|
+
code = 1;
|
|
1439
|
+
} finally {
|
|
1440
|
+
held.release();
|
|
1441
|
+
}
|
|
1442
|
+
count(recorder, present(recorder, threshold), { command: commandKey(command), was });
|
|
1443
|
+
return code;
|
|
1444
|
+
}
|
|
1445
|
+
async function readPiped(threshold, was = []) {
|
|
1446
|
+
const dir = await logDir();
|
|
1447
|
+
await cleanLogs(dir);
|
|
1448
|
+
const recorder = new Recorder(dir);
|
|
1449
|
+
for await (const data of Bun.stdin.stream())
|
|
1450
|
+
recorder.add({ stream: "stdout", data });
|
|
1451
|
+
count(recorder, present(recorder, threshold), { command: "(piped)", was });
|
|
1452
|
+
return 0;
|
|
1453
|
+
}
|
|
1454
|
+
function present(recorder, threshold) {
|
|
1455
|
+
const text = recorder.text;
|
|
1456
|
+
if (!recorder.overflowing && !shouldFold(text, threshold)) {
|
|
1457
|
+
replay(recorder.chunks);
|
|
1458
|
+
return recorder.bytes;
|
|
1459
|
+
}
|
|
1460
|
+
let printed;
|
|
1461
|
+
try {
|
|
1462
|
+
printed = fold(text, { threshold, logPath: recorder.save() });
|
|
1463
|
+
} catch (error) {
|
|
1464
|
+
console.error(`out: could not fold the output: ${error instanceof Error ? error.message : String(error)}`);
|
|
1465
|
+
printed = text.split(`
|
|
1466
|
+
`).slice(-FALLBACK_LINES).join(`
|
|
1467
|
+
`);
|
|
1468
|
+
}
|
|
1469
|
+
if (!recorder.overflowing && Buffer.byteLength(printed) >= recorder.bytes) {
|
|
1470
|
+
recorder.discard();
|
|
1471
|
+
replay(recorder.chunks);
|
|
1472
|
+
return recorder.bytes;
|
|
1473
|
+
}
|
|
1474
|
+
process10.stdout.write(printed);
|
|
1475
|
+
return Buffer.byteLength(printed);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// src/cli.ts
|
|
1479
|
+
var USAGE = `out [-n <lines>] -- <command> [args...]: runs the command and shortens its output when it is long, exiting with its code
|
|
1480
|
+
<command> | out [-n <lines>]: shortens the output piped in
|
|
1481
|
+
out --stats [--since 7d] [--json]: the runs recorded and about how many tokens they saved
|
|
1482
|
+
|
|
1483
|
+
Each run is recorded in ~/.local/state/kaynooo-cli/out/stats.jsonl with the words naming the command, never its arguments; tokens are counted as bytes / 4.
|
|
1484
|
+
Exits 0 when the command does, with its own code otherwise, 127 when it cannot be started, 2 on a usage error. Piped into, it exits 0.`;
|
|
1485
|
+
var OPTIONS = {
|
|
1486
|
+
lines: { type: "string", short: "n", description: "longest output left untouched (default 150)" },
|
|
1487
|
+
was: { type: "string", multiple: true, description: "a tail, head or grep stage out stands in for, so the stats count against what it would have printed (repeatable, in pipeline order)" },
|
|
1488
|
+
stats: { type: "boolean", description: "print the runs recorded and the tokens saved" },
|
|
1489
|
+
since: { type: "string", description: "with --stats, only the runs this recent (7d, 12h)" },
|
|
1490
|
+
json: jsonOption("with --stats, {runs, folded, bytes, shown, tokensSaved, commands}")
|
|
1491
|
+
};
|
|
1492
|
+
async function stats(since, json) {
|
|
1493
|
+
const window = since === undefined ? undefined : duration(since, "since", 0, "h");
|
|
1494
|
+
const summary = summarize(await readEntries(statsPath(), window === undefined ? 0 : Date.now() - window));
|
|
1495
|
+
if (json)
|
|
1496
|
+
printJson(summary);
|
|
1497
|
+
else
|
|
1498
|
+
console.log(renderSummary(summary, since === undefined ? "recorded" : `in the last ${since}`));
|
|
1499
|
+
return 0;
|
|
1500
|
+
}
|
|
1501
|
+
async function main(argv) {
|
|
1502
|
+
const bare = argv[0] !== undefined && !argv[0].startsWith("-");
|
|
1503
|
+
const parsed = parse(bare ? [] : argv, USAGE, OPTIONS, { rest: true, replaces: "piping a noisy command through tail or head", examples: ["out -- bun install", ["out -n 300 -- bun run build", "up to 300 lines left untouched"], ["bun run build 2>&1 | out", "what is piped in"], ["out --stats --since 7d", "the tokens saved this week"]] });
|
|
1504
|
+
const { values } = parsed;
|
|
1505
|
+
if (values.stats === true) {
|
|
1506
|
+
if ((parsed.rest ?? []).length > 0 || parsed.positionals.length > 0)
|
|
1507
|
+
badUsage("--stats runs no command");
|
|
1508
|
+
return stats(values.since, values.json === true);
|
|
1509
|
+
}
|
|
1510
|
+
if (values.since !== undefined || values.json === true)
|
|
1511
|
+
badUsage("--since and --json go with --stats");
|
|
1512
|
+
const command = bare ? argv : parsed.rest ?? [];
|
|
1513
|
+
const lines = wholeNumber(values.lines, "lines", FOLD_LINES);
|
|
1514
|
+
const was = values.was ?? [];
|
|
1515
|
+
if (command.length === 0 && parsed.positionals.length === 0 && isStdinPiped())
|
|
1516
|
+
return readPiped(lines, was);
|
|
1517
|
+
if (command.length === 0 || parsed.positionals.length > 0)
|
|
1518
|
+
fail(`give the command after --
|
|
1519
|
+
|
|
1520
|
+
${USAGE}`);
|
|
1521
|
+
return run(command, lines, was);
|
|
1522
|
+
}
|
|
1523
|
+
process11.exitCode = await runMain({ name: "out", version, run: main });
|