snapfail 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -60
- package/dist/index.js +2320 -397
- package/package.json +17 -13
- package/src/index.ts +95 -0
- package/bin/snapfail.js +0 -5
- package/dist/index.d.ts +0 -15
package/dist/index.js
CHANGED
|
@@ -1,451 +1,2374 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
31
|
+
return to;
|
|
20
32
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
|
|
35
|
+
// ../../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
|
|
36
|
+
var require_src = __commonJS((exports, module) => {
|
|
37
|
+
var ESC3 = "\x1B";
|
|
38
|
+
var CSI2 = `${ESC3}[`;
|
|
39
|
+
var beep = "\x07";
|
|
40
|
+
var cursor = {
|
|
41
|
+
to(x, y) {
|
|
42
|
+
if (!y)
|
|
43
|
+
return `${CSI2}${x + 1}G`;
|
|
44
|
+
return `${CSI2}${y + 1};${x + 1}H`;
|
|
45
|
+
},
|
|
46
|
+
move(x, y) {
|
|
47
|
+
let ret = "";
|
|
48
|
+
if (x < 0)
|
|
49
|
+
ret += `${CSI2}${-x}D`;
|
|
50
|
+
else if (x > 0)
|
|
51
|
+
ret += `${CSI2}${x}C`;
|
|
52
|
+
if (y < 0)
|
|
53
|
+
ret += `${CSI2}${-y}A`;
|
|
54
|
+
else if (y > 0)
|
|
55
|
+
ret += `${CSI2}${y}B`;
|
|
56
|
+
return ret;
|
|
57
|
+
},
|
|
58
|
+
up: (count = 1) => `${CSI2}${count}A`,
|
|
59
|
+
down: (count = 1) => `${CSI2}${count}B`,
|
|
60
|
+
forward: (count = 1) => `${CSI2}${count}C`,
|
|
61
|
+
backward: (count = 1) => `${CSI2}${count}D`,
|
|
62
|
+
nextLine: (count = 1) => `${CSI2}E`.repeat(count),
|
|
63
|
+
prevLine: (count = 1) => `${CSI2}F`.repeat(count),
|
|
64
|
+
left: `${CSI2}G`,
|
|
65
|
+
hide: `${CSI2}?25l`,
|
|
66
|
+
show: `${CSI2}?25h`,
|
|
67
|
+
save: `${ESC3}7`,
|
|
68
|
+
restore: `${ESC3}8`
|
|
69
|
+
};
|
|
70
|
+
var scroll = {
|
|
71
|
+
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
72
|
+
down: (count = 1) => `${CSI2}T`.repeat(count)
|
|
73
|
+
};
|
|
74
|
+
var erase = {
|
|
75
|
+
screen: `${CSI2}2J`,
|
|
76
|
+
up: (count = 1) => `${CSI2}1J`.repeat(count),
|
|
77
|
+
down: (count = 1) => `${CSI2}J`.repeat(count),
|
|
78
|
+
line: `${CSI2}2K`,
|
|
79
|
+
lineEnd: `${CSI2}K`,
|
|
80
|
+
lineStart: `${CSI2}1K`,
|
|
81
|
+
lines(count) {
|
|
82
|
+
let clear = "";
|
|
83
|
+
for (let i = 0;i < count; i++)
|
|
84
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
85
|
+
if (count)
|
|
86
|
+
clear += cursor.left;
|
|
87
|
+
return clear;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// src/config.ts
|
|
94
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
95
|
+
import { resolve } from "path";
|
|
96
|
+
var DEFAULT_ENDPOINT = "https://app.snapfail.com";
|
|
97
|
+
var ENV_FILE = ".env";
|
|
98
|
+
function loadConfig(cwd = process.cwd()) {
|
|
99
|
+
const fromEnv = process.env["SNAPFAIL_PROJECT_KEY"];
|
|
100
|
+
if (fromEnv)
|
|
101
|
+
return { projectKey: fromEnv, endpoint: DEFAULT_ENDPOINT };
|
|
102
|
+
const envPath = resolve(cwd, ENV_FILE);
|
|
103
|
+
if (existsSync(envPath)) {
|
|
104
|
+
const match = readFileSync(envPath, "utf-8").match(/^SNAPFAIL_PROJECT_KEY=(.+)$/m);
|
|
105
|
+
if (match)
|
|
106
|
+
return { projectKey: match[1].trim(), endpoint: DEFAULT_ENDPOINT };
|
|
107
|
+
}
|
|
108
|
+
throw new Error('No project key found. Run "snapfail init" or set SNAPFAIL_PROJECT_KEY.');
|
|
109
|
+
}
|
|
110
|
+
function writeProjectKey(projectKey, cwd = process.cwd(), keyName = "SNAPFAIL_PROJECT_KEY") {
|
|
111
|
+
const envPath = resolve(cwd, ENV_FILE);
|
|
112
|
+
const line = `${keyName}=${projectKey}`;
|
|
113
|
+
const pattern = new RegExp(`^${keyName}=.*`, "m");
|
|
114
|
+
if (existsSync(envPath)) {
|
|
115
|
+
let content = readFileSync(envPath, "utf-8");
|
|
116
|
+
if (pattern.test(content)) {
|
|
117
|
+
content = content.replace(pattern, line);
|
|
118
|
+
} else {
|
|
119
|
+
content = content.trimEnd() + `
|
|
120
|
+
${line}
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
writeFileSync(envPath, content, "utf-8");
|
|
124
|
+
} else {
|
|
125
|
+
writeFileSync(envPath, `${line}
|
|
126
|
+
`, "utf-8");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/api.ts
|
|
131
|
+
async function apiFetch(url, options) {
|
|
132
|
+
let res;
|
|
133
|
+
try {
|
|
134
|
+
res = await fetch(url, options);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
137
|
+
}
|
|
138
|
+
if (res.status === 401)
|
|
139
|
+
throw new Error("Unauthorized: check your project key.");
|
|
140
|
+
if (res.status === 404)
|
|
141
|
+
return null;
|
|
142
|
+
if (!res.ok) {
|
|
143
|
+
const body = await res.text().catch(() => "");
|
|
144
|
+
throw new Error(`API error ${res.status}: ${body}`);
|
|
145
|
+
}
|
|
146
|
+
return res.json();
|
|
147
|
+
}
|
|
148
|
+
async function fetchIncidents(config, opts = {}) {
|
|
149
|
+
const url = new URL(`${config.endpoint}/api/incidents`);
|
|
150
|
+
url.searchParams.set("projectKey", config.projectKey);
|
|
151
|
+
if (opts.status)
|
|
152
|
+
url.searchParams.set("status", opts.status);
|
|
153
|
+
if (opts.limit != null)
|
|
154
|
+
url.searchParams.set("limit", String(opts.limit));
|
|
155
|
+
if (opts.offset != null)
|
|
156
|
+
url.searchParams.set("offset", String(opts.offset));
|
|
157
|
+
const data = await apiFetch(url.toString());
|
|
158
|
+
return data;
|
|
159
|
+
}
|
|
160
|
+
async function fetchIncident(config, id) {
|
|
161
|
+
const url = `${config.endpoint}/api/incidents/${id}`;
|
|
162
|
+
const data = await apiFetch(url, {
|
|
163
|
+
headers: { "X-Project-Key": config.projectKey }
|
|
36
164
|
});
|
|
37
|
-
return
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
resolve2(defaultYes);
|
|
44
|
-
} else if (clean === "y" || clean === "yes") {
|
|
45
|
-
resolve2(true);
|
|
46
|
-
} else if (clean === "n" || clean === "no") {
|
|
47
|
-
resolve2(false);
|
|
48
|
-
} else {
|
|
49
|
-
resolve2(defaultYes);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
165
|
+
return data;
|
|
166
|
+
}
|
|
167
|
+
async function fetchSample(config, groupId, sampleIndex) {
|
|
168
|
+
const url = `${config.endpoint}/api/incidents/${groupId}/samples/${sampleIndex}`;
|
|
169
|
+
const data = await apiFetch(url, {
|
|
170
|
+
headers: { "X-Project-Key": config.projectKey }
|
|
52
171
|
});
|
|
172
|
+
return data;
|
|
53
173
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
174
|
+
|
|
175
|
+
// src/format.ts
|
|
176
|
+
var ESC = "\x1B[";
|
|
177
|
+
var bold = (s) => `${ESC}1m${s}${ESC}0m`;
|
|
178
|
+
var dim = (s) => `${ESC}2m${s}${ESC}0m`;
|
|
179
|
+
var red = (s) => `${ESC}31m${s}${ESC}0m`;
|
|
180
|
+
var green = (s) => `${ESC}32m${s}${ESC}0m`;
|
|
181
|
+
var yellow = (s) => `${ESC}33m${s}${ESC}0m`;
|
|
182
|
+
var cyan = (s) => `${ESC}36m${s}${ESC}0m`;
|
|
183
|
+
function truncate(s, n) {
|
|
184
|
+
if (s.length <= n)
|
|
185
|
+
return s;
|
|
186
|
+
return s.slice(0, n - 1) + "\u2026";
|
|
58
187
|
}
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
188
|
+
function relativeTime(ts) {
|
|
189
|
+
const diff = Date.now() - ts;
|
|
190
|
+
const s = Math.floor(diff / 1000);
|
|
191
|
+
if (s < 60)
|
|
192
|
+
return `${s}s ago`;
|
|
193
|
+
const m = Math.floor(s / 60);
|
|
194
|
+
if (m < 60)
|
|
195
|
+
return `${m}m ago`;
|
|
196
|
+
const h = Math.floor(m / 60);
|
|
197
|
+
if (h < 24)
|
|
198
|
+
return `${h}h ago`;
|
|
199
|
+
const d = Math.floor(h / 24);
|
|
200
|
+
return `${d}d ago`;
|
|
201
|
+
}
|
|
202
|
+
function formatTable(rows, headers) {
|
|
203
|
+
const allRows = [headers, ...rows];
|
|
204
|
+
const widths = headers.map((_, i) => Math.max(...allRows.map((r) => (r[i] ?? "").length)));
|
|
205
|
+
const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
206
|
+
const header = " " + headers.map((h, i) => bold(pad(h, widths[i]))).join(" ");
|
|
207
|
+
const divider = " " + widths.map((w) => dim("\u2500".repeat(w))).join(" ");
|
|
208
|
+
const body = rows.map((r) => " " + r.map((cell, i) => pad(cell, widths[i])).join(" ")).join(`
|
|
209
|
+
`);
|
|
210
|
+
return [header, divider, body].join(`
|
|
211
|
+
`);
|
|
212
|
+
}
|
|
213
|
+
function formatIncidentList(data, total, status) {
|
|
214
|
+
if (data.length === 0) {
|
|
215
|
+
return dim(`No ${status ?? "unresolved"} incidents found.`);
|
|
216
|
+
}
|
|
217
|
+
const rows = data.map((g) => [
|
|
218
|
+
cyan(truncate(g.id, 12)),
|
|
219
|
+
truncate(g.title, 38),
|
|
220
|
+
String(g.count),
|
|
221
|
+
g.environments.join(","),
|
|
222
|
+
relativeTime(g.lastSeen)
|
|
223
|
+
]);
|
|
224
|
+
const table = formatTable(rows, ["ID", "TITLE", "COUNT", "ENV", "LAST SEEN"]);
|
|
225
|
+
const summary = `
|
|
226
|
+
${bold(String(total))} ${status ?? "unresolved"} incident${total !== 1 ? "s" : ""}`;
|
|
227
|
+
return table + summary;
|
|
69
228
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
229
|
+
function formatIncidentDetail(group, sample) {
|
|
230
|
+
const lines = [];
|
|
231
|
+
lines.push(bold(`${group.errorType}: ${truncate(group.title, 80)}`));
|
|
232
|
+
lines.push(`${dim("Status:")} ${group.status} ${dim("\xB7")} ${group.count} occurrences ${dim("\xB7")} ${group.environments.join(", ")}`);
|
|
233
|
+
lines.push(`${dim("First seen:")} ${new Date(group.firstSeen).toISOString().slice(0, 10)} ${dim("\xB7")} ${dim("Last seen:")} ${relativeTime(group.lastSeen)}`);
|
|
234
|
+
if (sample.stackFrames.length > 0) {
|
|
235
|
+
lines.push("");
|
|
236
|
+
lines.push(bold("Stack"));
|
|
237
|
+
for (const f of sample.stackFrames.slice(0, 6)) {
|
|
238
|
+
const fn = f.fn ? `${cyan(f.fn)} ` : "";
|
|
239
|
+
lines.push(` ${fn}${dim(f.file + ":" + f.line)}`);
|
|
240
|
+
}
|
|
74
241
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
242
|
+
if (sample.consoleEntries.length > 0) {
|
|
243
|
+
lines.push("");
|
|
244
|
+
lines.push(bold("Console"));
|
|
245
|
+
for (const e of sample.consoleEntries.slice(-5)) {
|
|
246
|
+
const level = e.level === "error" ? red(`[${e.level}]`) : yellow(`[${e.level}]`);
|
|
247
|
+
const args = e.args.map((a) => truncate(String(a), 60)).join(" ");
|
|
248
|
+
lines.push(` ${level} ${args}`);
|
|
249
|
+
}
|
|
78
250
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
251
|
+
if (sample.networkEntries.length > 0) {
|
|
252
|
+
lines.push("");
|
|
253
|
+
lines.push(bold("Network"));
|
|
254
|
+
for (const n of sample.networkEntries.slice(-5)) {
|
|
255
|
+
const status = n.status ? n.status >= 400 ? red(String(n.status)) : green(String(n.status)) : dim("???");
|
|
256
|
+
lines.push(` ${dim(n.method)} ${truncate(n.url, 50)} ${dim("\u2192")} ${status} ${dim(`(${n.durationMs}ms)`)}`);
|
|
257
|
+
}
|
|
82
258
|
}
|
|
83
|
-
|
|
259
|
+
if (sample.timeline.length > 0) {
|
|
260
|
+
lines.push("");
|
|
261
|
+
lines.push(bold("Timeline"));
|
|
262
|
+
for (const e of sample.timeline.slice(0, 10)) {
|
|
263
|
+
const t = String(e.t).padStart(5);
|
|
264
|
+
lines.push(` ${dim(t + "ms")} ${e.summary}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return lines.join(`
|
|
268
|
+
`);
|
|
84
269
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
270
|
+
|
|
271
|
+
// src/commands/incidents.ts
|
|
272
|
+
async function runIncidents(opts) {
|
|
273
|
+
const config = loadConfig();
|
|
274
|
+
const result = await fetchIncidents(config, {
|
|
275
|
+
status: opts.status ?? "unresolved",
|
|
276
|
+
limit: opts.limit,
|
|
277
|
+
offset: opts.offset
|
|
278
|
+
});
|
|
279
|
+
if (opts.json) {
|
|
280
|
+
process.stdout.write(JSON.stringify(result, null, 2) + `
|
|
281
|
+
`);
|
|
282
|
+
return;
|
|
91
283
|
}
|
|
92
|
-
|
|
284
|
+
console.log(formatIncidentList(result.data, result.total, opts.status));
|
|
93
285
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
286
|
+
|
|
287
|
+
// src/commands/incident.ts
|
|
288
|
+
async function runIncident(opts) {
|
|
289
|
+
const config = loadConfig();
|
|
290
|
+
if (opts.sample != null) {
|
|
291
|
+
const s = await fetchSample(config, opts.id, opts.sample);
|
|
292
|
+
if (!s) {
|
|
293
|
+
console.error(`Sample ${opts.sample} not found for incident ${opts.id}`);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
if (opts.json) {
|
|
297
|
+
process.stdout.write(JSON.stringify(s, null, 2) + `
|
|
298
|
+
`);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const detail = await fetchIncident(config, opts.id);
|
|
302
|
+
if (!detail) {
|
|
303
|
+
console.error(`Incident ${opts.id} not found.`);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
console.log(formatIncidentDetail(detail.group, s));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const result = await fetchIncident(config, opts.id);
|
|
310
|
+
if (!result) {
|
|
311
|
+
console.error(`Incident ${opts.id} not found.`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
if (opts.json) {
|
|
315
|
+
process.stdout.write(JSON.stringify(result, null, 2) + `
|
|
316
|
+
`);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
console.log(formatIncidentDetail(result.group, result.sample));
|
|
99
320
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
321
|
+
|
|
322
|
+
// src/commands/init.ts
|
|
323
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
324
|
+
import { resolve as resolve2, join as join2 } from "path";
|
|
325
|
+
import { execSync as execSync2 } from "child_process";
|
|
326
|
+
|
|
327
|
+
// ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
|
|
328
|
+
import { styleText } from "util";
|
|
329
|
+
import { stdout, stdin } from "process";
|
|
330
|
+
import * as l from "readline";
|
|
331
|
+
import l__default from "readline";
|
|
332
|
+
|
|
333
|
+
// ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
|
|
334
|
+
var getCodePointsLength = (() => {
|
|
335
|
+
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
336
|
+
return (input) => {
|
|
337
|
+
let surrogatePairsNr = 0;
|
|
338
|
+
SURROGATE_PAIR_RE.lastIndex = 0;
|
|
339
|
+
while (SURROGATE_PAIR_RE.test(input)) {
|
|
340
|
+
surrogatePairsNr += 1;
|
|
341
|
+
}
|
|
342
|
+
return input.length - surrogatePairsNr;
|
|
343
|
+
};
|
|
344
|
+
})();
|
|
345
|
+
var isFullWidth = (x) => {
|
|
346
|
+
return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
|
|
347
|
+
};
|
|
348
|
+
var isWideNotCJKTNotEmoji = (x) => {
|
|
349
|
+
return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
|
|
353
|
+
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
354
|
+
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
355
|
+
var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
|
|
356
|
+
var TAB_RE = /\t{1,1000}/y;
|
|
357
|
+
var EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
|
|
358
|
+
var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
359
|
+
var MODIFIER_RE = /\p{M}+/gu;
|
|
360
|
+
var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
|
|
361
|
+
var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
|
|
362
|
+
const LIMIT = truncationOptions.limit ?? Infinity;
|
|
363
|
+
const ELLIPSIS = truncationOptions.ellipsis ?? "";
|
|
364
|
+
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
|
|
365
|
+
const ANSI_WIDTH = 0;
|
|
366
|
+
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
|
|
367
|
+
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
|
|
368
|
+
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
|
|
369
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
370
|
+
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
|
|
371
|
+
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
|
|
372
|
+
const PARSE_BLOCKS = [
|
|
373
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
374
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
375
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
376
|
+
[TAB_RE, TAB_WIDTH],
|
|
377
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
378
|
+
[CJKT_WIDE_RE, WIDE_WIDTH]
|
|
379
|
+
];
|
|
380
|
+
let indexPrev = 0;
|
|
381
|
+
let index = 0;
|
|
382
|
+
let length = input.length;
|
|
383
|
+
let lengthExtra = 0;
|
|
384
|
+
let truncationEnabled = false;
|
|
385
|
+
let truncationIndex = length;
|
|
386
|
+
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
|
|
387
|
+
let unmatchedStart = 0;
|
|
388
|
+
let unmatchedEnd = 0;
|
|
389
|
+
let width = 0;
|
|
390
|
+
let widthExtra = 0;
|
|
391
|
+
outer:
|
|
392
|
+
while (true) {
|
|
393
|
+
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
|
|
394
|
+
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
|
|
395
|
+
lengthExtra = 0;
|
|
396
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
397
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
398
|
+
if (isFullWidth(codePoint)) {
|
|
399
|
+
widthExtra = FULL_WIDTH_WIDTH;
|
|
400
|
+
} else if (isWideNotCJKTNotEmoji(codePoint)) {
|
|
401
|
+
widthExtra = WIDE_WIDTH;
|
|
402
|
+
} else {
|
|
403
|
+
widthExtra = REGULAR_WIDTH;
|
|
404
|
+
}
|
|
405
|
+
if (width + widthExtra > truncationLimit) {
|
|
406
|
+
truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
|
|
407
|
+
}
|
|
408
|
+
if (width + widthExtra > LIMIT) {
|
|
409
|
+
truncationEnabled = true;
|
|
410
|
+
break outer;
|
|
411
|
+
}
|
|
412
|
+
lengthExtra += char.length;
|
|
413
|
+
width += widthExtra;
|
|
414
|
+
}
|
|
415
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
416
|
+
}
|
|
417
|
+
if (index >= length) {
|
|
418
|
+
break outer;
|
|
419
|
+
}
|
|
420
|
+
for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
|
|
421
|
+
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
|
|
422
|
+
BLOCK_RE.lastIndex = index;
|
|
423
|
+
if (BLOCK_RE.test(input)) {
|
|
424
|
+
lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
|
|
425
|
+
widthExtra = lengthExtra * BLOCK_WIDTH;
|
|
426
|
+
if (width + widthExtra > truncationLimit) {
|
|
427
|
+
truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
|
|
428
|
+
}
|
|
429
|
+
if (width + widthExtra > LIMIT) {
|
|
430
|
+
truncationEnabled = true;
|
|
431
|
+
break outer;
|
|
432
|
+
}
|
|
433
|
+
width += widthExtra;
|
|
434
|
+
unmatchedStart = indexPrev;
|
|
435
|
+
unmatchedEnd = index;
|
|
436
|
+
index = indexPrev = BLOCK_RE.lastIndex;
|
|
437
|
+
continue outer;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
index += 1;
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
width: truncationEnabled ? truncationLimit : width,
|
|
444
|
+
index: truncationEnabled ? truncationIndex : length,
|
|
445
|
+
truncated: truncationEnabled,
|
|
446
|
+
ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
var dist_default = getStringTruncatedWidth;
|
|
450
|
+
|
|
451
|
+
// ../../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
|
|
452
|
+
var NO_TRUNCATION2 = {
|
|
453
|
+
limit: Infinity,
|
|
454
|
+
ellipsis: "",
|
|
455
|
+
ellipsisWidth: 0
|
|
456
|
+
};
|
|
457
|
+
var fastStringWidth = (input, options = {}) => {
|
|
458
|
+
return dist_default(input, NO_TRUNCATION2, options).width;
|
|
459
|
+
};
|
|
460
|
+
var dist_default2 = fastStringWidth;
|
|
461
|
+
|
|
462
|
+
// ../../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
|
|
463
|
+
var ESC2 = "\x1B";
|
|
464
|
+
var CSI = "\x9B";
|
|
465
|
+
var END_CODE = 39;
|
|
466
|
+
var ANSI_ESCAPE_BELL = "\x07";
|
|
467
|
+
var ANSI_CSI = "[";
|
|
468
|
+
var ANSI_OSC = "]";
|
|
469
|
+
var ANSI_SGR_TERMINATOR = "m";
|
|
470
|
+
var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
|
|
471
|
+
var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
|
|
472
|
+
var getClosingCode = (openingCode) => {
|
|
473
|
+
if (openingCode >= 30 && openingCode <= 37)
|
|
474
|
+
return 39;
|
|
475
|
+
if (openingCode >= 90 && openingCode <= 97)
|
|
476
|
+
return 39;
|
|
477
|
+
if (openingCode >= 40 && openingCode <= 47)
|
|
478
|
+
return 49;
|
|
479
|
+
if (openingCode >= 100 && openingCode <= 107)
|
|
480
|
+
return 49;
|
|
481
|
+
if (openingCode === 1 || openingCode === 2)
|
|
482
|
+
return 22;
|
|
483
|
+
if (openingCode === 3)
|
|
484
|
+
return 23;
|
|
485
|
+
if (openingCode === 4)
|
|
486
|
+
return 24;
|
|
487
|
+
if (openingCode === 7)
|
|
488
|
+
return 27;
|
|
489
|
+
if (openingCode === 8)
|
|
490
|
+
return 28;
|
|
491
|
+
if (openingCode === 9)
|
|
492
|
+
return 29;
|
|
493
|
+
if (openingCode === 0)
|
|
494
|
+
return 0;
|
|
495
|
+
return;
|
|
496
|
+
};
|
|
497
|
+
var wrapAnsiCode = (code) => `${ESC2}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
498
|
+
var wrapAnsiHyperlink = (url) => `${ESC2}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
499
|
+
var wrapWord = (rows, word, columns) => {
|
|
500
|
+
const characters = word[Symbol.iterator]();
|
|
501
|
+
let isInsideEscape = false;
|
|
502
|
+
let isInsideLinkEscape = false;
|
|
503
|
+
let lastRow = rows.at(-1);
|
|
504
|
+
let visible = lastRow === undefined ? 0 : dist_default2(lastRow);
|
|
505
|
+
let currentCharacter = characters.next();
|
|
506
|
+
let nextCharacter = characters.next();
|
|
507
|
+
let rawCharacterIndex = 0;
|
|
508
|
+
while (!currentCharacter.done) {
|
|
509
|
+
const character = currentCharacter.value;
|
|
510
|
+
const characterLength = dist_default2(character);
|
|
511
|
+
if (visible + characterLength <= columns) {
|
|
512
|
+
rows[rows.length - 1] += character;
|
|
513
|
+
} else {
|
|
514
|
+
rows.push(character);
|
|
515
|
+
visible = 0;
|
|
106
516
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
517
|
+
if (character === ESC2 || character === CSI) {
|
|
518
|
+
isInsideEscape = true;
|
|
519
|
+
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
|
|
520
|
+
}
|
|
521
|
+
if (isInsideEscape) {
|
|
522
|
+
if (isInsideLinkEscape) {
|
|
523
|
+
if (character === ANSI_ESCAPE_BELL) {
|
|
524
|
+
isInsideEscape = false;
|
|
525
|
+
isInsideLinkEscape = false;
|
|
526
|
+
}
|
|
527
|
+
} else if (character === ANSI_SGR_TERMINATOR) {
|
|
528
|
+
isInsideEscape = false;
|
|
529
|
+
}
|
|
116
530
|
} else {
|
|
117
|
-
|
|
118
|
-
|
|
531
|
+
visible += characterLength;
|
|
532
|
+
if (visible === columns && !nextCharacter.done) {
|
|
533
|
+
rows.push("");
|
|
534
|
+
visible = 0;
|
|
535
|
+
}
|
|
119
536
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
fail(`Could not modify ${basename(configPath)}: ${err.message}`);
|
|
124
|
-
return false;
|
|
537
|
+
currentCharacter = nextCharacter;
|
|
538
|
+
nextCharacter = characters.next();
|
|
539
|
+
rawCharacterIndex += character.length;
|
|
125
540
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
541
|
+
lastRow = rows.at(-1);
|
|
542
|
+
if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
|
|
543
|
+
rows[rows.length - 2] += rows.pop();
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
var stringVisibleTrimSpacesRight = (string) => {
|
|
547
|
+
const words = string.split(" ");
|
|
548
|
+
let last = words.length;
|
|
549
|
+
while (last) {
|
|
550
|
+
if (dist_default2(words[last - 1])) {
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
last--;
|
|
554
|
+
}
|
|
555
|
+
if (last === words.length) {
|
|
556
|
+
return string;
|
|
557
|
+
}
|
|
558
|
+
return words.slice(0, last).join(" ") + words.slice(last).join("");
|
|
559
|
+
};
|
|
560
|
+
var exec = (string, columns, options = {}) => {
|
|
561
|
+
if (options.trim !== false && string.trim() === "") {
|
|
562
|
+
return "";
|
|
563
|
+
}
|
|
564
|
+
let returnValue = "";
|
|
565
|
+
let escapeCode;
|
|
566
|
+
let escapeUrl;
|
|
567
|
+
const words = string.split(" ");
|
|
568
|
+
let rows = [""];
|
|
569
|
+
let rowLength = 0;
|
|
570
|
+
for (let index = 0;index < words.length; index++) {
|
|
571
|
+
const word = words[index];
|
|
572
|
+
if (options.trim !== false) {
|
|
573
|
+
const row = rows.at(-1) ?? "";
|
|
574
|
+
const trimmed = row.trimStart();
|
|
575
|
+
if (row.length !== trimmed.length) {
|
|
576
|
+
rows[rows.length - 1] = trimmed;
|
|
577
|
+
rowLength = dist_default2(trimmed);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (index !== 0) {
|
|
581
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
582
|
+
rows.push("");
|
|
583
|
+
rowLength = 0;
|
|
584
|
+
}
|
|
585
|
+
if (rowLength || options.trim === false) {
|
|
586
|
+
rows[rows.length - 1] += " ";
|
|
587
|
+
rowLength++;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const wordLength = dist_default2(word);
|
|
591
|
+
if (options.hard && wordLength > columns) {
|
|
592
|
+
const remainingColumns = columns - rowLength;
|
|
593
|
+
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
|
|
594
|
+
const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
|
|
595
|
+
if (breaksStartingNextLine < breaksStartingThisLine) {
|
|
596
|
+
rows.push("");
|
|
597
|
+
}
|
|
598
|
+
wrapWord(rows, word, columns);
|
|
599
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
if (rowLength + wordLength > columns && rowLength && wordLength) {
|
|
603
|
+
if (options.wordWrap === false && rowLength < columns) {
|
|
604
|
+
wrapWord(rows, word, columns);
|
|
605
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
rows.push("");
|
|
609
|
+
rowLength = 0;
|
|
610
|
+
}
|
|
611
|
+
if (rowLength + wordLength > columns && options.wordWrap === false) {
|
|
612
|
+
wrapWord(rows, word, columns);
|
|
613
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
614
|
+
continue;
|
|
133
615
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
616
|
+
rows[rows.length - 1] += word;
|
|
617
|
+
rowLength += wordLength;
|
|
618
|
+
}
|
|
619
|
+
if (options.trim !== false) {
|
|
620
|
+
rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
|
|
621
|
+
}
|
|
622
|
+
const preString = rows.join(`
|
|
623
|
+
`);
|
|
624
|
+
let inSurrogate = false;
|
|
625
|
+
for (let i = 0;i < preString.length; i++) {
|
|
626
|
+
const character = preString[i];
|
|
627
|
+
returnValue += character;
|
|
628
|
+
if (!inSurrogate) {
|
|
629
|
+
inSurrogate = character >= "\uD800" && character <= "\uDBFF";
|
|
630
|
+
if (inSurrogate) {
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
143
633
|
} else {
|
|
144
|
-
|
|
145
|
-
|
|
634
|
+
inSurrogate = false;
|
|
635
|
+
}
|
|
636
|
+
if (character === ESC2 || character === CSI) {
|
|
637
|
+
GROUP_REGEX.lastIndex = i + 1;
|
|
638
|
+
const groupsResult = GROUP_REGEX.exec(preString);
|
|
639
|
+
const groups = groupsResult?.groups;
|
|
640
|
+
if (groups?.code !== undefined) {
|
|
641
|
+
const code = Number.parseFloat(groups.code);
|
|
642
|
+
escapeCode = code === END_CODE ? undefined : code;
|
|
643
|
+
} else if (groups?.uri !== undefined) {
|
|
644
|
+
escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (preString[i + 1] === `
|
|
648
|
+
`) {
|
|
649
|
+
if (escapeUrl) {
|
|
650
|
+
returnValue += wrapAnsiHyperlink("");
|
|
651
|
+
}
|
|
652
|
+
const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
|
|
653
|
+
if (escapeCode && closingCode) {
|
|
654
|
+
returnValue += wrapAnsiCode(closingCode);
|
|
655
|
+
}
|
|
656
|
+
} else if (character === `
|
|
657
|
+
`) {
|
|
658
|
+
if (escapeCode && getClosingCode(escapeCode)) {
|
|
659
|
+
returnValue += wrapAnsiCode(escapeCode);
|
|
660
|
+
}
|
|
661
|
+
if (escapeUrl) {
|
|
662
|
+
returnValue += wrapAnsiHyperlink(escapeUrl);
|
|
663
|
+
}
|
|
146
664
|
}
|
|
147
|
-
writeFileSync(configPath, src, "utf8");
|
|
148
|
-
return true;
|
|
149
|
-
} catch (err) {
|
|
150
|
-
fail(`Could not modify ${basename(configPath)}: ${err.message}`);
|
|
151
|
-
return false;
|
|
152
665
|
}
|
|
666
|
+
return returnValue;
|
|
667
|
+
};
|
|
668
|
+
var CRLF_OR_LF = /\r?\n/;
|
|
669
|
+
function wrapAnsi(string, columns, options) {
|
|
670
|
+
return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join(`
|
|
671
|
+
`);
|
|
153
672
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
673
|
+
|
|
674
|
+
// ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
|
|
675
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
676
|
+
import { ReadStream } from "tty";
|
|
677
|
+
function findCursor(s, o, l2) {
|
|
678
|
+
if (!l2.some((r) => !r.disabled))
|
|
679
|
+
return s;
|
|
680
|
+
const t = s + o, n = Math.max(l2.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
|
|
681
|
+
return l2[e].disabled ? findCursor(e, o < 0 ? -1 : 1, l2) : e;
|
|
682
|
+
}
|
|
683
|
+
function findTextCursor(s, o, l2, i) {
|
|
684
|
+
const t = i.split(`
|
|
685
|
+
`);
|
|
686
|
+
let n = 0, e = s;
|
|
687
|
+
for (const r of t) {
|
|
688
|
+
if (e <= r.length)
|
|
689
|
+
break;
|
|
690
|
+
e -= r.length + 1, n++;
|
|
691
|
+
}
|
|
692
|
+
for (n = Math.max(0, Math.min(t.length - 1, n + l2)), e = Math.min(e, t[n].length) + o;e < 0 && n > 0; )
|
|
693
|
+
n--, e += t[n].length + 1;
|
|
694
|
+
for (;e > t[n].length && n < t.length - 1; )
|
|
695
|
+
e -= t[n].length + 1, n++;
|
|
696
|
+
e = Math.max(0, Math.min(t[n].length, e));
|
|
697
|
+
let h = 0;
|
|
698
|
+
for (let r = 0;r < n; r++)
|
|
699
|
+
h += t[r].length + 1;
|
|
700
|
+
return h + e;
|
|
701
|
+
}
|
|
702
|
+
var a$2 = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
703
|
+
var t = [
|
|
704
|
+
"January",
|
|
705
|
+
"February",
|
|
706
|
+
"March",
|
|
707
|
+
"April",
|
|
708
|
+
"May",
|
|
709
|
+
"June",
|
|
710
|
+
"July",
|
|
711
|
+
"August",
|
|
712
|
+
"September",
|
|
713
|
+
"October",
|
|
714
|
+
"November",
|
|
715
|
+
"December"
|
|
716
|
+
];
|
|
717
|
+
var settings = {
|
|
718
|
+
actions: new Set(a$2),
|
|
719
|
+
aliases: /* @__PURE__ */ new Map([
|
|
720
|
+
["k", "up"],
|
|
721
|
+
["j", "down"],
|
|
722
|
+
["h", "left"],
|
|
723
|
+
["l", "right"],
|
|
724
|
+
["\x03", "cancel"],
|
|
725
|
+
["escape", "cancel"]
|
|
726
|
+
]),
|
|
727
|
+
messages: {
|
|
728
|
+
cancel: "Canceled",
|
|
729
|
+
error: "Something went wrong"
|
|
730
|
+
},
|
|
731
|
+
withGuide: true,
|
|
732
|
+
date: {
|
|
733
|
+
monthNames: [...t],
|
|
734
|
+
messages: {
|
|
735
|
+
required: "Please enter a valid date",
|
|
736
|
+
invalidMonth: "There are only 12 months in a year",
|
|
737
|
+
invalidDay: (n, e) => `There are only ${n} days in ${e}`,
|
|
738
|
+
afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
|
|
739
|
+
beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
|
|
160
740
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
function isActionKey(n, e) {
|
|
744
|
+
if (typeof n == "string")
|
|
745
|
+
return settings.aliases.get(n) === e;
|
|
746
|
+
for (const s of n)
|
|
747
|
+
if (s !== undefined && isActionKey(s, e))
|
|
748
|
+
return true;
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
function diffLines(i, s) {
|
|
752
|
+
if (i === s)
|
|
753
|
+
return;
|
|
754
|
+
const e = i.split(`
|
|
755
|
+
`), t2 = s.split(`
|
|
756
|
+
`), r = Math.max(e.length, t2.length), f = [];
|
|
757
|
+
for (let n = 0;n < r; n++)
|
|
758
|
+
e[n] !== t2[n] && f.push(n);
|
|
759
|
+
return {
|
|
760
|
+
lines: f,
|
|
761
|
+
numLinesBefore: e.length,
|
|
762
|
+
numLinesAfter: t2.length,
|
|
763
|
+
numLines: r
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
var R = globalThis.process.platform.startsWith("win");
|
|
767
|
+
var CANCEL_SYMBOL = Symbol("clack:cancel");
|
|
768
|
+
function isCancel(e) {
|
|
769
|
+
return e === CANCEL_SYMBOL;
|
|
770
|
+
}
|
|
771
|
+
function setRawMode(e, r) {
|
|
772
|
+
const o = e;
|
|
773
|
+
o.isTTY && o.setRawMode(r);
|
|
774
|
+
}
|
|
775
|
+
function block({
|
|
776
|
+
input: e = stdin,
|
|
777
|
+
output: r = stdout,
|
|
778
|
+
overwrite: o = true,
|
|
779
|
+
hideCursor: t2 = true
|
|
780
|
+
} = {}) {
|
|
781
|
+
const s = l.createInterface({
|
|
782
|
+
input: e,
|
|
783
|
+
output: r,
|
|
784
|
+
prompt: "",
|
|
785
|
+
tabSize: 1
|
|
786
|
+
});
|
|
787
|
+
l.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
|
|
788
|
+
const n = (f, { name: a, sequence: p }) => {
|
|
789
|
+
const c = String(f);
|
|
790
|
+
if (isActionKey([c, a, p], "cancel")) {
|
|
791
|
+
t2 && r.write(import_sisteransi.cursor.show), process.exit(0);
|
|
792
|
+
return;
|
|
164
793
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
794
|
+
if (!o)
|
|
795
|
+
return;
|
|
796
|
+
const i = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
|
|
797
|
+
l.moveCursor(r, i, m, () => {
|
|
798
|
+
l.clearLine(r, 1, () => {
|
|
799
|
+
e.once("keypress", n);
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
};
|
|
803
|
+
return t2 && r.write(import_sisteransi.cursor.hide), e.once("keypress", n), () => {
|
|
804
|
+
e.off("keypress", n), t2 && r.write(import_sisteransi.cursor.show), e instanceof ReadStream && e.isTTY && !R && e.setRawMode(false), s.terminal = false, s.close();
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
var getColumns = (e) => ("columns" in e) && typeof e.columns == "number" ? e.columns : 80;
|
|
808
|
+
var getRows = (e) => ("rows" in e) && typeof e.rows == "number" ? e.rows : 20;
|
|
809
|
+
function wrapTextWithPrefix(e, r, o, t2 = o, s = o, n) {
|
|
810
|
+
const f = getColumns(e ?? stdout);
|
|
811
|
+
return wrapAnsi(r, f - o.length, {
|
|
812
|
+
hard: true,
|
|
813
|
+
trim: false
|
|
814
|
+
}).split(`
|
|
815
|
+
`).map((c, i, m) => {
|
|
816
|
+
const d = n ? n(c, i) : c;
|
|
817
|
+
return i === 0 ? `${t2}${d}` : i === m.length - 1 ? `${s}${d}` : `${o}${d}`;
|
|
818
|
+
}).join(`
|
|
819
|
+
`);
|
|
820
|
+
}
|
|
821
|
+
function runValidation(e, n) {
|
|
822
|
+
if ("~standard" in e) {
|
|
823
|
+
const a = e["~standard"].validate(n);
|
|
824
|
+
if (a instanceof Promise)
|
|
825
|
+
throw new TypeError("Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic.");
|
|
826
|
+
return a.issues?.at(0)?.message;
|
|
827
|
+
}
|
|
828
|
+
return e(n);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
class V {
|
|
832
|
+
input;
|
|
833
|
+
output;
|
|
834
|
+
_abortSignal;
|
|
835
|
+
rl;
|
|
836
|
+
opts;
|
|
837
|
+
_render;
|
|
838
|
+
_track = false;
|
|
839
|
+
_prevFrame = "";
|
|
840
|
+
_subscribers = /* @__PURE__ */ new Map;
|
|
841
|
+
_cursor = 0;
|
|
842
|
+
state = "initial";
|
|
843
|
+
error = "";
|
|
844
|
+
value;
|
|
845
|
+
userInput = "";
|
|
846
|
+
constructor(t2, e = true) {
|
|
847
|
+
const { input: i = stdin, output: n = stdout, render: s, signal: r, ...o } = t2;
|
|
848
|
+
this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = s.bind(this), this._track = e, this._abortSignal = r, this.input = i, this.output = n;
|
|
849
|
+
}
|
|
850
|
+
unsubscribe() {
|
|
851
|
+
this._subscribers.clear();
|
|
852
|
+
}
|
|
853
|
+
setSubscriber(t2, e) {
|
|
854
|
+
const i = this._subscribers.get(t2) ?? [];
|
|
855
|
+
i.push(e), this._subscribers.set(t2, i);
|
|
856
|
+
}
|
|
857
|
+
on(t2, e) {
|
|
858
|
+
this.setSubscriber(t2, { cb: e });
|
|
859
|
+
}
|
|
860
|
+
once(t2, e) {
|
|
861
|
+
this.setSubscriber(t2, { cb: e, once: true });
|
|
862
|
+
}
|
|
863
|
+
emit(t2, ...e) {
|
|
864
|
+
const i = this._subscribers.get(t2) ?? [], n = [];
|
|
865
|
+
for (const s of i)
|
|
866
|
+
s.cb(...e), s.once && n.push(() => i.splice(i.indexOf(s), 1));
|
|
867
|
+
for (const s of n)
|
|
868
|
+
s();
|
|
869
|
+
}
|
|
870
|
+
prompt() {
|
|
871
|
+
return new Promise((t2) => {
|
|
872
|
+
if (this._abortSignal) {
|
|
873
|
+
if (this._abortSignal.aborted)
|
|
874
|
+
return this.state = "cancel", this.close(), t2(CANCEL_SYMBOL);
|
|
875
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
876
|
+
this.state = "cancel", this.close();
|
|
877
|
+
}, { once: true });
|
|
878
|
+
}
|
|
879
|
+
this.rl = l__default.createInterface({
|
|
880
|
+
input: this.input,
|
|
881
|
+
tabSize: 2,
|
|
882
|
+
prompt: "",
|
|
883
|
+
escapeCodeTimeout: 50,
|
|
884
|
+
terminal: true
|
|
885
|
+
}), this.rl.prompt(), this.opts.initialUserInput !== undefined && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
886
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(this.value);
|
|
887
|
+
}), this.once("cancel", () => {
|
|
888
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(CANCEL_SYMBOL);
|
|
889
|
+
});
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
_isActionKey(t2, e) {
|
|
893
|
+
return t2 === "\t";
|
|
894
|
+
}
|
|
895
|
+
_shouldSubmit(t2, e) {
|
|
171
896
|
return true;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
897
|
+
}
|
|
898
|
+
_setValue(t2) {
|
|
899
|
+
this.value = t2, this.emit("value", this.value);
|
|
900
|
+
}
|
|
901
|
+
_setUserInput(t2, e) {
|
|
902
|
+
this.userInput = t2 ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
|
|
903
|
+
}
|
|
904
|
+
_clearUserInput() {
|
|
905
|
+
this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
|
|
906
|
+
}
|
|
907
|
+
onKeypress(t2, e) {
|
|
908
|
+
if (this._track && e.name !== "return" && (e.name && this._isActionKey(t2, e) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && settings.aliases.has(e.name) && this.emit("cursor", settings.aliases.get(e.name)), settings.actions.has(e.name) && this.emit("cursor", e.name)), t2 && (t2.toLowerCase() === "y" || t2.toLowerCase() === "n") && this.emit("confirm", t2.toLowerCase() === "y"), this.emit("key", t2, e), e?.name === "return" && this._shouldSubmit(t2, e)) {
|
|
909
|
+
if (this.opts.validate) {
|
|
910
|
+
const i = runValidation(this.opts.validate, this.value);
|
|
911
|
+
i && (this.error = i instanceof Error ? i.message : i, this.state = "error", this.rl?.write(this.userInput));
|
|
912
|
+
}
|
|
913
|
+
this.state !== "error" && (this.state = "submit");
|
|
914
|
+
}
|
|
915
|
+
isActionKey([t2, e?.name, e?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
916
|
+
}
|
|
917
|
+
close() {
|
|
918
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
919
|
+
`), setRawMode(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
920
|
+
}
|
|
921
|
+
restoreCursor() {
|
|
922
|
+
const t2 = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
|
|
923
|
+
`).length - 1;
|
|
924
|
+
this.output.write(import_sisteransi.cursor.move(-999, t2 * -1));
|
|
925
|
+
}
|
|
926
|
+
render() {
|
|
927
|
+
const t2 = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
|
|
928
|
+
hard: true,
|
|
929
|
+
trim: false
|
|
930
|
+
});
|
|
931
|
+
if (t2 !== this._prevFrame) {
|
|
932
|
+
if (this.state === "initial")
|
|
933
|
+
this.output.write(import_sisteransi.cursor.hide);
|
|
934
|
+
else {
|
|
935
|
+
const e = diffLines(this._prevFrame, t2), i = getRows(this.output);
|
|
936
|
+
if (this.restoreCursor(), e) {
|
|
937
|
+
const n = Math.max(0, e.numLinesAfter - i), s = Math.max(0, e.numLinesBefore - i);
|
|
938
|
+
let r = e.lines.find((o) => o >= n);
|
|
939
|
+
if (r === undefined) {
|
|
940
|
+
this._prevFrame = t2;
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
if (e.lines.length === 1) {
|
|
944
|
+
this.output.write(import_sisteransi.cursor.move(0, r - s)), this.output.write(import_sisteransi.erase.lines(1));
|
|
945
|
+
const o = t2.split(`
|
|
946
|
+
`);
|
|
947
|
+
this.output.write(o[r]), this._prevFrame = t2, this.output.write(import_sisteransi.cursor.move(0, o.length - r - 1));
|
|
948
|
+
return;
|
|
949
|
+
} else if (e.lines.length > 1) {
|
|
950
|
+
if (n < s)
|
|
951
|
+
r = n;
|
|
952
|
+
else {
|
|
953
|
+
const h = r - s;
|
|
954
|
+
h > 0 && this.output.write(import_sisteransi.cursor.move(0, h));
|
|
955
|
+
}
|
|
956
|
+
this.output.write(import_sisteransi.erase.down());
|
|
957
|
+
const f = t2.split(`
|
|
958
|
+
`).slice(r);
|
|
959
|
+
this.output.write(f.join(`
|
|
960
|
+
`)), this._prevFrame = t2;
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
this.output.write(import_sisteransi.erase.down());
|
|
965
|
+
}
|
|
966
|
+
this.output.write(t2), this.state === "initial" && (this.state = "active"), this._prevFrame = t2;
|
|
967
|
+
}
|
|
175
968
|
}
|
|
176
969
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
#
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
970
|
+
function p$1(l2, e) {
|
|
971
|
+
if (l2 === undefined || e.length === 0)
|
|
972
|
+
return 0;
|
|
973
|
+
const i = e.findIndex((s) => s.value === l2);
|
|
974
|
+
return i !== -1 ? i : 0;
|
|
975
|
+
}
|
|
976
|
+
function g(l2, e) {
|
|
977
|
+
return (e.label ?? String(e.value)).toLowerCase().includes(l2.toLowerCase());
|
|
978
|
+
}
|
|
979
|
+
function m(l2, e) {
|
|
980
|
+
if (e)
|
|
981
|
+
return l2 ? e : e[0];
|
|
982
|
+
}
|
|
983
|
+
var T$1 = class T extends V {
|
|
984
|
+
filteredOptions;
|
|
985
|
+
multiple;
|
|
986
|
+
isNavigating = false;
|
|
987
|
+
selectedValues = [];
|
|
988
|
+
focusedValue;
|
|
989
|
+
#e = 0;
|
|
990
|
+
#s = "";
|
|
991
|
+
#t;
|
|
992
|
+
#i;
|
|
993
|
+
#n;
|
|
994
|
+
get cursor() {
|
|
995
|
+
return this.#e;
|
|
996
|
+
}
|
|
997
|
+
get userInputWithCursor() {
|
|
998
|
+
if (!this.userInput)
|
|
999
|
+
return styleText(["inverse", "hidden"], "_");
|
|
1000
|
+
if (this._cursor >= this.userInput.length)
|
|
1001
|
+
return `${this.userInput}\u2588`;
|
|
1002
|
+
const e = this.userInput.slice(0, this._cursor), [t2, ...i] = this.userInput.slice(this._cursor);
|
|
1003
|
+
return `${e}${styleText("inverse", t2)}${i.join("")}`;
|
|
1004
|
+
}
|
|
1005
|
+
get options() {
|
|
1006
|
+
return typeof this.#i == "function" ? this.#i() : this.#i;
|
|
1007
|
+
}
|
|
1008
|
+
constructor(e) {
|
|
1009
|
+
super(e), this.#i = e.options, this.#n = e.placeholder;
|
|
1010
|
+
const t2 = this.options;
|
|
1011
|
+
this.filteredOptions = [...t2], this.multiple = e.multiple === true, this.#t = typeof e.options == "function" ? e.filter : e.filter ?? g;
|
|
1012
|
+
let i;
|
|
1013
|
+
if (e.initialValue && Array.isArray(e.initialValue) ? this.multiple ? i = e.initialValue : i = e.initialValue.slice(0, 1) : !this.multiple && this.options.length > 0 && (i = [this.options[0].value]), i)
|
|
1014
|
+
for (const s of i) {
|
|
1015
|
+
const n = t2.findIndex((o) => o.value === s);
|
|
1016
|
+
n !== -1 && (this.toggleSelected(s), this.#e = n);
|
|
201
1017
|
}
|
|
202
|
-
|
|
1018
|
+
this.focusedValue = this.options[this.#e]?.value, this.on("key", (s, n) => this.#l(s, n)), this.on("userInput", (s) => this.#u(s));
|
|
1019
|
+
}
|
|
1020
|
+
_isActionKey(e, t2) {
|
|
1021
|
+
return e === "\t" || this.multiple && this.isNavigating && t2.name === "space" && e !== undefined && e !== "";
|
|
1022
|
+
}
|
|
1023
|
+
#l(e, t2) {
|
|
1024
|
+
const i = t2.name === "up", s = t2.name === "down", n = t2.name === "return", o = this.userInput === "" || this.userInput === "\t", u = this.#n, h = this.options, f = u !== undefined && u !== "" && h.some((r) => !r.disabled && (this.#t ? this.#t(u, r) : true));
|
|
1025
|
+
if (t2.name === "tab" && o && f) {
|
|
1026
|
+
this.userInput === "\t" && this._clearUserInput(), this._setUserInput(u, true), this.isNavigating = false;
|
|
1027
|
+
return;
|
|
203
1028
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
1029
|
+
i || s ? (this.#e = findCursor(this.#e, i ? -1 : 1, this.filteredOptions), this.focusedValue = this.filteredOptions[this.#e]?.value, this.multiple || (this.selectedValues = [this.focusedValue]), this.isNavigating = true) : n ? this.value = m(this.multiple, this.selectedValues) : this.multiple ? this.focusedValue !== undefined && (t2.name === "tab" || this.isNavigating && t2.name === "space") ? this.toggleSelected(this.focusedValue) : this.isNavigating = false : (this.focusedValue && (this.selectedValues = [this.focusedValue]), this.isNavigating = false);
|
|
1030
|
+
}
|
|
1031
|
+
deselectAll() {
|
|
1032
|
+
this.selectedValues = [];
|
|
1033
|
+
}
|
|
1034
|
+
toggleSelected(e) {
|
|
1035
|
+
this.filteredOptions.length !== 0 && (this.multiple ? this.selectedValues.includes(e) ? this.selectedValues = this.selectedValues.filter((t2) => t2 !== e) : this.selectedValues = [...this.selectedValues, e] : this.selectedValues = [e]);
|
|
1036
|
+
}
|
|
1037
|
+
#u(e) {
|
|
1038
|
+
if (e !== this.#s) {
|
|
1039
|
+
this.#s = e;
|
|
1040
|
+
const t2 = this.options;
|
|
1041
|
+
e && this.#t ? this.filteredOptions = t2.filter((n) => this.#t?.(e, n)) : this.filteredOptions = [...t2];
|
|
1042
|
+
const i = p$1(this.focusedValue, this.filteredOptions);
|
|
1043
|
+
this.#e = findCursor(i, 0, this.filteredOptions);
|
|
1044
|
+
const s = this.filteredOptions[this.#e];
|
|
1045
|
+
s && !s.disabled ? this.focusedValue = s.value : this.focusedValue = undefined, this.multiple || (this.focusedValue !== undefined ? this.toggleSelected(this.focusedValue) : this.deselectAll());
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
var _ = {
|
|
1050
|
+
Y: { type: "year", len: 4 },
|
|
1051
|
+
M: { type: "month", len: 2 },
|
|
1052
|
+
D: { type: "day", len: 2 }
|
|
1053
|
+
};
|
|
1054
|
+
function M(r) {
|
|
1055
|
+
return [...r].map((t2) => _[t2]);
|
|
1056
|
+
}
|
|
1057
|
+
function P(r) {
|
|
1058
|
+
const i = new Intl.DateTimeFormat(r, {
|
|
1059
|
+
year: "numeric",
|
|
1060
|
+
month: "2-digit",
|
|
1061
|
+
day: "2-digit"
|
|
1062
|
+
}).formatToParts(new Date(2000, 0, 15)), s = [];
|
|
1063
|
+
let n = "/";
|
|
1064
|
+
for (const e of i)
|
|
1065
|
+
e.type === "literal" ? n = e.value.trim() || e.value : (e.type === "year" || e.type === "month" || e.type === "day") && s.push({ type: e.type, len: e.type === "year" ? 4 : 2 });
|
|
1066
|
+
return { segments: s, separator: n };
|
|
1067
|
+
}
|
|
1068
|
+
function p(r) {
|
|
1069
|
+
return Number.parseInt((r || "0").replace(/_/g, "0"), 10) || 0;
|
|
1070
|
+
}
|
|
1071
|
+
function f(r) {
|
|
1072
|
+
return {
|
|
1073
|
+
year: p(r.year),
|
|
1074
|
+
month: p(r.month),
|
|
1075
|
+
day: p(r.day)
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
function c(r, t2) {
|
|
1079
|
+
return new Date(r || 2001, t2 || 1, 0).getDate();
|
|
1080
|
+
}
|
|
1081
|
+
function b(r) {
|
|
1082
|
+
const { year: t2, month: i, day: s } = f(r);
|
|
1083
|
+
if (!t2 || t2 < 0 || t2 > 9999 || !i || i < 1 || i > 12 || !s || s < 1)
|
|
1084
|
+
return;
|
|
1085
|
+
const n = new Date(Date.UTC(t2, i - 1, s));
|
|
1086
|
+
if (!(n.getUTCFullYear() !== t2 || n.getUTCMonth() !== i - 1 || n.getUTCDate() !== s))
|
|
1087
|
+
return { year: t2, month: i, day: s };
|
|
1088
|
+
}
|
|
1089
|
+
function C(r) {
|
|
1090
|
+
const t2 = b(r);
|
|
1091
|
+
return t2 ? new Date(Date.UTC(t2.year, t2.month - 1, t2.day)) : undefined;
|
|
1092
|
+
}
|
|
1093
|
+
function T2(r, t2, i, s) {
|
|
1094
|
+
const n = i ? {
|
|
1095
|
+
year: i.getUTCFullYear(),
|
|
1096
|
+
month: i.getUTCMonth() + 1,
|
|
1097
|
+
day: i.getUTCDate()
|
|
1098
|
+
} : null, e = s ? {
|
|
1099
|
+
year: s.getUTCFullYear(),
|
|
1100
|
+
month: s.getUTCMonth() + 1,
|
|
1101
|
+
day: s.getUTCDate()
|
|
1102
|
+
} : null;
|
|
1103
|
+
return r === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r === "month" ? {
|
|
1104
|
+
min: n && t2.year === n.year ? n.month : 1,
|
|
1105
|
+
max: e && t2.year === e.year ? e.month : 12
|
|
1106
|
+
} : {
|
|
1107
|
+
min: n && t2.year === n.year && t2.month === n.month ? n.day : 1,
|
|
1108
|
+
max: e && t2.year === e.year && t2.month === e.month ? e.day : c(t2.year, t2.month)
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
class U extends V {
|
|
1113
|
+
#i;
|
|
1114
|
+
#o;
|
|
1115
|
+
#t;
|
|
1116
|
+
#h;
|
|
1117
|
+
#u;
|
|
1118
|
+
#e = { segmentIndex: 0, positionInSegment: 0 };
|
|
1119
|
+
#n = true;
|
|
1120
|
+
#s = null;
|
|
1121
|
+
inlineError = "";
|
|
1122
|
+
get segmentCursor() {
|
|
1123
|
+
return { ...this.#e };
|
|
1124
|
+
}
|
|
1125
|
+
get segmentValues() {
|
|
1126
|
+
return { ...this.#t };
|
|
1127
|
+
}
|
|
1128
|
+
get segments() {
|
|
1129
|
+
return this.#i;
|
|
1130
|
+
}
|
|
1131
|
+
get separator() {
|
|
1132
|
+
return this.#o;
|
|
1133
|
+
}
|
|
1134
|
+
get formattedValue() {
|
|
1135
|
+
return this.#l(this.#t);
|
|
1136
|
+
}
|
|
1137
|
+
#l(t2) {
|
|
1138
|
+
return this.#i.map((i) => t2[i.type]).join(this.#o);
|
|
1139
|
+
}
|
|
1140
|
+
#r() {
|
|
1141
|
+
this._setUserInput(this.#l(this.#t)), this._setValue(C(this.#t) ?? undefined);
|
|
1142
|
+
}
|
|
1143
|
+
constructor(t2) {
|
|
1144
|
+
const i = t2.format ? { segments: M(t2.format), separator: t2.separator ?? "/" } : P(t2.locale), s = t2.separator ?? i.separator, n = t2.format ? M(t2.format) : i.segments, e = t2.initialValue ?? t2.defaultValue, m2 = e ? {
|
|
1145
|
+
year: String(e.getUTCFullYear()).padStart(4, "0"),
|
|
1146
|
+
month: String(e.getUTCMonth() + 1).padStart(2, "0"),
|
|
1147
|
+
day: String(e.getUTCDate()).padStart(2, "0")
|
|
1148
|
+
} : { year: "____", month: "__", day: "__" }, o = n.map((a) => m2[a.type]).join(s);
|
|
1149
|
+
super({ ...t2, initialUserInput: o }, false), this.#i = n, this.#o = s, this.#t = m2, this.#h = t2.minDate, this.#u = t2.maxDate, this.#r(), this.on("cursor", (a) => this.#f(a)), this.on("key", (a, u) => this.#y(a, u)), this.on("finalize", () => this.#p(t2));
|
|
1150
|
+
}
|
|
1151
|
+
#a() {
|
|
1152
|
+
const t2 = Math.max(0, Math.min(this.#e.segmentIndex, this.#i.length - 1)), i = this.#i[t2];
|
|
1153
|
+
if (i)
|
|
1154
|
+
return this.#e.positionInSegment = Math.max(0, Math.min(this.#e.positionInSegment, i.len - 1)), { segment: i, index: t2 };
|
|
1155
|
+
}
|
|
1156
|
+
#m(t2) {
|
|
1157
|
+
this.inlineError = "", this.#s = null;
|
|
1158
|
+
const i = this.#a();
|
|
1159
|
+
i && (this.#e.segmentIndex = Math.max(0, Math.min(this.#i.length - 1, i.index + t2)), this.#e.positionInSegment = 0, this.#n = true);
|
|
1160
|
+
}
|
|
1161
|
+
#d(t2) {
|
|
1162
|
+
const i = this.#a();
|
|
1163
|
+
if (!i)
|
|
1164
|
+
return;
|
|
1165
|
+
const { segment: s } = i, n = this.#t[s.type], e = !n || n.replace(/_/g, "") === "", m2 = Number.parseInt((n || "0").replace(/_/g, "0"), 10) || 0, o = T2(s.type, f(this.#t), this.#h, this.#u);
|
|
1166
|
+
let a;
|
|
1167
|
+
e ? a = t2 === 1 ? o.min : o.max : a = Math.max(Math.min(o.max, m2 + t2), o.min), this.#t = {
|
|
1168
|
+
...this.#t,
|
|
1169
|
+
[s.type]: a.toString().padStart(s.len, "0")
|
|
1170
|
+
}, this.#n = true, this.#s = null, this.#r();
|
|
1171
|
+
}
|
|
1172
|
+
#f(t2) {
|
|
1173
|
+
if (t2)
|
|
1174
|
+
switch (t2) {
|
|
1175
|
+
case "right":
|
|
1176
|
+
return this.#m(1);
|
|
1177
|
+
case "left":
|
|
1178
|
+
return this.#m(-1);
|
|
1179
|
+
case "up":
|
|
1180
|
+
return this.#d(1);
|
|
1181
|
+
case "down":
|
|
1182
|
+
return this.#d(-1);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
#y(t2, i) {
|
|
1186
|
+
if (i?.name === "backspace" || i?.sequence === "\x7F" || i?.sequence === "\b" || t2 === "\x7F" || t2 === "\b") {
|
|
1187
|
+
this.inlineError = "";
|
|
1188
|
+
const n = this.#a();
|
|
1189
|
+
if (!n)
|
|
1190
|
+
return;
|
|
1191
|
+
if (!this.#t[n.segment.type].replace(/_/g, "")) {
|
|
1192
|
+
this.#m(-1);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
this.#t[n.segment.type] = "_".repeat(n.segment.len), this.#n = true, this.#e.positionInSegment = 0, this.#r();
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
if (i?.name === "tab") {
|
|
1199
|
+
this.inlineError = "";
|
|
1200
|
+
const n = this.#a();
|
|
1201
|
+
if (!n)
|
|
1202
|
+
return;
|
|
1203
|
+
const e = i.shift ? -1 : 1, m2 = n.index + e;
|
|
1204
|
+
m2 >= 0 && m2 < this.#i.length && (this.#e.segmentIndex = m2, this.#e.positionInSegment = 0, this.#n = true);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
if (t2 && /^[0-9]$/.test(t2)) {
|
|
1208
|
+
const n = this.#a();
|
|
1209
|
+
if (!n)
|
|
1210
|
+
return;
|
|
1211
|
+
const { segment: e } = n, m2 = !this.#t[e.type].replace(/_/g, "");
|
|
1212
|
+
if (this.#n && this.#s !== null && !m2) {
|
|
1213
|
+
const h = this.#s + t2, d = { ...this.#t, [e.type]: h }, g2 = this.#g(d, e);
|
|
1214
|
+
if (g2) {
|
|
1215
|
+
this.inlineError = g2, this.#s = null, this.#n = false;
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
this.inlineError = "", this.#t[e.type] = h, this.#s = null, this.#n = false, this.#r(), n.index < this.#i.length - 1 && (this.#e.segmentIndex = n.index + 1, this.#e.positionInSegment = 0, this.#n = true);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
this.#n && !m2 && (this.#t[e.type] = "_".repeat(e.len), this.#e.positionInSegment = 0), this.#n = false, this.#s = null;
|
|
1222
|
+
const o = this.#t[e.type], a = o.indexOf("_"), u = a >= 0 ? a : Math.min(this.#e.positionInSegment, e.len - 1);
|
|
1223
|
+
if (u < 0 || u >= e.len)
|
|
1224
|
+
return;
|
|
1225
|
+
let l2 = o.slice(0, u) + t2 + o.slice(u + 1), D = false;
|
|
1226
|
+
if (u === 0 && o === "__" && (e.type === "month" || e.type === "day")) {
|
|
1227
|
+
const h = Number.parseInt(t2, 10);
|
|
1228
|
+
l2 = `0${t2}`, D = h <= (e.type === "month" ? 1 : 2);
|
|
1229
|
+
}
|
|
1230
|
+
if (e.type === "year" && (l2 = (o.replace(/_/g, "") + t2).padStart(e.len, "_")), !l2.includes("_")) {
|
|
1231
|
+
const h = { ...this.#t, [e.type]: l2 }, d = this.#g(h, e);
|
|
1232
|
+
if (d) {
|
|
1233
|
+
this.inlineError = d;
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
this.inlineError = "", this.#t[e.type] = l2;
|
|
1238
|
+
const y = l2.includes("_") ? undefined : b(this.#t);
|
|
1239
|
+
if (y) {
|
|
1240
|
+
const { year: h, month: d } = y, g2 = c(h, d);
|
|
1241
|
+
this.#t = {
|
|
1242
|
+
year: String(Math.max(0, Math.min(9999, h))).padStart(4, "0"),
|
|
1243
|
+
month: String(Math.max(1, Math.min(12, d))).padStart(2, "0"),
|
|
1244
|
+
day: String(Math.max(1, Math.min(g2, y.day))).padStart(2, "0")
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
this.#r();
|
|
1248
|
+
const S = l2.indexOf("_");
|
|
1249
|
+
D ? (this.#n = true, this.#s = t2) : S >= 0 ? this.#e.positionInSegment = S : a >= 0 && n.index < this.#i.length - 1 ? (this.#e.segmentIndex = n.index + 1, this.#e.positionInSegment = 0, this.#n = true) : this.#e.positionInSegment = Math.min(u + 1, e.len - 1);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
#g(t2, i) {
|
|
1253
|
+
const { month: s, day: n } = f(t2);
|
|
1254
|
+
if (i.type === "month" && (s < 0 || s > 12))
|
|
1255
|
+
return settings.date.messages.invalidMonth;
|
|
1256
|
+
if (i.type === "day" && (n < 0 || n > 31))
|
|
1257
|
+
return settings.date.messages.invalidDay(31, "any month");
|
|
1258
|
+
}
|
|
1259
|
+
#p(t2) {
|
|
1260
|
+
const { year: i, month: s, day: n } = f(this.#t);
|
|
1261
|
+
if (i && s && n) {
|
|
1262
|
+
const e = c(i, s);
|
|
1263
|
+
this.#t = {
|
|
1264
|
+
...this.#t,
|
|
1265
|
+
day: String(Math.min(n, e)).padStart(2, "0")
|
|
261
1266
|
};
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
1267
|
+
}
|
|
1268
|
+
this.value = C(this.#t) ?? t2.defaultValue ?? undefined;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
var u$1 = class u extends V {
|
|
1272
|
+
options;
|
|
1273
|
+
cursor = 0;
|
|
1274
|
+
#t;
|
|
1275
|
+
getGroupItems(t2) {
|
|
1276
|
+
return this.options.filter((r) => r.group === t2);
|
|
1277
|
+
}
|
|
1278
|
+
isGroupSelected(t2) {
|
|
1279
|
+
const r = this.getGroupItems(t2), e = this.value;
|
|
1280
|
+
return e === undefined ? false : r.every((s) => e.includes(s.value));
|
|
1281
|
+
}
|
|
1282
|
+
toggleValue() {
|
|
1283
|
+
const t2 = this.options[this.cursor];
|
|
1284
|
+
if (this.value === undefined && (this.value = []), t2.group === true) {
|
|
1285
|
+
const r = t2.value, e = this.getGroupItems(r);
|
|
1286
|
+
this.isGroupSelected(r) ? this.value = this.value.filter((s) => e.findIndex((i) => i.value === s) === -1) : this.value = [...this.value, ...e.map((s) => s.value)], this.value = Array.from(new Set(this.value));
|
|
1287
|
+
} else {
|
|
1288
|
+
const r = this.value.includes(t2.value);
|
|
1289
|
+
this.value = r ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
constructor(t2) {
|
|
1293
|
+
super(t2, false);
|
|
1294
|
+
const { options: r } = t2;
|
|
1295
|
+
this.#t = t2.selectableGroups !== false, this.options = Object.entries(r).flatMap(([e, s]) => [
|
|
1296
|
+
{ value: e, group: true, label: e },
|
|
1297
|
+
...s.map((i) => ({ ...i, group: e }))
|
|
1298
|
+
]), this.value = [...t2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: e }) => e === t2.cursorAt), this.#t ? 0 : 1), this.on("cursor", (e) => {
|
|
1299
|
+
switch (e) {
|
|
1300
|
+
case "left":
|
|
1301
|
+
case "up": {
|
|
1302
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
1303
|
+
const s = this.options[this.cursor]?.group === true;
|
|
1304
|
+
!this.#t && s && (this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1);
|
|
1305
|
+
break;
|
|
1306
|
+
}
|
|
1307
|
+
case "down":
|
|
1308
|
+
case "right": {
|
|
1309
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
1310
|
+
const s = this.options[this.cursor]?.group === true;
|
|
1311
|
+
!this.#t && s && (this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1);
|
|
1312
|
+
break;
|
|
1313
|
+
}
|
|
1314
|
+
case "space":
|
|
1315
|
+
this.toggleValue();
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
var o$1 = /* @__PURE__ */ new Set(["up", "down", "left", "right"]);
|
|
1322
|
+
|
|
1323
|
+
class h extends V {
|
|
1324
|
+
#s = false;
|
|
1325
|
+
#t;
|
|
1326
|
+
focused = "editor";
|
|
1327
|
+
get userInputWithCursor() {
|
|
1328
|
+
if (this.state === "submit")
|
|
1329
|
+
return this.userInput;
|
|
1330
|
+
const t2 = this.userInput;
|
|
1331
|
+
if (this.cursor >= t2.length)
|
|
1332
|
+
return `${t2}\u2588`;
|
|
1333
|
+
const s = t2.slice(0, this.cursor), r = t2[this.cursor], e = t2.slice(this.cursor + 1);
|
|
1334
|
+
return r === `
|
|
1335
|
+
` ? `${s}\u2588
|
|
1336
|
+
${e}` : `${s}${styleText("inverse", r)}${e}`;
|
|
1337
|
+
}
|
|
1338
|
+
get cursor() {
|
|
1339
|
+
return this._cursor;
|
|
1340
|
+
}
|
|
1341
|
+
#r(t2) {
|
|
1342
|
+
if (this.userInput.length === 0) {
|
|
1343
|
+
this._setUserInput(t2);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
this._setUserInput(this.userInput.slice(0, this.cursor) + t2 + this.userInput.slice(this.cursor));
|
|
1347
|
+
}
|
|
1348
|
+
#i(t2) {
|
|
1349
|
+
const s = this.value ?? "";
|
|
1350
|
+
switch (t2) {
|
|
1351
|
+
case "up":
|
|
1352
|
+
this._cursor = findTextCursor(this._cursor, 0, -1, s);
|
|
1353
|
+
return;
|
|
1354
|
+
case "down":
|
|
1355
|
+
this._cursor = findTextCursor(this._cursor, 0, 1, s);
|
|
1356
|
+
return;
|
|
1357
|
+
case "left":
|
|
1358
|
+
this._cursor = findTextCursor(this._cursor, -1, 0, s);
|
|
1359
|
+
return;
|
|
1360
|
+
case "right":
|
|
1361
|
+
this._cursor = findTextCursor(this._cursor, 1, 0, s);
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
_shouldSubmit(t2, s) {
|
|
1366
|
+
if (this.#t)
|
|
1367
|
+
return this.focused === "submit" ? true : (this.#r(`
|
|
1368
|
+
`), this._cursor++, false);
|
|
1369
|
+
const r = this.#s;
|
|
1370
|
+
return this.#s = true, r ? (this.userInput[this.cursor - 1] === `
|
|
1371
|
+
` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
|
|
1372
|
+
`), this._cursor++, false);
|
|
1373
|
+
}
|
|
1374
|
+
constructor(t2) {
|
|
1375
|
+
super(t2, false), this.#t = t2.showSubmit ?? false, this.on("key", (s, r) => {
|
|
1376
|
+
if (r?.name && o$1.has(r.name)) {
|
|
1377
|
+
this.#i(r.name);
|
|
265
1378
|
return;
|
|
266
1379
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
res.writeHead(404, corsHeaders);
|
|
270
|
-
res.end("Not found");
|
|
1380
|
+
if (s === "\t" && this.#t) {
|
|
1381
|
+
this.focused = this.focused === "editor" ? "submit" : "editor";
|
|
271
1382
|
return;
|
|
272
1383
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
1384
|
+
if (r?.name !== "return") {
|
|
1385
|
+
if (this.#s = false, r?.name === "backspace" && this.cursor > 0) {
|
|
1386
|
+
this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--;
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (r?.name === "delete" && this.cursor < this.userInput.length) {
|
|
1390
|
+
this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
s && (this.#t && this.focused === "submit" && (this.focused = "editor"), this.#r(s ?? ""), this._cursor++);
|
|
1394
|
+
}
|
|
1395
|
+
}), this.on("userInput", (s) => {
|
|
1396
|
+
this._setValue(s);
|
|
1397
|
+
}), this.on("finalize", () => {
|
|
1398
|
+
this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
class a extends V {
|
|
1403
|
+
options;
|
|
1404
|
+
cursor = 0;
|
|
1405
|
+
get _selectedValue() {
|
|
1406
|
+
return this.options[this.cursor];
|
|
1407
|
+
}
|
|
1408
|
+
changeValue() {
|
|
1409
|
+
this.value = this._selectedValue.value;
|
|
1410
|
+
}
|
|
1411
|
+
constructor(t2) {
|
|
1412
|
+
super(t2, false), this.options = t2.options;
|
|
1413
|
+
const i = this.options.findIndex(({ value: s }) => s === t2.initialValue), e = i === -1 ? 0 : i;
|
|
1414
|
+
this.cursor = this.options[e].disabled ? findCursor(e, 1, this.options) : e, this.changeValue(), this.on("cursor", (s) => {
|
|
1415
|
+
switch (s) {
|
|
1416
|
+
case "left":
|
|
1417
|
+
case "up":
|
|
1418
|
+
this.cursor = findCursor(this.cursor, -1, this.options);
|
|
1419
|
+
break;
|
|
1420
|
+
case "down":
|
|
1421
|
+
case "right":
|
|
1422
|
+
this.cursor = findCursor(this.cursor, 1, this.options);
|
|
1423
|
+
break;
|
|
1424
|
+
}
|
|
1425
|
+
this.changeValue();
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
class n extends V {
|
|
1430
|
+
get userInputWithCursor() {
|
|
1431
|
+
if (this.state === "submit")
|
|
1432
|
+
return this.userInput;
|
|
1433
|
+
const t2 = this.userInput;
|
|
1434
|
+
if (this.cursor >= t2.length)
|
|
1435
|
+
return `${this.userInput}\u2588`;
|
|
1436
|
+
const e = t2.slice(0, this.cursor), [s, ...r] = t2.slice(this.cursor);
|
|
1437
|
+
return `${e}${styleText("inverse", s)}${r.join("")}`;
|
|
1438
|
+
}
|
|
1439
|
+
get cursor() {
|
|
1440
|
+
return this._cursor;
|
|
1441
|
+
}
|
|
1442
|
+
constructor(t2) {
|
|
1443
|
+
super({
|
|
1444
|
+
...t2,
|
|
1445
|
+
initialUserInput: t2.initialUserInput ?? t2.initialValue
|
|
1446
|
+
}), this.on("userInput", (e) => {
|
|
1447
|
+
this._setValue(e);
|
|
1448
|
+
}), this.on("finalize", () => {
|
|
1449
|
+
this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// ../../node_modules/.bun/@clack+prompts@1.5.1/node_modules/@clack/prompts/dist/index.mjs
|
|
1455
|
+
import { styleText as styleText2, stripVTControlCharacters } from "util";
|
|
1456
|
+
import process$1 from "process";
|
|
1457
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
1458
|
+
function isUnicodeSupported() {
|
|
1459
|
+
if (process$1.platform !== "win32") {
|
|
1460
|
+
return process$1.env.TERM !== "linux";
|
|
1461
|
+
}
|
|
1462
|
+
return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
1463
|
+
}
|
|
1464
|
+
var unicode = isUnicodeSupported();
|
|
1465
|
+
var isCI = () => process.env.CI === "true";
|
|
1466
|
+
var unicodeOr = (e, o2) => unicode ? e : o2;
|
|
1467
|
+
var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
|
|
1468
|
+
var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
|
|
1469
|
+
var S_STEP_ERROR = unicodeOr("\u25B2", "x");
|
|
1470
|
+
var S_STEP_SUBMIT = unicodeOr("\u25C7", "o");
|
|
1471
|
+
var S_BAR_START = unicodeOr("\u250C", "T");
|
|
1472
|
+
var S_BAR = unicodeOr("\u2502", "|");
|
|
1473
|
+
var S_BAR_END = unicodeOr("\u2514", "\u2014");
|
|
1474
|
+
var S_BAR_START_RIGHT = unicodeOr("\u2510", "T");
|
|
1475
|
+
var S_BAR_END_RIGHT = unicodeOr("\u2518", "\u2014");
|
|
1476
|
+
var S_RADIO_ACTIVE = unicodeOr("\u25CF", ">");
|
|
1477
|
+
var S_RADIO_INACTIVE = unicodeOr("\u25CB", " ");
|
|
1478
|
+
var S_CHECKBOX_ACTIVE = unicodeOr("\u25FB", "[\u2022]");
|
|
1479
|
+
var S_CHECKBOX_SELECTED = unicodeOr("\u25FC", "[+]");
|
|
1480
|
+
var S_CHECKBOX_INACTIVE = unicodeOr("\u25FB", "[ ]");
|
|
1481
|
+
var S_PASSWORD_MASK = unicodeOr("\u25AA", "\u2022");
|
|
1482
|
+
var S_BAR_H = unicodeOr("\u2500", "-");
|
|
1483
|
+
var S_CORNER_TOP_RIGHT = unicodeOr("\u256E", "+");
|
|
1484
|
+
var S_CONNECT_LEFT = unicodeOr("\u251C", "+");
|
|
1485
|
+
var S_CORNER_BOTTOM_RIGHT = unicodeOr("\u256F", "+");
|
|
1486
|
+
var S_CORNER_BOTTOM_LEFT = unicodeOr("\u2570", "+");
|
|
1487
|
+
var S_CORNER_TOP_LEFT = unicodeOr("\u256D", "+");
|
|
1488
|
+
var S_INFO = unicodeOr("\u25CF", "\u2022");
|
|
1489
|
+
var S_SUCCESS = unicodeOr("\u25C6", "*");
|
|
1490
|
+
var S_WARN = unicodeOr("\u25B2", "!");
|
|
1491
|
+
var S_ERROR = unicodeOr("\u25A0", "x");
|
|
1492
|
+
var symbol = (e) => {
|
|
1493
|
+
switch (e) {
|
|
1494
|
+
case "initial":
|
|
1495
|
+
case "active":
|
|
1496
|
+
return styleText2("cyan", S_STEP_ACTIVE);
|
|
1497
|
+
case "cancel":
|
|
1498
|
+
return styleText2("red", S_STEP_CANCEL);
|
|
1499
|
+
case "error":
|
|
1500
|
+
return styleText2("yellow", S_STEP_ERROR);
|
|
1501
|
+
case "submit":
|
|
1502
|
+
return styleText2("green", S_STEP_SUBMIT);
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
var symbolBar = (e) => {
|
|
1506
|
+
switch (e) {
|
|
1507
|
+
case "initial":
|
|
1508
|
+
case "active":
|
|
1509
|
+
return styleText2("cyan", S_BAR);
|
|
1510
|
+
case "cancel":
|
|
1511
|
+
return styleText2("red", S_BAR);
|
|
1512
|
+
case "error":
|
|
1513
|
+
return styleText2("yellow", S_BAR);
|
|
1514
|
+
case "submit":
|
|
1515
|
+
return styleText2("green", S_BAR);
|
|
1516
|
+
}
|
|
1517
|
+
};
|
|
1518
|
+
var E$1 = (l2, o2, g2, c2, h2, O = false) => {
|
|
1519
|
+
let r2 = o2, w = 0;
|
|
1520
|
+
if (O)
|
|
1521
|
+
for (let i = c2 - 1;i >= g2 && (r2 -= l2[i].length, w++, !(r2 <= h2)); i--)
|
|
1522
|
+
;
|
|
1523
|
+
else
|
|
1524
|
+
for (let i = g2;i < c2 && (r2 -= l2[i].length, w++, !(r2 <= h2)); i++)
|
|
1525
|
+
;
|
|
1526
|
+
return { lineCount: r2, removals: w };
|
|
1527
|
+
};
|
|
1528
|
+
var limitOptions = ({
|
|
1529
|
+
cursor: l2,
|
|
1530
|
+
options: o2,
|
|
1531
|
+
style: g2,
|
|
1532
|
+
output: c2 = process.stdout,
|
|
1533
|
+
maxItems: h2 = Number.POSITIVE_INFINITY,
|
|
1534
|
+
columnPadding: O = 0,
|
|
1535
|
+
rowPadding: r2 = 4
|
|
1536
|
+
}) => {
|
|
1537
|
+
const i = getColumns(c2) - O, I = getRows(c2), C2 = styleText2("dim", "..."), x = Math.max(I - r2, 0), m2 = Math.max(Math.min(h2, x), 5);
|
|
1538
|
+
let p2 = 0;
|
|
1539
|
+
l2 >= m2 - 3 && (p2 = Math.max(Math.min(l2 - m2 + 3, o2.length - m2), 0));
|
|
1540
|
+
let f2 = m2 < o2.length && p2 > 0, u3 = m2 < o2.length && p2 + m2 < o2.length;
|
|
1541
|
+
const W = Math.min(p2 + m2, o2.length), e = [];
|
|
1542
|
+
let d = 0;
|
|
1543
|
+
f2 && d++, u3 && d++;
|
|
1544
|
+
const v = p2 + (f2 ? 1 : 0), P2 = W - (u3 ? 1 : 0);
|
|
1545
|
+
for (let t2 = v;t2 < P2; t2++) {
|
|
1546
|
+
const n2 = wrapAnsi(g2(o2[t2], t2 === l2), i, {
|
|
1547
|
+
hard: true,
|
|
1548
|
+
trim: false
|
|
1549
|
+
}).split(`
|
|
1550
|
+
`);
|
|
1551
|
+
e.push(n2), d += n2.length;
|
|
1552
|
+
}
|
|
1553
|
+
if (d > x) {
|
|
1554
|
+
let t2 = 0, n2 = 0, s = d;
|
|
1555
|
+
const M2 = l2 - v;
|
|
1556
|
+
let a2 = x;
|
|
1557
|
+
const T3 = () => E$1(e, s, 0, M2, a2), L = () => E$1(e, s, M2 + 1, e.length, a2, true);
|
|
1558
|
+
f2 ? ({ lineCount: s, removals: t2 } = T3(), s > a2 && (u3 || (a2 -= 1), { lineCount: s, removals: n2 } = L())) : (u3 || (a2 -= 1), { lineCount: s, removals: n2 } = L(), s > a2 && (a2 -= 1, { lineCount: s, removals: t2 } = T3())), t2 > 0 && (f2 = true, e.splice(0, t2)), n2 > 0 && (u3 = true, e.splice(e.length - n2, n2));
|
|
1559
|
+
}
|
|
1560
|
+
const b2 = [];
|
|
1561
|
+
f2 && b2.push(C2);
|
|
1562
|
+
for (const t2 of e)
|
|
1563
|
+
for (const n2 of t2)
|
|
1564
|
+
b2.push(n2);
|
|
1565
|
+
return u3 && b2.push(C2), b2;
|
|
1566
|
+
};
|
|
1567
|
+
var log = {
|
|
1568
|
+
message: (s = [], {
|
|
1569
|
+
symbol: e = styleText2("gray", S_BAR),
|
|
1570
|
+
secondarySymbol: r2 = styleText2("gray", S_BAR),
|
|
1571
|
+
output: m2 = process.stdout,
|
|
1572
|
+
spacing: l2 = 1,
|
|
1573
|
+
withGuide: c2
|
|
1574
|
+
} = {}) => {
|
|
1575
|
+
const t2 = [], o2 = c2 ?? settings.withGuide, f2 = o2 ? r2 : "", O = o2 ? `${e} ` : "", u3 = o2 ? `${r2} ` : "";
|
|
1576
|
+
for (let i = 0;i < l2; i++)
|
|
1577
|
+
t2.push(f2);
|
|
1578
|
+
const g2 = Array.isArray(s) ? s : s.split(`
|
|
1579
|
+
`);
|
|
1580
|
+
if (g2.length > 0) {
|
|
1581
|
+
const [i, ...y] = g2;
|
|
1582
|
+
i.length > 0 ? t2.push(`${O}${i}`) : t2.push(o2 ? e : "");
|
|
1583
|
+
for (const p2 of y)
|
|
1584
|
+
p2.length > 0 ? t2.push(`${u3}${p2}`) : t2.push(o2 ? r2 : "");
|
|
1585
|
+
}
|
|
1586
|
+
m2.write(`${t2.join(`
|
|
1587
|
+
`)}
|
|
1588
|
+
`);
|
|
1589
|
+
},
|
|
1590
|
+
info: (s, e) => {
|
|
1591
|
+
log.message(s, { ...e, symbol: styleText2("blue", S_INFO) });
|
|
1592
|
+
},
|
|
1593
|
+
success: (s, e) => {
|
|
1594
|
+
log.message(s, { ...e, symbol: styleText2("green", S_SUCCESS) });
|
|
1595
|
+
},
|
|
1596
|
+
step: (s, e) => {
|
|
1597
|
+
log.message(s, { ...e, symbol: styleText2("green", S_STEP_SUBMIT) });
|
|
1598
|
+
},
|
|
1599
|
+
warn: (s, e) => {
|
|
1600
|
+
log.message(s, { ...e, symbol: styleText2("yellow", S_WARN) });
|
|
1601
|
+
},
|
|
1602
|
+
warning: (s, e) => {
|
|
1603
|
+
log.warn(s, e);
|
|
1604
|
+
},
|
|
1605
|
+
error: (s, e) => {
|
|
1606
|
+
log.message(s, { ...e, symbol: styleText2("red", S_ERROR) });
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
var cancel = (o2 = "", t2) => {
|
|
1610
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
|
|
1611
|
+
i.write(`${e}${styleText2("red", o2)}
|
|
1612
|
+
|
|
1613
|
+
`);
|
|
1614
|
+
};
|
|
1615
|
+
var intro = (o2 = "", t2) => {
|
|
1616
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
|
|
1617
|
+
i.write(`${e}${o2}
|
|
1618
|
+
`);
|
|
1619
|
+
};
|
|
1620
|
+
var outro = (o2 = "", t2) => {
|
|
1621
|
+
const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
|
|
1622
|
+
${styleText2("gray", S_BAR_END)} ` : "";
|
|
1623
|
+
i.write(`${e}${o2}
|
|
1624
|
+
|
|
1625
|
+
`);
|
|
1626
|
+
};
|
|
1627
|
+
var W = (l2) => styleText2("magenta", l2);
|
|
1628
|
+
var spinner = ({
|
|
1629
|
+
indicator: l2 = "dots",
|
|
1630
|
+
onCancel: h2,
|
|
1631
|
+
output: n2 = process.stdout,
|
|
1632
|
+
cancelMessage: G,
|
|
1633
|
+
errorMessage: O,
|
|
1634
|
+
frames: E = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"],
|
|
1635
|
+
delay: F = unicode ? 80 : 120,
|
|
1636
|
+
signal: m2,
|
|
1637
|
+
...I
|
|
1638
|
+
} = {}) => {
|
|
1639
|
+
const u3 = isCI();
|
|
1640
|
+
let M2, T3, d = false, S = false, s = "", p2, w = performance.now();
|
|
1641
|
+
const x = getColumns(n2), k = I?.styleFrame ?? W, g2 = (e) => {
|
|
1642
|
+
const r2 = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
|
|
1643
|
+
S = e === 1, d && (a2(r2, e), S && typeof h2 == "function" && h2());
|
|
1644
|
+
}, f2 = () => g2(2), i = () => g2(1), A = () => {
|
|
1645
|
+
process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i), process.on("SIGTERM", i), process.on("exit", g2), m2 && m2.addEventListener("abort", i);
|
|
1646
|
+
}, H = () => {
|
|
1647
|
+
process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i), process.removeListener("SIGTERM", i), process.removeListener("exit", g2), m2 && m2.removeEventListener("abort", i);
|
|
1648
|
+
}, y = () => {
|
|
1649
|
+
if (p2 === undefined)
|
|
1650
|
+
return;
|
|
1651
|
+
u3 && n2.write(`
|
|
1652
|
+
`);
|
|
1653
|
+
const r2 = wrapAnsi(p2, x, {
|
|
1654
|
+
hard: true,
|
|
1655
|
+
trim: false
|
|
1656
|
+
}).split(`
|
|
1657
|
+
`);
|
|
1658
|
+
r2.length > 1 && n2.write(import_sisteransi2.cursor.up(r2.length - 1)), n2.write(import_sisteransi2.cursor.to(0)), n2.write(import_sisteransi2.erase.down());
|
|
1659
|
+
}, C2 = (e) => e.replace(/\.+$/, ""), _2 = (e) => {
|
|
1660
|
+
const r2 = (performance.now() - e) / 1000, t2 = Math.floor(r2 / 60), o2 = Math.floor(r2 % 60);
|
|
1661
|
+
return t2 > 0 ? `[${t2}m ${o2}s]` : `[${o2}s]`;
|
|
1662
|
+
}, N = I.withGuide ?? settings.withGuide, P2 = (e = "") => {
|
|
1663
|
+
d = true, M2 = block({ output: n2 }), s = C2(e), w = performance.now(), N && n2.write(`${styleText2("gray", S_BAR)}
|
|
1664
|
+
`);
|
|
1665
|
+
let r2 = 0, t2 = 0;
|
|
1666
|
+
A(), T3 = setInterval(() => {
|
|
1667
|
+
if (u3 && s === p2)
|
|
280
1668
|
return;
|
|
1669
|
+
y(), p2 = s;
|
|
1670
|
+
const o2 = k(E[r2]);
|
|
1671
|
+
let v;
|
|
1672
|
+
if (u3)
|
|
1673
|
+
v = `${o2} ${s}...`;
|
|
1674
|
+
else if (l2 === "timer")
|
|
1675
|
+
v = `${o2} ${s} ${_2(w)}`;
|
|
1676
|
+
else {
|
|
1677
|
+
const B = ".".repeat(Math.floor(t2)).slice(0, 3);
|
|
1678
|
+
v = `${o2} ${s}${B}`;
|
|
1679
|
+
}
|
|
1680
|
+
const j = wrapAnsi(v, x, {
|
|
1681
|
+
hard: true,
|
|
1682
|
+
trim: false
|
|
1683
|
+
});
|
|
1684
|
+
n2.write(j), r2 = r2 + 1 < E.length ? r2 + 1 : 0, t2 = t2 < 4 ? t2 + 0.125 : 0;
|
|
1685
|
+
}, F);
|
|
1686
|
+
}, a2 = (e = "", r2 = 0, t2 = false) => {
|
|
1687
|
+
if (!d)
|
|
1688
|
+
return;
|
|
1689
|
+
d = false, clearInterval(T3), y();
|
|
1690
|
+
const o2 = r2 === 0 ? styleText2("green", S_STEP_SUBMIT) : r2 === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
|
|
1691
|
+
s = e ?? s, t2 || (l2 === "timer" ? n2.write(`${o2} ${s} ${_2(w)}
|
|
1692
|
+
`) : n2.write(`${o2} ${s}
|
|
1693
|
+
`)), H(), M2();
|
|
1694
|
+
};
|
|
1695
|
+
return {
|
|
1696
|
+
start: P2,
|
|
1697
|
+
stop: (e = "") => a2(e, 0),
|
|
1698
|
+
message: (e = "") => {
|
|
1699
|
+
s = C2(e ?? s);
|
|
1700
|
+
},
|
|
1701
|
+
cancel: (e = "") => a2(e, 1),
|
|
1702
|
+
error: (e = "") => a2(e, 2),
|
|
1703
|
+
clear: () => a2("", 0, true),
|
|
1704
|
+
get isCancelled() {
|
|
1705
|
+
return S;
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
};
|
|
1709
|
+
var u3 = {
|
|
1710
|
+
light: unicodeOr("\u2500", "-"),
|
|
1711
|
+
heavy: unicodeOr("\u2501", "="),
|
|
1712
|
+
block: unicodeOr("\u2588", "#")
|
|
1713
|
+
};
|
|
1714
|
+
var c2 = (e, a2) => e.includes(`
|
|
1715
|
+
`) ? e.split(`
|
|
1716
|
+
`).map((t2) => a2(t2)).join(`
|
|
1717
|
+
`) : a2(e);
|
|
1718
|
+
var select = (e) => {
|
|
1719
|
+
const a2 = (t2, d) => {
|
|
1720
|
+
const s = t2.label ?? String(t2.value);
|
|
1721
|
+
switch (d) {
|
|
1722
|
+
case "disabled":
|
|
1723
|
+
return `${styleText2("gray", S_RADIO_INACTIVE)} ${c2(s, (n2) => styleText2("gray", n2))}${t2.hint ? ` ${styleText2("dim", `(${t2.hint ?? "disabled"})`)}` : ""}`;
|
|
1724
|
+
case "selected":
|
|
1725
|
+
return `${c2(s, (n2) => styleText2("dim", n2))}`;
|
|
1726
|
+
case "active":
|
|
1727
|
+
return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${t2.hint ? ` ${styleText2("dim", `(${t2.hint})`)}` : ""}`;
|
|
1728
|
+
case "cancelled":
|
|
1729
|
+
return `${c2(s, (n2) => styleText2(["strikethrough", "dim"], n2))}`;
|
|
1730
|
+
default:
|
|
1731
|
+
return `${styleText2("dim", S_RADIO_INACTIVE)} ${c2(s, (n2) => styleText2("dim", n2))}`;
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
return new a({
|
|
1735
|
+
options: e.options,
|
|
1736
|
+
signal: e.signal,
|
|
1737
|
+
input: e.input,
|
|
1738
|
+
output: e.output,
|
|
1739
|
+
initialValue: e.initialValue,
|
|
1740
|
+
render() {
|
|
1741
|
+
const t2 = e.withGuide ?? settings.withGuide, d = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, n2 = wrapTextWithPrefix(e.output, e.message, s, d), u4 = `${t2 ? `${styleText2("gray", S_BAR)}
|
|
1742
|
+
` : ""}${n2}
|
|
1743
|
+
`;
|
|
1744
|
+
switch (this.state) {
|
|
1745
|
+
case "submit": {
|
|
1746
|
+
const r2 = t2 ? `${styleText2("gray", S_BAR)} ` : "", l2 = wrapTextWithPrefix(e.output, a2(this.options[this.cursor], "selected"), r2);
|
|
1747
|
+
return `${u4}${l2}`;
|
|
1748
|
+
}
|
|
1749
|
+
case "cancel": {
|
|
1750
|
+
const r2 = t2 ? `${styleText2("gray", S_BAR)} ` : "", l2 = wrapTextWithPrefix(e.output, a2(this.options[this.cursor], "cancelled"), r2);
|
|
1751
|
+
return `${u4}${l2}${t2 ? `
|
|
1752
|
+
${styleText2("gray", S_BAR)}` : ""}`;
|
|
1753
|
+
}
|
|
1754
|
+
default: {
|
|
1755
|
+
const r2 = t2 ? `${styleText2("cyan", S_BAR)} ` : "", l2 = t2 ? styleText2("cyan", S_BAR_END) : "", g2 = u4.split(`
|
|
1756
|
+
`).length, h2 = t2 ? 2 : 1;
|
|
1757
|
+
return `${u4}${r2}${limitOptions({
|
|
1758
|
+
output: e.output,
|
|
1759
|
+
cursor: this.cursor,
|
|
1760
|
+
options: this.options,
|
|
1761
|
+
maxItems: e.maxItems,
|
|
1762
|
+
columnPadding: r2.length,
|
|
1763
|
+
rowPadding: g2 + h2,
|
|
1764
|
+
style: (p2, b2) => a2(p2, p2.disabled ? "disabled" : b2 ? "active" : "inactive")
|
|
1765
|
+
}).join(`
|
|
1766
|
+
${r2}`)}
|
|
1767
|
+
${l2}
|
|
1768
|
+
`;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
}).prompt();
|
|
1773
|
+
};
|
|
1774
|
+
var i = `${styleText2("gray", S_BAR)} `;
|
|
1775
|
+
var text = (t2) => new n({
|
|
1776
|
+
validate: t2.validate,
|
|
1777
|
+
placeholder: t2.placeholder,
|
|
1778
|
+
defaultValue: t2.defaultValue,
|
|
1779
|
+
initialValue: t2.initialValue,
|
|
1780
|
+
output: t2.output,
|
|
1781
|
+
signal: t2.signal,
|
|
1782
|
+
input: t2.input,
|
|
1783
|
+
render() {
|
|
1784
|
+
const i2 = t2?.withGuide ?? settings.withGuide, s = `${`${i2 ? `${styleText2("gray", S_BAR)}
|
|
1785
|
+
` : ""}${symbol(this.state)} `}${t2.message}
|
|
1786
|
+
`, c3 = t2.placeholder ? styleText2("inverse", t2.placeholder[0]) + styleText2("dim", t2.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c3, a2 = this.value ?? "";
|
|
1787
|
+
switch (this.state) {
|
|
1788
|
+
case "error": {
|
|
1789
|
+
const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
|
|
1790
|
+
return `${s.trim()}
|
|
1791
|
+
${r2}${o2}
|
|
1792
|
+
${d}${n2}
|
|
1793
|
+
`;
|
|
281
1794
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
1795
|
+
case "submit": {
|
|
1796
|
+
const n2 = a2 ? ` ${styleText2("dim", a2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
|
|
1797
|
+
return `${s}${r2}${n2}`;
|
|
1798
|
+
}
|
|
1799
|
+
case "cancel": {
|
|
1800
|
+
const n2 = a2 ? ` ${styleText2(["strikethrough", "dim"], a2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
|
|
1801
|
+
return `${s}${r2}${n2}${a2.trim() ? `
|
|
1802
|
+
${r2}` : ""}`;
|
|
1803
|
+
}
|
|
1804
|
+
default: {
|
|
1805
|
+
const n2 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
|
|
1806
|
+
return `${s}${n2}${o2}
|
|
1807
|
+
${r2}
|
|
1808
|
+
`;
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}).prompt();
|
|
1813
|
+
|
|
1814
|
+
// src/skill.ts
|
|
1815
|
+
function generateSkillMd(config, framework) {
|
|
1816
|
+
return `# snapfail
|
|
1817
|
+
|
|
1818
|
+
snapfail captures browser error context (stack, console, network, replay timeline)
|
|
1819
|
+
and stores it so you can diagnose root causes. Evidence is structured for LLM reasoning.
|
|
1820
|
+
|
|
1821
|
+
## When to use
|
|
1822
|
+
|
|
1823
|
+
When the user reports an error or unexpected behavior in their app, run:
|
|
1824
|
+
|
|
1825
|
+
\`\`\`
|
|
1826
|
+
snapfail incidents --json
|
|
1827
|
+
\`\`\`
|
|
1828
|
+
|
|
1829
|
+
Then drill into a specific incident:
|
|
1830
|
+
|
|
1831
|
+
\`\`\`
|
|
1832
|
+
snapfail incident <id> --json
|
|
1833
|
+
\`\`\`
|
|
1834
|
+
|
|
1835
|
+
**Always use \`--json\` when querying from the LLM** \u2014 it returns structured data
|
|
1836
|
+
without ANSI color codes.
|
|
1837
|
+
|
|
1838
|
+
## Commands
|
|
1839
|
+
|
|
1840
|
+
\`\`\`
|
|
1841
|
+
snapfail incidents [--status=unresolved|resolved|ignored] [--json]
|
|
1842
|
+
List incident groups. Default status: unresolved.
|
|
1843
|
+
|
|
1844
|
+
snapfail incident <id> [--sample <n>] [--json]
|
|
1845
|
+
Show incident detail: group summary + most recent sample (stack, console, network, timeline).
|
|
1846
|
+
Use --sample <n> (0-indexed) to compare different occurrences of the same error.
|
|
1847
|
+
|
|
1848
|
+
snapfail explain <id>
|
|
1849
|
+
AI diagnosis: root cause, plain summary, fix prompt. (requires @snapfail/ai)
|
|
1850
|
+
\`\`\`
|
|
1851
|
+
|
|
1852
|
+
## Interpreting an incident
|
|
1853
|
+
|
|
1854
|
+
Key fields from \`snapfail incident <id> --json\`:
|
|
1855
|
+
|
|
1856
|
+
- \`group.title\` \u2014 normalized error message (dynamic values replaced with [uuid], [id], etc.)
|
|
1857
|
+
- \`group.count\` \u2014 total occurrences
|
|
1858
|
+
- \`group.environments\` \u2014 where it happened: "dev" | "prod"
|
|
1859
|
+
- \`group.severity\` \u2014 "critical" | "error" | "warning"
|
|
1860
|
+
- \`sample.stackFrames\` \u2014 call stack at the time of the error
|
|
1861
|
+
- \`sample.consoleEntries\` \u2014 last ~15s of console output before the error
|
|
1862
|
+
- \`sample.networkEntries\` \u2014 last ~15s of network requests (scrubbed)
|
|
1863
|
+
- \`sample.timeline\` \u2014 derived user interaction sequence (clicks, navigation, mutations)
|
|
1864
|
+
- \`sample.url\` / \`sample.route\` \u2014 where the error occurred
|
|
1865
|
+
|
|
1866
|
+
## Config
|
|
1867
|
+
|
|
1868
|
+
Project key: \`${config.projectKey}\`
|
|
1869
|
+
Endpoint: \`${config.endpoint}\`
|
|
1870
|
+
${framework ? `Framework: ${framework}
|
|
1871
|
+
` : ""}
|
|
1872
|
+
Config file: \`.snapfail.json\` (gitignored)
|
|
1873
|
+
`;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
// src/session.ts
|
|
1877
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync2, rmSync } from "fs";
|
|
1878
|
+
import { join } from "path";
|
|
1879
|
+
import { homedir } from "os";
|
|
1880
|
+
var SESSION_DIR = join(homedir(), ".snapfail");
|
|
1881
|
+
var SESSION_FILE = join(SESSION_DIR, "auth.json");
|
|
1882
|
+
function readSession() {
|
|
1883
|
+
try {
|
|
1884
|
+
if (!existsSync2(SESSION_FILE))
|
|
1885
|
+
return null;
|
|
1886
|
+
const raw = JSON.parse(readFileSync2(SESSION_FILE, "utf-8"));
|
|
1887
|
+
if (!raw.token || !raw.endpoint)
|
|
1888
|
+
return null;
|
|
1889
|
+
return raw;
|
|
1890
|
+
} catch {
|
|
1891
|
+
return null;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
function writeSession(session) {
|
|
1895
|
+
mkdirSync(SESSION_DIR, { recursive: true });
|
|
1896
|
+
writeFileSync2(SESSION_FILE, JSON.stringify(session, null, 2) + `
|
|
1897
|
+
`, "utf-8");
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
// src/auth.ts
|
|
1901
|
+
import { execSync } from "child_process";
|
|
1902
|
+
function openBrowser(url) {
|
|
1903
|
+
try {
|
|
1904
|
+
const platform = process.platform;
|
|
1905
|
+
if (platform === "darwin")
|
|
1906
|
+
execSync(`open "${url}"`, { stdio: "ignore" });
|
|
1907
|
+
else if (platform === "win32")
|
|
1908
|
+
execSync(`cmd /c start "" "${url}"`, { stdio: "ignore" });
|
|
1909
|
+
else
|
|
1910
|
+
execSync(`xdg-open "${url}"`, { stdio: "ignore" });
|
|
1911
|
+
} catch {}
|
|
1912
|
+
}
|
|
1913
|
+
async function ensureSession(endpoint) {
|
|
1914
|
+
const existing = readSession();
|
|
1915
|
+
if (existing && existing.endpoint === endpoint)
|
|
1916
|
+
return existing;
|
|
1917
|
+
const token = await waitForCliToken(endpoint);
|
|
1918
|
+
return token;
|
|
1919
|
+
}
|
|
1920
|
+
async function waitForCliToken(endpoint) {
|
|
1921
|
+
return new Promise((resolve2, reject) => {
|
|
1922
|
+
let resolved = false;
|
|
1923
|
+
const server = Bun.serve({
|
|
1924
|
+
port: 0,
|
|
1925
|
+
async fetch(req) {
|
|
1926
|
+
const url = new URL(req.url);
|
|
1927
|
+
if (url.pathname !== "/callback") {
|
|
1928
|
+
return new Response("Not found", { status: 404 });
|
|
1929
|
+
}
|
|
1930
|
+
const token = url.searchParams.get("token");
|
|
1931
|
+
const email = url.searchParams.get("email");
|
|
1932
|
+
const name = url.searchParams.get("name");
|
|
1933
|
+
if (!token || !email) {
|
|
1934
|
+
return new Response("Missing token or email", { status: 400 });
|
|
1935
|
+
}
|
|
1936
|
+
resolved = true;
|
|
1937
|
+
const session = { token, email, name: name ?? email, endpoint };
|
|
1938
|
+
writeSession(session);
|
|
1939
|
+
setTimeout(() => server.stop(), 200);
|
|
1940
|
+
resolve2(session);
|
|
1941
|
+
return new Response(`<!doctype html><html><head><meta charset="utf-8"><title>snapfail</title>
|
|
1942
|
+
<style>
|
|
1943
|
+
body{background:#0a0a0a;color:#f5f5f5;font-family:system-ui,sans-serif;
|
|
1944
|
+
display:flex;align-items:center;justify-content:center;height:100vh;margin:0}
|
|
1945
|
+
.box{text-align:center;max-width:360px}
|
|
1946
|
+
.logo{font-size:18px;font-weight:600;letter-spacing:-0.5px;margin-bottom:24px;color:#f5f5f5}
|
|
1947
|
+
h1{font-size:20px;font-weight:500;margin:0 0 8px}
|
|
1948
|
+
p{color:#525252;font-size:14px;margin:0}
|
|
1949
|
+
</style></head><body>
|
|
1950
|
+
<div class="box">
|
|
1951
|
+
<div class="logo">snapfail</div>
|
|
1952
|
+
<h1>You're authenticated</h1>
|
|
1953
|
+
<p>You can close this tab and return to the terminal.</p>
|
|
1954
|
+
</div>
|
|
1955
|
+
</body></html>`, { headers: { "Content-Type": "text/html" } });
|
|
293
1956
|
}
|
|
294
1957
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
1958
|
+
const port = server.port;
|
|
1959
|
+
const callbackUrl = `http://localhost:${port}/callback`;
|
|
1960
|
+
const authUrl = `${endpoint}/cli-auth?callback=${encodeURIComponent(callbackUrl)}`;
|
|
1961
|
+
console.log("");
|
|
1962
|
+
console.log("Opening your browser to authenticate\u2026");
|
|
1963
|
+
console.log("");
|
|
1964
|
+
console.log(" " + authUrl);
|
|
1965
|
+
console.log("");
|
|
1966
|
+
console.log("If the browser didn't open, copy the URL above and paste it manually.");
|
|
1967
|
+
console.log("");
|
|
1968
|
+
openBrowser(authUrl);
|
|
1969
|
+
setTimeout(() => {
|
|
1970
|
+
if (!resolved) {
|
|
1971
|
+
server.stop();
|
|
1972
|
+
reject(new Error("Authentication timed out after 5 minutes."));
|
|
1973
|
+
}
|
|
1974
|
+
}, 5 * 60 * 1000);
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
// src/commands/init.ts
|
|
1979
|
+
function detectFramework(cwd) {
|
|
1980
|
+
if (existsSync3(resolve2(cwd, "astro.config.ts")) || existsSync3(resolve2(cwd, "astro.config.mjs")) || existsSync3(resolve2(cwd, "astro.config.js")))
|
|
1981
|
+
return "astro";
|
|
1982
|
+
if (existsSync3(resolve2(cwd, "next.config.ts")) || existsSync3(resolve2(cwd, "next.config.mjs")) || existsSync3(resolve2(cwd, "next.config.js")))
|
|
1983
|
+
return "next";
|
|
1984
|
+
if (existsSync3(resolve2(cwd, "vite.config.ts")) || existsSync3(resolve2(cwd, "vite.config.mjs")) || existsSync3(resolve2(cwd, "vite.config.js")))
|
|
1985
|
+
return "vite";
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
function suggestProjectName(cwd) {
|
|
1989
|
+
try {
|
|
1990
|
+
const pkgPath = resolve2(cwd, "package.json");
|
|
1991
|
+
if (existsSync3(pkgPath)) {
|
|
1992
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
1993
|
+
if (pkg.name)
|
|
1994
|
+
return pkg.name.replace(/^@[^/]+\//, "");
|
|
1995
|
+
}
|
|
1996
|
+
} catch {}
|
|
1997
|
+
return "";
|
|
1998
|
+
}
|
|
1999
|
+
function addToGitignore(cwd, entry) {
|
|
2000
|
+
const gitignorePath = resolve2(cwd, ".gitignore");
|
|
2001
|
+
if (existsSync3(gitignorePath)) {
|
|
2002
|
+
const content = readFileSync3(gitignorePath, "utf-8");
|
|
2003
|
+
if (content.includes(entry))
|
|
2004
|
+
return;
|
|
2005
|
+
writeFileSync3(gitignorePath, content.trimEnd() + `
|
|
2006
|
+
` + entry + `
|
|
2007
|
+
`, "utf-8");
|
|
2008
|
+
} else {
|
|
2009
|
+
writeFileSync3(gitignorePath, entry + `
|
|
2010
|
+
`, "utf-8");
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
function detectPackageManager(cwd) {
|
|
2014
|
+
if (existsSync3(resolve2(cwd, "bun.lockb")) || existsSync3(resolve2(cwd, "bun.lock")))
|
|
2015
|
+
return "bun";
|
|
2016
|
+
if (existsSync3(resolve2(cwd, "pnpm-lock.yaml")))
|
|
2017
|
+
return "pnpm";
|
|
2018
|
+
if (existsSync3(resolve2(cwd, "yarn.lock")))
|
|
2019
|
+
return "yarn";
|
|
2020
|
+
return "npm";
|
|
2021
|
+
}
|
|
2022
|
+
function installPackage(pm, pkg, cwd) {
|
|
2023
|
+
const cmd = pm === "bun" ? `bun add ${pkg}` : pm === "pnpm" ? `pnpm add ${pkg}` : pm === "yarn" ? `yarn add ${pkg}` : `npm install ${pkg}`;
|
|
2024
|
+
execSync2(cmd, { cwd, stdio: "pipe" });
|
|
2025
|
+
}
|
|
2026
|
+
function findConfigFile(cwd, names) {
|
|
2027
|
+
return names.find((n2) => existsSync3(resolve2(cwd, n2)));
|
|
2028
|
+
}
|
|
2029
|
+
var ENV_CALL = `process.env.SNAPFAIL_PROJECT_KEY ?? ""`;
|
|
2030
|
+
function injectViteAdapter(configPath) {
|
|
2031
|
+
let src = readFileSync3(configPath, "utf-8");
|
|
2032
|
+
if (src.includes("@snapfail/vite"))
|
|
2033
|
+
return;
|
|
2034
|
+
src = src.replace(/((?:^import [^\n]+\n)+)/m, `$1import snapfail from "@snapfail/vite";
|
|
2035
|
+
`);
|
|
2036
|
+
src = src.replace(/plugins:\s*\[\s*\]/, `plugins: [snapfail(${ENV_CALL})]`);
|
|
2037
|
+
if (!src.includes(`snapfail(${ENV_CALL})`)) {
|
|
2038
|
+
src = src.replace(/plugins:\s*\[(\s*)/, (_2, ws) => `plugins: [snapfail(${ENV_CALL}),${ws}`);
|
|
2039
|
+
}
|
|
2040
|
+
writeFileSync3(configPath, src, "utf-8");
|
|
2041
|
+
}
|
|
2042
|
+
function injectAstroAdapter(configPath) {
|
|
2043
|
+
let src = readFileSync3(configPath, "utf-8");
|
|
2044
|
+
if (src.includes("@snapfail/astro"))
|
|
2045
|
+
return;
|
|
2046
|
+
src = src.replace(/((?:^import [^\n]+\n)+)/m, `$1import snapfail from "@snapfail/astro";
|
|
2047
|
+
`);
|
|
2048
|
+
if (/integrations:\s*\[/.test(src)) {
|
|
2049
|
+
src = src.replace(/integrations:\s*\[\s*\]/, `integrations: [snapfail(${ENV_CALL})]`);
|
|
2050
|
+
if (!src.includes(`snapfail(${ENV_CALL})`)) {
|
|
2051
|
+
src = src.replace(/integrations:\s*\[(\s*)/, (_2, ws) => `integrations: [snapfail(${ENV_CALL}),${ws}`);
|
|
2052
|
+
}
|
|
2053
|
+
} else {
|
|
2054
|
+
src = src.replace(/defineConfig\(\{/, `defineConfig({
|
|
2055
|
+
integrations: [snapfail(${ENV_CALL})],`);
|
|
2056
|
+
}
|
|
2057
|
+
writeFileSync3(configPath, src, "utf-8");
|
|
2058
|
+
}
|
|
2059
|
+
function injectNextProvider(cwd) {
|
|
2060
|
+
const providerSrc = `"use client";
|
|
2061
|
+
import { useEffect } from "react";
|
|
2062
|
+
import { initSnapfail } from "@snapfail/browser";
|
|
2063
|
+
|
|
2064
|
+
export function SnapfailProvider() {
|
|
2065
|
+
useEffect(() => {
|
|
2066
|
+
initSnapfail({
|
|
2067
|
+
projectKey: process.env.NEXT_PUBLIC_SNAPFAIL_PROJECT_KEY ?? "",
|
|
2068
|
+
environment: process.env.NODE_ENV === "production" ? "prod" : "dev",
|
|
306
2069
|
});
|
|
2070
|
+
}, []);
|
|
2071
|
+
return null;
|
|
2072
|
+
}
|
|
2073
|
+
`;
|
|
2074
|
+
const dirs = ["app", "src/app", "src"];
|
|
2075
|
+
const providerDir = dirs.find((d) => existsSync3(resolve2(cwd, d))) ?? "app";
|
|
2076
|
+
writeFileSync3(resolve2(cwd, providerDir, "snapfail-provider.tsx"), providerSrc, "utf-8");
|
|
2077
|
+
}
|
|
2078
|
+
async function fetchProjects(token) {
|
|
2079
|
+
const res = await fetch(`${DEFAULT_ENDPOINT}/api/cli/projects`, {
|
|
2080
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
307
2081
|
});
|
|
2082
|
+
if (!res.ok)
|
|
2083
|
+
throw new Error(`Failed to fetch projects (${res.status})`);
|
|
2084
|
+
return (await res.json()).projects;
|
|
308
2085
|
}
|
|
309
|
-
function
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
<body>
|
|
327
|
-
<div>
|
|
328
|
-
<h1>${esc(title)}</h1>
|
|
329
|
-
${body}
|
|
330
|
-
</div>
|
|
331
|
-
</body>
|
|
332
|
-
</html>`;
|
|
333
|
-
}
|
|
334
|
-
function esc(s) {
|
|
335
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
336
|
-
}
|
|
337
|
-
function getInstallCommand(cwd, version) {
|
|
338
|
-
if (existsSync(join(cwd, "bun.lock")) || existsSync(join(cwd, "bun.lockb"))) {
|
|
339
|
-
return `bun add --exact @snapfail/sdk@${version}`;
|
|
340
|
-
}
|
|
341
|
-
if (existsSync(join(cwd, "pnpm-lock.yaml")) || existsSync(join(cwd, "pnpm-workspace.yaml"))) {
|
|
342
|
-
return `pnpm add --save-exact @snapfail/sdk@${version}`;
|
|
343
|
-
}
|
|
344
|
-
if (existsSync(join(cwd, "yarn.lock"))) {
|
|
345
|
-
return `yarn add --exact @snapfail/sdk@${version}`;
|
|
346
|
-
}
|
|
347
|
-
return `npm install --save-exact @snapfail/sdk@${version}`;
|
|
348
|
-
}
|
|
349
|
-
async function cmdInit(cwd) {
|
|
350
|
-
console.log("");
|
|
351
|
-
console.log(` ${bold("SnapFail CLI")} ${dim(`v${VERSION}`)}`);
|
|
352
|
-
console.log(` ${dim("─".repeat(38))}`);
|
|
353
|
-
console.log("");
|
|
354
|
-
const project = detectProject(cwd);
|
|
355
|
-
if (project.kind === "unknown") {
|
|
356
|
-
fail("No astro.config, vite.config, or index.html found.");
|
|
357
|
-
fail("Run `snapfail init` from your project's root directory.");
|
|
358
|
-
process.exit(1);
|
|
2086
|
+
async function createRemoteProject(token, name) {
|
|
2087
|
+
const res = await fetch(`${DEFAULT_ENDPOINT}/api/cli/projects`, {
|
|
2088
|
+
method: "POST",
|
|
2089
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
2090
|
+
body: JSON.stringify({ name })
|
|
2091
|
+
});
|
|
2092
|
+
if (!res.ok)
|
|
2093
|
+
throw new Error(`Failed to create project (${res.status})`);
|
|
2094
|
+
return (await res.json()).project;
|
|
2095
|
+
}
|
|
2096
|
+
async function runInit(cwd = process.cwd()) {
|
|
2097
|
+
intro("snapfail init");
|
|
2098
|
+
const framework = detectFramework(cwd);
|
|
2099
|
+
if (framework) {
|
|
2100
|
+
log.success(`Detected framework: ${framework}`);
|
|
2101
|
+
} else {
|
|
2102
|
+
log.warn("Could not detect framework automatically.");
|
|
359
2103
|
}
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
2104
|
+
let session = readSession();
|
|
2105
|
+
if (session && session.endpoint !== DEFAULT_ENDPOINT)
|
|
2106
|
+
session = null;
|
|
2107
|
+
if (session) {
|
|
2108
|
+
log.success(`Logged in as ${session.email}`);
|
|
2109
|
+
} else {
|
|
2110
|
+
log.info("You need to sign in to snapfail.");
|
|
2111
|
+
session = await ensureSession(DEFAULT_ENDPOINT);
|
|
2112
|
+
log.success(`Logged in as ${session.email}`);
|
|
2113
|
+
}
|
|
2114
|
+
const spinner2 = spinner();
|
|
2115
|
+
spinner2.start("Fetching your projects\u2026");
|
|
2116
|
+
let projects;
|
|
2117
|
+
try {
|
|
2118
|
+
projects = await fetchProjects(session.token);
|
|
2119
|
+
spinner2.stop("Projects loaded.");
|
|
2120
|
+
} catch (err) {
|
|
2121
|
+
spinner2.stop("Failed to fetch projects.");
|
|
2122
|
+
log.error(err.message);
|
|
365
2123
|
process.exit(1);
|
|
366
|
-
const { apiKey, projectName } = auth;
|
|
367
|
-
console.log("");
|
|
368
|
-
success(`Authenticated! Project: ${bold(green(projectName))}`);
|
|
369
|
-
success(`API Key: ${bold(green(apiKey))}`);
|
|
370
|
-
console.log("");
|
|
371
|
-
if (project.kind !== "html") {
|
|
372
|
-
log("Writing API key to .env…");
|
|
373
|
-
writeEnvFile(cwd, apiKey);
|
|
374
|
-
console.log("");
|
|
375
2124
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
2125
|
+
let selectedKey = "";
|
|
2126
|
+
let selectedName = "";
|
|
2127
|
+
const CREATE_NEW = "__create_new__";
|
|
2128
|
+
if (projects.length === 0) {
|
|
2129
|
+
log.info("You don't have any projects yet.");
|
|
2130
|
+
const suggested = suggestProjectName(cwd);
|
|
2131
|
+
const name = await text({
|
|
2132
|
+
message: "Project name",
|
|
2133
|
+
placeholder: suggested || "my-app",
|
|
2134
|
+
defaultValue: suggested,
|
|
2135
|
+
validate: (v) => (v ?? "").trim() ? undefined : "Project name is required."
|
|
2136
|
+
});
|
|
2137
|
+
if (isCancel(name)) {
|
|
2138
|
+
cancel("Cancelled.");
|
|
2139
|
+
process.exit(0);
|
|
2140
|
+
}
|
|
2141
|
+
spinner2.start("Creating project\u2026");
|
|
2142
|
+
const created = await createRemoteProject(session.token, name.trim());
|
|
2143
|
+
spinner2.stop(`Project created.`);
|
|
2144
|
+
selectedKey = created.key;
|
|
2145
|
+
selectedName = created.name;
|
|
389
2146
|
} else {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
2147
|
+
const choices = [
|
|
2148
|
+
...projects.map((p2) => ({ value: p2.key, label: p2.name, hint: p2.key })),
|
|
2149
|
+
{ value: CREATE_NEW, label: "Create a new project" }
|
|
2150
|
+
];
|
|
2151
|
+
const pick = await select({
|
|
2152
|
+
message: "Select a project",
|
|
2153
|
+
options: choices
|
|
2154
|
+
});
|
|
2155
|
+
if (isCancel(pick)) {
|
|
2156
|
+
cancel("Cancelled.");
|
|
2157
|
+
process.exit(0);
|
|
2158
|
+
}
|
|
2159
|
+
if (pick === CREATE_NEW) {
|
|
2160
|
+
const suggested = suggestProjectName(cwd);
|
|
2161
|
+
const name = await text({
|
|
2162
|
+
message: "Project name",
|
|
2163
|
+
placeholder: suggested || "my-app",
|
|
2164
|
+
defaultValue: suggested,
|
|
2165
|
+
validate: (v) => (v ?? "").trim() ? undefined : "Project name is required."
|
|
2166
|
+
});
|
|
2167
|
+
if (isCancel(name)) {
|
|
2168
|
+
cancel("Cancelled.");
|
|
2169
|
+
process.exit(0);
|
|
411
2170
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
2171
|
+
spinner2.start("Creating project\u2026");
|
|
2172
|
+
const created = await createRemoteProject(session.token, name.trim());
|
|
2173
|
+
spinner2.stop("Project created.");
|
|
2174
|
+
selectedKey = created.key;
|
|
2175
|
+
selectedName = created.name;
|
|
2176
|
+
} else {
|
|
2177
|
+
const picked = projects.find((proj) => proj.key === pick);
|
|
2178
|
+
selectedKey = picked.key;
|
|
2179
|
+
selectedName = picked.name;
|
|
415
2180
|
}
|
|
416
|
-
console.log("");
|
|
417
2181
|
}
|
|
2182
|
+
writeProjectKey(selectedKey, cwd);
|
|
2183
|
+
if (framework === "next")
|
|
2184
|
+
writeProjectKey(selectedKey, cwd, "NEXT_PUBLIC_SNAPFAIL_PROJECT_KEY");
|
|
2185
|
+
addToGitignore(cwd, ".env");
|
|
2186
|
+
log.success("SNAPFAIL_PROJECT_KEY written to .env");
|
|
2187
|
+
const skillDir = join2(cwd, ".agents", "skills", "snapfail");
|
|
2188
|
+
mkdirSync2(skillDir, { recursive: true });
|
|
2189
|
+
writeFileSync3(join2(skillDir, "SKILL.md"), generateSkillMd({ projectKey: selectedKey, endpoint: DEFAULT_ENDPOINT }, framework), "utf-8");
|
|
2190
|
+
log.success("SKILL.md created at .agents/skills/snapfail/SKILL.md");
|
|
2191
|
+
const pm = detectPackageManager(cwd);
|
|
2192
|
+
if (framework === "astro") {
|
|
2193
|
+
const cfg = findConfigFile(cwd, ["astro.config.ts", "astro.config.mjs", "astro.config.js"]);
|
|
2194
|
+
if (cfg) {
|
|
2195
|
+
spinner2.start(`Installing @snapfail/astro\u2026`);
|
|
2196
|
+
try {
|
|
2197
|
+
installPackage(pm, "@snapfail/astro", cwd);
|
|
2198
|
+
spinner2.stop("Adapter installed.");
|
|
2199
|
+
} catch {
|
|
2200
|
+
spinner2.stop("Skipping install (not yet on npm).");
|
|
2201
|
+
}
|
|
2202
|
+
injectAstroAdapter(resolve2(cwd, cfg));
|
|
2203
|
+
log.success(`Injected snapfail into ${cfg}`);
|
|
2204
|
+
}
|
|
2205
|
+
} else if (framework === "next") {
|
|
2206
|
+
spinner2.start("Installing @snapfail/next\u2026");
|
|
2207
|
+
try {
|
|
2208
|
+
installPackage(pm, "@snapfail/next @snapfail/browser", cwd);
|
|
2209
|
+
spinner2.stop("Adapter installed.");
|
|
2210
|
+
} catch {
|
|
2211
|
+
spinner2.stop("Skipping install (not yet on npm).");
|
|
2212
|
+
}
|
|
2213
|
+
injectNextProvider(cwd);
|
|
2214
|
+
log.success("Created snapfail-provider.tsx");
|
|
2215
|
+
log.warn("Add <SnapfailProvider /> to your root layout.");
|
|
2216
|
+
} else if (framework === "vite") {
|
|
2217
|
+
const cfg = findConfigFile(cwd, ["vite.config.ts", "vite.config.mjs", "vite.config.js"]);
|
|
2218
|
+
spinner2.start("Installing @snapfail/vite\u2026");
|
|
2219
|
+
try {
|
|
2220
|
+
installPackage(pm, "@snapfail/vite", cwd);
|
|
2221
|
+
spinner2.stop("Adapter installed.");
|
|
2222
|
+
} catch {
|
|
2223
|
+
spinner2.stop("Skipping install (not yet on npm).");
|
|
2224
|
+
}
|
|
2225
|
+
if (cfg) {
|
|
2226
|
+
injectViteAdapter(resolve2(cwd, cfg));
|
|
2227
|
+
log.success(`Injected snapfail into ${cfg}`);
|
|
2228
|
+
}
|
|
2229
|
+
} else {
|
|
2230
|
+
log.warn("No framework detected \u2014 install an adapter manually once published:");
|
|
2231
|
+
log.info(" @snapfail/vite | @snapfail/astro | @snapfail/next");
|
|
2232
|
+
}
|
|
2233
|
+
outro(`snapfail is ready \xB7 project: ${selectedName}`);
|
|
418
2234
|
}
|
|
419
|
-
function printHelp() {
|
|
420
|
-
console.log(`
|
|
421
|
-
${bold("snapfail")} ${dim(`v${VERSION}`)} — Error-tracking CLI for SnapFail Protocol
|
|
422
|
-
|
|
423
|
-
${bold("Usage:")}
|
|
424
|
-
snapfail init [path] Authenticate & inject the SDK into your project
|
|
425
|
-
snapfail --version Print version
|
|
426
|
-
snapfail --help Show this help
|
|
427
|
-
|
|
428
|
-
${bold("Examples:")}
|
|
429
|
-
snapfail init ${dim("# run from your project root")}
|
|
430
|
-
snapfail init ./my-app ${dim("# run against a specific directory")}
|
|
431
2235
|
|
|
432
|
-
|
|
433
|
-
|
|
2236
|
+
// src/commands/explain.ts
|
|
2237
|
+
async function fetchDiagnosis(config, id, force) {
|
|
2238
|
+
const url = new URL(`${config.endpoint}/api/diagnose/${id}`);
|
|
2239
|
+
if (force)
|
|
2240
|
+
url.searchParams.set("force", "1");
|
|
2241
|
+
let res;
|
|
2242
|
+
try {
|
|
2243
|
+
res = await fetch(url.toString(), {
|
|
2244
|
+
method: "POST",
|
|
2245
|
+
headers: { "X-Project-Key": config.projectKey }
|
|
2246
|
+
});
|
|
2247
|
+
} catch (err) {
|
|
2248
|
+
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2249
|
+
}
|
|
2250
|
+
if (res.status === 401)
|
|
2251
|
+
throw new Error("Unauthorized: check your project key.");
|
|
2252
|
+
if (res.status === 404)
|
|
2253
|
+
return null;
|
|
2254
|
+
if (res.status === 422)
|
|
2255
|
+
throw new Error("No samples available to diagnose this incident.");
|
|
2256
|
+
if (!res.ok) {
|
|
2257
|
+
const body = await res.text().catch(() => "");
|
|
2258
|
+
throw new Error(`API error ${res.status}: ${body}`);
|
|
2259
|
+
}
|
|
2260
|
+
return res.json();
|
|
2261
|
+
}
|
|
2262
|
+
function confidenceColor(c3) {
|
|
2263
|
+
if (c3 === "high")
|
|
2264
|
+
return green(c3);
|
|
2265
|
+
if (c3 === "medium")
|
|
2266
|
+
return yellow(c3);
|
|
2267
|
+
return red(c3);
|
|
2268
|
+
}
|
|
2269
|
+
function formatDiagnosis(d) {
|
|
2270
|
+
const lines = [];
|
|
2271
|
+
lines.push(bold("Root cause"));
|
|
2272
|
+
lines.push(` ${d.rootCause}`);
|
|
2273
|
+
lines.push("");
|
|
2274
|
+
lines.push(bold("In plain language"));
|
|
2275
|
+
lines.push(` ${d.plainSummary}`);
|
|
2276
|
+
if (d.fixPrompt) {
|
|
2277
|
+
lines.push("");
|
|
2278
|
+
lines.push(bold("Fix prompt") + dim(" (paste into your AI assistant)"));
|
|
2279
|
+
lines.push(` ${d.fixPrompt}`);
|
|
2280
|
+
}
|
|
2281
|
+
lines.push("");
|
|
2282
|
+
lines.push(dim("Confidence:") + " " + confidenceColor(d.confidence) + dim(" \xB7 analyzed ") + d.analyzedSampleIds.length + dim(" samples \xB7 model: ") + dim(d.model));
|
|
2283
|
+
return lines.join(`
|
|
434
2284
|
`);
|
|
435
2285
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
} else if (cmd === "init") {
|
|
442
|
-
const target = rest[0] ? resolve(rest[0]) : process.cwd();
|
|
443
|
-
cmdInit(target).catch((err) => {
|
|
444
|
-
fail(err instanceof Error ? err.message : String(err));
|
|
2286
|
+
async function runExplain(opts) {
|
|
2287
|
+
const config = loadConfig();
|
|
2288
|
+
const diagnosis = await fetchDiagnosis(config, opts.id, opts.force ?? false);
|
|
2289
|
+
if (!diagnosis) {
|
|
2290
|
+
console.error(`Incident ${opts.id} not found.`);
|
|
445
2291
|
process.exit(1);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
2292
|
+
}
|
|
2293
|
+
if (opts.json) {
|
|
2294
|
+
process.stdout.write(JSON.stringify(diagnosis, null, 2) + `
|
|
2295
|
+
`);
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
console.log(formatDiagnosis(diagnosis));
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
// src/index.ts
|
|
2302
|
+
function parseArgs(argv) {
|
|
2303
|
+
const [, , rawCommand = "incidents", ...rest] = argv;
|
|
2304
|
+
const command = rawCommand;
|
|
2305
|
+
const args = [];
|
|
2306
|
+
const flags = {};
|
|
2307
|
+
for (const token of rest) {
|
|
2308
|
+
if (token.startsWith("--")) {
|
|
2309
|
+
const eq = token.indexOf("=");
|
|
2310
|
+
if (eq !== -1) {
|
|
2311
|
+
flags[token.slice(2, eq)] = token.slice(eq + 1);
|
|
2312
|
+
} else {
|
|
2313
|
+
flags[token.slice(2)] = true;
|
|
2314
|
+
}
|
|
2315
|
+
} else {
|
|
2316
|
+
args.push(token);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
return { command, args, flags };
|
|
2320
|
+
}
|
|
2321
|
+
var VERSION = "0.0.17";
|
|
2322
|
+
async function main() {
|
|
2323
|
+
const { command, args, flags } = parseArgs(process.argv);
|
|
2324
|
+
const json = flags["json"] === true;
|
|
2325
|
+
if (command === "--version" || command === "-v" || flags["version"] === true) {
|
|
2326
|
+
console.log(VERSION);
|
|
2327
|
+
return;
|
|
2328
|
+
}
|
|
2329
|
+
try {
|
|
2330
|
+
if (command === "init") {
|
|
2331
|
+
await runInit();
|
|
2332
|
+
return;
|
|
2333
|
+
}
|
|
2334
|
+
if (command === "incidents") {
|
|
2335
|
+
await runIncidents({
|
|
2336
|
+
json,
|
|
2337
|
+
status: typeof flags["status"] === "string" ? flags["status"] : undefined,
|
|
2338
|
+
limit: typeof flags["limit"] === "string" ? parseInt(flags["limit"]) : undefined,
|
|
2339
|
+
offset: typeof flags["offset"] === "string" ? parseInt(flags["offset"]) : undefined
|
|
2340
|
+
});
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
if (command === "incident") {
|
|
2344
|
+
const id = args[0];
|
|
2345
|
+
if (!id) {
|
|
2346
|
+
console.error("Usage: snapfail incident <id> [--sample <n>] [--json]");
|
|
2347
|
+
process.exit(1);
|
|
2348
|
+
}
|
|
2349
|
+
const sampleFlag = flags["sample"];
|
|
2350
|
+
const sample = typeof sampleFlag === "string" ? parseInt(sampleFlag) : undefined;
|
|
2351
|
+
await runIncident({ id, sample, json });
|
|
2352
|
+
return;
|
|
2353
|
+
}
|
|
2354
|
+
if (command === "explain") {
|
|
2355
|
+
const id = args[0];
|
|
2356
|
+
if (!id) {
|
|
2357
|
+
console.error("Usage: snapfail explain <id> [--force] [--json]");
|
|
2358
|
+
process.exit(1);
|
|
2359
|
+
}
|
|
2360
|
+
await runExplain({ id, force: flags["force"] === true, json });
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
console.error(`Unknown command: ${command}`);
|
|
2364
|
+
console.error(`snapfail v${VERSION} \u2014 Usage: snapfail [incidents|incident|init|explain] [--version]`);
|
|
2365
|
+
process.exit(1);
|
|
2366
|
+
} catch (err) {
|
|
2367
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2368
|
+
console.error(`Error: ${message}`);
|
|
2369
|
+
process.exit(1);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
if (import.meta.main) {
|
|
2373
|
+
main();
|
|
451
2374
|
}
|