create-rakta-app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4094 @@
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;
32
+ };
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 ESC2 = "\x1B";
38
+ var CSI2 = `${ESC2}[`;
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: `${ESC2}7`,
68
+ restore: `${ESC2}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
+ // ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
94
+ var require_picocolors = __commonJS((exports, module) => {
95
+ var p2 = process || {};
96
+ var argv = p2.argv || [];
97
+ var env = p2.env || {};
98
+ var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
99
+ var formatter = (open, close, replace = open) => (input) => {
100
+ let string = "" + input, index = string.indexOf(close, open.length);
101
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
102
+ };
103
+ var replaceClose = (string, close, replace, index) => {
104
+ let result = "", cursor3 = 0;
105
+ do {
106
+ result += string.substring(cursor3, index) + replace;
107
+ cursor3 = index + close.length;
108
+ index = string.indexOf(close, cursor3);
109
+ } while (~index);
110
+ return result + string.substring(cursor3);
111
+ };
112
+ var createColors = (enabled = isColorSupported) => {
113
+ let f2 = enabled ? formatter : () => String;
114
+ return {
115
+ isColorSupported: enabled,
116
+ reset: f2("\x1B[0m", "\x1B[0m"),
117
+ bold: f2("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
118
+ dim: f2("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
119
+ italic: f2("\x1B[3m", "\x1B[23m"),
120
+ underline: f2("\x1B[4m", "\x1B[24m"),
121
+ inverse: f2("\x1B[7m", "\x1B[27m"),
122
+ hidden: f2("\x1B[8m", "\x1B[28m"),
123
+ strikethrough: f2("\x1B[9m", "\x1B[29m"),
124
+ black: f2("\x1B[30m", "\x1B[39m"),
125
+ red: f2("\x1B[31m", "\x1B[39m"),
126
+ green: f2("\x1B[32m", "\x1B[39m"),
127
+ yellow: f2("\x1B[33m", "\x1B[39m"),
128
+ blue: f2("\x1B[34m", "\x1B[39m"),
129
+ magenta: f2("\x1B[35m", "\x1B[39m"),
130
+ cyan: f2("\x1B[36m", "\x1B[39m"),
131
+ white: f2("\x1B[37m", "\x1B[39m"),
132
+ gray: f2("\x1B[90m", "\x1B[39m"),
133
+ bgBlack: f2("\x1B[40m", "\x1B[49m"),
134
+ bgRed: f2("\x1B[41m", "\x1B[49m"),
135
+ bgGreen: f2("\x1B[42m", "\x1B[49m"),
136
+ bgYellow: f2("\x1B[43m", "\x1B[49m"),
137
+ bgBlue: f2("\x1B[44m", "\x1B[49m"),
138
+ bgMagenta: f2("\x1B[45m", "\x1B[49m"),
139
+ bgCyan: f2("\x1B[46m", "\x1B[49m"),
140
+ bgWhite: f2("\x1B[47m", "\x1B[49m"),
141
+ blackBright: f2("\x1B[90m", "\x1B[39m"),
142
+ redBright: f2("\x1B[91m", "\x1B[39m"),
143
+ greenBright: f2("\x1B[92m", "\x1B[39m"),
144
+ yellowBright: f2("\x1B[93m", "\x1B[39m"),
145
+ blueBright: f2("\x1B[94m", "\x1B[39m"),
146
+ magentaBright: f2("\x1B[95m", "\x1B[39m"),
147
+ cyanBright: f2("\x1B[96m", "\x1B[39m"),
148
+ whiteBright: f2("\x1B[97m", "\x1B[39m"),
149
+ bgBlackBright: f2("\x1B[100m", "\x1B[49m"),
150
+ bgRedBright: f2("\x1B[101m", "\x1B[49m"),
151
+ bgGreenBright: f2("\x1B[102m", "\x1B[49m"),
152
+ bgYellowBright: f2("\x1B[103m", "\x1B[49m"),
153
+ bgBlueBright: f2("\x1B[104m", "\x1B[49m"),
154
+ bgMagentaBright: f2("\x1B[105m", "\x1B[49m"),
155
+ bgCyanBright: f2("\x1B[106m", "\x1B[49m"),
156
+ bgWhiteBright: f2("\x1B[107m", "\x1B[49m")
157
+ };
158
+ };
159
+ module.exports = createColors();
160
+ module.exports.createColors = createColors;
161
+ });
162
+
163
+ // src/index.ts
164
+ import { existsSync as existsSync2 } from "fs";
165
+ import { resolve as resolve2 } from "path";
166
+
167
+ // ../../node_modules/.bun/@clack+core@1.4.2/node_modules/@clack/core/dist/index.mjs
168
+ import { styleText } from "util";
169
+ import { stdout, stdin } from "process";
170
+ import * as l from "readline";
171
+ import l__default from "readline";
172
+
173
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
174
+ var getCodePointsLength = (() => {
175
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
176
+ return (input) => {
177
+ let surrogatePairsNr = 0;
178
+ SURROGATE_PAIR_RE.lastIndex = 0;
179
+ while (SURROGATE_PAIR_RE.test(input)) {
180
+ surrogatePairsNr += 1;
181
+ }
182
+ return input.length - surrogatePairsNr;
183
+ };
184
+ })();
185
+ var isFullWidth = (x) => {
186
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
187
+ };
188
+ var isWideNotCJKTNotEmoji = (x) => {
189
+ 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;
190
+ };
191
+
192
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
193
+ var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
194
+ var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
195
+ 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;
196
+ var TAB_RE = /\t{1,1000}/y;
197
+ 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;
198
+ var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
199
+ var MODIFIER_RE = /\p{M}+/gu;
200
+ var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
201
+ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
202
+ const LIMIT = truncationOptions.limit ?? Infinity;
203
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
204
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
205
+ const ANSI_WIDTH = 0;
206
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
207
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
208
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
209
+ const FULL_WIDTH_WIDTH = 2;
210
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
211
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
212
+ const PARSE_BLOCKS = [
213
+ [LATIN_RE, REGULAR_WIDTH],
214
+ [ANSI_RE, ANSI_WIDTH],
215
+ [CONTROL_RE, CONTROL_WIDTH],
216
+ [TAB_RE, TAB_WIDTH],
217
+ [EMOJI_RE, EMOJI_WIDTH],
218
+ [CJKT_WIDE_RE, WIDE_WIDTH]
219
+ ];
220
+ let indexPrev = 0;
221
+ let index = 0;
222
+ let length = input.length;
223
+ let lengthExtra = 0;
224
+ let truncationEnabled = false;
225
+ let truncationIndex = length;
226
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
227
+ let unmatchedStart = 0;
228
+ let unmatchedEnd = 0;
229
+ let width = 0;
230
+ let widthExtra = 0;
231
+ outer:
232
+ while (true) {
233
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
234
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
235
+ lengthExtra = 0;
236
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
237
+ const codePoint = char.codePointAt(0) || 0;
238
+ if (isFullWidth(codePoint)) {
239
+ widthExtra = FULL_WIDTH_WIDTH;
240
+ } else if (isWideNotCJKTNotEmoji(codePoint)) {
241
+ widthExtra = WIDE_WIDTH;
242
+ } else {
243
+ widthExtra = REGULAR_WIDTH;
244
+ }
245
+ if (width + widthExtra > truncationLimit) {
246
+ truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
247
+ }
248
+ if (width + widthExtra > LIMIT) {
249
+ truncationEnabled = true;
250
+ break outer;
251
+ }
252
+ lengthExtra += char.length;
253
+ width += widthExtra;
254
+ }
255
+ unmatchedStart = unmatchedEnd = 0;
256
+ }
257
+ if (index >= length) {
258
+ break outer;
259
+ }
260
+ for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
261
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
262
+ BLOCK_RE.lastIndex = index;
263
+ if (BLOCK_RE.test(input)) {
264
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
265
+ widthExtra = lengthExtra * BLOCK_WIDTH;
266
+ if (width + widthExtra > truncationLimit) {
267
+ truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
268
+ }
269
+ if (width + widthExtra > LIMIT) {
270
+ truncationEnabled = true;
271
+ break outer;
272
+ }
273
+ width += widthExtra;
274
+ unmatchedStart = indexPrev;
275
+ unmatchedEnd = index;
276
+ index = indexPrev = BLOCK_RE.lastIndex;
277
+ continue outer;
278
+ }
279
+ }
280
+ index += 1;
281
+ }
282
+ return {
283
+ width: truncationEnabled ? truncationLimit : width,
284
+ index: truncationEnabled ? truncationIndex : length,
285
+ truncated: truncationEnabled,
286
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
287
+ };
288
+ };
289
+ var dist_default = getStringTruncatedWidth;
290
+
291
+ // ../../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
292
+ var NO_TRUNCATION2 = {
293
+ limit: Infinity,
294
+ ellipsis: "",
295
+ ellipsisWidth: 0
296
+ };
297
+ var fastStringWidth = (input, options = {}) => {
298
+ return dist_default(input, NO_TRUNCATION2, options).width;
299
+ };
300
+ var dist_default2 = fastStringWidth;
301
+
302
+ // ../../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
303
+ var ESC = "\x1B";
304
+ var CSI = "\x9B";
305
+ var END_CODE = 39;
306
+ var ANSI_ESCAPE_BELL = "\x07";
307
+ var ANSI_CSI = "[";
308
+ var ANSI_OSC = "]";
309
+ var ANSI_SGR_TERMINATOR = "m";
310
+ var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
311
+ var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
312
+ var getClosingCode = (openingCode) => {
313
+ if (openingCode >= 30 && openingCode <= 37)
314
+ return 39;
315
+ if (openingCode >= 90 && openingCode <= 97)
316
+ return 39;
317
+ if (openingCode >= 40 && openingCode <= 47)
318
+ return 49;
319
+ if (openingCode >= 100 && openingCode <= 107)
320
+ return 49;
321
+ if (openingCode === 1 || openingCode === 2)
322
+ return 22;
323
+ if (openingCode === 3)
324
+ return 23;
325
+ if (openingCode === 4)
326
+ return 24;
327
+ if (openingCode === 7)
328
+ return 27;
329
+ if (openingCode === 8)
330
+ return 28;
331
+ if (openingCode === 9)
332
+ return 29;
333
+ if (openingCode === 0)
334
+ return 0;
335
+ return;
336
+ };
337
+ var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
338
+ var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
339
+ var wrapWord = (rows, word, columns) => {
340
+ const characters = word[Symbol.iterator]();
341
+ let isInsideEscape = false;
342
+ let isInsideLinkEscape = false;
343
+ let lastRow = rows.at(-1);
344
+ let visible = lastRow === undefined ? 0 : dist_default2(lastRow);
345
+ let currentCharacter = characters.next();
346
+ let nextCharacter = characters.next();
347
+ let rawCharacterIndex = 0;
348
+ while (!currentCharacter.done) {
349
+ const character = currentCharacter.value;
350
+ const characterLength = dist_default2(character);
351
+ if (visible + characterLength <= columns) {
352
+ rows[rows.length - 1] += character;
353
+ } else {
354
+ rows.push(character);
355
+ visible = 0;
356
+ }
357
+ if (character === ESC || character === CSI) {
358
+ isInsideEscape = true;
359
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
360
+ }
361
+ if (isInsideEscape) {
362
+ if (isInsideLinkEscape) {
363
+ if (character === ANSI_ESCAPE_BELL) {
364
+ isInsideEscape = false;
365
+ isInsideLinkEscape = false;
366
+ }
367
+ } else if (character === ANSI_SGR_TERMINATOR) {
368
+ isInsideEscape = false;
369
+ }
370
+ } else {
371
+ visible += characterLength;
372
+ if (visible === columns && !nextCharacter.done) {
373
+ rows.push("");
374
+ visible = 0;
375
+ }
376
+ }
377
+ currentCharacter = nextCharacter;
378
+ nextCharacter = characters.next();
379
+ rawCharacterIndex += character.length;
380
+ }
381
+ lastRow = rows.at(-1);
382
+ if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
383
+ rows[rows.length - 2] += rows.pop();
384
+ }
385
+ };
386
+ var stringVisibleTrimSpacesRight = (string) => {
387
+ const words = string.split(" ");
388
+ let last = words.length;
389
+ while (last) {
390
+ if (dist_default2(words[last - 1])) {
391
+ break;
392
+ }
393
+ last--;
394
+ }
395
+ if (last === words.length) {
396
+ return string;
397
+ }
398
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
399
+ };
400
+ var exec = (string, columns, options = {}) => {
401
+ if (options.trim !== false && string.trim() === "") {
402
+ return "";
403
+ }
404
+ let returnValue = "";
405
+ let escapeCode;
406
+ let escapeUrl;
407
+ const words = string.split(" ");
408
+ let rows = [""];
409
+ let rowLength = 0;
410
+ for (let index = 0;index < words.length; index++) {
411
+ const word = words[index];
412
+ if (options.trim !== false) {
413
+ const row = rows.at(-1) ?? "";
414
+ const trimmed = row.trimStart();
415
+ if (row.length !== trimmed.length) {
416
+ rows[rows.length - 1] = trimmed;
417
+ rowLength = dist_default2(trimmed);
418
+ }
419
+ }
420
+ if (index !== 0) {
421
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
422
+ rows.push("");
423
+ rowLength = 0;
424
+ }
425
+ if (rowLength || options.trim === false) {
426
+ rows[rows.length - 1] += " ";
427
+ rowLength++;
428
+ }
429
+ }
430
+ const wordLength = dist_default2(word);
431
+ if (options.hard && wordLength > columns) {
432
+ const remainingColumns = columns - rowLength;
433
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
434
+ const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
435
+ if (breaksStartingNextLine < breaksStartingThisLine) {
436
+ rows.push("");
437
+ }
438
+ wrapWord(rows, word, columns);
439
+ rowLength = dist_default2(rows.at(-1) ?? "");
440
+ continue;
441
+ }
442
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
443
+ if (options.wordWrap === false && rowLength < columns) {
444
+ wrapWord(rows, word, columns);
445
+ rowLength = dist_default2(rows.at(-1) ?? "");
446
+ continue;
447
+ }
448
+ rows.push("");
449
+ rowLength = 0;
450
+ }
451
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
452
+ wrapWord(rows, word, columns);
453
+ rowLength = dist_default2(rows.at(-1) ?? "");
454
+ continue;
455
+ }
456
+ rows[rows.length - 1] += word;
457
+ rowLength += wordLength;
458
+ }
459
+ if (options.trim !== false) {
460
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
461
+ }
462
+ const preString = rows.join(`
463
+ `);
464
+ let inSurrogate = false;
465
+ for (let i = 0;i < preString.length; i++) {
466
+ const character = preString[i];
467
+ returnValue += character;
468
+ if (!inSurrogate) {
469
+ inSurrogate = character >= "\uD800" && character <= "\uDBFF";
470
+ if (inSurrogate) {
471
+ continue;
472
+ }
473
+ } else {
474
+ inSurrogate = false;
475
+ }
476
+ if (character === ESC || character === CSI) {
477
+ GROUP_REGEX.lastIndex = i + 1;
478
+ const groupsResult = GROUP_REGEX.exec(preString);
479
+ const groups = groupsResult?.groups;
480
+ if (groups?.code !== undefined) {
481
+ const code = Number.parseFloat(groups.code);
482
+ escapeCode = code === END_CODE ? undefined : code;
483
+ } else if (groups?.uri !== undefined) {
484
+ escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
485
+ }
486
+ }
487
+ if (preString[i + 1] === `
488
+ `) {
489
+ if (escapeUrl) {
490
+ returnValue += wrapAnsiHyperlink("");
491
+ }
492
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
493
+ if (escapeCode && closingCode) {
494
+ returnValue += wrapAnsiCode(closingCode);
495
+ }
496
+ } else if (character === `
497
+ `) {
498
+ if (escapeCode && getClosingCode(escapeCode)) {
499
+ returnValue += wrapAnsiCode(escapeCode);
500
+ }
501
+ if (escapeUrl) {
502
+ returnValue += wrapAnsiHyperlink(escapeUrl);
503
+ }
504
+ }
505
+ }
506
+ return returnValue;
507
+ };
508
+ var CRLF_OR_LF = /\r?\n/;
509
+ function wrapAnsi(string, columns, options) {
510
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join(`
511
+ `);
512
+ }
513
+
514
+ // ../../node_modules/.bun/@clack+core@1.4.2/node_modules/@clack/core/dist/index.mjs
515
+ var import_sisteransi = __toESM(require_src(), 1);
516
+ import { ReadStream } from "tty";
517
+ function findCursor(s, o, l2) {
518
+ if (!l2.some((r) => !r.disabled))
519
+ return s;
520
+ const t = s + o, n = Math.max(l2.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
521
+ return l2[e].disabled ? findCursor(e, o < 0 ? -1 : 1, l2) : e;
522
+ }
523
+ function findTextCursor(s, o, l2, i) {
524
+ const t = i.split(`
525
+ `);
526
+ let n = 0, e = s;
527
+ for (const r of t) {
528
+ if (e <= r.length)
529
+ break;
530
+ e -= r.length + 1, n++;
531
+ }
532
+ for (n = Math.max(0, Math.min(t.length - 1, n + l2)), e = Math.min(e, t[n].length) + o;e < 0 && n > 0; )
533
+ n--, e += t[n].length + 1;
534
+ for (;e > t[n].length && n < t.length - 1; )
535
+ e -= t[n].length + 1, n++;
536
+ e = Math.max(0, Math.min(t[n].length, e));
537
+ let h = 0;
538
+ for (let r = 0;r < n; r++)
539
+ h += t[r].length + 1;
540
+ return h + e;
541
+ }
542
+ var a$2 = ["up", "down", "left", "right", "space", "enter", "cancel"];
543
+ var t = [
544
+ "January",
545
+ "February",
546
+ "March",
547
+ "April",
548
+ "May",
549
+ "June",
550
+ "July",
551
+ "August",
552
+ "September",
553
+ "October",
554
+ "November",
555
+ "December"
556
+ ];
557
+ var settings = {
558
+ actions: new Set(a$2),
559
+ aliases: /* @__PURE__ */ new Map([
560
+ ["k", "up"],
561
+ ["j", "down"],
562
+ ["h", "left"],
563
+ ["l", "right"],
564
+ ["\x03", "cancel"],
565
+ ["escape", "cancel"]
566
+ ]),
567
+ messages: {
568
+ cancel: "Canceled",
569
+ error: "Something went wrong"
570
+ },
571
+ withGuide: true,
572
+ date: {
573
+ monthNames: [...t],
574
+ messages: {
575
+ required: "Please enter a valid date",
576
+ invalidMonth: "There are only 12 months in a year",
577
+ invalidDay: (n, e) => `There are only ${n} days in ${e}`,
578
+ afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
579
+ beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
580
+ }
581
+ }
582
+ };
583
+ function isActionKey(n, e) {
584
+ if (typeof n == "string")
585
+ return settings.aliases.get(n) === e;
586
+ for (const s of n)
587
+ if (s !== undefined && isActionKey(s, e))
588
+ return true;
589
+ return false;
590
+ }
591
+ function diffLines(i, s) {
592
+ if (i === s)
593
+ return;
594
+ const e = i.split(`
595
+ `), t2 = s.split(`
596
+ `), r = Math.max(e.length, t2.length), f = [];
597
+ for (let n = 0;n < r; n++)
598
+ e[n] !== t2[n] && f.push(n);
599
+ return {
600
+ lines: f,
601
+ numLinesBefore: e.length,
602
+ numLinesAfter: t2.length,
603
+ numLines: r
604
+ };
605
+ }
606
+ var R = globalThis.process.platform.startsWith("win");
607
+ var CANCEL_SYMBOL = Symbol("clack:cancel");
608
+ function isCancel(e) {
609
+ return e === CANCEL_SYMBOL;
610
+ }
611
+ function setRawMode(e, r) {
612
+ const o = e;
613
+ o.isTTY && o.setRawMode(r);
614
+ }
615
+ function block({
616
+ input: e = stdin,
617
+ output: r = stdout,
618
+ overwrite: o = true,
619
+ hideCursor: t2 = true
620
+ } = {}) {
621
+ const s = l.createInterface({
622
+ input: e,
623
+ output: r,
624
+ prompt: "",
625
+ tabSize: 1
626
+ });
627
+ l.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
628
+ const n = (f, { name: a, sequence: p }) => {
629
+ const c = String(f);
630
+ if (isActionKey([c, a, p], "cancel")) {
631
+ t2 && r.write(import_sisteransi.cursor.show), process.exit(0);
632
+ return;
633
+ }
634
+ if (!o)
635
+ return;
636
+ const i = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
637
+ l.moveCursor(r, i, m, () => {
638
+ l.clearLine(r, 1, () => {
639
+ e.once("keypress", n);
640
+ });
641
+ });
642
+ };
643
+ return t2 && r.write(import_sisteransi.cursor.hide), e.once("keypress", n), () => {
644
+ 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();
645
+ };
646
+ }
647
+ var getColumns = (e) => ("columns" in e) && typeof e.columns == "number" ? e.columns : 80;
648
+ var getRows = (e) => ("rows" in e) && typeof e.rows == "number" ? e.rows : 20;
649
+ function wrapTextWithPrefix(e, r, o, t2 = o, s = o, n) {
650
+ const f = getColumns(e ?? stdout);
651
+ return wrapAnsi(r, f - o.length, {
652
+ hard: true,
653
+ trim: false
654
+ }).split(`
655
+ `).map((c, i, m) => {
656
+ const d = n ? n(c, i) : c;
657
+ return i === 0 ? `${t2}${d}` : i === m.length - 1 ? `${s}${d}` : `${o}${d}`;
658
+ }).join(`
659
+ `);
660
+ }
661
+ function runValidation(e, n) {
662
+ if ("~standard" in e) {
663
+ const a = e["~standard"].validate(n);
664
+ if (a instanceof Promise)
665
+ throw new TypeError("Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic.");
666
+ return a.issues?.at(0)?.message;
667
+ }
668
+ return e(n);
669
+ }
670
+
671
+ class V {
672
+ input;
673
+ output;
674
+ _abortSignal;
675
+ rl;
676
+ opts;
677
+ _render;
678
+ _track = false;
679
+ _prevFrame = "";
680
+ _subscribers = /* @__PURE__ */ new Map;
681
+ _cursor = 0;
682
+ state = "initial";
683
+ error = "";
684
+ value;
685
+ userInput = "";
686
+ constructor(t2, e = true) {
687
+ const { input: i = stdin, output: n = stdout, render: s, signal: r, ...o } = t2;
688
+ 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;
689
+ }
690
+ unsubscribe() {
691
+ this._subscribers.clear();
692
+ }
693
+ setSubscriber(t2, e) {
694
+ const i = this._subscribers.get(t2) ?? [];
695
+ i.push(e), this._subscribers.set(t2, i);
696
+ }
697
+ on(t2, e) {
698
+ this.setSubscriber(t2, { cb: e });
699
+ }
700
+ once(t2, e) {
701
+ this.setSubscriber(t2, { cb: e, once: true });
702
+ }
703
+ emit(t2, ...e) {
704
+ const i = this._subscribers.get(t2) ?? [], n = [];
705
+ for (const s of i)
706
+ s.cb(...e), s.once && n.push(() => i.splice(i.indexOf(s), 1));
707
+ for (const s of n)
708
+ s();
709
+ }
710
+ prompt() {
711
+ return new Promise((t2) => {
712
+ if (this._abortSignal) {
713
+ if (this._abortSignal.aborted)
714
+ return this.state = "cancel", this.close(), t2(CANCEL_SYMBOL);
715
+ this._abortSignal.addEventListener("abort", () => {
716
+ this.state = "cancel", this.close();
717
+ }, { once: true });
718
+ }
719
+ this.rl = l__default.createInterface({
720
+ input: this.input,
721
+ tabSize: 2,
722
+ prompt: "",
723
+ escapeCodeTimeout: 50,
724
+ terminal: true
725
+ }), 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", () => {
726
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(this.value);
727
+ }), this.once("cancel", () => {
728
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t2(CANCEL_SYMBOL);
729
+ });
730
+ });
731
+ }
732
+ _isActionKey(t2, e) {
733
+ return t2 === "\t";
734
+ }
735
+ _shouldSubmit(t2, e) {
736
+ return true;
737
+ }
738
+ _setValue(t2) {
739
+ this.value = t2, this.emit("value", this.value);
740
+ }
741
+ _setUserInput(t2, e) {
742
+ this.userInput = t2 ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
743
+ }
744
+ _clearUserInput() {
745
+ this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
746
+ }
747
+ onKeypress(t2, e) {
748
+ 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)) {
749
+ if (this.opts.validate) {
750
+ const i = runValidation(this.opts.validate, this.value);
751
+ i && (this.error = i instanceof Error ? i.message : i, this.state = "error", this.rl?.write(this.userInput));
752
+ }
753
+ this.state !== "error" && (this.state = "submit");
754
+ }
755
+ 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();
756
+ }
757
+ close() {
758
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
759
+ `), setRawMode(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
760
+ }
761
+ restoreCursor() {
762
+ const t2 = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
763
+ `).length - 1;
764
+ this.output.write(import_sisteransi.cursor.move(-999, t2 * -1));
765
+ }
766
+ render() {
767
+ const t2 = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
768
+ hard: true,
769
+ trim: false
770
+ });
771
+ if (t2 !== this._prevFrame) {
772
+ if (this.state === "initial")
773
+ this.output.write(import_sisteransi.cursor.hide);
774
+ else {
775
+ const e = diffLines(this._prevFrame, t2), i = getRows(this.output);
776
+ if (this.restoreCursor(), e) {
777
+ const n = Math.max(0, e.numLinesAfter - i), s = Math.max(0, e.numLinesBefore - i);
778
+ let r = e.lines.find((o) => o >= n);
779
+ if (r === undefined) {
780
+ this._prevFrame = t2;
781
+ return;
782
+ }
783
+ if (e.lines.length === 1) {
784
+ this.output.write(import_sisteransi.cursor.move(0, r - s)), this.output.write(import_sisteransi.erase.lines(1));
785
+ const o = t2.split(`
786
+ `);
787
+ this.output.write(o[r]), this._prevFrame = t2, this.output.write(import_sisteransi.cursor.move(0, o.length - r - 1));
788
+ return;
789
+ } else if (e.lines.length > 1) {
790
+ if (n < s)
791
+ r = n;
792
+ else {
793
+ const h = r - s;
794
+ h > 0 && this.output.write(import_sisteransi.cursor.move(0, h));
795
+ }
796
+ this.output.write(import_sisteransi.erase.down());
797
+ const f = t2.split(`
798
+ `).slice(r);
799
+ this.output.write(f.join(`
800
+ `)), this._prevFrame = t2;
801
+ return;
802
+ }
803
+ }
804
+ this.output.write(import_sisteransi.erase.down());
805
+ }
806
+ this.output.write(t2), this.state === "initial" && (this.state = "active"), this._prevFrame = t2;
807
+ }
808
+ }
809
+ }
810
+ function p$1(l2, e) {
811
+ if (l2 === undefined || e.length === 0)
812
+ return 0;
813
+ const i = e.findIndex((s) => s.value === l2);
814
+ return i !== -1 ? i : 0;
815
+ }
816
+ function g(l2, e) {
817
+ return (e.label ?? String(e.value)).toLowerCase().includes(l2.toLowerCase());
818
+ }
819
+ function m(l2, e) {
820
+ if (e)
821
+ return l2 ? e : e[0];
822
+ }
823
+ var T$1 = class T extends V {
824
+ filteredOptions;
825
+ multiple;
826
+ isNavigating = false;
827
+ selectedValues = [];
828
+ focusedValue;
829
+ #e = 0;
830
+ #s = "";
831
+ #t;
832
+ #i;
833
+ #n;
834
+ get cursor() {
835
+ return this.#e;
836
+ }
837
+ get userInputWithCursor() {
838
+ if (!this.userInput)
839
+ return styleText(["inverse", "hidden"], "_");
840
+ if (this._cursor >= this.userInput.length)
841
+ return `${this.userInput}\u2588`;
842
+ const e = this.userInput.slice(0, this._cursor), [t2, ...i] = this.userInput.slice(this._cursor);
843
+ return `${e}${styleText("inverse", t2)}${i.join("")}`;
844
+ }
845
+ get options() {
846
+ return typeof this.#i == "function" ? this.#i() : this.#i;
847
+ }
848
+ constructor(e) {
849
+ super(e), this.#i = e.options, this.#n = e.placeholder;
850
+ const t2 = this.options;
851
+ this.filteredOptions = [...t2], this.multiple = e.multiple === true, this.#t = typeof e.options == "function" ? e.filter : e.filter ?? g;
852
+ let i;
853
+ 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)
854
+ for (const s of i) {
855
+ const n = t2.findIndex((o) => o.value === s);
856
+ n !== -1 && (this.toggleSelected(s), this.#e = n);
857
+ }
858
+ this.focusedValue = this.options[this.#e]?.value, this.on("key", (s, n) => this.#l(s, n)), this.on("userInput", (s) => this.#u(s));
859
+ }
860
+ _isActionKey(e, t2) {
861
+ return e === "\t" || this.multiple && this.isNavigating && t2.name === "space" && e !== undefined && e !== "";
862
+ }
863
+ #l(e, t2) {
864
+ 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));
865
+ if (t2.name === "tab" && o && f) {
866
+ this.userInput === "\t" && this._clearUserInput(), this._setUserInput(u, true), this.isNavigating = false;
867
+ return;
868
+ }
869
+ 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);
870
+ }
871
+ deselectAll() {
872
+ this.selectedValues = [];
873
+ }
874
+ toggleSelected(e) {
875
+ 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]);
876
+ }
877
+ #u(e) {
878
+ if (e !== this.#s) {
879
+ this.#s = e;
880
+ const t2 = this.options;
881
+ e && this.#t ? this.filteredOptions = t2.filter((n) => this.#t?.(e, n)) : this.filteredOptions = [...t2];
882
+ const i = p$1(this.focusedValue, this.filteredOptions);
883
+ this.#e = findCursor(i, 0, this.filteredOptions);
884
+ const s = this.filteredOptions[this.#e];
885
+ s && !s.disabled ? this.focusedValue = s.value : this.focusedValue = undefined, this.multiple || (this.focusedValue !== undefined ? this.toggleSelected(this.focusedValue) : this.deselectAll());
886
+ }
887
+ }
888
+ };
889
+ var _ = {
890
+ Y: { type: "year", len: 4 },
891
+ M: { type: "month", len: 2 },
892
+ D: { type: "day", len: 2 }
893
+ };
894
+ function M(r) {
895
+ return [...r].map((t2) => _[t2]);
896
+ }
897
+ function P(r) {
898
+ const i = new Intl.DateTimeFormat(r, {
899
+ year: "numeric",
900
+ month: "2-digit",
901
+ day: "2-digit"
902
+ }).formatToParts(new Date(2000, 0, 15)), s = [];
903
+ let n = "/";
904
+ for (const e of i)
905
+ 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 });
906
+ return { segments: s, separator: n };
907
+ }
908
+ function p(r) {
909
+ return Number.parseInt((r || "0").replace(/_/g, "0"), 10) || 0;
910
+ }
911
+ function f(r) {
912
+ return {
913
+ year: p(r.year),
914
+ month: p(r.month),
915
+ day: p(r.day)
916
+ };
917
+ }
918
+ function c(r, t2) {
919
+ return new Date(r || 2001, t2 || 1, 0).getDate();
920
+ }
921
+ function b(r) {
922
+ const { year: t2, month: i, day: s } = f(r);
923
+ if (!t2 || t2 < 0 || t2 > 9999 || !i || i < 1 || i > 12 || !s || s < 1)
924
+ return;
925
+ const n = new Date(Date.UTC(t2, i - 1, s));
926
+ if (!(n.getUTCFullYear() !== t2 || n.getUTCMonth() !== i - 1 || n.getUTCDate() !== s))
927
+ return { year: t2, month: i, day: s };
928
+ }
929
+ function C(r) {
930
+ const t2 = b(r);
931
+ return t2 ? new Date(Date.UTC(t2.year, t2.month - 1, t2.day)) : undefined;
932
+ }
933
+ function T2(r, t2, i, s) {
934
+ const n = i ? {
935
+ year: i.getUTCFullYear(),
936
+ month: i.getUTCMonth() + 1,
937
+ day: i.getUTCDate()
938
+ } : null, e = s ? {
939
+ year: s.getUTCFullYear(),
940
+ month: s.getUTCMonth() + 1,
941
+ day: s.getUTCDate()
942
+ } : null;
943
+ return r === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r === "month" ? {
944
+ min: n && t2.year === n.year ? n.month : 1,
945
+ max: e && t2.year === e.year ? e.month : 12
946
+ } : {
947
+ min: n && t2.year === n.year && t2.month === n.month ? n.day : 1,
948
+ max: e && t2.year === e.year && t2.month === e.month ? e.day : c(t2.year, t2.month)
949
+ };
950
+ }
951
+
952
+ class U extends V {
953
+ #i;
954
+ #o;
955
+ #t;
956
+ #h;
957
+ #u;
958
+ #e = { segmentIndex: 0, positionInSegment: 0 };
959
+ #n = true;
960
+ #s = null;
961
+ inlineError = "";
962
+ get segmentCursor() {
963
+ return { ...this.#e };
964
+ }
965
+ get segmentValues() {
966
+ return { ...this.#t };
967
+ }
968
+ get segments() {
969
+ return this.#i;
970
+ }
971
+ get separator() {
972
+ return this.#o;
973
+ }
974
+ get formattedValue() {
975
+ return this.#l(this.#t);
976
+ }
977
+ #l(t2) {
978
+ return this.#i.map((i) => t2[i.type]).join(this.#o);
979
+ }
980
+ #r() {
981
+ this._setUserInput(this.#l(this.#t)), this._setValue(C(this.#t) ?? undefined);
982
+ }
983
+ constructor(t2) {
984
+ 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 ? {
985
+ year: String(e.getUTCFullYear()).padStart(4, "0"),
986
+ month: String(e.getUTCMonth() + 1).padStart(2, "0"),
987
+ day: String(e.getUTCDate()).padStart(2, "0")
988
+ } : { year: "____", month: "__", day: "__" }, o = n.map((a) => m2[a.type]).join(s);
989
+ 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));
990
+ }
991
+ #a() {
992
+ const t2 = Math.max(0, Math.min(this.#e.segmentIndex, this.#i.length - 1)), i = this.#i[t2];
993
+ if (i)
994
+ return this.#e.positionInSegment = Math.max(0, Math.min(this.#e.positionInSegment, i.len - 1)), { segment: i, index: t2 };
995
+ }
996
+ #m(t2) {
997
+ this.inlineError = "", this.#s = null;
998
+ const i = this.#a();
999
+ i && (this.#e.segmentIndex = Math.max(0, Math.min(this.#i.length - 1, i.index + t2)), this.#e.positionInSegment = 0, this.#n = true);
1000
+ }
1001
+ #d(t2) {
1002
+ const i = this.#a();
1003
+ if (!i)
1004
+ return;
1005
+ 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);
1006
+ let a;
1007
+ e ? a = t2 === 1 ? o.min : o.max : a = Math.max(Math.min(o.max, m2 + t2), o.min), this.#t = {
1008
+ ...this.#t,
1009
+ [s.type]: a.toString().padStart(s.len, "0")
1010
+ }, this.#n = true, this.#s = null, this.#r();
1011
+ }
1012
+ #f(t2) {
1013
+ if (t2)
1014
+ switch (t2) {
1015
+ case "right":
1016
+ return this.#m(1);
1017
+ case "left":
1018
+ return this.#m(-1);
1019
+ case "up":
1020
+ return this.#d(1);
1021
+ case "down":
1022
+ return this.#d(-1);
1023
+ }
1024
+ }
1025
+ #y(t2, i) {
1026
+ if (i?.name === "backspace" || i?.sequence === "\x7F" || i?.sequence === "\b" || t2 === "\x7F" || t2 === "\b") {
1027
+ this.inlineError = "";
1028
+ const n = this.#a();
1029
+ if (!n)
1030
+ return;
1031
+ if (!this.#t[n.segment.type].replace(/_/g, "")) {
1032
+ this.#m(-1);
1033
+ return;
1034
+ }
1035
+ this.#t[n.segment.type] = "_".repeat(n.segment.len), this.#n = true, this.#e.positionInSegment = 0, this.#r();
1036
+ return;
1037
+ }
1038
+ if (i?.name === "tab") {
1039
+ this.inlineError = "";
1040
+ const n = this.#a();
1041
+ if (!n)
1042
+ return;
1043
+ const e = i.shift ? -1 : 1, m2 = n.index + e;
1044
+ m2 >= 0 && m2 < this.#i.length && (this.#e.segmentIndex = m2, this.#e.positionInSegment = 0, this.#n = true);
1045
+ return;
1046
+ }
1047
+ if (t2 && /^[0-9]$/.test(t2)) {
1048
+ const n = this.#a();
1049
+ if (!n)
1050
+ return;
1051
+ const { segment: e } = n, m2 = !this.#t[e.type].replace(/_/g, "");
1052
+ if (this.#n && this.#s !== null && !m2) {
1053
+ const h = this.#s + t2, d = { ...this.#t, [e.type]: h }, g2 = this.#g(d, e);
1054
+ if (g2) {
1055
+ this.inlineError = g2, this.#s = null, this.#n = false;
1056
+ return;
1057
+ }
1058
+ 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);
1059
+ return;
1060
+ }
1061
+ this.#n && !m2 && (this.#t[e.type] = "_".repeat(e.len), this.#e.positionInSegment = 0), this.#n = false, this.#s = null;
1062
+ const o = this.#t[e.type], a = o.indexOf("_"), u = a >= 0 ? a : Math.min(this.#e.positionInSegment, e.len - 1);
1063
+ if (u < 0 || u >= e.len)
1064
+ return;
1065
+ let l2 = o.slice(0, u) + t2 + o.slice(u + 1), D = false;
1066
+ if (u === 0 && o === "__" && (e.type === "month" || e.type === "day")) {
1067
+ const h = Number.parseInt(t2, 10);
1068
+ l2 = `0${t2}`, D = h <= (e.type === "month" ? 1 : 2);
1069
+ }
1070
+ if (e.type === "year" && (l2 = (o.replace(/_/g, "") + t2).padStart(e.len, "_")), !l2.includes("_")) {
1071
+ const h = { ...this.#t, [e.type]: l2 }, d = this.#g(h, e);
1072
+ if (d) {
1073
+ this.inlineError = d;
1074
+ return;
1075
+ }
1076
+ }
1077
+ this.inlineError = "", this.#t[e.type] = l2;
1078
+ const y = l2.includes("_") ? undefined : b(this.#t);
1079
+ if (y) {
1080
+ const { year: h, month: d } = y, g2 = c(h, d);
1081
+ this.#t = {
1082
+ year: String(Math.max(0, Math.min(9999, h))).padStart(4, "0"),
1083
+ month: String(Math.max(1, Math.min(12, d))).padStart(2, "0"),
1084
+ day: String(Math.max(1, Math.min(g2, y.day))).padStart(2, "0")
1085
+ };
1086
+ }
1087
+ this.#r();
1088
+ const S = l2.indexOf("_");
1089
+ 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);
1090
+ }
1091
+ }
1092
+ #g(t2, i) {
1093
+ const { month: s, day: n } = f(t2);
1094
+ if (i.type === "month" && (s < 0 || s > 12))
1095
+ return settings.date.messages.invalidMonth;
1096
+ if (i.type === "day" && (n < 0 || n > 31))
1097
+ return settings.date.messages.invalidDay(31, "any month");
1098
+ }
1099
+ #p(t2) {
1100
+ const { year: i, month: s, day: n } = f(this.#t);
1101
+ if (i && s && n) {
1102
+ const e = c(i, s);
1103
+ this.#t = {
1104
+ ...this.#t,
1105
+ day: String(Math.min(n, e)).padStart(2, "0")
1106
+ };
1107
+ }
1108
+ this.value = C(this.#t) ?? t2.defaultValue ?? undefined;
1109
+ }
1110
+ }
1111
+ var u$1 = class u extends V {
1112
+ options;
1113
+ cursor = 0;
1114
+ #t;
1115
+ getGroupItems(t2) {
1116
+ return this.options.filter((r) => r.group === t2);
1117
+ }
1118
+ isGroupSelected(t2) {
1119
+ const r = this.getGroupItems(t2), e = this.value;
1120
+ return e === undefined ? false : r.every((s) => e.includes(s.value));
1121
+ }
1122
+ toggleValue() {
1123
+ const t2 = this.options[this.cursor];
1124
+ if (this.value === undefined && (this.value = []), t2.group === true) {
1125
+ const r = t2.value, e = this.getGroupItems(r);
1126
+ 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));
1127
+ } else {
1128
+ const r = this.value.includes(t2.value);
1129
+ this.value = r ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
1130
+ }
1131
+ }
1132
+ constructor(t2) {
1133
+ super(t2, false);
1134
+ const { options: r } = t2;
1135
+ this.#t = t2.selectableGroups !== false, this.options = Object.entries(r).flatMap(([e, s]) => [
1136
+ { value: e, group: true, label: e },
1137
+ ...s.map((i) => ({ ...i, group: e }))
1138
+ ]), this.value = [...t2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: e }) => e === t2.cursorAt), this.#t ? 0 : 1), this.on("cursor", (e) => {
1139
+ switch (e) {
1140
+ case "left":
1141
+ case "up": {
1142
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
1143
+ const s = this.options[this.cursor]?.group === true;
1144
+ !this.#t && s && (this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1);
1145
+ break;
1146
+ }
1147
+ case "down":
1148
+ case "right": {
1149
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
1150
+ const s = this.options[this.cursor]?.group === true;
1151
+ !this.#t && s && (this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1);
1152
+ break;
1153
+ }
1154
+ case "space":
1155
+ this.toggleValue();
1156
+ break;
1157
+ }
1158
+ });
1159
+ }
1160
+ };
1161
+ var o$1 = /* @__PURE__ */ new Set(["up", "down", "left", "right"]);
1162
+
1163
+ class h extends V {
1164
+ #t = false;
1165
+ #s;
1166
+ focused = "editor";
1167
+ get userInputWithCursor() {
1168
+ if (this.state === "submit")
1169
+ return this.userInput;
1170
+ const t2 = this.userInput;
1171
+ if (this.cursor >= t2.length)
1172
+ return `${t2}\u2588`;
1173
+ const s = t2.slice(0, this.cursor), r = t2[this.cursor], i = t2.slice(this.cursor + 1);
1174
+ return r === `
1175
+ ` ? `${s}\u2588
1176
+ ${i}` : `${s}${styleText("inverse", r)}${i}`;
1177
+ }
1178
+ get cursor() {
1179
+ return this._cursor;
1180
+ }
1181
+ #r(t2) {
1182
+ if (this.userInput.length === 0) {
1183
+ this._setUserInput(t2);
1184
+ return;
1185
+ }
1186
+ this._setUserInput(this.userInput.slice(0, this.cursor) + t2 + this.userInput.slice(this.cursor));
1187
+ }
1188
+ #i(t2) {
1189
+ const s = this.value ?? "";
1190
+ switch (t2) {
1191
+ case "up":
1192
+ this._cursor = findTextCursor(this._cursor, 0, -1, s);
1193
+ return;
1194
+ case "down":
1195
+ this._cursor = findTextCursor(this._cursor, 0, 1, s);
1196
+ return;
1197
+ case "left":
1198
+ this._cursor = findTextCursor(this._cursor, -1, 0, s);
1199
+ return;
1200
+ case "right":
1201
+ this._cursor = findTextCursor(this._cursor, 1, 0, s);
1202
+ return;
1203
+ }
1204
+ }
1205
+ _shouldSubmit(t2, s) {
1206
+ if (this.#s)
1207
+ return this.focused === "submit" ? true : (this.#r(`
1208
+ `), this._cursor++, false);
1209
+ const r = this.#t;
1210
+ return this.#t = true, r && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
1211
+ ` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
1212
+ `), this._cursor++, false);
1213
+ }
1214
+ constructor(t2) {
1215
+ const s = t2.initialUserInput ?? t2.initialValue;
1216
+ super({
1217
+ ...t2,
1218
+ initialUserInput: s
1219
+ }, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r, i) => {
1220
+ if (i?.name && o$1.has(i.name)) {
1221
+ this.#t = false, this.#i(i.name);
1222
+ return;
1223
+ }
1224
+ if (r === "\t" && this.#s) {
1225
+ this.focused = this.focused === "editor" ? "submit" : "editor";
1226
+ return;
1227
+ }
1228
+ if (i?.name !== "return") {
1229
+ if (this.#t = false, i?.name === "backspace" && this.cursor > 0) {
1230
+ this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--;
1231
+ return;
1232
+ }
1233
+ if (i?.name === "delete" && this.cursor < this.userInput.length) {
1234
+ this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
1235
+ return;
1236
+ }
1237
+ r && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r ?? ""), this._cursor++);
1238
+ }
1239
+ }), this.on("userInput", (r) => {
1240
+ this._setValue(r);
1241
+ }), this.on("finalize", () => {
1242
+ this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
1243
+ });
1244
+ }
1245
+ }
1246
+ class a extends V {
1247
+ options;
1248
+ cursor = 0;
1249
+ get _selectedValue() {
1250
+ return this.options[this.cursor];
1251
+ }
1252
+ changeValue() {
1253
+ this.value = this._selectedValue.value;
1254
+ }
1255
+ constructor(t2) {
1256
+ super(t2, false), this.options = t2.options;
1257
+ const i = this.options.findIndex(({ value: s }) => s === t2.initialValue), e = i === -1 ? 0 : i;
1258
+ this.cursor = this.options[e].disabled ? findCursor(e, 1, this.options) : e, this.changeValue(), this.on("cursor", (s) => {
1259
+ switch (s) {
1260
+ case "left":
1261
+ case "up":
1262
+ this.cursor = findCursor(this.cursor, -1, this.options);
1263
+ break;
1264
+ case "down":
1265
+ case "right":
1266
+ this.cursor = findCursor(this.cursor, 1, this.options);
1267
+ break;
1268
+ }
1269
+ this.changeValue();
1270
+ });
1271
+ }
1272
+ }
1273
+ class n extends V {
1274
+ get userInputWithCursor() {
1275
+ if (this.state === "submit")
1276
+ return this.userInput;
1277
+ const t2 = this.userInput;
1278
+ if (this.cursor >= t2.length)
1279
+ return `${this.userInput}\u2588`;
1280
+ const e = t2.slice(0, this.cursor), [s, ...r] = t2.slice(this.cursor);
1281
+ return `${e}${styleText("inverse", s)}${r.join("")}`;
1282
+ }
1283
+ get cursor() {
1284
+ return this._cursor;
1285
+ }
1286
+ constructor(t2) {
1287
+ super({
1288
+ ...t2,
1289
+ initialUserInput: t2.initialUserInput ?? t2.initialValue
1290
+ }), this.on("userInput", (e) => {
1291
+ this._setValue(e);
1292
+ }), this.on("finalize", () => {
1293
+ this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
1294
+ });
1295
+ }
1296
+ }
1297
+
1298
+ // ../../node_modules/.bun/@clack+prompts@1.6.0/node_modules/@clack/prompts/dist/index.mjs
1299
+ import { styleText as styleText2, stripVTControlCharacters } from "util";
1300
+ import process$1 from "process";
1301
+ var import_sisteransi2 = __toESM(require_src(), 1);
1302
+ function isUnicodeSupported() {
1303
+ if (process$1.platform !== "win32") {
1304
+ return process$1.env.TERM !== "linux";
1305
+ }
1306
+ 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";
1307
+ }
1308
+ var unicode = isUnicodeSupported();
1309
+ var isCI = () => process.env.CI === "true";
1310
+ var unicodeOr = (o2, e) => unicode ? o2 : e;
1311
+ var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
1312
+ var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
1313
+ var S_STEP_ERROR = unicodeOr("\u25B2", "x");
1314
+ var S_STEP_SUBMIT = unicodeOr("\u25C7", "o");
1315
+ var S_BAR_START = unicodeOr("\u250C", "T");
1316
+ var S_BAR = unicodeOr("\u2502", "|");
1317
+ var S_BAR_END = unicodeOr("\u2514", "\u2014");
1318
+ var S_BAR_START_RIGHT = unicodeOr("\u2510", "T");
1319
+ var S_BAR_END_RIGHT = unicodeOr("\u2518", "\u2014");
1320
+ var S_RADIO_ACTIVE = unicodeOr("\u25CF", ">");
1321
+ var S_RADIO_INACTIVE = unicodeOr("\u25CB", " ");
1322
+ var S_CHECKBOX_ACTIVE = unicodeOr("\u25FB", "[\u2022]");
1323
+ var S_CHECKBOX_SELECTED = unicodeOr("\u25FC", "[+]");
1324
+ var S_CHECKBOX_INACTIVE = unicodeOr("\u25FB", "[ ]");
1325
+ var S_PASSWORD_MASK = unicodeOr("\u25AA", "\u2022");
1326
+ var S_BAR_H = unicodeOr("\u2500", "-");
1327
+ var S_CORNER_TOP_RIGHT = unicodeOr("\u256E", "+");
1328
+ var S_CONNECT_LEFT = unicodeOr("\u251C", "+");
1329
+ var S_CORNER_BOTTOM_RIGHT = unicodeOr("\u256F", "+");
1330
+ var S_CORNER_BOTTOM_LEFT = unicodeOr("\u2570", "+");
1331
+ var S_CORNER_TOP_LEFT = unicodeOr("\u256D", "+");
1332
+ var S_INFO = unicodeOr("\u25CF", "\u2022");
1333
+ var S_SUCCESS = unicodeOr("\u25C6", "*");
1334
+ var S_WARN = unicodeOr("\u25B2", "!");
1335
+ var S_ERROR = unicodeOr("\u25A0", "x");
1336
+ var symbol = (o2) => {
1337
+ switch (o2) {
1338
+ case "initial":
1339
+ case "active":
1340
+ return styleText2("cyan", S_STEP_ACTIVE);
1341
+ case "cancel":
1342
+ return styleText2("red", S_STEP_CANCEL);
1343
+ case "error":
1344
+ return styleText2("yellow", S_STEP_ERROR);
1345
+ case "submit":
1346
+ return styleText2("green", S_STEP_SUBMIT);
1347
+ }
1348
+ };
1349
+ var symbolBar = (o2) => {
1350
+ switch (o2) {
1351
+ case "initial":
1352
+ case "active":
1353
+ return styleText2("cyan", S_BAR);
1354
+ case "cancel":
1355
+ return styleText2("red", S_BAR);
1356
+ case "error":
1357
+ return styleText2("yellow", S_BAR);
1358
+ case "submit":
1359
+ return styleText2("green", S_BAR);
1360
+ }
1361
+ };
1362
+ function formatInstructionFooter(o2, e) {
1363
+ const r2 = [`${e ? `${styleText2("cyan", S_BAR)} ` : ""}${o2.join(" \u2022 ")}`];
1364
+ return e && r2.push(styleText2("cyan", S_BAR_END)), r2;
1365
+ }
1366
+ var E$1 = (l2, o2, g2, c2, h2, O = false) => {
1367
+ let r2 = o2, w = 0;
1368
+ if (O)
1369
+ for (let i = c2 - 1;i >= g2 && (r2 -= l2[i].length, w++, !(r2 <= h2)); i--)
1370
+ ;
1371
+ else
1372
+ for (let i = g2;i < c2 && (r2 -= l2[i].length, w++, !(r2 <= h2)); i++)
1373
+ ;
1374
+ return { lineCount: r2, removals: w };
1375
+ };
1376
+ var limitOptions = ({
1377
+ cursor: l2,
1378
+ options: o2,
1379
+ style: g2,
1380
+ output: c2 = process.stdout,
1381
+ maxItems: h2 = Number.POSITIVE_INFINITY,
1382
+ columnPadding: O = 0,
1383
+ rowPadding: r2 = 4
1384
+ }) => {
1385
+ 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);
1386
+ let p2 = 0;
1387
+ l2 >= m2 - 3 && (p2 = Math.max(Math.min(l2 - m2 + 3, o2.length - m2), 0));
1388
+ let f2 = m2 < o2.length && p2 > 0, u3 = m2 < o2.length && p2 + m2 < o2.length;
1389
+ const W = Math.min(p2 + m2, o2.length), e = [];
1390
+ let d = 0;
1391
+ f2 && d++, u3 && d++;
1392
+ const v = p2 + (f2 ? 1 : 0), P2 = W - (u3 ? 1 : 0);
1393
+ for (let t2 = v;t2 < P2; t2++) {
1394
+ const n2 = wrapAnsi(g2(o2[t2], t2 === l2), i, {
1395
+ hard: true,
1396
+ trim: false
1397
+ }).split(`
1398
+ `);
1399
+ e.push(n2), d += n2.length;
1400
+ }
1401
+ if (d > x) {
1402
+ let t2 = 0, n2 = 0, s = d;
1403
+ const M2 = l2 - v;
1404
+ let a2 = x;
1405
+ const T3 = () => E$1(e, s, 0, M2, a2), L = () => E$1(e, s, M2 + 1, e.length, a2, true);
1406
+ 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));
1407
+ }
1408
+ const b2 = [];
1409
+ f2 && b2.push(C2);
1410
+ for (const t2 of e)
1411
+ for (const n2 of t2)
1412
+ b2.push(n2);
1413
+ return u3 && b2.push(C2), b2;
1414
+ };
1415
+ var MULTISELECT_INSTRUCTIONS = [
1416
+ `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1417
+ `${styleText2("dim", "Space:")} select`,
1418
+ `${styleText2("dim", "Enter:")} confirm`
1419
+ ];
1420
+ var cancel = (o2 = "", t2) => {
1421
+ const i = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
1422
+ i.write(`${e}${styleText2("red", o2)}
1423
+
1424
+ `);
1425
+ };
1426
+ var W = (l2) => styleText2("magenta", l2);
1427
+ var spinner = ({
1428
+ indicator: l2 = "dots",
1429
+ onCancel: h2,
1430
+ output: n2 = process.stdout,
1431
+ cancelMessage: G,
1432
+ errorMessage: O,
1433
+ frames: E = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"],
1434
+ delay: F = unicode ? 80 : 120,
1435
+ signal: m2,
1436
+ ...I
1437
+ } = {}) => {
1438
+ const u3 = isCI();
1439
+ let M2, T3, d = false, S = false, s = "", p2, w = performance.now();
1440
+ const x = getColumns(n2), k = I?.styleFrame ?? W, g2 = (e) => {
1441
+ const r2 = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
1442
+ S = e === 1, d && (a2(r2, e), S && typeof h2 == "function" && h2());
1443
+ }, f2 = () => g2(2), i = () => g2(1), A = () => {
1444
+ 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);
1445
+ }, H = () => {
1446
+ 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);
1447
+ }, y = () => {
1448
+ if (p2 === undefined)
1449
+ return;
1450
+ u3 && n2.write(`
1451
+ `);
1452
+ const r2 = wrapAnsi(p2, x, {
1453
+ hard: true,
1454
+ trim: false
1455
+ }).split(`
1456
+ `);
1457
+ 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());
1458
+ }, C2 = (e) => e.replace(/\.+$/, ""), _2 = (e) => {
1459
+ const r2 = (performance.now() - e) / 1000, t2 = Math.floor(r2 / 60), o2 = Math.floor(r2 % 60);
1460
+ return t2 > 0 ? `[${t2}m ${o2}s]` : `[${o2}s]`;
1461
+ }, N = I.withGuide ?? settings.withGuide, P2 = (e = "") => {
1462
+ d = true, M2 = block({ output: n2 }), s = C2(e), w = performance.now(), N && n2.write(`${styleText2("gray", S_BAR)}
1463
+ `);
1464
+ let r2 = 0, t2 = 0;
1465
+ A(), T3 = setInterval(() => {
1466
+ if (u3 && s === p2)
1467
+ return;
1468
+ y(), p2 = s;
1469
+ const o2 = k(E[r2]);
1470
+ let v;
1471
+ if (u3)
1472
+ v = `${o2} ${s}...`;
1473
+ else if (l2 === "timer")
1474
+ v = `${o2} ${s} ${_2(w)}`;
1475
+ else {
1476
+ const B = ".".repeat(Math.floor(t2)).slice(0, 3);
1477
+ v = `${o2} ${s}${B}`;
1478
+ }
1479
+ const j = wrapAnsi(v, x, {
1480
+ hard: true,
1481
+ trim: false
1482
+ });
1483
+ n2.write(j), r2 = r2 + 1 < E.length ? r2 + 1 : 0, t2 = t2 < 4 ? t2 + 0.125 : 0;
1484
+ }, F);
1485
+ }, a2 = (e = "", r2 = 0, t2 = false) => {
1486
+ if (!d)
1487
+ return;
1488
+ d = false, clearInterval(T3), y();
1489
+ const o2 = r2 === 0 ? styleText2("green", S_STEP_SUBMIT) : r2 === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
1490
+ s = e ?? s, t2 || (l2 === "timer" ? n2.write(`${o2} ${s} ${_2(w)}
1491
+ `) : n2.write(`${o2} ${s}
1492
+ `)), H(), M2();
1493
+ };
1494
+ return {
1495
+ start: P2,
1496
+ stop: (e = "") => a2(e, 0),
1497
+ message: (e = "") => {
1498
+ s = C2(e ?? s);
1499
+ },
1500
+ cancel: (e = "") => a2(e, 1),
1501
+ error: (e = "") => a2(e, 2),
1502
+ clear: () => a2("", 0, true),
1503
+ get isCancelled() {
1504
+ return S;
1505
+ }
1506
+ };
1507
+ };
1508
+ var u3 = {
1509
+ light: unicodeOr("\u2500", "-"),
1510
+ heavy: unicodeOr("\u2501", "="),
1511
+ block: unicodeOr("\u2588", "#")
1512
+ };
1513
+ var SELECT_INSTRUCTIONS = [
1514
+ `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1515
+ `${styleText2("dim", "Enter:")} confirm`
1516
+ ];
1517
+ var c2 = (t2, a2) => t2.includes(`
1518
+ `) ? t2.split(`
1519
+ `).map((i) => a2(i)).join(`
1520
+ `) : a2(t2);
1521
+ var select = (t2) => {
1522
+ const a2 = (i, m2) => {
1523
+ const s = i.label ?? String(i.value);
1524
+ switch (m2) {
1525
+ case "disabled":
1526
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c2(s, (n2) => styleText2("gray", n2))}${i.hint ? ` ${styleText2("dim", `(${i.hint ?? "disabled"})`)}` : ""}`;
1527
+ case "selected":
1528
+ return `${c2(s, (n2) => styleText2("dim", n2))}`;
1529
+ case "active":
1530
+ return `${styleText2("green", S_RADIO_ACTIVE)} ${s}${i.hint ? ` ${styleText2("dim", `(${i.hint})`)}` : ""}`;
1531
+ case "cancelled":
1532
+ return `${c2(s, (n2) => styleText2(["strikethrough", "dim"], n2))}`;
1533
+ default:
1534
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c2(s, (n2) => styleText2("dim", n2))}`;
1535
+ }
1536
+ };
1537
+ return new a({
1538
+ options: t2.options,
1539
+ signal: t2.signal,
1540
+ input: t2.input,
1541
+ output: t2.output,
1542
+ initialValue: t2.initialValue,
1543
+ render() {
1544
+ const i = t2.withGuide ?? settings.withGuide, m2 = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, n2 = wrapTextWithPrefix(t2.output, t2.message, s, m2), u4 = `${i ? `${styleText2("gray", S_BAR)}
1545
+ ` : ""}${n2}
1546
+ `;
1547
+ switch (this.state) {
1548
+ case "submit": {
1549
+ const r2 = i ? `${styleText2("gray", S_BAR)} ` : "", o2 = wrapTextWithPrefix(t2.output, a2(this.options[this.cursor], "selected"), r2);
1550
+ return `${u4}${o2}`;
1551
+ }
1552
+ case "cancel": {
1553
+ const r2 = i ? `${styleText2("gray", S_BAR)} ` : "", o2 = wrapTextWithPrefix(t2.output, a2(this.options[this.cursor], "cancelled"), r2);
1554
+ return `${u4}${o2}${i ? `
1555
+ ${styleText2("gray", S_BAR)}` : ""}`;
1556
+ }
1557
+ default: {
1558
+ const r2 = i ? `${styleText2("cyan", S_BAR)} ` : "", o2 = u4.split(`
1559
+ `).length, $ = formatInstructionFooter(SELECT_INSTRUCTIONS, i), h2 = $.join(`
1560
+ `), b2 = $.length + 1;
1561
+ return `${u4}${r2}${limitOptions({
1562
+ output: t2.output,
1563
+ cursor: this.cursor,
1564
+ options: this.options,
1565
+ maxItems: t2.maxItems,
1566
+ columnPadding: r2.length,
1567
+ rowPadding: o2 + b2,
1568
+ style: (p2, x) => a2(p2, p2.disabled ? "disabled" : x ? "active" : "inactive")
1569
+ }).join(`
1570
+ ${r2}`)}
1571
+ ${h2}
1572
+ `;
1573
+ }
1574
+ }
1575
+ }
1576
+ }).prompt();
1577
+ };
1578
+ var i = `${styleText2("gray", S_BAR)} `;
1579
+ var text = (t2) => new n({
1580
+ validate: t2.validate,
1581
+ placeholder: t2.placeholder,
1582
+ defaultValue: t2.defaultValue,
1583
+ initialValue: t2.initialValue,
1584
+ output: t2.output,
1585
+ signal: t2.signal,
1586
+ input: t2.input,
1587
+ render() {
1588
+ const i2 = t2?.withGuide ?? settings.withGuide, s = `${`${i2 ? `${styleText2("gray", S_BAR)}
1589
+ ` : ""}${symbol(this.state)} `}${t2.message}
1590
+ `, 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 ?? "";
1591
+ switch (this.state) {
1592
+ case "error": {
1593
+ const n2 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r2 = i2 ? `${styleText2("yellow", S_BAR)} ` : "", d = i2 ? styleText2("yellow", S_BAR_END) : "";
1594
+ return `${s.trim()}
1595
+ ${r2}${o2}
1596
+ ${d}${n2}
1597
+ `;
1598
+ }
1599
+ case "submit": {
1600
+ const n2 = a2 ? ` ${styleText2("dim", a2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
1601
+ return `${s}${r2}${n2}`;
1602
+ }
1603
+ case "cancel": {
1604
+ const n2 = a2 ? ` ${styleText2(["strikethrough", "dim"], a2)}` : "", r2 = i2 ? styleText2("gray", S_BAR) : "";
1605
+ return `${s}${r2}${n2}${a2.trim() ? `
1606
+ ${r2}` : ""}`;
1607
+ }
1608
+ default: {
1609
+ const n2 = i2 ? `${styleText2("cyan", S_BAR)} ` : "", r2 = i2 ? styleText2("cyan", S_BAR_END) : "";
1610
+ return `${s}${n2}${o2}
1611
+ ${r2}
1612
+ `;
1613
+ }
1614
+ }
1615
+ }
1616
+ }).prompt();
1617
+
1618
+ // src/index.ts
1619
+ var import_picocolors = __toESM(require_picocolors(), 1);
1620
+
1621
+ // src/ascii.ts
1622
+ var RED = "\x1B[31m";
1623
+ var BOLD = "\x1B[1m";
1624
+ var RESET = "\x1B[0m";
1625
+ var BANNER = [
1626
+ "",
1627
+ `${BOLD}${RED} \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${RESET}`,
1628
+ `${BOLD}${RED} \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u255D \u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D${RESET}`,
1629
+ `${BOLD}${RED} \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${RESET}`,
1630
+ `${BOLD}${RED} \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588 \u2588\u2588\u2551 \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551${RESET}`,
1631
+ `${BOLD}${RED} \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551${RESET}`,
1632
+ `${BOLD}${RED} \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D${RESET}`,
1633
+ "",
1634
+ `${BOLD}${RED} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500Rhein Sullivan\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${RESET}`,
1635
+ `${BOLD}${RED} Rakta.js \u2014 React.js, Bun, TypeScript, Easy Router, and Fullstack Generator${RESET}`,
1636
+ `${BOLD}${RED} Small in size. Fierce in speed. Alive in every route.${RESET}`,
1637
+ `${BOLD}${RED} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500Vyagra Nexus\u2122\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${RESET}`,
1638
+ ""
1639
+ ].join(`
1640
+ `);
1641
+ function printBanner() {
1642
+ console.log(BANNER);
1643
+ }
1644
+
1645
+ // src/fileSystem.ts
1646
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
1647
+ import { dirname, join, resolve } from "path";
1648
+ function ensureDirectory(dirPath) {
1649
+ if (!existsSync(dirPath)) {
1650
+ mkdirSync(dirPath, {
1651
+ recursive: true
1652
+ });
1653
+ }
1654
+ }
1655
+ function writeFile(absolutePath, fileContent) {
1656
+ ensureDirectory(dirname(absolutePath));
1657
+ writeFileSync(absolutePath, fileContent, "utf-8");
1658
+ }
1659
+ function writeProjectFiles(projectRoot, generatedFiles) {
1660
+ for (const projectFile of generatedFiles) {
1661
+ const absolutePath = join(resolve(projectRoot), projectFile.path);
1662
+ writeFile(absolutePath, projectFile.content);
1663
+ }
1664
+ }
1665
+
1666
+ // src/types.ts
1667
+ var CSS_DISPLAY = {
1668
+ tailwind: "Tailwind CSS",
1669
+ bootstrap: "Bootstrap",
1670
+ sass: "SASS",
1671
+ none: "None"
1672
+ };
1673
+ var BACKEND_DISPLAY = {
1674
+ gaman: "Gaman.js",
1675
+ express: "Express.js",
1676
+ nest: "Nest.js",
1677
+ adonis: "Adonis.js"
1678
+ };
1679
+ var DATABASE_DISPLAY = {
1680
+ postgresql: "PostgreSQL",
1681
+ mysql: "MySQL",
1682
+ mongodb: "MongoDB",
1683
+ firebase: "Firebase",
1684
+ sqlite: "SQLite",
1685
+ mariadb: "MariaDB",
1686
+ redis: "Redis",
1687
+ planetscale: "PlanetScale",
1688
+ neon: "Neon",
1689
+ turso: "Turso"
1690
+ };
1691
+ var RENDER_MODE_DISPLAY = {
1692
+ csr: "CSR \u2014 Client-Side Rendering",
1693
+ ssr: "SSR \u2014 Server-Side Rendering",
1694
+ ssg: "SSG \u2014 Static Site Generation",
1695
+ csg: "CSG \u2014 Configurable Static Generation",
1696
+ spa: "SPA \u2014 Single Page Application",
1697
+ hybrid: "Hybrid \u2014 Mixed per-route"
1698
+ };
1699
+ var PROJECT_MODE_DISPLAY = {
1700
+ fullstack: "Fullstack app (frontend + backend + database)",
1701
+ "frontend-only": "Frontend only (no backend, no database)"
1702
+ };
1703
+
1704
+ // src/generator.ts
1705
+ function getRootFiles(projectConfig) {
1706
+ const { projectName, projectMode } = projectConfig;
1707
+ const workspaces = projectMode === "fullstack" ? ["frontend", "backend", "shared"] : [];
1708
+ return [
1709
+ {
1710
+ path: "package.json",
1711
+ content: JSON.stringify({
1712
+ name: projectName,
1713
+ version: "0.1.0",
1714
+ private: true,
1715
+ ...projectMode === "fullstack" ? { workspaces } : {},
1716
+ scripts: projectMode === "fullstack" ? {
1717
+ "dev:frontend": "cd frontend && bun run dev",
1718
+ "dev:backend": "cd backend && bun run dev",
1719
+ "build:frontend": "cd frontend && bun run build",
1720
+ "build:backend": "cd backend && bun run build",
1721
+ build: "bun run build:frontend && bun run build:backend",
1722
+ start: "cd backend && bun run start",
1723
+ typecheck: "cd frontend && bun run typecheck && cd ../backend && bun run typecheck"
1724
+ } : {
1725
+ dev: "rakta dev",
1726
+ build: "rakta build",
1727
+ start: "rakta start",
1728
+ typecheck: "tsc --noEmit"
1729
+ },
1730
+ description: `${projectName} \u2014 built with Rakta.js`
1731
+ }, null, 2)
1732
+ },
1733
+ {
1734
+ path: "tsconfig.base.json",
1735
+ content: JSON.stringify({
1736
+ compilerOptions: {
1737
+ target: "ESNext",
1738
+ module: "ESNext",
1739
+ moduleResolution: "Bundler",
1740
+ jsx: "react-jsx",
1741
+ lib: ["ESNext", "DOM", "DOM.Iterable"],
1742
+ strict: true,
1743
+ noUncheckedIndexedAccess: true,
1744
+ exactOptionalPropertyTypes: true,
1745
+ skipLibCheck: true,
1746
+ esModuleInterop: true,
1747
+ allowSyntheticDefaultImports: true,
1748
+ resolveJsonModule: true,
1749
+ verbatimModuleSyntax: true,
1750
+ isolatedModules: true
1751
+ },
1752
+ exclude: ["node_modules", "dist", "**/dist/**"]
1753
+ }, null, 2)
1754
+ },
1755
+ {
1756
+ path: "bunfig.toml",
1757
+ content: `[install]
1758
+ auto = "fallback"
1759
+ exact = false
1760
+ registry = "https://registry.npmjs.org/"
1761
+
1762
+ [run]
1763
+ bun = true
1764
+ `
1765
+ },
1766
+ {
1767
+ path: ".npmrc",
1768
+ content: `registry=https://registry.npmjs.org/
1769
+ strict-ssl=true
1770
+ fetch-retries=5
1771
+ fetch-retry-mintimeout=20000
1772
+ fetch-retry-maxtimeout=120000
1773
+ `
1774
+ },
1775
+ {
1776
+ path: ".env.example",
1777
+ content: `NODE_ENV=development
1778
+ `
1779
+ },
1780
+ {
1781
+ path: ".gitignore",
1782
+ content: `node_modules/
1783
+ dist/
1784
+ .env
1785
+ .env.*
1786
+ !.env.example
1787
+ .DS_Store
1788
+ *.log
1789
+ .rakta/
1790
+ `
1791
+ },
1792
+ {
1793
+ path: "README.md",
1794
+ content: generateProjectReadme(projectConfig)
1795
+ }
1796
+ ];
1797
+ }
1798
+ function getFrontendOnlyFiles(projectConfig) {
1799
+ const { projectName, cssFramework } = projectConfig;
1800
+ const styleFileName = cssFramework === "sass" ? "globals.scss" : "globals.css";
1801
+ return [
1802
+ {
1803
+ path: "package.json",
1804
+ content: JSON.stringify({
1805
+ name: projectName,
1806
+ version: "0.1.0",
1807
+ private: true,
1808
+ type: "module",
1809
+ scripts: {
1810
+ dev: "rakta dev",
1811
+ build: "rakta build",
1812
+ start: "rakta start",
1813
+ routes: "rakta routes",
1814
+ typecheck: "tsc --noEmit"
1815
+ },
1816
+ dependencies: {
1817
+ rakta: "^0.1.0",
1818
+ react: "^19.2.7",
1819
+ "react-dom": "^19.2.7",
1820
+ ...getCssDependencies(cssFramework)
1821
+ },
1822
+ devDependencies: {
1823
+ "@types/react": "^19.2.17",
1824
+ "@types/react-dom": "^19.2.3",
1825
+ typescript: "^6.0.3",
1826
+ ...getCssDevDependencies(cssFramework)
1827
+ }
1828
+ }, null, 2)
1829
+ },
1830
+ {
1831
+ path: "tsconfig.json",
1832
+ content: JSON.stringify({
1833
+ extends: "./tsconfig.base.json",
1834
+ compilerOptions: {
1835
+ outDir: "./dist",
1836
+ rootDir: "./",
1837
+ types: ["react", "react-dom"]
1838
+ },
1839
+ include: [
1840
+ "rakta-env.d.ts",
1841
+ "app/**/*",
1842
+ "components/**/*",
1843
+ "styles/**/*",
1844
+ "rakta.config.ts"
1845
+ ],
1846
+ exclude: ["node_modules", "dist"]
1847
+ }, null, 2)
1848
+ },
1849
+ {
1850
+ path: "rakta-env.d.ts",
1851
+ content: generateFrontendOnlyRaktaEnv()
1852
+ },
1853
+ {
1854
+ path: "rakta.config.ts",
1855
+ content: `import { defineRaktaConfig } from "rakta";
1856
+
1857
+ export default defineRaktaConfig({
1858
+ appName: "${projectName}",
1859
+ render: {
1860
+ defaultMode: "csr",
1861
+ routes: {},
1862
+ },
1863
+ });
1864
+ `
1865
+ },
1866
+ {
1867
+ path: "app/layout.tsx",
1868
+ content: generateFrontendOnlyLayout()
1869
+ },
1870
+ {
1871
+ path: "app/page.tsx",
1872
+ content: generateFrontendOnlyPage(projectName)
1873
+ },
1874
+ {
1875
+ path: "app/loading.tsx",
1876
+ content: generateFrontendOnlyLoading()
1877
+ },
1878
+ {
1879
+ path: "app/error.tsx",
1880
+ content: generateFrontendOnlyError()
1881
+ },
1882
+ {
1883
+ path: "app/notFound.tsx",
1884
+ content: generateFrontendOnlyNotFound()
1885
+ },
1886
+ {
1887
+ path: "app/components/raktaShrimpMascot.tsx",
1888
+ content: generateShrimpMascotComponent()
1889
+ },
1890
+ {
1891
+ path: "app/components/shrimpRunGame.tsx",
1892
+ content: generateShrimpRunGameComponent()
1893
+ },
1894
+ {
1895
+ path: `styles/${styleFileName}`,
1896
+ content: getFrontendOnlyCssGlobals(cssFramework)
1897
+ },
1898
+ {
1899
+ path: "public/.gitkeep",
1900
+ content: ""
1901
+ }
1902
+ ];
1903
+ }
1904
+ function getFullstackFrontendFiles(projectConfig) {
1905
+ const { projectName, cssFramework } = projectConfig;
1906
+ const styleFileName = cssFramework === "sass" ? "globals.scss" : "globals.css";
1907
+ return [
1908
+ {
1909
+ path: "frontend/package.json",
1910
+ content: JSON.stringify({
1911
+ name: `${projectName}-frontend`,
1912
+ version: "0.1.0",
1913
+ private: true,
1914
+ scripts: {
1915
+ dev: "rakta dev",
1916
+ build: "rakta build",
1917
+ start: "rakta start",
1918
+ routes: "rakta routes",
1919
+ "imports:generate": "rakta imports:generate",
1920
+ "rpc:types": "rakta rpc:types",
1921
+ typecheck: "tsc --noEmit"
1922
+ },
1923
+ dependencies: {
1924
+ rakta: "^0.1.0",
1925
+ react: "^19.2.7",
1926
+ "react-dom": "^19.2.7",
1927
+ ...getCssDependencies(cssFramework)
1928
+ },
1929
+ devDependencies: {
1930
+ "@types/react": "^19.2.17",
1931
+ "@types/react-dom": "^19.2.3",
1932
+ typescript: "^6.0.3",
1933
+ ...getCssDevDependencies(cssFramework)
1934
+ }
1935
+ }, null, 2)
1936
+ },
1937
+ {
1938
+ path: "frontend/tsconfig.json",
1939
+ content: JSON.stringify({
1940
+ extends: "../tsconfig.base.json",
1941
+ compilerOptions: {
1942
+ outDir: "./dist",
1943
+ rootDir: "./"
1944
+ },
1945
+ include: [
1946
+ "app/**/*",
1947
+ "components/**/*",
1948
+ "lib/**/*",
1949
+ "stores/**/*",
1950
+ "schemas/**/*",
1951
+ "rakta.config.ts"
1952
+ ],
1953
+ exclude: ["node_modules", "dist"]
1954
+ }, null, 2)
1955
+ },
1956
+ {
1957
+ path: "frontend/rakta.config.ts",
1958
+ content: `import { defineRaktaConfig } from "rakta";
1959
+
1960
+ export default defineRaktaConfig({
1961
+ appName: "${projectName}",
1962
+ render: {
1963
+ defaultMode: "csr",
1964
+ routes: {
1965
+ "/": "ssg",
1966
+ "/about": "ssg",
1967
+ "/blog": "csg",
1968
+ "/blog/:slug": "csg",
1969
+ "/dashboard": "csr"
1970
+ }
1971
+ }
1972
+ });
1973
+ `
1974
+ },
1975
+ {
1976
+ path: "frontend/app/layout.tsx",
1977
+ content: `import React from "react";
1978
+ import "../styles/${styleFileName}";
1979
+
1980
+ interface RootLayoutProps {
1981
+ readonly children: React.ReactNode;
1982
+ }
1983
+
1984
+ export default function RootLayout({ children }: RootLayoutProps) {
1985
+ return (
1986
+ <html lang="en">
1987
+ <body>{children}</body>
1988
+ </html>
1989
+ );
1990
+ }
1991
+ `
1992
+ },
1993
+ {
1994
+ path: "frontend/app/page.tsx",
1995
+ content: generateFullstackHomePage(projectName)
1996
+ },
1997
+ {
1998
+ path: "frontend/app/about/page.tsx",
1999
+ content: `import React from "react";
2000
+
2001
+ export default function AboutPage() {
2002
+ return (
2003
+ <main className="page-shell">
2004
+ <section className="hero-card">
2005
+ <p className="eyebrow">ABOUT</p>
2006
+ <h1>About ${projectName}</h1>
2007
+ <p>This project is built with Rakta.js, React, Bun, and TypeScript.</p>
2008
+ <a href="/">Back to home</a>
2009
+ </section>
2010
+ </main>
2011
+ );
2012
+ }
2013
+ `
2014
+ },
2015
+ {
2016
+ path: "frontend/app/blog/page.tsx",
2017
+ content: `import React from "react";
2018
+
2019
+ const BLOG_POSTS = [
2020
+ { slug: "getting-started", title: "Getting started with Rakta.js" },
2021
+ { slug: "file-based-routing", title: "File-based routing explained" },
2022
+ { slug: "type-safe-rpc", title: "Type-safe API with CarubanWire" },
2023
+ ];
2024
+
2025
+ export default function BlogPage() {
2026
+ return (
2027
+ <main className="page-shell">
2028
+ <section className="hero-card">
2029
+ <p className="eyebrow">BLOG</p>
2030
+ <h1>Articles</h1>
2031
+ <ul>
2032
+ {BLOG_POSTS.map((post) => (
2033
+ <li key={post.slug}>
2034
+ <a href={\`/blog/\${post.slug}\`}>{post.title}</a>
2035
+ </li>
2036
+ ))}
2037
+ </ul>
2038
+ </section>
2039
+ </main>
2040
+ );
2041
+ }
2042
+ `
2043
+ },
2044
+ {
2045
+ path: "frontend/app/blog/[slug]/page.tsx",
2046
+ content: `import React from "react";
2047
+
2048
+ interface BlogPostPageProps {
2049
+ readonly params: {
2050
+ readonly slug?: string;
2051
+ };
2052
+ }
2053
+
2054
+ export default function BlogPostPage({ params }: BlogPostPageProps) {
2055
+ const postTitle = params.slug?.replaceAll("-", " ") ?? "Article";
2056
+
2057
+ return (
2058
+ <main className="page-shell">
2059
+ <section className="hero-card">
2060
+ <p className="eyebrow">BLOG POST</p>
2061
+ <h1>{postTitle}</h1>
2062
+ <p>Slug: <code>{params.slug}</code></p>
2063
+ <a href="/blog">Back to blog</a>
2064
+ </section>
2065
+ </main>
2066
+ );
2067
+ }
2068
+ `
2069
+ },
2070
+ {
2071
+ path: "frontend/app/loading.tsx",
2072
+ content: `import React from "react";
2073
+
2074
+ export default function Loading() {
2075
+ return (
2076
+ <main className="page-shell">
2077
+ <p>Loading...</p>
2078
+ </main>
2079
+ );
2080
+ }
2081
+ `
2082
+ },
2083
+ {
2084
+ path: "frontend/app/error.tsx",
2085
+ content: `import React from "react";
2086
+
2087
+ interface ErrorPageProps {
2088
+ readonly error: Error;
2089
+ readonly reset: () => void;
2090
+ }
2091
+
2092
+ export default function ErrorPage({ error, reset }: ErrorPageProps) {
2093
+ return (
2094
+ <main className="page-shell">
2095
+ <section className="hero-card">
2096
+ <h1>Something went wrong</h1>
2097
+ <p>{error.message}</p>
2098
+ <button type="button" onClick={reset}>Try again</button>
2099
+ </section>
2100
+ </main>
2101
+ );
2102
+ }
2103
+ `
2104
+ },
2105
+ {
2106
+ path: "frontend/app/not-found.tsx",
2107
+ content: `import React from "react";
2108
+
2109
+ export default function NotFound() {
2110
+ return (
2111
+ <main className="page-shell">
2112
+ <section className="hero-card">
2113
+ <h1>404</h1>
2114
+ <p>The page you are looking for does not exist.</p>
2115
+ <a href="/">Return home</a>
2116
+ </section>
2117
+ </main>
2118
+ );
2119
+ }
2120
+ `
2121
+ },
2122
+ {
2123
+ path: "frontend/app/api/hello/route.ts",
2124
+ content: `export async function GET(request: Request): Promise<Response> {
2125
+ const requestUrl = new URL(request.url);
2126
+
2127
+ return Response.json({
2128
+ message: "Hello from Rakta.js API",
2129
+ pathname: requestUrl.pathname,
2130
+ timestamp: new Date().toISOString(),
2131
+ });
2132
+ }
2133
+
2134
+ export async function POST(request: Request): Promise<Response> {
2135
+ const requestBody = await request.json() as Record<string, unknown>;
2136
+
2137
+ return Response.json({
2138
+ received: requestBody,
2139
+ timestamp: new Date().toISOString(),
2140
+ });
2141
+ }
2142
+ `
2143
+ },
2144
+ {
2145
+ path: "frontend/lib/http.ts",
2146
+ content: `export const API_URL = process.env["API_URL"] ?? "http://localhost:4000";
2147
+
2148
+ export async function apiGet<TData>(path: string): Promise<TData> {
2149
+ const response = await fetch(\`\${API_URL}\${path}\`);
2150
+
2151
+ if (!response.ok) {
2152
+ throw new Error(\`Request failed with status \${response.status}\`);
2153
+ }
2154
+
2155
+ return response.json() as Promise<TData>;
2156
+ }
2157
+ `
2158
+ },
2159
+ {
2160
+ path: "frontend/lib/routes.ts",
2161
+ content: `export const ROUTES = {
2162
+ home: "/",
2163
+ about: "/about",
2164
+ blog: "/blog",
2165
+ blogPost: (slug: string) => \`/blog/\${slug}\`,
2166
+ apiHello: "/api/hello",
2167
+ } as const;
2168
+ `
2169
+ },
2170
+ {
2171
+ path: "frontend/lib/utils.ts",
2172
+ content: `export function cn(...classNames: Array<string | undefined | null | false>): string {
2173
+ return classNames.filter(Boolean).join(" ");
2174
+ }
2175
+
2176
+ export function slugify(text: string): string {
2177
+ return text
2178
+ .toLowerCase()
2179
+ .replace(/[^a-z0-9]+/g, "-")
2180
+ .replace(/(^-|-$)/g, "");
2181
+ }
2182
+ `
2183
+ },
2184
+ {
2185
+ path: "frontend/stores/counter.store.ts",
2186
+ content: `import { createRaktaStore } from "rakta";
2187
+
2188
+ interface CounterState {
2189
+ readonly count: number;
2190
+ readonly increment: () => void;
2191
+ readonly decrement: () => void;
2192
+ }
2193
+
2194
+ export const useCounterStore = createRaktaStore<CounterState>((setState, getState) => ({
2195
+ count: 0,
2196
+ increment: () => setState({ count: getState().count + 1 }),
2197
+ decrement: () => setState({ count: getState().count - 1 }),
2198
+ }));
2199
+ `
2200
+ },
2201
+ {
2202
+ path: "frontend/schemas/user.schema.ts",
2203
+ content: `import { object, string, number } from "rakta";
2204
+
2205
+ export const userSchema = object({
2206
+ name: string().min(1),
2207
+ email: string().min(5),
2208
+ age: number().min(0).max(120),
2209
+ });
2210
+
2211
+ export type UserSchema = typeof userSchema;
2212
+ `
2213
+ },
2214
+ {
2215
+ path: `frontend/styles/${styleFileName}`,
2216
+ content: getCssGlobals(cssFramework)
2217
+ },
2218
+ {
2219
+ path: "frontend/public/.gitkeep",
2220
+ content: ""
2221
+ },
2222
+ {
2223
+ path: "frontend/components/ui/.gitkeep",
2224
+ content: ""
2225
+ },
2226
+ {
2227
+ path: "frontend/components/layout/.gitkeep",
2228
+ content: ""
2229
+ }
2230
+ ];
2231
+ }
2232
+ function getBackendFiles(projectConfig) {
2233
+ return [
2234
+ ...getBackendCommonFiles(projectConfig),
2235
+ ...getBackendFrameworkFiles(projectConfig.backendFramework, projectConfig)
2236
+ ];
2237
+ }
2238
+ function getBackendCommonFiles(projectConfig) {
2239
+ return [
2240
+ {
2241
+ path: "backend/src/env.ts",
2242
+ content: `function optionalEnv(envKey: string, fallbackValue: string): string {
2243
+ return process.env[envKey] ?? fallbackValue;
2244
+ }
2245
+
2246
+ export const env = {
2247
+ port: Number(optionalEnv("PORT", "4000")),
2248
+ nodeEnv: optionalEnv("NODE_ENV", "development"),
2249
+ corsOrigin: optionalEnv("CORS_ORIGIN", "http://localhost:3000"),
2250
+ databaseUrl: optionalEnv("DATABASE_URL", ""),
2251
+ } as const;
2252
+ `
2253
+ },
2254
+ {
2255
+ path: "backend/src/config/app.config.ts",
2256
+ content: `import { env } from "../env";
2257
+
2258
+ export const appConfig = {
2259
+ name: "${projectConfig.projectName} API",
2260
+ version: "0.1.0",
2261
+ port: env.port,
2262
+ nodeEnv: env.nodeEnv,
2263
+ corsOrigin: env.corsOrigin,
2264
+ isDev: env.nodeEnv === "development",
2265
+ } as const;
2266
+ `
2267
+ },
2268
+ {
2269
+ path: "backend/src/config/database.config.ts",
2270
+ content: getDatabaseConfig(projectConfig.database)
2271
+ },
2272
+ {
2273
+ path: "backend/src/database/client.ts",
2274
+ content: getDatabaseClient(projectConfig.database)
2275
+ },
2276
+ {
2277
+ path: "backend/src/controllers/hello.controller.ts",
2278
+ content: `export interface HelloResponse {
2279
+ readonly success: boolean;
2280
+ readonly message: string;
2281
+ readonly framework: string;
2282
+ readonly version: string;
2283
+ readonly timestamp: string;
2284
+ }
2285
+
2286
+ export function helloController(): HelloResponse {
2287
+ return {
2288
+ success: true,
2289
+ message: "Hello from ${projectConfig.projectName} API",
2290
+ framework: "${BACKEND_DISPLAY[projectConfig.backendFramework]}",
2291
+ version: "0.1.0",
2292
+ timestamp: new Date().toISOString(),
2293
+ };
2294
+ }
2295
+ `
2296
+ },
2297
+ {
2298
+ path: "backend/.env.example",
2299
+ content: getDatabaseEnvExample(projectConfig.database)
2300
+ },
2301
+ {
2302
+ path: "backend/tsconfig.json",
2303
+ content: JSON.stringify({
2304
+ extends: "../tsconfig.base.json",
2305
+ compilerOptions: {
2306
+ outDir: "./dist",
2307
+ rootDir: "./src",
2308
+ types: ["node", "bun"]
2309
+ },
2310
+ include: ["src/**/*"],
2311
+ exclude: ["node_modules", "dist"]
2312
+ }, null, 2)
2313
+ },
2314
+ {
2315
+ path: "backend/src/database/schema/.gitkeep",
2316
+ content: ""
2317
+ }
2318
+ ];
2319
+ }
2320
+ function getBackendFrameworkFiles(selectedFramework, projectConfig) {
2321
+ switch (selectedFramework) {
2322
+ case "gaman":
2323
+ return getGamanFiles(projectConfig);
2324
+ case "express":
2325
+ return getExpressFiles(projectConfig);
2326
+ case "nest":
2327
+ return getNestFiles(projectConfig);
2328
+ case "adonis":
2329
+ return getAdonisFiles(projectConfig);
2330
+ default:
2331
+ return getGamanFiles(projectConfig);
2332
+ }
2333
+ }
2334
+ function getGamanFiles(projectConfig) {
2335
+ return [
2336
+ {
2337
+ path: "backend/package.json",
2338
+ content: getBackendPackageJson(projectConfig, {
2339
+ dependencies: { ...getDatabaseDependencies(projectConfig.database) },
2340
+ devDependencies: { "@types/bun": "^1.3.14" }
2341
+ })
2342
+ },
2343
+ {
2344
+ path: "backend/src/app.ts",
2345
+ content: `import { appConfig } from "./config/app.config";
2346
+ import { helloController } from "./controllers/hello.controller";
2347
+
2348
+ const corsHeaders = {
2349
+ "Access-Control-Allow-Origin": appConfig.corsOrigin,
2350
+ "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
2351
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
2352
+ };
2353
+
2354
+ const server = Bun.serve({
2355
+ port: appConfig.port,
2356
+ fetch(request: Request): Response {
2357
+ const requestUrl = new URL(request.url);
2358
+
2359
+ if (request.method === "OPTIONS") {
2360
+ return new Response(null, { status: 204, headers: corsHeaders });
2361
+ }
2362
+
2363
+ if (requestUrl.pathname === "/api/hello" && request.method === "GET") {
2364
+ return Response.json(helloController(), { headers: corsHeaders });
2365
+ }
2366
+
2367
+ return Response.json(
2368
+ { success: false, error: "Not found" },
2369
+ { status: 404, headers: corsHeaders }
2370
+ );
2371
+ },
2372
+ });
2373
+
2374
+ console.log(\`[${projectConfig.projectName}] Backend running at http://localhost:\${server.port}\`);
2375
+ `
2376
+ }
2377
+ ];
2378
+ }
2379
+ function getExpressFiles(projectConfig) {
2380
+ return [
2381
+ {
2382
+ path: "backend/package.json",
2383
+ content: getBackendPackageJson(projectConfig, {
2384
+ dependencies: {
2385
+ express: "^4.19.2",
2386
+ cors: "^2.8.5",
2387
+ ...getDatabaseDependencies(projectConfig.database)
2388
+ },
2389
+ devDependencies: {
2390
+ "@types/express": "^4.17.21",
2391
+ "@types/cors": "^2.8.17",
2392
+ "@types/node": "^26.0.1"
2393
+ }
2394
+ })
2395
+ },
2396
+ {
2397
+ path: "backend/src/app.ts",
2398
+ content: `import cors from "cors";
2399
+ import express from "express";
2400
+ import { appConfig } from "./config/app.config";
2401
+ import { helloController } from "./controllers/hello.controller";
2402
+
2403
+ const app = express();
2404
+
2405
+ app.use(cors({ origin: appConfig.corsOrigin }));
2406
+ app.use(express.json());
2407
+
2408
+ app.get("/api/hello", (_request, response) => {
2409
+ response.json(helloController());
2410
+ });
2411
+
2412
+ app.use((_request, response) => {
2413
+ response.status(404).json({ success: false, error: "Not found" });
2414
+ });
2415
+
2416
+ app.listen(appConfig.port, () => {
2417
+ console.log(\`[${projectConfig.projectName}] Backend running at http://localhost:\${appConfig.port}\`);
2418
+ });
2419
+ `
2420
+ },
2421
+ {
2422
+ path: "backend/src/middlewares/.gitkeep",
2423
+ content: ""
2424
+ },
2425
+ {
2426
+ path: "backend/src/routes/.gitkeep",
2427
+ content: ""
2428
+ },
2429
+ {
2430
+ path: "backend/src/services/.gitkeep",
2431
+ content: ""
2432
+ }
2433
+ ];
2434
+ }
2435
+ function getNestFiles(projectConfig) {
2436
+ return [
2437
+ {
2438
+ path: "backend/package.json",
2439
+ content: getBackendPackageJson(projectConfig, {
2440
+ dependencies: {
2441
+ "@nestjs/common": "^10.3.0",
2442
+ "@nestjs/core": "^10.3.0",
2443
+ "@nestjs/platform-express": "^10.3.0",
2444
+ "reflect-metadata": "^0.2.2",
2445
+ ...getDatabaseDependencies(projectConfig.database)
2446
+ },
2447
+ devDependencies: {
2448
+ "@types/node": "^26.0.1"
2449
+ }
2450
+ })
2451
+ },
2452
+ {
2453
+ path: "backend/nest-cli.json",
2454
+ content: JSON.stringify({
2455
+ $schema: "https://json.schemastore.org/nest-cli",
2456
+ collection: "@nestjs/schematics",
2457
+ sourceRoot: "src"
2458
+ }, null, 2)
2459
+ },
2460
+ {
2461
+ path: "backend/src/app.module.ts",
2462
+ content: `import { Module } from "@nestjs/common";
2463
+ import { AppController } from "./app.controller";
2464
+
2465
+ @Module({
2466
+ controllers: [AppController],
2467
+ })
2468
+ export class AppModule {}
2469
+ `
2470
+ },
2471
+ {
2472
+ path: "backend/src/app.controller.ts",
2473
+ content: `import { Controller, Get } from "@nestjs/common";
2474
+ import { helloController } from "./controllers/hello.controller";
2475
+
2476
+ @Controller("api")
2477
+ export class AppController {
2478
+ @Get("hello")
2479
+ hello() {
2480
+ return helloController();
2481
+ }
2482
+ }
2483
+ `
2484
+ },
2485
+ {
2486
+ path: "backend/src/main.ts",
2487
+ content: `import "reflect-metadata";
2488
+ import { NestFactory } from "@nestjs/core";
2489
+ import { AppModule } from "./app.module";
2490
+ import { appConfig } from "./config/app.config";
2491
+
2492
+ async function bootstrap(): Promise<void> {
2493
+ const app = await NestFactory.create(AppModule);
2494
+ app.enableCors({ origin: appConfig.corsOrigin });
2495
+ await app.listen(appConfig.port);
2496
+ console.log(\`[${projectConfig.projectName}] Backend running at http://localhost:\${appConfig.port}\`);
2497
+ }
2498
+
2499
+ bootstrap().catch(console.error);
2500
+ `
2501
+ },
2502
+ {
2503
+ path: "backend/src/modules/.gitkeep",
2504
+ content: ""
2505
+ },
2506
+ {
2507
+ path: "backend/src/common/.gitkeep",
2508
+ content: ""
2509
+ }
2510
+ ];
2511
+ }
2512
+ function getAdonisFiles(projectConfig) {
2513
+ return [
2514
+ {
2515
+ path: "backend/package.json",
2516
+ content: getBackendPackageJson(projectConfig, {
2517
+ dependencies: {
2518
+ "@adonisjs/core": "^6.9.0",
2519
+ ...getDatabaseDependencies(projectConfig.database)
2520
+ },
2521
+ devDependencies: {
2522
+ "@adonisjs/assembler": "^7.7.0",
2523
+ "@types/node": "^26.0.1"
2524
+ }
2525
+ })
2526
+ },
2527
+ {
2528
+ path: "backend/app/controllers/.gitkeep",
2529
+ content: ""
2530
+ },
2531
+ {
2532
+ path: "backend/app/middleware/.gitkeep",
2533
+ content: ""
2534
+ },
2535
+ {
2536
+ path: "backend/app/services/.gitkeep",
2537
+ content: ""
2538
+ },
2539
+ {
2540
+ path: "backend/start/.gitkeep",
2541
+ content: ""
2542
+ },
2543
+ {
2544
+ path: "backend/config/.gitkeep",
2545
+ content: ""
2546
+ },
2547
+ {
2548
+ path: "backend/src/app.ts",
2549
+ content: `import { appConfig } from "./config/app.config";
2550
+ import { helloController } from "./controllers/hello.controller";
2551
+
2552
+ const corsHeaders = {
2553
+ "Access-Control-Allow-Origin": appConfig.corsOrigin,
2554
+ "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
2555
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
2556
+ };
2557
+
2558
+ const server = Bun.serve({
2559
+ port: appConfig.port,
2560
+ fetch(request: Request): Response {
2561
+ const requestUrl = new URL(request.url);
2562
+
2563
+ if (request.method === "OPTIONS") {
2564
+ return new Response(null, { status: 204, headers: corsHeaders });
2565
+ }
2566
+
2567
+ if (requestUrl.pathname === "/api/hello" && request.method === "GET") {
2568
+ return Response.json(helloController(), { headers: corsHeaders });
2569
+ }
2570
+
2571
+ return Response.json(
2572
+ { success: false, error: "Not found" },
2573
+ { status: 404, headers: corsHeaders }
2574
+ );
2575
+ },
2576
+ });
2577
+
2578
+ console.log(\`[${projectConfig.projectName}] Backend running at http://localhost:\${server.port}\`);
2579
+ `
2580
+ }
2581
+ ];
2582
+ }
2583
+ function getBackendPackageJson(projectConfig, packageDeps) {
2584
+ return JSON.stringify({
2585
+ name: `${projectConfig.projectName}-backend`,
2586
+ version: "0.1.0",
2587
+ private: true,
2588
+ type: "module",
2589
+ scripts: {
2590
+ dev: "bun run --watch src/app.ts",
2591
+ build: "bun build src/app.ts --outfile dist/app.js --target bun",
2592
+ start: "bun run dist/app.js",
2593
+ typecheck: "tsc --noEmit"
2594
+ },
2595
+ dependencies: {
2596
+ ...packageDeps.dependencies
2597
+ },
2598
+ devDependencies: {
2599
+ "@types/bun": "^1.3.14",
2600
+ typescript: "^6.0.3",
2601
+ ...packageDeps.devDependencies
2602
+ }
2603
+ }, null, 2);
2604
+ }
2605
+ function getSharedFiles(projectConfig) {
2606
+ return [
2607
+ {
2608
+ path: "shared/types/index.ts",
2609
+ content: `export interface ApiResponse<TData = unknown> {
2610
+ readonly success: boolean;
2611
+ readonly data?: TData;
2612
+ readonly error?: string;
2613
+ readonly message?: string;
2614
+ }
2615
+
2616
+ export interface User {
2617
+ readonly id: string;
2618
+ readonly name: string;
2619
+ readonly email: string;
2620
+ readonly createdAt: string;
2621
+ readonly updatedAt: string;
2622
+ }
2623
+ `
2624
+ },
2625
+ {
2626
+ path: "shared/constants/index.ts",
2627
+ content: `export const APP_NAME = "${projectConfig.projectName}";
2628
+ export const API_VERSION = "v1";
2629
+ export const DEFAULT_PAGE_SIZE = 20;
2630
+ `
2631
+ }
2632
+ ];
2633
+ }
2634
+ function getCssDependencies(cssFramework) {
2635
+ switch (cssFramework) {
2636
+ case "tailwind":
2637
+ return { tailwindcss: "^4.3.1" };
2638
+ case "bootstrap":
2639
+ return { bootstrap: "^5.3.3" };
2640
+ case "sass":
2641
+ case "none":
2642
+ return {};
2643
+ }
2644
+ }
2645
+ function getCssDevDependencies(cssFramework) {
2646
+ switch (cssFramework) {
2647
+ case "sass":
2648
+ return { sass: "^1.77.0" };
2649
+ default:
2650
+ return {};
2651
+ }
2652
+ }
2653
+ function getFrontendOnlyCssGlobals(cssFramework) {
2654
+ const cssImport = cssFramework === "tailwind" ? `@import "tailwindcss";
2655
+
2656
+ ` : cssFramework === "bootstrap" ? `@import url("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css");
2657
+
2658
+ ` : cssFramework === "sass" ? `$color-primary: #dc2626;
2659
+ $color-background: #050505;
2660
+ $color-foreground: #f8fafc;
2661
+
2662
+ ` : "";
2663
+ return `${cssImport}:root {
2664
+ --color-primary: #dc2626;
2665
+ --color-background: #050505;
2666
+ --color-foreground: #f8fafc;
2667
+ --color-surface: #0e111a;
2668
+ --color-border: rgba(255, 255, 255, 0.1);
2669
+ --color-muted: #94a3b8;
2670
+ color-scheme: dark;
2671
+ }
2672
+
2673
+ html {
2674
+ scroll-behavior: smooth;
2675
+ }
2676
+
2677
+ body {
2678
+ margin: 0;
2679
+ min-width: 320px;
2680
+ min-height: 100vh;
2681
+ color: var(--color-foreground);
2682
+ background: var(--color-background);
2683
+ font-family:
2684
+ ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
2685
+ Roboto, sans-serif;
2686
+ -webkit-font-smoothing: antialiased;
2687
+ }
2688
+
2689
+ *,
2690
+ *::before,
2691
+ *::after {
2692
+ box-sizing: border-box;
2693
+ }
2694
+
2695
+ @keyframes shrimpLegs {
2696
+ 0% {
2697
+ transform: translateY(0);
2698
+ }
2699
+
2700
+ 50% {
2701
+ transform: translateY(2px);
2702
+ }
2703
+ }
2704
+ `;
2705
+ }
2706
+ function getCssGlobals(cssFramework) {
2707
+ const sharedBase = `
2708
+ :root {
2709
+ --color-primary: #dc2626;
2710
+ --color-background: #050505;
2711
+ --color-foreground: #f8fafc;
2712
+ }
2713
+
2714
+ * {
2715
+ box-sizing: border-box;
2716
+ }
2717
+
2718
+ body {
2719
+ margin: 0;
2720
+ color: var(--color-foreground);
2721
+ background: var(--color-background);
2722
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
2723
+ }
2724
+
2725
+ .page-shell {
2726
+ width: min(100% - 2rem, 960px);
2727
+ margin: 0 auto;
2728
+ padding: 4rem 0;
2729
+ }
2730
+
2731
+ .hero-card,
2732
+ .feature-card {
2733
+ border: 1px solid rgba(255, 255, 255, 0.1);
2734
+ background: #0e111a;
2735
+ border-radius: 24px;
2736
+ padding: 2rem;
2737
+ margin-bottom: 1.5rem;
2738
+ }
2739
+
2740
+ .eyebrow {
2741
+ color: #dc2626;
2742
+ font-weight: 700;
2743
+ letter-spacing: 0.12em;
2744
+ font-size: 0.75rem;
2745
+ text-transform: uppercase;
2746
+ }
2747
+
2748
+ .button-row {
2749
+ display: flex;
2750
+ gap: 0.75rem;
2751
+ flex-wrap: wrap;
2752
+ margin-top: 1rem;
2753
+ }
2754
+
2755
+ a {
2756
+ color: #dc2626;
2757
+ }
2758
+
2759
+ button {
2760
+ cursor: pointer;
2761
+ }
2762
+ `;
2763
+ switch (cssFramework) {
2764
+ case "tailwind":
2765
+ return `@import "tailwindcss";
2766
+ ${sharedBase}`;
2767
+ case "bootstrap":
2768
+ return `@import url("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css");
2769
+ ${sharedBase}`;
2770
+ case "sass":
2771
+ return `$color-primary: #dc2626;
2772
+ $color-background: #050505;
2773
+ $color-foreground: #f8fafc;
2774
+ ${sharedBase}`;
2775
+ case "none":
2776
+ return sharedBase;
2777
+ }
2778
+ }
2779
+ function generateFrontendOnlyRaktaEnv() {
2780
+ return `declare module "*.css";
2781
+ declare module "*.scss";
2782
+ declare module "*.sass";
2783
+
2784
+ type RaktaClickAttributes = Omit<
2785
+ import("react").AnchorHTMLAttributes<HTMLAnchorElement>,
2786
+ "href"
2787
+ > & {
2788
+ readonly to: string;
2789
+ };
2790
+
2791
+ declare global {
2792
+ namespace JSX {
2793
+ interface IntrinsicElements {
2794
+ click: RaktaClickAttributes;
2795
+ }
2796
+ }
2797
+
2798
+ const useCallback: typeof import("react").useCallback;
2799
+ const useEffect: typeof import("react").useEffect;
2800
+ const useRef: typeof import("react").useRef;
2801
+ const useState: typeof import("react").useState;
2802
+
2803
+ const ShrimpRunGame: typeof import("./app/components/shrimpRunGame").default;
2804
+ const RaktaShrimpMascot: typeof import("./app/components/raktaShrimpMascot").default;
2805
+ }
2806
+
2807
+ declare module "react/jsx-runtime" {
2808
+ namespace JSX {
2809
+ interface IntrinsicElements {
2810
+ click: RaktaClickAttributes;
2811
+ }
2812
+ }
2813
+ }
2814
+
2815
+ declare module "react/jsx-dev-runtime" {
2816
+ namespace JSX {
2817
+ interface IntrinsicElements {
2818
+ click: RaktaClickAttributes;
2819
+ }
2820
+ }
2821
+ }
2822
+
2823
+ export {};
2824
+ `;
2825
+ }
2826
+ function generateFrontendOnlyLayout() {
2827
+ return `interface RootLayoutProps {
2828
+ readonly children: import("react").ReactNode;
2829
+ }
2830
+
2831
+ export default function RootLayout({ children }: RootLayoutProps) {
2832
+ return (
2833
+ <html lang="en">
2834
+ <head>
2835
+ <meta charSet="UTF-8" />
2836
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
2837
+ <title>Rakta.js App</title>
2838
+ </head>
2839
+ <body className="min-h-screen bg-[#050505] text-slate-50 antialiased">
2840
+ {children}
2841
+ </body>
2842
+ </html>
2843
+ );
2844
+ }
2845
+ `;
2846
+ }
2847
+ function generateFrontendOnlyPage(projectName) {
2848
+ return `export default function HomePage() {
2849
+ return (
2850
+ <main className="mx-auto flex min-h-screen w-full max-w-4xl flex-col gap-6 px-4 py-16 sm:px-6 lg:px-8">
2851
+ <section className="rounded-3xl border border-white/10 bg-[#0e111a] p-8 shadow-2xl shadow-red-950/20">
2852
+ <p className="mb-2 text-xs font-bold uppercase tracking-[0.3em] text-red-600">
2853
+ THE RED ROUTER FRAMEWORK
2854
+ </p>
2855
+ <h1 className="mb-3 text-4xl font-extrabold leading-tight text-white md:text-6xl">
2856
+ Welcome to ${projectName}
2857
+ </h1>
2858
+ <p className="max-w-2xl text-base leading-7 text-slate-400">
2859
+ Built with Rakta.js \u2014 Small in size. Fierce in speed. Alive in every route.
2860
+ </p>
2861
+
2862
+ <div className="mt-6 flex flex-wrap gap-3">
2863
+ <click
2864
+ to="/offline"
2865
+ className="rounded-xl border border-red-500/40 px-4 py-2 text-sm font-semibold text-red-400 transition hover:border-red-400 hover:text-red-300"
2866
+ >
2867
+ Open offline page
2868
+ </click>
2869
+ <click
2870
+ to="/dashboard"
2871
+ className="rounded-xl bg-red-600 px-4 py-2 text-sm font-semibold text-white transition hover:bg-red-700"
2872
+ >
2873
+ View dashboard
2874
+ </click>
2875
+ </div>
2876
+ </section>
2877
+
2878
+ <section className="rounded-3xl border border-white/10 bg-[#0e111a] p-8 shadow-2xl shadow-red-950/20">
2879
+ <p className="mb-2 text-xs font-bold uppercase tracking-[0.3em] text-red-600">
2880
+ SHRIMPRUN
2881
+ </p>
2882
+ <h2 className="mb-1 text-2xl font-bold text-white">Play ShrimpRun</h2>
2883
+ <p className="mb-6 text-sm leading-6 text-slate-400">
2884
+ Press Space or click the game area to jump. Avoid the red obstacles!
2885
+ </p>
2886
+
2887
+ <ShrimpRunGame />
2888
+ </section>
2889
+ </main>
2890
+ );
2891
+ }
2892
+ `;
2893
+ }
2894
+ function generateFrontendOnlyLoading() {
2895
+ return `export default function Loading() {
2896
+ return (
2897
+ <main className="flex min-h-screen items-center justify-center bg-[#050505] px-4">
2898
+ <p className="text-sm font-medium text-slate-400">Loading...</p>
2899
+ </main>
2900
+ );
2901
+ }
2902
+ `;
2903
+ }
2904
+ function generateFrontendOnlyError() {
2905
+ return `interface ErrorPageProps {
2906
+ readonly error: Error;
2907
+ readonly reset: () => void;
2908
+ }
2909
+
2910
+ export default function ErrorPage({ error, reset }: ErrorPageProps) {
2911
+ return (
2912
+ <main className="mx-auto flex min-h-screen w-full max-w-3xl items-center px-4 py-16">
2913
+ <section className="w-full rounded-3xl border border-white/10 bg-[#0e111a] p-8 shadow-2xl shadow-red-950/20">
2914
+ <p className="mb-2 text-xs font-bold uppercase tracking-[0.3em] text-red-600">
2915
+ ERROR
2916
+ </p>
2917
+ <h1 className="mb-3 text-3xl font-extrabold text-white">
2918
+ Something went wrong
2919
+ </h1>
2920
+ <p className="mb-6 wrap-break-word text-sm leading-6 text-slate-400">
2921
+ {error.message}
2922
+ </p>
2923
+ <button
2924
+ type="button"
2925
+ onClick={reset}
2926
+ className="rounded-lg bg-red-600 px-6 py-2 font-semibold text-white transition hover:bg-red-700 active:bg-red-800 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
2927
+ >
2928
+ Try again
2929
+ </button>
2930
+ </section>
2931
+ </main>
2932
+ );
2933
+ }
2934
+ `;
2935
+ }
2936
+ function generateFrontendOnlyNotFound() {
2937
+ return `export default function NotFound() {
2938
+ return (
2939
+ <main className="mx-auto flex min-h-screen w-full max-w-3xl items-center px-4 py-16">
2940
+ <section className="w-full rounded-3xl border border-white/10 bg-[#0e111a] p-8 shadow-2xl shadow-red-950/20">
2941
+ <p className="mb-2 text-xs font-bold uppercase tracking-[0.3em] text-red-600">
2942
+ 404
2943
+ </p>
2944
+ <h1 className="mb-3 text-3xl font-extrabold text-white">
2945
+ Page not found
2946
+ </h1>
2947
+ <p className="mb-6 text-sm leading-6 text-slate-400">
2948
+ The page you are looking for does not exist.
2949
+ </p>
2950
+ <click
2951
+ to="/"
2952
+ className="font-semibold text-red-500 underline-offset-4 transition hover:text-red-400 hover:underline"
2953
+ >
2954
+ Return home
2955
+ </click>
2956
+ </section>
2957
+ </main>
2958
+ );
2959
+ }
2960
+ `;
2961
+ }
2962
+ function generateShrimpMascotComponent() {
2963
+ return `interface RaktaShrimpMascotProps {
2964
+ readonly isJumping: boolean;
2965
+ readonly isDead: boolean;
2966
+ readonly style?: import("react").CSSProperties;
2967
+ }
2968
+
2969
+ /**
2970
+ * RaktaShrimpMascot \u2014 The animated shrimp hero of ShrimpRun.
2971
+ * Drawn entirely with inline SVG. No external assets required.
2972
+ */
2973
+ export default function RaktaShrimpMascot({
2974
+ isJumping,
2975
+ isDead,
2976
+ style,
2977
+ }: RaktaShrimpMascotProps) {
2978
+ const bodyColor = isDead ? "#6b7280" : "#dc2626";
2979
+ const eyeColor = isDead ? "#374151" : "#fff";
2980
+ const legAnimation =
2981
+ isJumping || isDead ? "none" : "shrimpLegs 0.3s steps(2) infinite";
2982
+
2983
+ return (
2984
+ <svg
2985
+ viewBox="0 0 48 48"
2986
+ width="48"
2987
+ height="48"
2988
+ style={{ display: "block", ...style }}
2989
+ aria-label={
2990
+ isDead ? "dead shrimp" : isJumping ? "shrimp jumping" : "running shrimp"
2991
+ }
2992
+ role="img"
2993
+ >
2994
+ <style>{\`
2995
+ @keyframes shrimpLegs {
2996
+ 0% { transform: translateY(0); }
2997
+ 50% { transform: translateY(2px); }
2998
+ }
2999
+ \`}</style>
3000
+
3001
+ {/* Body */}
3002
+ <path
3003
+ d="M8 30 Q10 14 24 12 Q38 10 40 22 Q42 32 32 36 Q20 40 8 30Z"
3004
+ fill={bodyColor}
3005
+ />
3006
+
3007
+ {/* Shell segments */}
3008
+ <path
3009
+ d="M12 28 Q16 20 24 18 Q30 17 34 22"
3010
+ stroke="#b91c1c"
3011
+ strokeWidth="1.5"
3012
+ fill="none"
3013
+ opacity={isDead ? 0.3 : 0.6}
3014
+ />
3015
+ <path
3016
+ d="M14 32 Q19 24 28 22 Q33 21 36 26"
3017
+ stroke="#b91c1c"
3018
+ strokeWidth="1.5"
3019
+ fill="none"
3020
+ opacity={isDead ? 0.3 : 0.6}
3021
+ />
3022
+
3023
+ {/* Eye */}
3024
+ <circle cx="34" cy="18" r="4" fill="#1e293b" />
3025
+ <circle cx="35" cy="17" r="2" fill={eyeColor} />
3026
+
3027
+ {isDead && (
3028
+ <>
3029
+ <line
3030
+ x1="32"
3031
+ y1="16"
3032
+ x2="36"
3033
+ y2="20"
3034
+ stroke="#374151"
3035
+ strokeWidth="1.5"
3036
+ />
3037
+ <line
3038
+ x1="36"
3039
+ y1="16"
3040
+ x2="32"
3041
+ y2="20"
3042
+ stroke="#374151"
3043
+ strokeWidth="1.5"
3044
+ />
3045
+ </>
3046
+ )}
3047
+
3048
+ {/* Antennae */}
3049
+ <line
3050
+ x1="34"
3051
+ y1="14"
3052
+ x2="40"
3053
+ y2="6"
3054
+ stroke={bodyColor}
3055
+ strokeWidth="1.5"
3056
+ strokeLinecap="round"
3057
+ />
3058
+ <line
3059
+ x1="32"
3060
+ y1="13"
3061
+ x2="36"
3062
+ y2="4"
3063
+ stroke={bodyColor}
3064
+ strokeWidth="1.5"
3065
+ strokeLinecap="round"
3066
+ />
3067
+
3068
+ {/* Tail */}
3069
+ <path
3070
+ d="M10 30 Q4 26 6 20"
3071
+ stroke={bodyColor}
3072
+ strokeWidth="2"
3073
+ fill="none"
3074
+ strokeLinecap="round"
3075
+ />
3076
+ <path
3077
+ d="M10 30 Q2 30 4 36"
3078
+ stroke={bodyColor}
3079
+ strokeWidth="2"
3080
+ fill="none"
3081
+ strokeLinecap="round"
3082
+ />
3083
+ <path
3084
+ d="M10 30 Q6 34 8 40"
3085
+ stroke={bodyColor}
3086
+ strokeWidth="2"
3087
+ fill="none"
3088
+ strokeLinecap="round"
3089
+ />
3090
+
3091
+ {/* Legs */}
3092
+ <g
3093
+ style={{
3094
+ animation: legAnimation,
3095
+ transformOrigin: "24px 36px",
3096
+ }}
3097
+ >
3098
+ <line
3099
+ x1="18"
3100
+ y1="36"
3101
+ x2="14"
3102
+ y2="44"
3103
+ stroke={bodyColor}
3104
+ strokeWidth="1.5"
3105
+ strokeLinecap="round"
3106
+ />
3107
+ <line
3108
+ x1="22"
3109
+ y1="38"
3110
+ x2="18"
3111
+ y2="46"
3112
+ stroke={bodyColor}
3113
+ strokeWidth="1.5"
3114
+ strokeLinecap="round"
3115
+ />
3116
+ <line
3117
+ x1="26"
3118
+ y1="38"
3119
+ x2="24"
3120
+ y2="46"
3121
+ stroke={bodyColor}
3122
+ strokeWidth="1.5"
3123
+ strokeLinecap="round"
3124
+ />
3125
+ <line
3126
+ x1="30"
3127
+ y1="37"
3128
+ x2="28"
3129
+ y2="45"
3130
+ stroke={bodyColor}
3131
+ strokeWidth="1.5"
3132
+ strokeLinecap="round"
3133
+ />
3134
+ </g>
3135
+ </svg>
3136
+ );
3137
+ }
3138
+ `;
3139
+ }
3140
+ function generateShrimpRunGameComponent() {
3141
+ return `// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3142
+
3143
+ type GameStatus = "idle" | "running" | "dead";
3144
+
3145
+ interface ObstacleState {
3146
+ readonly id: number;
3147
+ readonly xPosition: number;
3148
+ readonly width: number;
3149
+ readonly height: number;
3150
+ }
3151
+
3152
+ interface ShrimpState {
3153
+ readonly yPosition: number;
3154
+ readonly velocityY: number;
3155
+ readonly isJumping: boolean;
3156
+ }
3157
+
3158
+ // \u2500\u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3159
+
3160
+ const CANVAS_WIDTH = 640;
3161
+ const CANVAS_HEIGHT = 160;
3162
+ const GROUND_STRIP_HEIGHT = 4;
3163
+ const SHRIMP_START_X = 60;
3164
+ const SHRIMP_WIDTH = 48;
3165
+ const SHRIMP_HEIGHT = 48;
3166
+ const GRAVITY = 1.4;
3167
+ const JUMP_VELOCITY = -18;
3168
+ const INITIAL_OBSTACLE_SPEED = 5;
3169
+ const SPEED_INCREMENT_PER_SCORE = 0.003;
3170
+ const OBSTACLE_SPAWN_INTERVAL_MS = 1600;
3171
+ const SCORE_TICK_MS = 80;
3172
+ const COLLISION_MARGIN = 8;
3173
+ const MAX_CONCURRENT_OBSTACLES = 3;
3174
+ const FRAME_SKIP_THRESHOLD_MS = 100;
3175
+
3176
+ // \u2500\u2500\u2500 Physics helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3177
+
3178
+ function getObstacleSpeed(currentScore: number): number {
3179
+ return INITIAL_OBSTACLE_SPEED + currentScore * SPEED_INCREMENT_PER_SCORE;
3180
+ }
3181
+
3182
+ function checkCollision(
3183
+ shrimpYPosition: number,
3184
+ obstacle: ObstacleState,
3185
+ ): boolean {
3186
+ const shrimpLeft = SHRIMP_START_X + COLLISION_MARGIN;
3187
+ const shrimpRight = SHRIMP_START_X + SHRIMP_WIDTH - COLLISION_MARGIN;
3188
+ const shrimpTop =
3189
+ CANVAS_HEIGHT -
3190
+ GROUND_STRIP_HEIGHT -
3191
+ shrimpYPosition -
3192
+ SHRIMP_HEIGHT +
3193
+ COLLISION_MARGIN;
3194
+ const shrimpBottom = CANVAS_HEIGHT - GROUND_STRIP_HEIGHT - shrimpYPosition;
3195
+
3196
+ const obstacleLeft = obstacle.xPosition + COLLISION_MARGIN;
3197
+ const obstacleRight = obstacle.xPosition + obstacle.width - COLLISION_MARGIN;
3198
+ const obstacleTop = CANVAS_HEIGHT - GROUND_STRIP_HEIGHT - obstacle.height;
3199
+ const obstacleBottom = CANVAS_HEIGHT - GROUND_STRIP_HEIGHT;
3200
+
3201
+ return (
3202
+ shrimpLeft < obstacleRight &&
3203
+ shrimpRight > obstacleLeft &&
3204
+ shrimpTop < obstacleBottom &&
3205
+ shrimpBottom > obstacleTop
3206
+ );
3207
+ }
3208
+
3209
+ // \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3210
+
3211
+ /**
3212
+ * ShrimpRun \u2014 Default Rakta.js interactive starter game.
3213
+ *
3214
+ * Like the Chrome offline Dino game, but the dinosaur is an animated shrimp.
3215
+ * Press Space or click the game canvas to jump. Avoid the red obstacles!
3216
+ *
3217
+ * Features:
3218
+ * - React state only \u2014 no external game library
3219
+ * - requestAnimationFrame game loop
3220
+ * - Physics: gravity + jump velocity
3221
+ * - Score that increases over time
3222
+ * - Speed ramps up as score grows
3223
+ * - Collision detection with margin
3224
+ * - High score tracked in component state
3225
+ * - Keyboard (Space) and click/tap support
3226
+ * - Accessible button game canvas
3227
+ * - SVG shrimp mascot \u2014 no external assets
3228
+ */
3229
+ export default function ShrimpRunGame() {
3230
+ const [gameStatus, setGameStatus] = useState<GameStatus>("idle");
3231
+ const [score, setScore] = useState(0);
3232
+ const [highScore, setHighScore] = useState(0);
3233
+ const [obstacles, setObstacles] = useState<ObstacleState[]>([]);
3234
+ const [shrimp, setShrimp] = useState<ShrimpState>({
3235
+ yPosition: 0,
3236
+ velocityY: 0,
3237
+ isJumping: false,
3238
+ });
3239
+
3240
+ const gameStatusRef = useRef<GameStatus>("idle");
3241
+ const scoreRef = useRef(0);
3242
+ const shrimpRef = useRef<ShrimpState>({
3243
+ yPosition: 0,
3244
+ velocityY: 0,
3245
+ isJumping: false,
3246
+ });
3247
+ const obstaclesRef = useRef<ObstacleState[]>([]);
3248
+ const obstacleIdRef = useRef(0);
3249
+ const animationFrameRef = useRef<number>(0);
3250
+ const lastObstacleTimeRef = useRef(0);
3251
+ const lastScoreTickRef = useRef(0);
3252
+
3253
+ const jump = useCallback((): void => {
3254
+ if (gameStatusRef.current === "dead") {
3255
+ return;
3256
+ }
3257
+
3258
+ if (gameStatusRef.current === "idle") {
3259
+ gameStatusRef.current = "running";
3260
+ setGameStatus("running");
3261
+ }
3262
+
3263
+ if (!shrimpRef.current.isJumping) {
3264
+ const nextShrimp: ShrimpState = {
3265
+ ...shrimpRef.current,
3266
+ velocityY: JUMP_VELOCITY,
3267
+ isJumping: true,
3268
+ };
3269
+
3270
+ shrimpRef.current = nextShrimp;
3271
+ setShrimp(nextShrimp);
3272
+ }
3273
+ }, []);
3274
+
3275
+ const resetGame = useCallback((): void => {
3276
+ const freshShrimp: ShrimpState = {
3277
+ yPosition: 0,
3278
+ velocityY: 0,
3279
+ isJumping: false,
3280
+ };
3281
+
3282
+ shrimpRef.current = freshShrimp;
3283
+ obstaclesRef.current = [];
3284
+ obstacleIdRef.current = 0;
3285
+ scoreRef.current = 0;
3286
+ gameStatusRef.current = "idle";
3287
+ lastObstacleTimeRef.current = 0;
3288
+ lastScoreTickRef.current = 0;
3289
+
3290
+ setShrimp(freshShrimp);
3291
+ setObstacles([]);
3292
+ setScore(0);
3293
+ setGameStatus("idle");
3294
+ }, []);
3295
+
3296
+ useEffect(() => {
3297
+ let previousTimestamp = 0;
3298
+
3299
+ function gameTick(timestamp: number): void {
3300
+ if (gameStatusRef.current !== "running") {
3301
+ animationFrameRef.current = requestAnimationFrame(gameTick);
3302
+ return;
3303
+ }
3304
+
3305
+ const deltaTime = timestamp - previousTimestamp;
3306
+ previousTimestamp = timestamp;
3307
+
3308
+ if (deltaTime > FRAME_SKIP_THRESHOLD_MS) {
3309
+ animationFrameRef.current = requestAnimationFrame(gameTick);
3310
+ return;
3311
+ }
3312
+
3313
+ const currentShrimp = shrimpRef.current;
3314
+ let nextVelocityY = currentShrimp.velocityY + GRAVITY;
3315
+ let nextYPosition = currentShrimp.yPosition - nextVelocityY;
3316
+
3317
+ if (nextYPosition <= 0) {
3318
+ nextYPosition = 0;
3319
+ nextVelocityY = 0;
3320
+ }
3321
+
3322
+ const nextShrimp: ShrimpState = {
3323
+ yPosition: nextYPosition,
3324
+ velocityY: nextVelocityY,
3325
+ isJumping: nextYPosition > 0,
3326
+ };
3327
+
3328
+ shrimpRef.current = nextShrimp;
3329
+ setShrimp(nextShrimp);
3330
+
3331
+ const obstacleSpeed = getObstacleSpeed(scoreRef.current);
3332
+
3333
+ const movedObstacles = obstaclesRef.current
3334
+ .map(
3335
+ (obstacle): ObstacleState => ({
3336
+ ...obstacle,
3337
+ xPosition: obstacle.xPosition - obstacleSpeed,
3338
+ }),
3339
+ )
3340
+ .filter((obstacle) => obstacle.xPosition + obstacle.width > -10);
3341
+
3342
+ if (
3343
+ timestamp - lastObstacleTimeRef.current > OBSTACLE_SPAWN_INTERVAL_MS &&
3344
+ movedObstacles.length < MAX_CONCURRENT_OBSTACLES
3345
+ ) {
3346
+ const obstacleHeight = 30 + Math.floor(Math.random() * 30);
3347
+ const obstacleWidth = 20 + Math.floor(Math.random() * 20);
3348
+
3349
+ movedObstacles.push({
3350
+ id: obstacleIdRef.current,
3351
+ xPosition: CANVAS_WIDTH + 20,
3352
+ width: obstacleWidth,
3353
+ height: obstacleHeight,
3354
+ });
3355
+
3356
+ obstacleIdRef.current += 1;
3357
+ lastObstacleTimeRef.current = timestamp;
3358
+ }
3359
+
3360
+ obstaclesRef.current = movedObstacles;
3361
+ setObstacles([...movedObstacles]);
3362
+
3363
+ for (const obstacle of movedObstacles) {
3364
+ if (checkCollision(nextShrimp.yPosition, obstacle)) {
3365
+ gameStatusRef.current = "dead";
3366
+ setGameStatus("dead");
3367
+ setHighScore((previousHighScore: number) =>
3368
+ Math.max(previousHighScore, scoreRef.current),
3369
+ );
3370
+ animationFrameRef.current = requestAnimationFrame(gameTick);
3371
+ return;
3372
+ }
3373
+ }
3374
+
3375
+ if (timestamp - lastScoreTickRef.current > SCORE_TICK_MS) {
3376
+ scoreRef.current += 1;
3377
+ setScore(scoreRef.current);
3378
+ lastScoreTickRef.current = timestamp;
3379
+ }
3380
+
3381
+ animationFrameRef.current = requestAnimationFrame(gameTick);
3382
+ }
3383
+
3384
+ animationFrameRef.current = requestAnimationFrame(gameTick);
3385
+
3386
+ return () => {
3387
+ cancelAnimationFrame(animationFrameRef.current);
3388
+ };
3389
+ }, []);
3390
+
3391
+ useEffect(() => {
3392
+ function handleKeyDown(keyboardEvent: KeyboardEvent): void {
3393
+ if (keyboardEvent.code === "Space") {
3394
+ keyboardEvent.preventDefault();
3395
+ jump();
3396
+ }
3397
+ }
3398
+
3399
+ window.addEventListener("keydown", handleKeyDown);
3400
+
3401
+ return () => {
3402
+ window.removeEventListener("keydown", handleKeyDown);
3403
+ };
3404
+ }, [jump]);
3405
+
3406
+ const shrimpBottomOffset = GROUND_STRIP_HEIGHT + shrimp.yPosition;
3407
+ const isDead = gameStatus === "dead";
3408
+ const isIdle = gameStatus === "idle";
3409
+ const isRunning = gameStatus === "running";
3410
+
3411
+ return (
3412
+ <div className="flex flex-col items-start gap-4 py-4">
3413
+ <div className="flex flex-wrap items-center gap-8">
3414
+ <span className="font-mono text-xl font-bold tabular-nums text-red-600">
3415
+ Score: {score}
3416
+ </span>
3417
+ {highScore > 0 && (
3418
+ <span className="text-sm text-slate-400">Best: {highScore}</span>
3419
+ )}
3420
+ </div>
3421
+
3422
+ <button
3423
+ type="button"
3424
+ className="relative block max-w-full cursor-pointer select-none overflow-hidden rounded-2xl border-2 border-red-600/30 bg-[#0e111a] p-0 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
3425
+ aria-label="ShrimpRun game area. Click or press Space to jump."
3426
+ onClick={jump}
3427
+ onKeyDown={(keyboardEvent: import("react").KeyboardEvent) => {
3428
+ if (keyboardEvent.code === "Space") {
3429
+ keyboardEvent.preventDefault();
3430
+ jump();
3431
+ }
3432
+ }}
3433
+ style={{
3434
+ width: CANVAS_WIDTH,
3435
+ height: CANVAS_HEIGHT,
3436
+ }}
3437
+ >
3438
+ <span
3439
+ className="absolute bottom-0 left-0 w-full rounded-sm bg-red-600"
3440
+ style={{
3441
+ height: GROUND_STRIP_HEIGHT,
3442
+ }}
3443
+ />
3444
+
3445
+ <span
3446
+ className="absolute"
3447
+ style={{
3448
+ left: SHRIMP_START_X,
3449
+ bottom: shrimpBottomOffset,
3450
+ width: SHRIMP_WIDTH,
3451
+ height: SHRIMP_HEIGHT,
3452
+ }}
3453
+ >
3454
+ <RaktaShrimpMascot isJumping={shrimp.isJumping} isDead={isDead} />
3455
+ </span>
3456
+
3457
+ {obstacles.map((obstacle) => (
3458
+ <span
3459
+ key={obstacle.id}
3460
+ className="absolute rounded-t bg-red-600"
3461
+ style={{
3462
+ left: obstacle.xPosition,
3463
+ bottom: GROUND_STRIP_HEIGHT,
3464
+ width: obstacle.width,
3465
+ height: obstacle.height,
3466
+ }}
3467
+ />
3468
+ ))}
3469
+
3470
+ {isIdle && (
3471
+ <span className="pointer-events-none absolute inset-0 flex items-center justify-center text-sm text-slate-400">
3472
+ Press Space or click to start
3473
+ </span>
3474
+ )}
3475
+
3476
+ {isDead && (
3477
+ <span className="absolute inset-0 flex flex-col items-center justify-center gap-2 bg-black/75">
3478
+ <span className="text-lg font-bold tracking-widest text-red-600">
3479
+ GAME OVER
3480
+ </span>
3481
+ <span className="text-sm text-slate-400">Score: {score}</span>
3482
+ </span>
3483
+ )}
3484
+
3485
+ {isRunning && score > 0 && score % 50 === 0 && (
3486
+ <span className="absolute right-3 top-2 text-xs font-bold tracking-widest text-red-600 opacity-80">
3487
+ {score}!
3488
+ </span>
3489
+ )}
3490
+ </button>
3491
+
3492
+ <p className="min-h-5 text-sm text-slate-400">
3493
+ {isIdle && "\uD83E\uDD90 Click or press Space to make the shrimp jump!"}
3494
+ {isRunning && "\uD83E\uDD90 Don't hit the obstacles!"}
3495
+ {isDead && "The shrimp got cooked. Try again!"}
3496
+ </p>
3497
+
3498
+ {isDead && (
3499
+ <button
3500
+ type="button"
3501
+ className="w-fit rounded-lg bg-red-600 px-6 py-2 font-semibold text-white transition hover:bg-red-700 active:bg-red-800 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
3502
+ onClick={resetGame}
3503
+ >
3504
+ Restart
3505
+ </button>
3506
+ )}
3507
+ </div>
3508
+ );
3509
+ }
3510
+ `;
3511
+ }
3512
+ function generateFullstackHomePage(projectName) {
3513
+ return `import React from "react";
3514
+
3515
+ export default function HomePage() {
3516
+ return (
3517
+ <main className="page-shell">
3518
+ <section className="hero-card">
3519
+ <p className="eyebrow">THE RED ROUTER FRAMEWORK</p>
3520
+ <h1>Welcome to ${projectName}</h1>
3521
+ <p>
3522
+ Built with Rakta.js \u2014 Small in size. Fierce in speed. Alive in every route.
3523
+ </p>
3524
+ <div className="button-row">
3525
+ <a href="/about">About</a>
3526
+ <a href="/blog">Blog</a>
3527
+ </div>
3528
+ </section>
3529
+ </main>
3530
+ );
3531
+ }
3532
+ `;
3533
+ }
3534
+ function getDatabaseDependencies(selectedDatabase) {
3535
+ switch (selectedDatabase) {
3536
+ case "postgresql":
3537
+ return { postgres: "^3.4.4" };
3538
+ case "mysql":
3539
+ case "mariadb":
3540
+ return { mysql2: "^3.9.8" };
3541
+ case "mongodb":
3542
+ return { mongodb: "^6.8.0" };
3543
+ case "firebase":
3544
+ return { "firebase-admin": "^12.7.0" };
3545
+ case "sqlite":
3546
+ return {};
3547
+ case "redis":
3548
+ return { ioredis: "^5.4.1" };
3549
+ case "planetscale":
3550
+ return { "@planetscale/database": "^1.18.0" };
3551
+ case "neon":
3552
+ return { "@neondatabase/serverless": "^0.9.4" };
3553
+ case "turso":
3554
+ return { "@libsql/client": "^0.6.2" };
3555
+ default:
3556
+ return {};
3557
+ }
3558
+ }
3559
+ function getDatabaseConfig(selectedDatabase) {
3560
+ switch (selectedDatabase) {
3561
+ case "sqlite":
3562
+ return `export const databaseConfig = {
3563
+ path: process.env["DATABASE_PATH"] ?? "./database.sqlite",
3564
+ provider: "sqlite" as const,
3565
+ } as const;
3566
+ `;
3567
+ case "firebase":
3568
+ return `export const databaseConfig = {
3569
+ projectId: process.env["FIREBASE_PROJECT_ID"] ?? "",
3570
+ clientEmail: process.env["FIREBASE_CLIENT_EMAIL"] ?? "",
3571
+ privateKey: process.env["FIREBASE_PRIVATE_KEY"]?.replace(/\\\\\\\\n/g, "\\\\n") ?? "",
3572
+ databaseUrl: process.env["FIREBASE_DATABASE_URL"] ?? "",
3573
+ provider: "firebase" as const,
3574
+ } as const;
3575
+ `;
3576
+ case "turso":
3577
+ return `export const databaseConfig = {
3578
+ url: process.env["TURSO_DATABASE_URL"] ?? "",
3579
+ authToken: process.env["TURSO_AUTH_TOKEN"] ?? "",
3580
+ provider: "turso" as const,
3581
+ } as const;
3582
+ `;
3583
+ default:
3584
+ return `import { env } from "../env";
3585
+
3586
+ export const databaseConfig = {
3587
+ url: env.databaseUrl,
3588
+ provider: "${selectedDatabase}" as const,
3589
+ } as const;
3590
+ `;
3591
+ }
3592
+ }
3593
+ function getDatabaseClient(selectedDatabase) {
3594
+ switch (selectedDatabase) {
3595
+ case "postgresql":
3596
+ return `import postgres from "postgres";
3597
+ import { databaseConfig } from "../config/database.config";
3598
+
3599
+ export const sql = databaseConfig.url ? postgres(databaseConfig.url) : null;
3600
+ `;
3601
+ case "mysql":
3602
+ case "mariadb":
3603
+ return `import mysql from "mysql2/promise";
3604
+ import { databaseConfig } from "../config/database.config";
3605
+
3606
+ export const pool = databaseConfig.url
3607
+ ? mysql.createPool({ uri: databaseConfig.url, connectionLimit: 10 })
3608
+ : null;
3609
+ `;
3610
+ case "mongodb":
3611
+ return `import { MongoClient } from "mongodb";
3612
+ import { databaseConfig } from "../config/database.config";
3613
+
3614
+ export const mongoClient = databaseConfig.url
3615
+ ? new MongoClient(databaseConfig.url)
3616
+ : null;
3617
+ `;
3618
+ case "firebase":
3619
+ return `import { cert, getApps, initializeApp } from "firebase-admin/app";
3620
+ import { getFirestore } from "firebase-admin/firestore";
3621
+ import { databaseConfig } from "../config/database.config";
3622
+
3623
+ const credentialReady =
3624
+ databaseConfig.projectId.length > 0 &&
3625
+ databaseConfig.clientEmail.length > 0 &&
3626
+ databaseConfig.privateKey.length > 0;
3627
+
3628
+ export const firebaseApp = getApps()[0] ?? initializeApp(
3629
+ credentialReady
3630
+ ? {
3631
+ credential: cert({
3632
+ projectId: databaseConfig.projectId,
3633
+ clientEmail: databaseConfig.clientEmail,
3634
+ privateKey: databaseConfig.privateKey,
3635
+ }),
3636
+ databaseURL: databaseConfig.databaseUrl || undefined,
3637
+ }
3638
+ : undefined
3639
+ );
3640
+
3641
+ export const firestore = getFirestore(firebaseApp);
3642
+ `;
3643
+ case "sqlite":
3644
+ return `import { Database } from "bun:sqlite";
3645
+ import { databaseConfig } from "../config/database.config";
3646
+
3647
+ export const db = new Database(databaseConfig.path, { create: true });
3648
+ `;
3649
+ case "redis":
3650
+ return `import Redis from "ioredis";
3651
+ import { databaseConfig } from "../config/database.config";
3652
+
3653
+ export const redis = databaseConfig.url ? new Redis(databaseConfig.url) : null;
3654
+ `;
3655
+ case "planetscale":
3656
+ return `import { connect } from "@planetscale/database";
3657
+ import { databaseConfig } from "../config/database.config";
3658
+
3659
+ export const connection = databaseConfig.url
3660
+ ? connect({ url: databaseConfig.url })
3661
+ : null;
3662
+ `;
3663
+ case "neon":
3664
+ return `import { neon } from "@neondatabase/serverless";
3665
+ import { databaseConfig } from "../config/database.config";
3666
+
3667
+ export const sql = databaseConfig.url ? neon(databaseConfig.url) : null;
3668
+ `;
3669
+ case "turso":
3670
+ return `import { createClient } from "@libsql/client";
3671
+ import { databaseConfig } from "../config/database.config";
3672
+
3673
+ export const db =
3674
+ databaseConfig.url && databaseConfig.authToken
3675
+ ? createClient({ url: databaseConfig.url, authToken: databaseConfig.authToken })
3676
+ : null;
3677
+ `;
3678
+ default:
3679
+ return `export const databaseClient = null;
3680
+ `;
3681
+ }
3682
+ }
3683
+ function getDatabaseEnvExample(selectedDatabase) {
3684
+ const baseEnv = `NODE_ENV=development
3685
+ PORT=4000
3686
+ CORS_ORIGIN=http://localhost:3000
3687
+ `;
3688
+ switch (selectedDatabase) {
3689
+ case "postgresql":
3690
+ return `${baseEnv}DATABASE_URL=postgresql://user:password@localhost:5432/dbname
3691
+ `;
3692
+ case "mysql":
3693
+ return `${baseEnv}DATABASE_URL=mysql://user:password@localhost:3306/dbname
3694
+ `;
3695
+ case "mariadb":
3696
+ return `${baseEnv}DATABASE_URL=mysql://user:password@localhost:3306/dbname
3697
+ `;
3698
+ case "mongodb":
3699
+ return `${baseEnv}DATABASE_URL=mongodb://localhost:27017/dbname
3700
+ `;
3701
+ case "firebase":
3702
+ return `${baseEnv}FIREBASE_PROJECT_ID=your-project-id
3703
+ FIREBASE_CLIENT_EMAIL=firebase-adminsdk@your-project.iam.gserviceaccount.com
3704
+ FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\\nyour-key\\n-----END PRIVATE KEY-----\\n"
3705
+ FIREBASE_DATABASE_URL=https://your-project.firebaseio.com
3706
+ `;
3707
+ case "sqlite":
3708
+ return `${baseEnv}DATABASE_PATH=./database.sqlite
3709
+ `;
3710
+ case "redis":
3711
+ return `${baseEnv}DATABASE_URL=redis://localhost:6379
3712
+ `;
3713
+ case "planetscale":
3714
+ return `${baseEnv}DATABASE_URL=mysql://user:password@aws.connect.psdb.cloud/dbname
3715
+ `;
3716
+ case "neon":
3717
+ return `${baseEnv}DATABASE_URL=postgresql://user:password@ep-xxx.neon.tech/neondb?sslmode=require
3718
+ `;
3719
+ case "turso":
3720
+ return `${baseEnv}TURSO_DATABASE_URL=libsql://your-db.turso.io
3721
+ TURSO_AUTH_TOKEN=your-auth-token
3722
+ `;
3723
+ default:
3724
+ return `${baseEnv}DATABASE_URL=
3725
+ `;
3726
+ }
3727
+ }
3728
+ function generateProjectReadme(projectConfig) {
3729
+ const { projectName, projectMode } = projectConfig;
3730
+ if (projectMode === "frontend-only") {
3731
+ return `# ${projectName}
3732
+
3733
+ Built with Rakta.js \u2014 Small in size. Fierce in speed. Alive in every route.
3734
+
3735
+ ## Stack
3736
+
3737
+ | Layer | Technology |
3738
+ | --- | --- |
3739
+ | Frontend | Rakta.js + React + TypeScript |
3740
+ | CSS | ${CSS_DISPLAY[projectConfig.cssFramework]} |
3741
+ | Runtime | Bun |
3742
+
3743
+ ## Run
3744
+
3745
+ \`\`\`bash
3746
+ bun install
3747
+ bun run dev
3748
+ \`\`\`
3749
+
3750
+ ## ShrimpRun
3751
+
3752
+ Your starter includes ShrimpRun \u2014 an interactive game where a shrimp dodges obstacles. Press Space or click to jump!
3753
+ `;
3754
+ }
3755
+ return `# ${projectName}
3756
+
3757
+ Built with Rakta.js \u2014 Small in size. Fierce in speed. Alive in every route.
3758
+
3759
+ ## Stack
3760
+
3761
+ | Layer | Technology |
3762
+ | --- | --- |
3763
+ | Frontend | Rakta.js + React + TypeScript |
3764
+ | CSS | ${CSS_DISPLAY[projectConfig.cssFramework]} |
3765
+ | Backend | ${BACKEND_DISPLAY[projectConfig.backendFramework]} |
3766
+ | Database | ${DATABASE_DISPLAY[projectConfig.database]} |
3767
+ | Runtime | Bun |
3768
+
3769
+ ## Run
3770
+
3771
+ \`\`\`bash
3772
+ bun install
3773
+
3774
+ # Terminal 1
3775
+ bun run dev:frontend
3776
+
3777
+ # Terminal 2
3778
+ bun run dev:backend
3779
+ \`\`\`
3780
+
3781
+ ## Endpoints
3782
+
3783
+ - Frontend: http://localhost:3000
3784
+ - Backend: http://localhost:4000
3785
+ `;
3786
+ }
3787
+ function generateProjectFiles(projectConfig) {
3788
+ if (projectConfig.projectMode === "frontend-only") {
3789
+ return [
3790
+ ...getRootFiles(projectConfig),
3791
+ ...getFrontendOnlyFiles(projectConfig)
3792
+ ];
3793
+ }
3794
+ return [
3795
+ ...getRootFiles(projectConfig),
3796
+ ...getFullstackFrontendFiles(projectConfig),
3797
+ ...getBackendFiles(projectConfig),
3798
+ ...getSharedFiles(projectConfig)
3799
+ ];
3800
+ }
3801
+
3802
+ // src/prompts.ts
3803
+ function getPromptValue(promptResult) {
3804
+ if (isCancel(promptResult)) {
3805
+ cancel("Setup cancelled.");
3806
+ process.exit(0);
3807
+ }
3808
+ return promptResult;
3809
+ }
3810
+ async function promptProjectName(fallbackName) {
3811
+ const promptResult = await text({
3812
+ message: "Project name:",
3813
+ placeholder: fallbackName,
3814
+ defaultValue: fallbackName,
3815
+ validate(inputValue) {
3816
+ const trimmedInput = (inputValue ?? "").trim();
3817
+ if (trimmedInput.length === 0) {
3818
+ return "Project name cannot be empty.";
3819
+ }
3820
+ if (!/^[a-z0-9-_]+$/i.test(trimmedInput)) {
3821
+ return "Use only letters, numbers, hyphens, and underscores.";
3822
+ }
3823
+ return;
3824
+ }
3825
+ });
3826
+ return getPromptValue(promptResult).trim();
3827
+ }
3828
+ async function promptProjectMode() {
3829
+ const promptResult = await select({
3830
+ message: "What do you want to create?",
3831
+ options: [
3832
+ {
3833
+ value: "frontend-only",
3834
+ label: PROJECT_MODE_DISPLAY["frontend-only"],
3835
+ hint: "recommended for starters"
3836
+ },
3837
+ {
3838
+ value: "fullstack",
3839
+ label: PROJECT_MODE_DISPLAY.fullstack
3840
+ }
3841
+ ],
3842
+ initialValue: "frontend-only"
3843
+ });
3844
+ return getPromptValue(promptResult);
3845
+ }
3846
+ async function promptCssFramework() {
3847
+ const promptResult = await select({
3848
+ message: "Choose a CSS framework:",
3849
+ options: [
3850
+ {
3851
+ value: "tailwind",
3852
+ label: CSS_DISPLAY.tailwind,
3853
+ hint: "recommended"
3854
+ },
3855
+ {
3856
+ value: "bootstrap",
3857
+ label: CSS_DISPLAY.bootstrap
3858
+ },
3859
+ {
3860
+ value: "sass",
3861
+ label: CSS_DISPLAY.sass
3862
+ },
3863
+ {
3864
+ value: "none",
3865
+ label: CSS_DISPLAY.none
3866
+ }
3867
+ ],
3868
+ initialValue: "tailwind"
3869
+ });
3870
+ return getPromptValue(promptResult);
3871
+ }
3872
+ async function promptRenderMode() {
3873
+ const promptResult = await select({
3874
+ message: "Choose a render mode:",
3875
+ options: [
3876
+ {
3877
+ value: "csr",
3878
+ label: RENDER_MODE_DISPLAY.csr,
3879
+ hint: "recommended"
3880
+ },
3881
+ {
3882
+ value: "spa",
3883
+ label: RENDER_MODE_DISPLAY.spa
3884
+ },
3885
+ {
3886
+ value: "hybrid",
3887
+ label: RENDER_MODE_DISPLAY.hybrid
3888
+ },
3889
+ {
3890
+ value: "ssr",
3891
+ label: RENDER_MODE_DISPLAY.ssr
3892
+ },
3893
+ {
3894
+ value: "ssg",
3895
+ label: RENDER_MODE_DISPLAY.ssg
3896
+ },
3897
+ {
3898
+ value: "csg",
3899
+ label: RENDER_MODE_DISPLAY.csg
3900
+ }
3901
+ ],
3902
+ initialValue: "csr"
3903
+ });
3904
+ return getPromptValue(promptResult);
3905
+ }
3906
+ async function promptBackendFramework() {
3907
+ const promptResult = await select({
3908
+ message: "Choose a backend framework:",
3909
+ options: [
3910
+ {
3911
+ value: "gaman",
3912
+ label: BACKEND_DISPLAY.gaman,
3913
+ hint: "recommended"
3914
+ },
3915
+ {
3916
+ value: "express",
3917
+ label: BACKEND_DISPLAY.express
3918
+ },
3919
+ {
3920
+ value: "nest",
3921
+ label: BACKEND_DISPLAY.nest
3922
+ },
3923
+ {
3924
+ value: "adonis",
3925
+ label: BACKEND_DISPLAY.adonis
3926
+ }
3927
+ ],
3928
+ initialValue: "gaman"
3929
+ });
3930
+ return getPromptValue(promptResult);
3931
+ }
3932
+ async function promptDatabase() {
3933
+ const promptResult = await select({
3934
+ message: "Choose a database:",
3935
+ options: [
3936
+ {
3937
+ value: "postgresql",
3938
+ label: DATABASE_DISPLAY.postgresql,
3939
+ hint: "recommended"
3940
+ },
3941
+ {
3942
+ value: "mysql",
3943
+ label: DATABASE_DISPLAY.mysql
3944
+ },
3945
+ {
3946
+ value: "mongodb",
3947
+ label: DATABASE_DISPLAY.mongodb
3948
+ },
3949
+ {
3950
+ value: "firebase",
3951
+ label: DATABASE_DISPLAY.firebase
3952
+ },
3953
+ {
3954
+ value: "sqlite",
3955
+ label: DATABASE_DISPLAY.sqlite
3956
+ },
3957
+ {
3958
+ value: "mariadb",
3959
+ label: DATABASE_DISPLAY.mariadb
3960
+ },
3961
+ {
3962
+ value: "redis",
3963
+ label: DATABASE_DISPLAY.redis
3964
+ },
3965
+ {
3966
+ value: "planetscale",
3967
+ label: DATABASE_DISPLAY.planetscale
3968
+ },
3969
+ {
3970
+ value: "neon",
3971
+ label: DATABASE_DISPLAY.neon
3972
+ },
3973
+ {
3974
+ value: "turso",
3975
+ label: DATABASE_DISPLAY.turso
3976
+ }
3977
+ ],
3978
+ initialValue: "postgresql"
3979
+ });
3980
+ return getPromptValue(promptResult);
3981
+ }
3982
+ async function runPrompts(suggestedName) {
3983
+ const projectName = await promptProjectName(suggestedName);
3984
+ const projectMode = await promptProjectMode();
3985
+ const cssFramework = await promptCssFramework();
3986
+ const renderMode = await promptRenderMode();
3987
+ if (projectMode === "frontend-only") {
3988
+ return {
3989
+ projectName,
3990
+ projectMode,
3991
+ cssFramework,
3992
+ renderMode,
3993
+ backendFramework: "gaman",
3994
+ database: "postgresql"
3995
+ };
3996
+ }
3997
+ const backendFramework = await promptBackendFramework();
3998
+ const selectedDatabase = await promptDatabase();
3999
+ return {
4000
+ projectName,
4001
+ projectMode,
4002
+ cssFramework,
4003
+ renderMode,
4004
+ backendFramework,
4005
+ database: selectedDatabase
4006
+ };
4007
+ }
4008
+
4009
+ // src/index.ts
4010
+ function getProjectNameFromArgs(cliArgs) {
4011
+ const nameArg = cliArgs.find((arg) => !arg.startsWith("--"));
4012
+ if (nameArg !== undefined && nameArg.trim().length > 0) {
4013
+ return nameArg.trim();
4014
+ }
4015
+ return;
4016
+ }
4017
+ function formatFullstackCommands() {
4018
+ return [
4019
+ `${import_picocolors.default.dim("# Terminal 1")}`,
4020
+ "cd frontend",
4021
+ "bun install",
4022
+ "bun run dev",
4023
+ "",
4024
+ `${import_picocolors.default.dim("# Terminal 2")}`,
4025
+ "cd backend",
4026
+ "bun install",
4027
+ "bun run dev"
4028
+ ].join(`
4029
+ `);
4030
+ }
4031
+ function formatFrontendOnlyCommands(projectName) {
4032
+ return [`cd ${projectName}`, "bun install", "bun run dev"].join(`
4033
+ `);
4034
+ }
4035
+ function printSuccessMessage(projectConfig) {
4036
+ const modeLabel = PROJECT_MODE_DISPLAY[projectConfig.projectMode];
4037
+ const cssLabel = CSS_DISPLAY[projectConfig.cssFramework];
4038
+ const renderLabel = RENDER_MODE_DISPLAY[projectConfig.renderMode];
4039
+ const isFullstack = projectConfig.projectMode === "fullstack";
4040
+ const backendLine = isFullstack ? `${import_picocolors.default.dim("Backend:")} ${BACKEND_DISPLAY[projectConfig.backendFramework]}` : "";
4041
+ const databaseLine = isFullstack ? `${import_picocolors.default.dim("DB:")} ${DATABASE_DISPLAY[projectConfig.database]}` : "";
4042
+ const nextSteps = isFullstack ? formatFullstackCommands() : formatFrontendOnlyCommands(projectConfig.projectName);
4043
+ console.log(`
4044
+ ${import_picocolors.default.bold(import_picocolors.default.green("Project created!"))}
4045
+
4046
+ ${import_picocolors.default.dim("Mode:")} ${modeLabel}
4047
+ ${import_picocolors.default.dim("CSS:")} ${cssLabel}
4048
+ ${import_picocolors.default.dim("Render:")} ${renderLabel}
4049
+ ${backendLine}
4050
+ ${databaseLine}
4051
+
4052
+ ${import_picocolors.default.bold("Next steps:")}
4053
+
4054
+ ${nextSteps}
4055
+
4056
+ ${import_picocolors.default.bold("Frontend:")} ${import_picocolors.default.cyan("http://localhost:3000")}
4057
+ ${isFullstack ? `${import_picocolors.default.bold("Backend:")} ${import_picocolors.default.cyan("http://localhost:4000")}` : ""}
4058
+ `);
4059
+ }
4060
+ async function main() {
4061
+ const rawArgs = process.argv.slice(2);
4062
+ printBanner();
4063
+ const projectNameFromArgs = getProjectNameFromArgs(rawArgs);
4064
+ const projectName = projectNameFromArgs ?? await promptProjectName("my-rakta-app");
4065
+ const targetPath = resolve2(process.cwd(), projectName);
4066
+ if (existsSync2(targetPath)) {
4067
+ cancel(`Directory ${import_picocolors.default.bold(import_picocolors.default.yellow(projectName))} already exists. Choose a different name.`);
4068
+ process.exit(1);
4069
+ }
4070
+ const projectConfig = await runPrompts(projectName);
4071
+ const loadingSpinner = spinner();
4072
+ loadingSpinner.start("Generating project files...");
4073
+ const generatedFiles = generateProjectFiles(projectConfig);
4074
+ try {
4075
+ writeProjectFiles(targetPath, generatedFiles);
4076
+ loadingSpinner.stop(import_picocolors.default.green("Project files generated."));
4077
+ } catch (caughtError) {
4078
+ loadingSpinner.stop(import_picocolors.default.red("File generation failed."));
4079
+ if (caughtError instanceof Error) {
4080
+ console.error(import_picocolors.default.red(caughtError.message));
4081
+ }
4082
+ process.exit(1);
4083
+ }
4084
+ printSuccessMessage(projectConfig);
4085
+ }
4086
+ main().catch((caughtError) => {
4087
+ const errorMessage = caughtError instanceof Error ? caughtError.message : String(caughtError);
4088
+ console.error(import_picocolors.default.red(`
4089
+ Error: ${errorMessage}
4090
+ `));
4091
+ process.exit(1);
4092
+ });
4093
+
4094
+ //# debugId=B9AF63AAAD27EC1C64756E2164756E21