create-soda 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,122 +1,1440 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * @module
4
- * `create-soda`: creates a Soda project.
5
- *
6
- * ```bash
7
- * bun create soda my-app
8
- * npm create soda@latest my-app
9
- * ```
10
- *
11
- * Interactive in a terminal, flag-driven otherwise (CI, scripts). Uses only
12
- * Node built-ins, so it runs the same under `npm create` (Node) and `bun create`.
13
- */
14
- import { existsSync, readFileSync } from 'node:fs';
15
- import { basename, relative, resolve } from 'node:path';
16
- import { stdin, stdout } from 'node:process';
17
- import { createInterface } from 'node:readline/promises';
18
- import { fileURLToPath } from 'node:url';
19
- import { createProject, detectPackageManager, emptyDir, formatTargetDir, isEmptyDir, isValidPackageName, toValidPackageName, } from './project.js';
20
- const DEFAULT_DIR = 'soda-app';
21
- const HELP = `Usage: create-soda [directory] [options]
22
-
23
- Creates a Soda project. Interactive in a terminal.
24
2
 
25
- Options:
26
- --overwrite empty the directory if it is not empty
27
- --interactive, --no-interactive
28
- force or disable questions
29
- --core-version <range> version of @getsoda/core to depend on
30
- -h, --help show this help
31
- `;
32
- const parseArguments = (args) => {
33
- let dir;
34
- let overwrite = false;
35
- let interactive;
36
- let coreVersion;
37
- let help = false;
38
- for (let i = 0; i < args.length; i++) {
39
- const arg = args[i];
40
- if (arg === '--overwrite') {
41
- overwrite = true;
3
+ // ../../node_modules/.bun/@clack+core@1.6.0/node_modules/@clack/core/dist/index.mjs
4
+ import { styleText } from "node:util";
5
+ import { stdout, stdin } from "node:process";
6
+ import * as f$1 from "node:readline";
7
+ import f__default from "node:readline";
8
+
9
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
10
+ var getCodePointsLength = (() => {
11
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
12
+ return (input) => {
13
+ let surrogatePairsNr = 0;
14
+ SURROGATE_PAIR_RE.lastIndex = 0;
15
+ while (SURROGATE_PAIR_RE.test(input)) {
16
+ surrogatePairsNr += 1;
17
+ }
18
+ return input.length - surrogatePairsNr;
19
+ };
20
+ })();
21
+ var isFullWidth = (x) => {
22
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
23
+ };
24
+ var isWideNotCJKTNotEmoji = (x) => {
25
+ 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;
26
+ };
27
+
28
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
29
+ var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
30
+ var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
31
+ 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;
32
+ var TAB_RE = /\t{1,1000}/y;
33
+ 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;
34
+ var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
35
+ var MODIFIER_RE = /\p{M}+/gu;
36
+ var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
37
+ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
38
+ const LIMIT = truncationOptions.limit ?? Infinity;
39
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
40
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
41
+ const ANSI_WIDTH = 0;
42
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
43
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
44
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
45
+ const FULL_WIDTH_WIDTH = 2;
46
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
47
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
48
+ const PARSE_BLOCKS = [
49
+ [LATIN_RE, REGULAR_WIDTH],
50
+ [ANSI_RE, ANSI_WIDTH],
51
+ [CONTROL_RE, CONTROL_WIDTH],
52
+ [TAB_RE, TAB_WIDTH],
53
+ [EMOJI_RE, EMOJI_WIDTH],
54
+ [CJKT_WIDE_RE, WIDE_WIDTH]
55
+ ];
56
+ let indexPrev = 0;
57
+ let index = 0;
58
+ let length = input.length;
59
+ let lengthExtra = 0;
60
+ let truncationEnabled = false;
61
+ let truncationIndex = length;
62
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
63
+ let unmatchedStart = 0;
64
+ let unmatchedEnd = 0;
65
+ let width = 0;
66
+ let widthExtra = 0;
67
+ outer:
68
+ while (true) {
69
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
70
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
71
+ lengthExtra = 0;
72
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
73
+ const codePoint = char.codePointAt(0) || 0;
74
+ if (isFullWidth(codePoint)) {
75
+ widthExtra = FULL_WIDTH_WIDTH;
76
+ } else if (isWideNotCJKTNotEmoji(codePoint)) {
77
+ widthExtra = WIDE_WIDTH;
78
+ } else {
79
+ widthExtra = REGULAR_WIDTH;
80
+ }
81
+ if (width + widthExtra > truncationLimit) {
82
+ truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
83
+ }
84
+ if (width + widthExtra > LIMIT) {
85
+ truncationEnabled = true;
86
+ break outer;
87
+ }
88
+ lengthExtra += char.length;
89
+ width += widthExtra;
42
90
  }
43
- else if (arg === '--interactive' || arg === '--no-interactive') {
44
- interactive = arg === '--interactive';
91
+ unmatchedStart = unmatchedEnd = 0;
92
+ }
93
+ if (index >= length) {
94
+ break outer;
95
+ }
96
+ for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
97
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
98
+ BLOCK_RE.lastIndex = index;
99
+ if (BLOCK_RE.test(input)) {
100
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
101
+ widthExtra = lengthExtra * BLOCK_WIDTH;
102
+ if (width + widthExtra > truncationLimit) {
103
+ truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
104
+ }
105
+ if (width + widthExtra > LIMIT) {
106
+ truncationEnabled = true;
107
+ break outer;
108
+ }
109
+ width += widthExtra;
110
+ unmatchedStart = indexPrev;
111
+ unmatchedEnd = index;
112
+ index = indexPrev = BLOCK_RE.lastIndex;
113
+ continue outer;
45
114
  }
46
- else if (arg === '--core-version') {
47
- coreVersion = args[++i];
115
+ }
116
+ index += 1;
117
+ }
118
+ return {
119
+ width: truncationEnabled ? truncationLimit : width,
120
+ index: truncationEnabled ? truncationIndex : length,
121
+ truncated: truncationEnabled,
122
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
123
+ };
124
+ };
125
+ var dist_default = getStringTruncatedWidth;
126
+
127
+ // ../../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
128
+ var NO_TRUNCATION2 = {
129
+ limit: Infinity,
130
+ ellipsis: "",
131
+ ellipsisWidth: 0
132
+ };
133
+ var fastStringWidth = (input, options = {}) => {
134
+ return dist_default(input, NO_TRUNCATION2, options).width;
135
+ };
136
+ var dist_default2 = fastStringWidth;
137
+
138
+ // ../../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
139
+ var ESC = "\x1B";
140
+ var CSI = "›";
141
+ var END_CODE = 39;
142
+ var ANSI_ESCAPE_BELL = "\x07";
143
+ var ANSI_CSI = "[";
144
+ var ANSI_OSC = "]";
145
+ var ANSI_SGR_TERMINATOR = "m";
146
+ var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
147
+ var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
148
+ var getClosingCode = (openingCode) => {
149
+ if (openingCode >= 30 && openingCode <= 37)
150
+ return 39;
151
+ if (openingCode >= 90 && openingCode <= 97)
152
+ return 39;
153
+ if (openingCode >= 40 && openingCode <= 47)
154
+ return 49;
155
+ if (openingCode >= 100 && openingCode <= 107)
156
+ return 49;
157
+ if (openingCode === 1 || openingCode === 2)
158
+ return 22;
159
+ if (openingCode === 3)
160
+ return 23;
161
+ if (openingCode === 4)
162
+ return 24;
163
+ if (openingCode === 7)
164
+ return 27;
165
+ if (openingCode === 8)
166
+ return 28;
167
+ if (openingCode === 9)
168
+ return 29;
169
+ if (openingCode === 0)
170
+ return 0;
171
+ return;
172
+ };
173
+ var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
174
+ var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
175
+ var wrapWord = (rows, word, columns) => {
176
+ const characters = word[Symbol.iterator]();
177
+ let isInsideEscape = false;
178
+ let isInsideLinkEscape = false;
179
+ let lastRow = rows.at(-1);
180
+ let visible = lastRow === undefined ? 0 : dist_default2(lastRow);
181
+ let currentCharacter = characters.next();
182
+ let nextCharacter = characters.next();
183
+ let rawCharacterIndex = 0;
184
+ while (!currentCharacter.done) {
185
+ const character = currentCharacter.value;
186
+ const characterLength = dist_default2(character);
187
+ if (visible + characterLength <= columns) {
188
+ rows[rows.length - 1] += character;
189
+ } else {
190
+ rows.push(character);
191
+ visible = 0;
192
+ }
193
+ if (character === ESC || character === CSI) {
194
+ isInsideEscape = true;
195
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
196
+ }
197
+ if (isInsideEscape) {
198
+ if (isInsideLinkEscape) {
199
+ if (character === ANSI_ESCAPE_BELL) {
200
+ isInsideEscape = false;
201
+ isInsideLinkEscape = false;
48
202
  }
49
- else if (arg === '-h' || arg === '--help') {
50
- help = true;
203
+ } else if (character === ANSI_SGR_TERMINATOR) {
204
+ isInsideEscape = false;
205
+ }
206
+ } else {
207
+ visible += characterLength;
208
+ if (visible === columns && !nextCharacter.done) {
209
+ rows.push("");
210
+ visible = 0;
211
+ }
212
+ }
213
+ currentCharacter = nextCharacter;
214
+ nextCharacter = characters.next();
215
+ rawCharacterIndex += character.length;
216
+ }
217
+ lastRow = rows.at(-1);
218
+ if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
219
+ rows[rows.length - 2] += rows.pop();
220
+ }
221
+ };
222
+ var stringVisibleTrimSpacesRight = (string) => {
223
+ const words = string.split(" ");
224
+ let last = words.length;
225
+ while (last) {
226
+ if (dist_default2(words[last - 1])) {
227
+ break;
228
+ }
229
+ last--;
230
+ }
231
+ if (last === words.length) {
232
+ return string;
233
+ }
234
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
235
+ };
236
+ var exec = (string, columns, options = {}) => {
237
+ if (options.trim !== false && string.trim() === "") {
238
+ return "";
239
+ }
240
+ let returnValue = "";
241
+ let escapeCode;
242
+ let escapeUrl;
243
+ const words = string.split(" ");
244
+ let rows = [""];
245
+ let rowLength = 0;
246
+ for (let index = 0;index < words.length; index++) {
247
+ const word = words[index];
248
+ if (options.trim !== false) {
249
+ const row = rows.at(-1) ?? "";
250
+ const trimmed = row.trimStart();
251
+ if (row.length !== trimmed.length) {
252
+ rows[rows.length - 1] = trimmed;
253
+ rowLength = dist_default2(trimmed);
254
+ }
255
+ }
256
+ if (index !== 0) {
257
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
258
+ rows.push("");
259
+ rowLength = 0;
260
+ }
261
+ if (rowLength || options.trim === false) {
262
+ rows[rows.length - 1] += " ";
263
+ rowLength++;
264
+ }
265
+ }
266
+ const wordLength = dist_default2(word);
267
+ if (options.hard && wordLength > columns) {
268
+ const remainingColumns = columns - rowLength;
269
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
270
+ const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
271
+ if (breaksStartingNextLine < breaksStartingThisLine) {
272
+ rows.push("");
273
+ }
274
+ wrapWord(rows, word, columns);
275
+ rowLength = dist_default2(rows.at(-1) ?? "");
276
+ continue;
277
+ }
278
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
279
+ if (options.wordWrap === false && rowLength < columns) {
280
+ wrapWord(rows, word, columns);
281
+ rowLength = dist_default2(rows.at(-1) ?? "");
282
+ continue;
283
+ }
284
+ rows.push("");
285
+ rowLength = 0;
286
+ }
287
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
288
+ wrapWord(rows, word, columns);
289
+ rowLength = dist_default2(rows.at(-1) ?? "");
290
+ continue;
291
+ }
292
+ rows[rows.length - 1] += word;
293
+ rowLength += wordLength;
294
+ }
295
+ if (options.trim !== false) {
296
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
297
+ }
298
+ const preString = rows.join(`
299
+ `);
300
+ let inSurrogate = false;
301
+ for (let i = 0;i < preString.length; i++) {
302
+ const character = preString[i];
303
+ returnValue += character;
304
+ if (!inSurrogate) {
305
+ inSurrogate = character >= "\uD800" && character <= "\uDBFF";
306
+ if (inSurrogate) {
307
+ continue;
308
+ }
309
+ } else {
310
+ inSurrogate = false;
311
+ }
312
+ if (character === ESC || character === CSI) {
313
+ GROUP_REGEX.lastIndex = i + 1;
314
+ const groupsResult = GROUP_REGEX.exec(preString);
315
+ const groups = groupsResult?.groups;
316
+ if (groups?.code !== undefined) {
317
+ const code = Number.parseFloat(groups.code);
318
+ escapeCode = code === END_CODE ? undefined : code;
319
+ } else if (groups?.uri !== undefined) {
320
+ escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
321
+ }
322
+ }
323
+ if (preString[i + 1] === `
324
+ `) {
325
+ if (escapeUrl) {
326
+ returnValue += wrapAnsiHyperlink("");
327
+ }
328
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
329
+ if (escapeCode && closingCode) {
330
+ returnValue += wrapAnsiCode(closingCode);
331
+ }
332
+ } else if (character === `
333
+ `) {
334
+ if (escapeCode && getClosingCode(escapeCode)) {
335
+ returnValue += wrapAnsiCode(escapeCode);
336
+ }
337
+ if (escapeUrl) {
338
+ returnValue += wrapAnsiHyperlink(escapeUrl);
339
+ }
340
+ }
341
+ }
342
+ return returnValue;
343
+ };
344
+ var CRLF_OR_LF = /\r?\n/;
345
+ function wrapAnsi(string, columns, options) {
346
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join(`
347
+ `);
348
+ }
349
+
350
+ // ../../node_modules/.bun/sisteransi@2.0.0/node_modules/sisteransi/dist/index.js
351
+ var ESC2 = "\x1B";
352
+ var CSI2 = `${ESC2}[`;
353
+ var cursor = {
354
+ to(x, y) {
355
+ if (!y)
356
+ return `${CSI2}${x + 1}G`;
357
+ return `${CSI2}${y + 1};${x + 1}H`;
358
+ },
359
+ move(x, y) {
360
+ let ret = "";
361
+ if (x < 0)
362
+ ret += `${CSI2}${-x}D`;
363
+ else if (x > 0)
364
+ ret += `${CSI2}${x}C`;
365
+ if (y < 0)
366
+ ret += `${CSI2}${-y}A`;
367
+ else if (y > 0)
368
+ ret += `${CSI2}${y}B`;
369
+ return ret;
370
+ },
371
+ up: (count = 1) => `${CSI2}${count}A`,
372
+ down: (count = 1) => `${CSI2}${count}B`,
373
+ forward: (count = 1) => `${CSI2}${count}C`,
374
+ backward: (count = 1) => `${CSI2}${count}D`,
375
+ nextLine: (count = 1) => `${CSI2}E`.repeat(count),
376
+ prevLine: (count = 1) => `${CSI2}F`.repeat(count),
377
+ left: `${CSI2}G`,
378
+ hide: `${CSI2}?25l`,
379
+ show: `${CSI2}?25h`,
380
+ save: `${ESC2}7`,
381
+ restore: `${ESC2}8`
382
+ };
383
+ var erase = {
384
+ screen: `${CSI2}2J`,
385
+ up: (count = 1) => `${CSI2}1J`.repeat(count),
386
+ down: (count = 1) => `${CSI2}J`.repeat(count),
387
+ line: `${CSI2}2K`,
388
+ lineEnd: `${CSI2}K`,
389
+ lineStart: `${CSI2}1K`,
390
+ lines(count) {
391
+ let clear = "";
392
+ for (let i = 0;i < count; i++)
393
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
394
+ if (count)
395
+ clear += cursor.left;
396
+ return clear;
397
+ }
398
+ };
399
+ var clear = {
400
+ screen: `${ESC2}c`
401
+ };
402
+
403
+ // ../../node_modules/.bun/@clack+core@1.6.0/node_modules/@clack/core/dist/index.mjs
404
+ import { ReadStream } from "node:tty";
405
+ function findCursor(o, s, l) {
406
+ if (!l.some((r) => !r.disabled))
407
+ return o;
408
+ const t = o + s, n = Math.max(l.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
409
+ return l[e]?.disabled ? findCursor(e, s < 0 ? -1 : 1, l) : e;
410
+ }
411
+ var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
412
+ var t = [
413
+ "January",
414
+ "February",
415
+ "March",
416
+ "April",
417
+ "May",
418
+ "June",
419
+ "July",
420
+ "August",
421
+ "September",
422
+ "October",
423
+ "November",
424
+ "December"
425
+ ];
426
+ var settings = {
427
+ actions: new Set(a$1),
428
+ aliases: /* @__PURE__ */ new Map([
429
+ ["k", "up"],
430
+ ["j", "down"],
431
+ ["h", "left"],
432
+ ["l", "right"],
433
+ ["\x03", "cancel"],
434
+ ["escape", "cancel"]
435
+ ]),
436
+ messages: {
437
+ cancel: "Canceled",
438
+ error: "Something went wrong"
439
+ },
440
+ withGuide: true,
441
+ accessible: undefined,
442
+ date: {
443
+ monthNames: [...t],
444
+ messages: {
445
+ required: "Please enter a valid date",
446
+ invalidMonth: "There are only 12 months in a year",
447
+ invalidDay: (n, e) => `There are only ${n} days in ${e}`,
448
+ afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
449
+ beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
450
+ }
451
+ }
452
+ };
453
+ function isAccessible(n) {
454
+ if (n !== undefined)
455
+ return n;
456
+ if (settings.accessible !== undefined)
457
+ return settings.accessible;
458
+ const e = process.env.ACCESSIBLE;
459
+ return e !== undefined && e !== "" && e !== "0" && e !== "false";
460
+ }
461
+ function isActionKey(n, e) {
462
+ if (typeof n == "string")
463
+ return settings.aliases.get(n) === e;
464
+ for (const s of n)
465
+ if (s !== undefined && isActionKey(s, e))
466
+ return true;
467
+ return false;
468
+ }
469
+ function diffLines(i, s) {
470
+ if (i === s)
471
+ return;
472
+ const e = i.split(`
473
+ `), t = s.split(`
474
+ `), r = Math.max(e.length, t.length), f = [];
475
+ for (let n = 0;n < r; n++)
476
+ e[n] !== t[n] && f.push(n);
477
+ return {
478
+ lines: f,
479
+ numLinesBefore: e.length,
480
+ numLinesAfter: t.length,
481
+ numLines: r
482
+ };
483
+ }
484
+ var R = globalThis.process.platform.startsWith("win");
485
+ var CANCEL_SYMBOL = Symbol("clack:cancel");
486
+ function isCancel(e) {
487
+ return e === CANCEL_SYMBOL;
488
+ }
489
+ function setRawMode(e, r) {
490
+ const o = e;
491
+ o.isTTY && o.setRawMode(r);
492
+ }
493
+ function block({
494
+ input: e = stdin,
495
+ output: r = stdout,
496
+ overwrite: o = true,
497
+ hideCursor: n = true
498
+ } = {}) {
499
+ const s = f$1.createInterface({
500
+ input: e,
501
+ output: r,
502
+ prompt: "",
503
+ tabSize: 1
504
+ });
505
+ f$1.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
506
+ const t = (l, { name: i, sequence: p }) => {
507
+ const w = String(l);
508
+ if (isActionKey([w, i, p], "cancel")) {
509
+ n && r.write(cursor.show), process.exit(0);
510
+ return;
511
+ }
512
+ if (!o)
513
+ return;
514
+ const c = i === "return" ? 0 : -1, a = i === "return" ? -1 : 0;
515
+ f$1.moveCursor(r, c, a, () => {
516
+ f$1.clearLine(r, 1, () => {
517
+ e.once("keypress", t);
518
+ });
519
+ });
520
+ };
521
+ return n && r.write(cursor.hide), e.once("keypress", t), () => {
522
+ e.off("keypress", t), n && r.write(cursor.show), e instanceof ReadStream && e.isTTY && !R && e.setRawMode(false), s.terminal = false, s.close();
523
+ };
524
+ }
525
+ var getColumns = (e) => ("columns" in e) && typeof e.columns == "number" ? e.columns : 80;
526
+ var getRows = (e) => ("rows" in e) && typeof e.rows == "number" ? e.rows : 20;
527
+ function wrapTextWithPrefix(e, r, o, n = o, s = o, t) {
528
+ const l = getColumns(e ?? stdout), i = dist_default2(o);
529
+ return wrapAnsi(r, l - i, {
530
+ hard: true,
531
+ trim: false
532
+ }).split(`
533
+ `).map((c, a, g) => {
534
+ const m = t ? t(c, a) : c;
535
+ return a === 0 ? `${n}${m}` : a === g.length - 1 ? `${s}${m}` : `${o}${m}`;
536
+ }).join(`
537
+ `);
538
+ }
539
+ function runValidation(e, a) {
540
+ if ("~standard" in e) {
541
+ const n = e["~standard"].validate(a);
542
+ return n instanceof Promise ? n.then((r) => r.issues?.at(0)?.message) : n.issues?.at(0)?.message;
543
+ }
544
+ return e(a);
545
+ }
546
+ var C$1 = class C {
547
+ input;
548
+ output;
549
+ _abortSignal;
550
+ rl;
551
+ opts;
552
+ _render;
553
+ _track = false;
554
+ _prevFrame = "";
555
+ _subscribers = /* @__PURE__ */ new Map;
556
+ _cursor = 0;
557
+ state = "initial";
558
+ error = "";
559
+ value;
560
+ userInput = "";
561
+ get accessible() {
562
+ return isAccessible(this.opts.accessible);
563
+ }
564
+ constructor(t, e = true) {
565
+ const { input: i = stdin, output: s = stdout, render: r, signal: n, ...o } = t;
566
+ this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = r.bind(this), this._track = e, this._abortSignal = n, this.input = i, this.output = s;
567
+ }
568
+ unsubscribe() {
569
+ this._subscribers.clear();
570
+ }
571
+ setSubscriber(t, e) {
572
+ const i = this._subscribers.get(t) ?? [];
573
+ i.push(e), this._subscribers.set(t, i);
574
+ }
575
+ on(t, e) {
576
+ this.setSubscriber(t, { cb: e });
577
+ }
578
+ once(t, e) {
579
+ this.setSubscriber(t, { cb: e, once: true });
580
+ }
581
+ emit(t, ...e) {
582
+ const i = this._subscribers.get(t) ?? [], s = [];
583
+ for (const r of i)
584
+ r.cb(...e), r.once && s.push(() => i.splice(i.indexOf(r), 1));
585
+ for (const r of s)
586
+ r();
587
+ }
588
+ prompt() {
589
+ return new Promise((t) => {
590
+ if (this._abortSignal) {
591
+ if (this._abortSignal.aborted)
592
+ return this.state = "cancel", this.close(), t(CANCEL_SYMBOL);
593
+ this._abortSignal.addEventListener("abort", () => {
594
+ this.state = "cancel", this.close();
595
+ }, { once: true });
596
+ }
597
+ this.rl = f__default.createInterface({
598
+ input: this.input,
599
+ tabSize: 2,
600
+ prompt: "",
601
+ escapeCodeTimeout: 50,
602
+ terminal: true
603
+ }), 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", () => {
604
+ this.output.write(cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(this.value);
605
+ }), this.once("cancel", () => {
606
+ this.output.write(cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(CANCEL_SYMBOL);
607
+ });
608
+ });
609
+ }
610
+ _isActionKey(t, e) {
611
+ return t === "\t";
612
+ }
613
+ _shouldSubmit(t, e) {
614
+ return true;
615
+ }
616
+ _setValue(t) {
617
+ this.value = t, this.emit("value", this.value);
618
+ }
619
+ _setUserInput(t, e) {
620
+ this.userInput = t ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
621
+ }
622
+ _clearUserInput() {
623
+ this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
624
+ }
625
+ async onKeypress(t, e) {
626
+ if (this.state !== "validating") {
627
+ if (this._track && e.name !== "return" && (e.name && this._isActionKey(t, 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)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t, e), e?.name === "return" && this._shouldSubmit(t, e)) {
628
+ if (this.opts.validate) {
629
+ const i = runValidation(this.opts.validate, this.value);
630
+ let s;
631
+ i instanceof Promise ? (this.state = "validating", this.render(), s = await i) : s = i, s && (this.error = s instanceof Error ? s.message : s, this.state = "error", this.rl?.write(this.userInput));
51
632
  }
52
- else if (arg.startsWith('-')) {
53
- throw new Error(`Unknown option ${arg}\n\n${HELP}`);
633
+ this.state !== "error" && (this.state = "submit");
634
+ }
635
+ isActionKey([t, 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();
636
+ }
637
+ }
638
+ close() {
639
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
640
+ `), setRawMode(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
641
+ }
642
+ restoreCursor() {
643
+ const t = wrapAnsi(this._prevFrame, getColumns(this.output), { hard: true, trim: false }).split(`
644
+ `).length - 1;
645
+ this.output.write(cursor.move(-999, t * -1));
646
+ }
647
+ render() {
648
+ const t = wrapAnsi(this._render(this) ?? "", getColumns(this.output), {
649
+ hard: true,
650
+ trim: false
651
+ });
652
+ if (t !== this._prevFrame) {
653
+ if (this.state === "initial")
654
+ this.output.write(cursor.hide);
655
+ else {
656
+ const e = diffLines(this._prevFrame, t), i = getRows(this.output);
657
+ if (this.restoreCursor(), e) {
658
+ const s = Math.max(0, e.numLinesAfter - i), r = Math.max(0, e.numLinesBefore - i);
659
+ let n = e.lines.find((o) => o >= s);
660
+ if (n === undefined) {
661
+ this._prevFrame = t;
662
+ return;
663
+ }
664
+ if (e.lines.length === 1) {
665
+ this.output.write(cursor.move(0, n - r)), this.output.write(erase.lines(1));
666
+ const o = t.split(`
667
+ `);
668
+ this.output.write(o[n]), this._prevFrame = t, this.output.write(cursor.move(0, o.length - n - 1));
669
+ return;
670
+ } else if (e.lines.length > 1) {
671
+ if (s < r)
672
+ n = s;
673
+ else {
674
+ const h = n - r;
675
+ h > 0 && this.output.write(cursor.move(0, h));
676
+ }
677
+ this.output.write(erase.down());
678
+ const m = t.split(`
679
+ `).slice(n);
680
+ this.output.write(m.join(`
681
+ `)), this._prevFrame = t;
682
+ return;
683
+ }
54
684
  }
55
- else {
56
- dir ??= arg;
685
+ this.output.write(erase.down());
686
+ }
687
+ this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
688
+ }
689
+ }
690
+ };
691
+ class r extends C$1 {
692
+ get cursor() {
693
+ return this.value ? 0 : 1;
694
+ }
695
+ get _value() {
696
+ return this.cursor === 0;
697
+ }
698
+ constructor(t) {
699
+ super(t, false), this.value = !!t.initialValue, this.on("userInput", () => {
700
+ this.value = this._value;
701
+ }), this.on("confirm", (i) => {
702
+ this.output.write(cursor.move(0, -1)), this.value = i, this.state = "submit", this.close();
703
+ }), this.on("cursor", () => {
704
+ this.value = !this.value;
705
+ });
706
+ }
707
+ }
708
+ var n$1 = class n extends C$1 {
709
+ options;
710
+ cursor = 0;
711
+ get _selectedValue() {
712
+ return this.options[this.cursor];
713
+ }
714
+ changeValue() {
715
+ const e = this._selectedValue;
716
+ this.value = e === undefined ? undefined : e.value;
717
+ }
718
+ constructor(e) {
719
+ super(e, false), this.options = e.options;
720
+ const o = this.options.findIndex(({ value: s }) => s === e.initialValue), t = o === -1 ? 0 : o;
721
+ this.cursor = this.options[t]?.disabled ? findCursor(t, 1, this.options) : t, this.changeValue(), this.on("cursor", (s) => {
722
+ switch (s) {
723
+ case "left":
724
+ case "up":
725
+ this.cursor = findCursor(this.cursor, -1, this.options);
726
+ break;
727
+ case "down":
728
+ case "right":
729
+ this.cursor = findCursor(this.cursor, 1, this.options);
730
+ break;
731
+ }
732
+ this.changeValue();
733
+ });
734
+ }
735
+ };
736
+ class n extends C$1 {
737
+ get userInputWithCursor() {
738
+ if (this.state === "submit")
739
+ return this.userInput;
740
+ const t = this.userInput;
741
+ if (this.cursor >= t.length)
742
+ return `${this.userInput}█`;
743
+ const r = t.slice(0, this.cursor), s = t.slice(this.cursor, this.cursor + 1), e = t.slice(this.cursor + 1);
744
+ return `${r}${styleText("inverse", s)}${e}`;
745
+ }
746
+ get cursor() {
747
+ return this._cursor;
748
+ }
749
+ constructor(t) {
750
+ super({
751
+ ...t,
752
+ initialUserInput: t.initialUserInput ?? t.initialValue
753
+ }), this.on("userInput", (r) => {
754
+ this._setValue(r);
755
+ }), this.on("finalize", () => {
756
+ this.value || (this.value = t.defaultValue), this.value === undefined && (this.value = "");
757
+ });
758
+ }
759
+ }
760
+
761
+ // ../../node_modules/.bun/@clack+prompts@1.9.0/node_modules/@clack/prompts/dist/index.mjs
762
+ import { styleText as styleText2, stripVTControlCharacters } from "node:util";
763
+ import process$1 from "node:process";
764
+ function isUnicodeSupported() {
765
+ if (process$1.platform !== "win32") {
766
+ return process$1.env.TERM !== "linux";
767
+ }
768
+ 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";
769
+ }
770
+ var unicode = isUnicodeSupported();
771
+ var isCI = () => process.env.CI === "true";
772
+ var unicodeOr = (e, o) => unicode ? e : o;
773
+ var S_STEP_ACTIVE = unicodeOr("◆", "*");
774
+ var S_STEP_CANCEL = unicodeOr("■", "x");
775
+ var S_STEP_ERROR = unicodeOr("▲", "x");
776
+ var S_STEP_SUBMIT = unicodeOr("◇", "o");
777
+ var S_BAR_START = unicodeOr("┌", "T");
778
+ var S_BAR = unicodeOr("│", "|");
779
+ var S_BAR_END = unicodeOr("└", "—");
780
+ var S_BAR_START_RIGHT = unicodeOr("┐", "T");
781
+ var S_BAR_END_RIGHT = unicodeOr("┘", "—");
782
+ var S_RADIO_ACTIVE = unicodeOr("●", ">");
783
+ var S_RADIO_INACTIVE = unicodeOr("○", " ");
784
+ var S_CHECKBOX_ACTIVE = unicodeOr("◻", "[•]");
785
+ var S_CHECKBOX_SELECTED = unicodeOr("◼", "[+]");
786
+ var S_CHECKBOX_INACTIVE = unicodeOr("◻", "[ ]");
787
+ var S_PASSWORD_MASK = unicodeOr("▪", "•");
788
+ var S_BAR_H = unicodeOr("─", "-");
789
+ var S_CORNER_TOP_RIGHT = unicodeOr("╮", "+");
790
+ var S_CONNECT_LEFT = unicodeOr("├", "+");
791
+ var S_CORNER_BOTTOM_RIGHT = unicodeOr("╯", "+");
792
+ var S_CORNER_BOTTOM_LEFT = unicodeOr("╰", "+");
793
+ var S_CORNER_TOP_LEFT = unicodeOr("╭", "+");
794
+ var S_INFO = unicodeOr("●", "•");
795
+ var S_SUCCESS = unicodeOr("◆", "*");
796
+ var S_WARN = unicodeOr("▲", "!");
797
+ var S_ERROR = unicodeOr("■", "x");
798
+ var symbol = (e) => {
799
+ switch (e) {
800
+ case "initial":
801
+ case "active":
802
+ return styleText2("cyan", S_STEP_ACTIVE);
803
+ case "cancel":
804
+ return styleText2("red", S_STEP_CANCEL);
805
+ case "error":
806
+ return styleText2("yellow", S_STEP_ERROR);
807
+ case "submit":
808
+ return styleText2("green", S_STEP_SUBMIT);
809
+ case "validating":
810
+ return styleText2("dim", S_STEP_ACTIVE);
811
+ }
812
+ };
813
+ var symbolBar = (e) => {
814
+ switch (e) {
815
+ case "initial":
816
+ case "active":
817
+ return styleText2("cyan", S_BAR);
818
+ case "cancel":
819
+ return styleText2("red", S_BAR);
820
+ case "error":
821
+ return styleText2("yellow", S_BAR);
822
+ case "submit":
823
+ return styleText2("green", S_BAR);
824
+ }
825
+ };
826
+ function formatInstructionFooter(e, o, r) {
827
+ const s = r ? `${styleText2("cyan", S_BAR)} ` : "", n = wrapTextWithPrefix(e, o.join(" • "), s).split(`
828
+ `);
829
+ return r && n.push(styleText2("cyan", S_BAR_END)), n;
830
+ }
831
+ var E$1 = (l, e, w, p, b, C = false) => {
832
+ let r = e, O = 0;
833
+ if (C)
834
+ for (let i = p - 1;i >= w; i--) {
835
+ const m = l[i];
836
+ if (m && (r -= m.length), O++, r <= b)
837
+ break;
838
+ }
839
+ else
840
+ for (let i = w;i < p; i++) {
841
+ const m = l[i];
842
+ if (m && (r -= m.length), O++, r <= b)
843
+ break;
844
+ }
845
+ return { lineCount: r, removals: O };
846
+ };
847
+ var limitOptions = ({
848
+ cursor: l,
849
+ options: e,
850
+ style: w,
851
+ output: p = process.stdout,
852
+ maxItems: b = Number.POSITIVE_INFINITY,
853
+ columnPadding: C = 0,
854
+ rowPadding: r = 4
855
+ }) => {
856
+ const i = getColumns(p) - C, m = getRows(p), M = styleText2("dim", "..."), v = Math.max(m - r, 0), a = Math.max(Math.min(b, v), 5);
857
+ let f = 0;
858
+ l >= a - 3 && (f = Math.max(Math.min(l - a + 3, e.length - a), 0));
859
+ let d = a < e.length && f > 0, c = a < e.length && f + a < e.length;
860
+ const I = Math.min(f + a, e.length), s = [];
861
+ let g = 0;
862
+ d && g++, c && g++;
863
+ const T = f + (d ? 1 : 0), W = I - (c ? 1 : 0);
864
+ for (let t = T;t < W; t++) {
865
+ const n = e[t], o = n !== undefined ? w(n, t === l) : "", h = wrapAnsi(o, i, {
866
+ hard: true,
867
+ trim: false
868
+ }).split(`
869
+ `);
870
+ s.push(h), g += h.length;
871
+ }
872
+ if (g > v) {
873
+ let t = 0, n = 0, o = g;
874
+ const h = l - T;
875
+ let u = v;
876
+ const L = () => E$1(s, o, 0, h, u), y = () => E$1(s, o, h + 1, s.length, u, true);
877
+ d ? ({ lineCount: o, removals: t } = L(), o > u && (c || (u -= 1), { lineCount: o, removals: n } = y())) : (c || (u -= 1), { lineCount: o, removals: n } = y(), o > u && (u -= 1, { lineCount: o, removals: t } = L())), t > 0 && (d = true, s.splice(0, t)), n > 0 && (c = true, s.splice(s.length - n, n));
878
+ }
879
+ const x = [];
880
+ d && x.push(M);
881
+ for (const t of s)
882
+ for (const n of t)
883
+ x.push(n);
884
+ return c && x.push(M), x;
885
+ };
886
+ var confirm = (e) => {
887
+ const a = e.active ?? "Yes", o = e.inactive ?? "No";
888
+ return new r({
889
+ active: a,
890
+ inactive: o,
891
+ signal: e.signal,
892
+ input: e.input,
893
+ output: e.output,
894
+ initialValue: e.initialValue ?? true,
895
+ render() {
896
+ const i = e.withGuide ?? settings.withGuide, u = `${symbol(this.state)} `, l = i ? `${styleText2("gray", S_BAR)} ` : "", f = wrapTextWithPrefix(e.output, e.message, l, u), s = `${i ? `${styleText2("gray", S_BAR)}
897
+ ` : ""}${f}
898
+ `, c = this.value ? a : o;
899
+ switch (this.state) {
900
+ case "submit": {
901
+ const r = i ? `${styleText2("gray", S_BAR)} ` : "";
902
+ return `${s}${r}${styleText2("dim", c)}`;
903
+ }
904
+ case "cancel": {
905
+ const r = i ? `${styleText2("gray", S_BAR)} ` : "";
906
+ return `${s}${r}${styleText2(["strikethrough", "dim"], c)}${i ? `
907
+ ${styleText2("gray", S_BAR)}` : ""}`;
908
+ }
909
+ default: {
910
+ const r = i ? `${styleText2("cyan", S_BAR)} ` : "", g = i ? styleText2("cyan", S_BAR_END) : "";
911
+ return `${s}${r}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a)}`}${e.vertical ? i ? `
912
+ ${styleText2("cyan", S_BAR)} ` : `
913
+ ` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", o)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${o}`}
914
+ ${g}
915
+ `;
57
916
  }
917
+ }
58
918
  }
59
- return { dir, overwrite, interactive, coreVersion, help };
919
+ }).prompt();
60
920
  };
61
- /** Version range of `@getsoda/core`: written next to the build, or read from the monorepo when run from sources. */
62
- const readCoreVersion = () => {
63
- const built = fileURLToPath(new URL('../core-version.json', import.meta.url));
64
- if (existsSync(built)) {
65
- return `^${JSON.parse(readFileSync(built, 'utf8')).version}`;
921
+ var MULTISELECT_INSTRUCTIONS = [
922
+ `${styleText2("dim", "↑/↓")} to navigate`,
923
+ `${styleText2("dim", "Space:")} select`,
924
+ `${styleText2("dim", "Enter:")} confirm`
925
+ ];
926
+ var log = {
927
+ message: (s = [], {
928
+ symbol: e = styleText2("gray", S_BAR),
929
+ secondarySymbol: r = styleText2("gray", S_BAR),
930
+ output: m = process.stdout,
931
+ spacing: l = 1,
932
+ withGuide: c
933
+ } = {}) => {
934
+ const t = [], o = c ?? settings.withGuide, f = o ? r : "", O = o ? `${e} ` : "", u = o ? `${r} ` : "";
935
+ for (let i = 0;i < l; i++)
936
+ t.push(f);
937
+ const g = Array.isArray(s) ? s : s.split(`
938
+ `);
939
+ if (g.length > 0) {
940
+ const [i, ...y] = g;
941
+ i.length > 0 ? t.push(`${O}${i}`) : t.push(o ? e : "");
942
+ for (const p of y)
943
+ p.length > 0 ? t.push(`${u}${p}`) : t.push(o ? r : "");
66
944
  }
67
- const workspace = fileURLToPath(new URL('../../core/package.json', import.meta.url));
68
- return `^${JSON.parse(readFileSync(workspace, 'utf8')).version}`;
945
+ m.write(`${t.join(`
946
+ `)}
947
+ `);
948
+ },
949
+ info: (s, e) => {
950
+ log.message(s, { ...e, symbol: styleText2("blue", S_INFO) });
951
+ },
952
+ success: (s, e) => {
953
+ log.message(s, { ...e, symbol: styleText2("green", S_SUCCESS) });
954
+ },
955
+ step: (s, e) => {
956
+ log.message(s, { ...e, symbol: styleText2("green", S_STEP_SUBMIT) });
957
+ },
958
+ warn: (s, e) => {
959
+ log.message(s, { ...e, symbol: styleText2("yellow", S_WARN) });
960
+ },
961
+ warning: (s, e) => {
962
+ log.warn(s, e);
963
+ },
964
+ error: (s, e) => {
965
+ log.message(s, { ...e, symbol: styleText2("red", S_ERROR) });
966
+ }
69
967
  };
70
- const main = async () => {
71
- const args = parseArguments(process.argv.slice(2));
72
- if (args.help) {
73
- stdout.write(HELP);
74
- return;
968
+ var cancel = (o = "", t) => {
969
+ const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
970
+ i.write(`${e}${styleText2("red", o)}
971
+
972
+ `);
973
+ };
974
+ var intro = (o = "", t) => {
975
+ const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
976
+ i.write(`${e}${o}
977
+ `);
978
+ };
979
+ var outro = (o = "", t) => {
980
+ const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
981
+ ${styleText2("gray", S_BAR_END)} ` : "";
982
+ i.write(`${e}${o}
983
+
984
+ `);
985
+ };
986
+ var W = (o) => o;
987
+ var C = (o, e, s) => {
988
+ const a = {
989
+ hard: true,
990
+ trim: false
991
+ }, i = wrapAnsi(o, e, a).split(`
992
+ `), c = i.reduce((n, t) => Math.max(dist_default2(t), n), 0), u = i.map(s).reduce((n, t) => Math.max(dist_default2(t), n), 0), g = e - (u - c);
993
+ return wrapAnsi(o, g, a);
994
+ };
995
+ var note = (o = "", e = "", s) => {
996
+ const a = s?.output ?? process$1.stdout, i = s?.withGuide ?? settings.withGuide, c = s?.format ?? W, g = ["", ...C(o, getColumns(a) - 6, c).split(`
997
+ `).map(c), ""], n = dist_default2(e), t = Math.max(g.reduce((m, F) => {
998
+ const O = dist_default2(F);
999
+ return O > m ? O : m;
1000
+ }, 0), n) + 2, h = g.map((m) => `${styleText2("gray", S_BAR)} ${m}${" ".repeat(t - dist_default2(m))}${styleText2("gray", S_BAR)}`).join(`
1001
+ `), T = i ? `${styleText2("gray", S_BAR)}
1002
+ ` : "", l$1 = i ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;
1003
+ a.write(`${T}${styleText2("green", S_STEP_SUBMIT)} ${styleText2("reset", e)} ${styleText2("gray", S_BAR_H.repeat(Math.max(t - n - 1, 1)) + S_CORNER_TOP_RIGHT)}
1004
+ ${h}
1005
+ ${styleText2("gray", l$1 + S_BAR_H.repeat(t + 2) + S_CORNER_BOTTOM_RIGHT)}
1006
+ `);
1007
+ };
1008
+ var Y = 30000;
1009
+ var Z = (c) => styleText2("magenta", c);
1010
+ var spinner = ({
1011
+ indicator: c = "dots",
1012
+ onCancel: b,
1013
+ output: n = process.stdout,
1014
+ cancelMessage: _,
1015
+ errorMessage: C,
1016
+ frames: M = unicode ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"],
1017
+ delay: O = unicode ? 80 : 120,
1018
+ signal: g,
1019
+ ...E
1020
+ } = {}) => {
1021
+ const u = isCI(), h = isAccessible(E.accessible);
1022
+ let x, I, p = false, l = false, r = "", v, w = performance.now();
1023
+ const y = getColumns(n), F = E?.styleFrame ?? Z, S = (e) => {
1024
+ const s = e > 1 ? C ?? settings.messages.error : _ ?? settings.messages.cancel;
1025
+ l = e === 1, p && (m(s, e), l && typeof b == "function" && b());
1026
+ }, $ = () => S(2), a = () => S(1), H = () => {
1027
+ process.on("uncaughtExceptionMonitor", $), process.on("unhandledRejection", $), process.on("SIGINT", a), process.on("SIGTERM", a), process.on("exit", S), g && g.addEventListener("abort", a);
1028
+ }, B = () => {
1029
+ process.removeListener("uncaughtExceptionMonitor", $), process.removeListener("unhandledRejection", $), process.removeListener("SIGINT", a), process.removeListener("SIGTERM", a), process.removeListener("exit", S), g && g.removeEventListener("abort", a);
1030
+ }, R = () => {
1031
+ if (v === undefined)
1032
+ return;
1033
+ u && n.write(`
1034
+ `);
1035
+ const s = wrapAnsi(v, y, {
1036
+ hard: true,
1037
+ trim: false
1038
+ }).split(`
1039
+ `);
1040
+ s.length > 1 && n.write(cursor.up(s.length - 1)), n.write(cursor.to(0)), n.write(erase.down());
1041
+ }, L = (e) => e.replace(/\.+$/, ""), T = (e) => {
1042
+ const s = (performance.now() - e) / 1000, i = Math.floor(s / 60), t = Math.floor(s % 60);
1043
+ return i > 0 ? `[${i}m ${t}s]` : `[${t}s]`;
1044
+ }, N = E.withGuide ?? settings.withGuide, P = (e = "") => {
1045
+ if (p = true, l = false, r = L(e), w = performance.now(), H(), h) {
1046
+ r !== "" && n.write(`${r}
1047
+ `), I = setInterval(() => {
1048
+ n.write(r === "" ? `still working
1049
+ ` : `still working: ${r}
1050
+ `);
1051
+ }, Y);
1052
+ return;
75
1053
  }
76
- const interactive = args.interactive ?? stdin.isTTY === true;
77
- const prompt = interactive ? createInterface({ input: stdin, output: stdout }) : undefined;
78
- try {
79
- let dir = args.dir === undefined ? '' : formatTargetDir(args.dir);
80
- if (dir === '' && prompt !== undefined) {
81
- dir = formatTargetDir((await prompt.question(`Project directory (${DEFAULT_DIR}): `)) || DEFAULT_DIR);
1054
+ x = block({ output: n }), N && n.write(`${styleText2("gray", S_BAR)}
1055
+ `);
1056
+ let s = 0, i = 0;
1057
+ I = setInterval(() => {
1058
+ if (u && r === v)
1059
+ return;
1060
+ R(), v = r;
1061
+ const t = F(M[s]);
1062
+ let o;
1063
+ if (u)
1064
+ o = `${t} ${r}...`;
1065
+ else if (c === "timer")
1066
+ o = `${t} ${r} ${T(w)}`;
1067
+ else {
1068
+ const j = ".".repeat(Math.floor(i)).slice(0, 3);
1069
+ o = `${t} ${r}${j}`;
1070
+ }
1071
+ const D = wrapAnsi(o, y, {
1072
+ hard: true,
1073
+ trim: false
1074
+ });
1075
+ n.write(D), s = s + 1 < M.length ? s + 1 : 0, i = i < 4 ? i + 0.125 : 0;
1076
+ }, O);
1077
+ }, m = (e = "", s = 0, i = false) => {
1078
+ if (p) {
1079
+ if (p = false, l = s === 1, clearInterval(I), h || R(), r = e ?? r, !i)
1080
+ if (h) {
1081
+ const t = s === 1 ? _ ?? settings.messages.cancel : s === 2 ? C ?? settings.messages.error : "Done", o = r || t;
1082
+ c === "timer" ? n.write(`${o} ${T(w)}
1083
+ `) : n.write(`${o}
1084
+ `);
1085
+ } else {
1086
+ const t = s === 0 ? styleText2("green", S_STEP_SUBMIT) : s === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
1087
+ c === "timer" ? n.write(`${t} ${r} ${T(w)}
1088
+ `) : n.write(`${t} ${r}
1089
+ `);
82
1090
  }
83
- dir ||= DEFAULT_DIR;
84
- if (!(await isEmptyDir(dir))) {
85
- const overwrite = args.overwrite ||
86
- (prompt !== undefined &&
87
- /^y(?:es)?$/i.test(await prompt.question(`${dir} is not empty. Remove its files and continue? (y/N) `)));
88
- if (!overwrite) {
89
- throw new Error(`${dir} is not empty; choose another directory or pass --overwrite`);
90
- }
91
- await emptyDir(dir);
1091
+ B(), x?.();
1092
+ }
1093
+ };
1094
+ return {
1095
+ start: P,
1096
+ stop: (e = "") => m(e, 0),
1097
+ message: (e = "") => {
1098
+ r = L(e ?? r);
1099
+ },
1100
+ cancel: (e = "") => m(e, 1),
1101
+ error: (e = "") => m(e, 2),
1102
+ clear: () => m("", 0, true),
1103
+ get isCancelled() {
1104
+ return l;
1105
+ }
1106
+ };
1107
+ };
1108
+ var u2 = {
1109
+ light: unicodeOr("─", "-"),
1110
+ heavy: unicodeOr("━", "="),
1111
+ block: unicodeOr("█", "#")
1112
+ };
1113
+ var SELECT_INSTRUCTIONS = [
1114
+ `${styleText2("dim", "↑/↓")} to navigate`,
1115
+ `${styleText2("dim", "Enter:")} confirm`
1116
+ ];
1117
+ var c2 = (t, o) => t.includes(`
1118
+ `) ? t.split(`
1119
+ `).map((d) => o(d)).join(`
1120
+ `) : o(t);
1121
+ var select = (t) => {
1122
+ const o = (n, m) => {
1123
+ if (n === undefined)
1124
+ return "";
1125
+ const s = n.label ?? String(n.value);
1126
+ switch (m) {
1127
+ case "disabled":
1128
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c2(s, (i) => styleText2("gray", i))}${n.hint ? ` ${styleText2("dim", `(${n.hint ?? "disabled"})`)}` : ""}`;
1129
+ case "selected":
1130
+ return `${c2(s, (i) => styleText2("dim", i))}`;
1131
+ case "active":
1132
+ return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${n.hint ? ` ${styleText2("dim", `(${n.hint})`)}` : ""}`;
1133
+ case "cancelled":
1134
+ return `${c2(s, (i) => styleText2(["strikethrough", "dim"], i))}`;
1135
+ default:
1136
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c2(s, (i) => styleText2("dim", i))}`;
1137
+ }
1138
+ }, d = t.showInstructions ?? true;
1139
+ return new n$1({
1140
+ options: t.options,
1141
+ signal: t.signal,
1142
+ input: t.input,
1143
+ output: t.output,
1144
+ initialValue: t.initialValue,
1145
+ render() {
1146
+ const n = t.withGuide ?? settings.withGuide, m = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, i = wrapTextWithPrefix(t.output, t.message, s, m), u = `${n ? `${styleText2("gray", S_BAR)}
1147
+ ` : ""}${i}
1148
+ `;
1149
+ switch (this.state) {
1150
+ case "submit": {
1151
+ const r = n ? `${styleText2("gray", S_BAR)} ` : "", a = wrapTextWithPrefix(t.output, o(this.options[this.cursor], "selected"), r);
1152
+ return `${u}${a}`;
92
1153
  }
93
- let name = toValidPackageName(basename(resolve(dir)));
94
- if (prompt !== undefined) {
95
- const answer = (await prompt.question(`Package name (${name}): `)).trim();
96
- if (answer !== '' && !isValidPackageName(answer)) {
97
- throw new Error(`"${answer}" is not a valid npm package name`);
98
- }
99
- name = answer || name;
1154
+ case "cancel": {
1155
+ const r = n ? `${styleText2("gray", S_BAR)} ` : "", a = wrapTextWithPrefix(t.output, o(this.options[this.cursor], "cancelled"), r);
1156
+ return `${u}${a}${n ? `
1157
+ ${styleText2("gray", S_BAR)}` : ""}`;
100
1158
  }
101
- await createProject({
102
- dir,
103
- name,
104
- coreVersion: args.coreVersion ?? readCoreVersion(),
105
- template: fileURLToPath(new URL('../template', import.meta.url)),
106
- });
107
- const manager = detectPackageManager(process.env.npm_config_user_agent);
108
- const cd = relative(process.cwd(), resolve(dir));
109
- stdout.write(`\nCreated ${name} in ${resolve(dir)}\n\nNext steps:\n`);
110
- if (cd !== '') {
111
- stdout.write(` cd ${cd.includes(' ') ? JSON.stringify(cd) : cd}\n`);
1159
+ default: {
1160
+ const r = n ? `${styleText2("cyan", S_BAR)} ` : "", a = u.split(`
1161
+ `).length, p = d ? formatInstructionFooter(t.output, SELECT_INSTRUCTIONS, n) : n ? [styleText2("cyan", S_BAR_END)] : [], f = p.join(`
1162
+ `), b = p.length + 1;
1163
+ return `${u}${r}${limitOptions({
1164
+ output: t.output,
1165
+ cursor: this.cursor,
1166
+ options: this.options,
1167
+ maxItems: t.maxItems,
1168
+ columnPadding: r.length,
1169
+ rowPadding: a + b,
1170
+ style: (g, x) => o(g, g.disabled ? "disabled" : x ? "active" : "inactive")
1171
+ }).join(`
1172
+ ${r}`)}
1173
+ ${f}
1174
+ `;
112
1175
  }
113
- stdout.write(` ${manager} install\n ${manager === 'npm' ? 'npm run' : manager} dev\n`);
1176
+ }
114
1177
  }
115
- finally {
116
- prompt?.close();
1178
+ }).prompt();
1179
+ };
1180
+ var i = `${styleText2("gray", S_BAR)} `;
1181
+ var text = (t) => new n({
1182
+ validate: t.validate,
1183
+ placeholder: t.placeholder,
1184
+ defaultValue: t.defaultValue,
1185
+ initialValue: t.initialValue,
1186
+ output: t.output,
1187
+ signal: t.signal,
1188
+ input: t.input,
1189
+ render() {
1190
+ const r = t?.withGuide ?? settings.withGuide, l = `${`${r ? `${styleText2("gray", S_BAR)}
1191
+ ` : ""}${symbol(this.state)} `}${t.message}
1192
+ `, d = t.placeholder && t.placeholder.length > 0 ? styleText2("inverse", t.placeholder[0]) + styleText2("dim", t.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor : d, s = this.value ?? "";
1193
+ switch (this.state) {
1194
+ case "validating": {
1195
+ const n = r ? `${styleText2("cyan", S_BAR)} ` : "", i = r ? styleText2("cyan", S_BAR_END) : "", c = styleText2("dim", o), $ = styleText2("dim", "Validating...");
1196
+ return `${l}${n}${c}
1197
+ ${i} ${$}
1198
+ `;
1199
+ }
1200
+ case "error": {
1201
+ const n = this.error ? ` ${styleText2("yellow", this.error)}` : "", i = r ? `${styleText2("yellow", S_BAR)} ` : "", c = r ? styleText2("yellow", S_BAR_END) : "";
1202
+ return `${l.trim()}
1203
+ ${i}${o}
1204
+ ${c}${n}
1205
+ `;
1206
+ }
1207
+ case "submit": {
1208
+ const n = s ? `${r ? " " : ""}${styleText2("dim", s)}` : "", i = r ? styleText2("gray", S_BAR) : "";
1209
+ return `${l}${i}${n}`;
1210
+ }
1211
+ case "cancel": {
1212
+ const n = s ? ` ${styleText2(["strikethrough", "dim"], s)}` : "", i = r ? styleText2("gray", S_BAR) : "";
1213
+ return `${l}${i}${n}${s.trim() ? `
1214
+ ${i}` : ""}`;
1215
+ }
1216
+ default: {
1217
+ const n = r ? `${styleText2("cyan", S_BAR)} ` : "", i = r ? styleText2("cyan", S_BAR_END) : "";
1218
+ return `${l}${n}${o}
1219
+ ${i}
1220
+ `;
1221
+ }
1222
+ }
1223
+ }
1224
+ }).prompt();
1225
+
1226
+ // src/index.ts
1227
+ import { spawn } from "node:child_process";
1228
+ import { basename as basename2, relative, resolve as resolve2 } from "node:path";
1229
+ import { stdin as stdin2, stdout as stdout2 } from "node:process";
1230
+ import { fileURLToPath } from "node:url";
1231
+ import { styleText as styleText3 } from "node:util";
1232
+ // ../core/package.json
1233
+ var version = "0.2.1";
1234
+ // package.json
1235
+ var version2 = "0.2.1";
1236
+
1237
+ // src/project.ts
1238
+ import { existsSync } from "node:fs";
1239
+ import { cp, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
1240
+ import { basename, join, resolve } from "node:path";
1241
+ var TEMPLATES = [
1242
+ { name: "minimal", label: "Minimal", hint: "a module, a controller, a service and a test" },
1243
+ { name: "demo", label: "Demo", hint: "users with validation, a guard, logging and CORS" }
1244
+ ];
1245
+ var RENAMED = { _gitignore: ".gitignore", "_oxlintrc.json": ".oxlintrc.json" };
1246
+ var formatTargetDir = (dir) => dir.trim().replace(/[<>:"\\|?*]/g, "").replace(/\/+$/, "");
1247
+ var isValidPackageName = (name) => /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(name);
1248
+ var toValidPackageName = (name) => name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z\d\-~]+/g, "-");
1249
+ var isEmptyDir = async (dir) => {
1250
+ if (!existsSync(dir)) {
1251
+ return true;
1252
+ }
1253
+ const entries = await readdir(dir);
1254
+ return entries.length === 0 || entries.length === 1 && entries[0] === ".git";
1255
+ };
1256
+ var emptyDir = async (dir) => {
1257
+ for (const entry of await readdir(dir)) {
1258
+ if (entry !== ".git") {
1259
+ await rm(join(dir, entry), { recursive: true, force: true });
117
1260
  }
1261
+ }
1262
+ };
1263
+ var createProject = async (options) => {
1264
+ const root = resolve(options.dir);
1265
+ await cp(options.template, root, { recursive: true });
1266
+ for (const [from, to] of Object.entries(RENAMED)) {
1267
+ if (existsSync(join(root, from))) {
1268
+ await rename(join(root, from), join(root, to));
1269
+ }
1270
+ }
1271
+ const manifestPath = join(root, "package.json");
1272
+ const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
1273
+ manifest.name = options.name ?? toValidPackageName(basename(root));
1274
+ manifest.dependencies["@getsoda/core"] = options.coreVersion;
1275
+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
1276
+ `);
1277
+ };
1278
+ var detectPackageManager = (userAgent) => {
1279
+ const name = userAgent?.split(" ")[0]?.split("/")[0];
1280
+ return name === undefined || name === "" ? "bun" : name;
1281
+ };
1282
+ var runScriptCommand = (manager, script) => manager === "npm" ? `npm run ${script}` : `${manager} ${script}`;
1283
+
1284
+ // src/index.ts
1285
+ var DEFAULT_DIR = "soda-app";
1286
+ var HELP = `Usage: create-soda [directory] [options]
1287
+
1288
+ Creates a Soda project. Asks questions in a terminal.
1289
+
1290
+ Options:
1291
+ -t, --template <name> template to use (default: ${TEMPLATES[0].name})
1292
+ --install, --no-install install dependencies
1293
+ --overwrite empty the directory if it is not empty
1294
+ --interactive, --no-interactive force or disable questions
1295
+ --core-version <range> version of @getsoda/core to depend on
1296
+ -h, --help show this help
1297
+
1298
+ Templates:
1299
+ ${TEMPLATES.map((template) => ` ${template.name.padEnd(10)} ${template.hint}`).join(`
1300
+ `)}
1301
+ `;
1302
+ var parseArguments = (args) => {
1303
+ let dir;
1304
+ let template;
1305
+ let install;
1306
+ let overwrite = false;
1307
+ let interactive;
1308
+ let coreVersion;
1309
+ let help = false;
1310
+ for (let i = 0;i < args.length; i++) {
1311
+ const arg = args[i];
1312
+ if (arg === "-t" || arg === "--template") {
1313
+ template = args[++i];
1314
+ } else if (arg === "--install" || arg === "--no-install") {
1315
+ install = arg === "--install";
1316
+ } else if (arg === "--overwrite") {
1317
+ overwrite = true;
1318
+ } else if (arg === "--interactive" || arg === "--no-interactive") {
1319
+ interactive = arg === "--interactive";
1320
+ } else if (arg === "--core-version") {
1321
+ coreVersion = args[++i];
1322
+ } else if (arg === "-h" || arg === "--help") {
1323
+ help = true;
1324
+ } else if (arg.startsWith("-")) {
1325
+ throw new Error(`Unknown option ${arg}
1326
+
1327
+ ${HELP}`);
1328
+ } else {
1329
+ dir ??= arg;
1330
+ }
1331
+ }
1332
+ return { dir, template, install, overwrite, interactive, coreVersion, help };
1333
+ };
1334
+
1335
+ class Cancelled extends Error {
1336
+ }
1337
+ var answer = async (question) => {
1338
+ const value = await question;
1339
+ if (isCancel(value)) {
1340
+ throw new Cancelled;
1341
+ }
1342
+ return value;
1343
+ };
1344
+ var run = (command, args, cwd) => new Promise((done, fail) => {
1345
+ const child = spawn(command, args, { cwd, shell: process.platform === "win32" });
1346
+ let output = "";
1347
+ child.stdout.on("data", (chunk) => output += chunk);
1348
+ child.stderr.on("data", (chunk) => output += chunk);
1349
+ child.on("error", fail);
1350
+ child.on("close", (code) => done({ code: code ?? 1, output }));
1351
+ });
1352
+ var installDependencies = async (root, manager) => {
1353
+ const spinner2 = spinner();
1354
+ spinner2.start(`Installing dependencies with ${manager}`);
1355
+ const { code, output } = await run(manager, ["install"], root);
1356
+ if (code !== 0) {
1357
+ spinner2.error(`${manager} install failed`);
1358
+ process.stderr.write(output);
1359
+ throw new Error(`${manager} install exited with code ${code}`);
1360
+ }
1361
+ spinner2.stop("Installed dependencies");
1362
+ };
1363
+ var main = async () => {
1364
+ const args = parseArguments(process.argv.slice(2));
1365
+ if (args.help) {
1366
+ stdout2.write(HELP);
1367
+ return;
1368
+ }
1369
+ if (args.template !== undefined && !TEMPLATES.some((template) => template.name === args.template)) {
1370
+ throw new Error(`Unknown template "${args.template}"; use ${TEMPLATES.map((template) => template.name).join(" or ")}`);
1371
+ }
1372
+ const interactive = args.interactive ?? stdin2.isTTY === true;
1373
+ intro(`${styleText3(["bgCyan", "black"], " create-soda ")} ${styleText3("dim", `v${version2}`)}`);
1374
+ let dir = formatTargetDir(args.dir ?? "");
1375
+ if (dir === "" && interactive) {
1376
+ const input = await answer(text({
1377
+ message: "Project directory",
1378
+ placeholder: DEFAULT_DIR,
1379
+ defaultValue: DEFAULT_DIR,
1380
+ validate: (value) => value === undefined || value === "" || formatTargetDir(value) !== "" ? undefined : "Invalid directory name"
1381
+ }));
1382
+ dir = formatTargetDir(input);
1383
+ }
1384
+ dir ||= DEFAULT_DIR;
1385
+ const empty = await isEmptyDir(dir);
1386
+ const overwrite = !empty && (args.overwrite || interactive && await answer(confirm({
1387
+ message: `${dir === "." ? "The current directory" : dir} is not empty. Remove its files and continue?`,
1388
+ initialValue: false
1389
+ })));
1390
+ if (!empty && !overwrite) {
1391
+ throw new Error(`${dir} is not empty; choose another directory or pass --overwrite`);
1392
+ }
1393
+ const root = resolve2(dir);
1394
+ let name = basename2(root);
1395
+ if (!isValidPackageName(name)) {
1396
+ const suggested = toValidPackageName(name);
1397
+ name = interactive ? await answer(text({
1398
+ message: "Package name",
1399
+ placeholder: suggested,
1400
+ defaultValue: suggested,
1401
+ validate: (value) => value === undefined || value === "" || isValidPackageName(value) ? undefined : "Invalid package name"
1402
+ })) : suggested;
1403
+ }
1404
+ const template = args.template ?? (interactive ? await answer(select({
1405
+ message: "Template",
1406
+ options: TEMPLATES.map((option) => ({ value: option.name, label: option.label, hint: option.hint }))
1407
+ })) : TEMPLATES[0].name);
1408
+ const manager = detectPackageManager(process.env.npm_config_user_agent);
1409
+ const install = args.install ?? (interactive && await answer(confirm({ message: `Install dependencies with ${manager}?` })));
1410
+ if (overwrite) {
1411
+ await emptyDir(dir);
1412
+ }
1413
+ await createProject({
1414
+ dir,
1415
+ name,
1416
+ coreVersion: args.coreVersion ?? `^${version}`,
1417
+ template: fileURLToPath(new URL(`../templates/${template}`, import.meta.url))
1418
+ });
1419
+ log.success(`Created ${name} in ${root}`);
1420
+ if (install) {
1421
+ await installDependencies(root, manager);
1422
+ }
1423
+ const cd = relative(process.cwd(), root);
1424
+ const steps = [
1425
+ ...cd === "" ? [] : [`cd ${cd.includes(" ") ? JSON.stringify(cd) : cd}`],
1426
+ ...install ? [] : [`${manager} install`],
1427
+ runScriptCommand(manager, "dev")
1428
+ ];
1429
+ note(steps.join(`
1430
+ `), "Next steps");
1431
+ outro(`Docs: ${styleText3("underline", "https://github.com/getsodajs/soda")}`);
118
1432
  };
119
1433
  main().catch((error) => {
120
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
121
- process.exit(1);
1434
+ if (error instanceof Cancelled) {
1435
+ cancel("Cancelled");
1436
+ } else {
1437
+ cancel(error instanceof Error ? error.message : String(error), { output: process.stderr });
1438
+ }
1439
+ process.exit(1);
122
1440
  });