create-morax 2.0.2 → 2.0.4
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 +440 -454
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,10 +4,36 @@
|
|
|
4
4
|
import pc29 from "picocolors";
|
|
5
5
|
|
|
6
6
|
// src/core/runner.ts
|
|
7
|
-
import
|
|
7
|
+
import path36 from "path";
|
|
8
8
|
import { spinner as spinner20 } from "@clack/prompts";
|
|
9
9
|
import pc28 from "picocolors";
|
|
10
10
|
|
|
11
|
+
// src/utils/cleanBunLock.ts
|
|
12
|
+
import fsPromises from "fs/promises";
|
|
13
|
+
import path from "path";
|
|
14
|
+
var BUN_LOCK_NAMES = ["bun.lock", "bun.lockb"];
|
|
15
|
+
async function removeBunLockfiles(...targetDirs) {
|
|
16
|
+
for (const dir of targetDirs) {
|
|
17
|
+
if (!dir) continue;
|
|
18
|
+
const pathsToCheck = [
|
|
19
|
+
dir,
|
|
20
|
+
path.join(dir, "apps"),
|
|
21
|
+
path.join(dir, "apps", "web")
|
|
22
|
+
];
|
|
23
|
+
for (const targetPath of pathsToCheck) {
|
|
24
|
+
for (const lockFileName of BUN_LOCK_NAMES) {
|
|
25
|
+
try {
|
|
26
|
+
await fsPromises.rm(path.join(targetPath, lockFileName), {
|
|
27
|
+
force: true,
|
|
28
|
+
recursive: true
|
|
29
|
+
});
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
11
37
|
// src/core/startcli.ts
|
|
12
38
|
import gradient from "gradient-string";
|
|
13
39
|
import pc from "picocolors";
|
|
@@ -44,7 +70,7 @@ function startCli() {
|
|
|
44
70
|
// src/core/preflight.ts
|
|
45
71
|
import ora from "ora";
|
|
46
72
|
import pc3 from "picocolors";
|
|
47
|
-
import
|
|
73
|
+
import fsPromises2 from "fs/promises";
|
|
48
74
|
|
|
49
75
|
// src/utils/exec.ts
|
|
50
76
|
import { exec, spawn } from "child_process";
|
|
@@ -52,14 +78,18 @@ import { promisify } from "util";
|
|
|
52
78
|
import pc2 from "picocolors";
|
|
53
79
|
var execAsync = promisify(exec);
|
|
54
80
|
async function runCommand(command, options = {}) {
|
|
55
|
-
const isSilent = options.silent ??
|
|
81
|
+
const isSilent = options.silent ?? true;
|
|
56
82
|
if (!isSilent) {
|
|
57
83
|
console.log(pc2.cyan(`> ${command}`));
|
|
58
84
|
}
|
|
59
85
|
try {
|
|
60
86
|
const { stdout, stderr } = await execAsync(command, {
|
|
61
87
|
cwd: options.cwd,
|
|
62
|
-
env: {
|
|
88
|
+
env: {
|
|
89
|
+
...process.env,
|
|
90
|
+
NODE_NO_WARNINGS: "1",
|
|
91
|
+
NODE_OPTIONS: `${process.env.NODE_OPTIONS || ""} --no-deprecation`.trim()
|
|
92
|
+
}
|
|
63
93
|
});
|
|
64
94
|
if (!isSilent) {
|
|
65
95
|
if (stdout && stdout.trim()) {
|
|
@@ -88,11 +118,15 @@ ${error.stderr.trim()}`;
|
|
|
88
118
|
function runInteractiveCommand(command, args, cwd) {
|
|
89
119
|
return new Promise((resolve, reject) => {
|
|
90
120
|
const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
|
|
91
|
-
const child = spawn(fullCommand,
|
|
121
|
+
const child = spawn(fullCommand, {
|
|
92
122
|
cwd,
|
|
93
123
|
stdio: "inherit",
|
|
94
124
|
shell: true,
|
|
95
|
-
env: {
|
|
125
|
+
env: {
|
|
126
|
+
...process.env,
|
|
127
|
+
NODE_NO_WARNINGS: "1",
|
|
128
|
+
NODE_OPTIONS: `${process.env.NODE_OPTIONS || ""} --no-deprecation`.trim()
|
|
129
|
+
}
|
|
96
130
|
});
|
|
97
131
|
child.on("close", (code) => {
|
|
98
132
|
if (code === 0) {
|
|
@@ -179,7 +213,7 @@ async function runPreflightChecks() {
|
|
|
179
213
|
color: "cyan"
|
|
180
214
|
}).start();
|
|
181
215
|
await sleep(150);
|
|
182
|
-
let bunVersion =
|
|
216
|
+
let bunVersion = "";
|
|
183
217
|
try {
|
|
184
218
|
const { stdout } = await runCommand("bun --version", { silent: true });
|
|
185
219
|
bunVersion = stdout.trim();
|
|
@@ -192,9 +226,19 @@ async function runPreflightChecks() {
|
|
|
192
226
|
});
|
|
193
227
|
} catch {
|
|
194
228
|
bunSpinner.stopAndPersist({
|
|
195
|
-
symbol:
|
|
196
|
-
text:
|
|
229
|
+
symbol: cross,
|
|
230
|
+
text: "Verifying Bun runtime. Not found."
|
|
197
231
|
});
|
|
232
|
+
console.log(
|
|
233
|
+
"\n" + pc3.red(
|
|
234
|
+
"\u2716 Error: Bun is required to scaffold and execute high-performance Morax apps.\n"
|
|
235
|
+
) + pc3.cyan(" \u2022 Install Bun: https://bun.sh\n") + pc3.cyan(
|
|
236
|
+
' \u2022 Windows: powershell -c "irm bun.sh/install.ps1 | iex"\n'
|
|
237
|
+
) + pc3.cyan(
|
|
238
|
+
" \u2022 macOS / Linux: curl -fsSL https://bun.sh/install | bash\n"
|
|
239
|
+
)
|
|
240
|
+
);
|
|
241
|
+
process.exit(1);
|
|
198
242
|
}
|
|
199
243
|
const dockerSpinner = ora({
|
|
200
244
|
text: "Verifying Docker installation...",
|
|
@@ -247,7 +291,7 @@ async function runPreflightChecks() {
|
|
|
247
291
|
}
|
|
248
292
|
async function checkTargetDirectory(projectPath, name) {
|
|
249
293
|
try {
|
|
250
|
-
const files = await
|
|
294
|
+
const files = await fsPromises2.readdir(projectPath);
|
|
251
295
|
if (files.length > 0) {
|
|
252
296
|
console.log(
|
|
253
297
|
"\n" + pc3.red(
|
|
@@ -313,8 +357,8 @@ import { select as select2 } from "@clack/prompts";
|
|
|
313
357
|
// src/modules/packages/db/drizzle.ts
|
|
314
358
|
import { select, spinner } from "@clack/prompts";
|
|
315
359
|
import pc5 from "picocolors";
|
|
316
|
-
import
|
|
317
|
-
import
|
|
360
|
+
import fsPromises3 from "fs/promises";
|
|
361
|
+
import path2 from "path";
|
|
318
362
|
async function promptDrizzle() {
|
|
319
363
|
const dialectChoice = await select({
|
|
320
364
|
message: "Which database dialect would you like to use with Drizzle?",
|
|
@@ -379,15 +423,15 @@ async function promptDrizzle() {
|
|
|
379
423
|
return { dialect };
|
|
380
424
|
}
|
|
381
425
|
async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none", postgresProvider = "docker", neonMode = "serverless") {
|
|
382
|
-
const dbDir =
|
|
383
|
-
const srcDir =
|
|
384
|
-
const schemaDir =
|
|
385
|
-
const seedDir =
|
|
386
|
-
await
|
|
387
|
-
await
|
|
426
|
+
const dbDir = path2.join(projectPath, "packages", "db");
|
|
427
|
+
const srcDir = path2.join(dbDir, "src");
|
|
428
|
+
const schemaDir = path2.join(srcDir, "schema");
|
|
429
|
+
const seedDir = path2.join(srcDir, "seed");
|
|
430
|
+
await fsPromises3.mkdir(schemaDir, { recursive: true });
|
|
431
|
+
await fsPromises3.mkdir(seedDir, { recursive: true });
|
|
388
432
|
await runCommand("pnpm init", { cwd: dbDir, silent: true });
|
|
389
|
-
const dbPackagePath =
|
|
390
|
-
const dbPackageRaw = await
|
|
433
|
+
const dbPackagePath = path2.join(dbDir, "package.json");
|
|
434
|
+
const dbPackageRaw = await fsPromises3.readFile(dbPackagePath, "utf8");
|
|
391
435
|
const dbPkg = JSON.parse(dbPackageRaw);
|
|
392
436
|
const providerLabel = dialect === "sqlite" ? "SQLite" : postgresProvider === "neon" ? `PostgreSQL (Neon ${neonMode === "pool" ? "Pool" : "Serverless"})` : "PostgreSQL (Docker)";
|
|
393
437
|
dbPkg.name = "@repo/db";
|
|
@@ -427,7 +471,7 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
427
471
|
delete dbPkg.keywords;
|
|
428
472
|
delete dbPkg.author;
|
|
429
473
|
delete dbPkg.license;
|
|
430
|
-
await
|
|
474
|
+
await fsPromises3.writeFile(
|
|
431
475
|
dbPackagePath,
|
|
432
476
|
JSON.stringify(dbPkg, null, 2),
|
|
433
477
|
"utf8"
|
|
@@ -442,35 +486,35 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
442
486
|
},
|
|
443
487
|
include: ["src/**/*", "drizzle.config.ts"]
|
|
444
488
|
};
|
|
445
|
-
await
|
|
446
|
-
|
|
489
|
+
await fsPromises3.writeFile(
|
|
490
|
+
path2.join(dbDir, "tsconfig.json"),
|
|
447
491
|
JSON.stringify(tsconfigContent, null, 2),
|
|
448
492
|
"utf8"
|
|
449
493
|
);
|
|
450
494
|
if (dialect === "sqlite") {
|
|
451
495
|
await runCommand("pnpm add drizzle-orm@rc @libsql/client dotenv", {
|
|
452
496
|
cwd: dbDir,
|
|
453
|
-
silent:
|
|
497
|
+
silent: true
|
|
454
498
|
});
|
|
455
499
|
} else if (postgresProvider === "neon") {
|
|
456
500
|
await runCommand(
|
|
457
501
|
"pnpm add drizzle-orm@rc @neondatabase/serverless dotenv",
|
|
458
502
|
{
|
|
459
503
|
cwd: dbDir,
|
|
460
|
-
silent:
|
|
504
|
+
silent: true
|
|
461
505
|
}
|
|
462
506
|
);
|
|
463
507
|
} else {
|
|
464
508
|
await runCommand("pnpm add drizzle-orm@rc pg dotenv @types/pg", {
|
|
465
509
|
cwd: dbDir,
|
|
466
|
-
silent:
|
|
510
|
+
silent: true
|
|
467
511
|
});
|
|
468
512
|
}
|
|
469
513
|
await runCommand(
|
|
470
514
|
"pnpm add -D drizzle-kit@rc @types/node tsx typescript@latest",
|
|
471
515
|
{
|
|
472
516
|
cwd: dbDir,
|
|
473
|
-
silent:
|
|
517
|
+
silent: true
|
|
474
518
|
}
|
|
475
519
|
);
|
|
476
520
|
const envVar = dialect === "sqlite" ? "DB_FILE_NAME" : "DATABASE_URL";
|
|
@@ -499,8 +543,8 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
499
543
|
"});",
|
|
500
544
|
""
|
|
501
545
|
].join("\n");
|
|
502
|
-
await
|
|
503
|
-
|
|
546
|
+
await fsPromises3.writeFile(
|
|
547
|
+
path2.join(dbDir, "drizzle.config.ts"),
|
|
504
548
|
drizzleConfigContent,
|
|
505
549
|
"utf8"
|
|
506
550
|
);
|
|
@@ -542,8 +586,8 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
542
586
|
""
|
|
543
587
|
].join("\n");
|
|
544
588
|
}
|
|
545
|
-
await
|
|
546
|
-
|
|
589
|
+
await fsPromises3.writeFile(
|
|
590
|
+
path2.join(schemaDir, "index.ts"),
|
|
547
591
|
schemaContent,
|
|
548
592
|
"utf8"
|
|
549
593
|
);
|
|
@@ -653,8 +697,8 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
653
697
|
""
|
|
654
698
|
].join("\n");
|
|
655
699
|
}
|
|
656
|
-
await
|
|
657
|
-
|
|
700
|
+
await fsPromises3.writeFile(
|
|
701
|
+
path2.join(srcDir, "client.ts"),
|
|
658
702
|
clientContent,
|
|
659
703
|
"utf8"
|
|
660
704
|
);
|
|
@@ -672,8 +716,8 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
672
716
|
"export * from 'drizzle-orm';",
|
|
673
717
|
""
|
|
674
718
|
].join("\n");
|
|
675
|
-
await
|
|
676
|
-
|
|
719
|
+
await fsPromises3.writeFile(
|
|
720
|
+
path2.join(srcDir, "index.ts"),
|
|
677
721
|
indexContent,
|
|
678
722
|
"utf8"
|
|
679
723
|
);
|
|
@@ -725,14 +769,14 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
725
769
|
"});",
|
|
726
770
|
""
|
|
727
771
|
].join("\n");
|
|
728
|
-
await
|
|
729
|
-
|
|
772
|
+
await fsPromises3.writeFile(
|
|
773
|
+
path2.join(seedDir, "seed.ts"),
|
|
730
774
|
seedScriptContent,
|
|
731
775
|
"utf8"
|
|
732
776
|
);
|
|
733
777
|
const seedIndexContent = ["export { seed } from './seed.js';", ""].join("\n");
|
|
734
|
-
await
|
|
735
|
-
|
|
778
|
+
await fsPromises3.writeFile(
|
|
779
|
+
path2.join(seedDir, "index.ts"),
|
|
736
780
|
seedIndexContent,
|
|
737
781
|
"utf8"
|
|
738
782
|
);
|
|
@@ -745,8 +789,8 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
745
789
|
"*.db-journal",
|
|
746
790
|
""
|
|
747
791
|
].join("\n");
|
|
748
|
-
await
|
|
749
|
-
|
|
792
|
+
await fsPromises3.writeFile(
|
|
793
|
+
path2.join(dbDir, ".gitignore"),
|
|
750
794
|
gitignoreContent,
|
|
751
795
|
"utf8"
|
|
752
796
|
);
|
|
@@ -773,16 +817,16 @@ async function setupDrizzle(projectPath, dialect = "postgresql", linter = "none"
|
|
|
773
817
|
"- `pnpm db:check` \u2014 Check migration history and verify consistency.",
|
|
774
818
|
""
|
|
775
819
|
].filter(Boolean).join("\n");
|
|
776
|
-
await
|
|
777
|
-
|
|
820
|
+
await fsPromises3.writeFile(
|
|
821
|
+
path2.join(dbDir, "README.md"),
|
|
778
822
|
readmeContent,
|
|
779
823
|
"utf8"
|
|
780
824
|
);
|
|
781
825
|
}
|
|
782
826
|
async function runDrizzleSetup(projectPath, dialect = "postgresql", linter = "none", postgresProvider = "docker", neonMode = "serverless") {
|
|
783
|
-
const packagesDir =
|
|
827
|
+
const packagesDir = path2.join(projectPath, "packages");
|
|
784
828
|
try {
|
|
785
|
-
await
|
|
829
|
+
await fsPromises3.access(packagesDir);
|
|
786
830
|
} catch {
|
|
787
831
|
return;
|
|
788
832
|
}
|
|
@@ -1043,43 +1087,17 @@ ${pc6.bold("Database commands (packages/db - Drizzle ORM):")}
|
|
|
1043
1087
|
}
|
|
1044
1088
|
|
|
1045
1089
|
// src/standalone/react-runner.ts
|
|
1046
|
-
import
|
|
1090
|
+
import path6 from "path";
|
|
1047
1091
|
import { spinner as spinner4 } from "@clack/prompts";
|
|
1048
1092
|
import pc9 from "picocolors";
|
|
1049
1093
|
|
|
1050
1094
|
// src/modules/apps/web/react.ts
|
|
1051
1095
|
import pc7 from "picocolors";
|
|
1052
|
-
import
|
|
1053
|
-
import
|
|
1054
|
-
import { spawn as spawn2 } from "child_process";
|
|
1096
|
+
import fsPromises4 from "fs/promises";
|
|
1097
|
+
import path3 from "path";
|
|
1055
1098
|
import { confirm, spinner as spinner2, text as text2 } from "@clack/prompts";
|
|
1056
|
-
function runInteractiveCommand2(command, args, cwd) {
|
|
1057
|
-
return new Promise((resolve, reject) => {
|
|
1058
|
-
const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
|
|
1059
|
-
const child = spawn2(fullCommand, [], {
|
|
1060
|
-
cwd,
|
|
1061
|
-
stdio: "inherit",
|
|
1062
|
-
shell: true,
|
|
1063
|
-
env: { ...process.env, NODE_NO_WARNINGS: "1" }
|
|
1064
|
-
});
|
|
1065
|
-
child.on("close", (code) => {
|
|
1066
|
-
if (code === 0) {
|
|
1067
|
-
resolve();
|
|
1068
|
-
} else {
|
|
1069
|
-
reject(
|
|
1070
|
-
new Error(
|
|
1071
|
-
`Command "${command} ${args.join(" ")}" exited with code ${code}`
|
|
1072
|
-
)
|
|
1073
|
-
);
|
|
1074
|
-
}
|
|
1075
|
-
});
|
|
1076
|
-
child.on("error", (err) => {
|
|
1077
|
-
reject(err);
|
|
1078
|
-
});
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
1099
|
async function setupReact(projectPath, isMonorepo = true) {
|
|
1082
|
-
const appsDir = isMonorepo ?
|
|
1100
|
+
const appsDir = isMonorepo ? path3.join(projectPath, "apps") : path3.dirname(projectPath);
|
|
1083
1101
|
console.log(pc7.magentaBright("\n\u{1F537} IMPORTANT INSTRUCTIONS:"));
|
|
1084
1102
|
console.log(
|
|
1085
1103
|
pc7.magentaBright(
|
|
@@ -1101,14 +1119,14 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1101
1119
|
);
|
|
1102
1120
|
let beforeDirs = [];
|
|
1103
1121
|
try {
|
|
1104
|
-
beforeDirs = await
|
|
1122
|
+
beforeDirs = await fsPromises4.readdir(appsDir);
|
|
1105
1123
|
} catch {
|
|
1106
1124
|
}
|
|
1107
1125
|
try {
|
|
1108
|
-
await
|
|
1126
|
+
await runInteractiveCommand("bunx", ["create-vite@latest"], appsDir);
|
|
1109
1127
|
let afterDirs = [];
|
|
1110
1128
|
try {
|
|
1111
|
-
afterDirs = await
|
|
1129
|
+
afterDirs = await fsPromises4.readdir(appsDir);
|
|
1112
1130
|
} catch {
|
|
1113
1131
|
}
|
|
1114
1132
|
const newDirs = afterDirs.filter((d) => !beforeDirs.includes(d));
|
|
@@ -1116,17 +1134,18 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1116
1134
|
if (newDirs.length > 0) {
|
|
1117
1135
|
createdDirName = newDirs[0];
|
|
1118
1136
|
}
|
|
1119
|
-
const webDir =
|
|
1137
|
+
const webDir = path3.join(appsDir, createdDirName);
|
|
1120
1138
|
try {
|
|
1121
|
-
await
|
|
1139
|
+
await fsPromises4.access(webDir);
|
|
1122
1140
|
} catch {
|
|
1123
1141
|
throw new Error(
|
|
1124
1142
|
`Vite React application directory "apps/${createdDirName}" was not found. Please ensure you complete the Vite installation.`
|
|
1125
1143
|
);
|
|
1126
1144
|
}
|
|
1127
|
-
|
|
1145
|
+
await removeBunLockfiles(webDir, projectPath);
|
|
1146
|
+
const pkgPath = path3.join(webDir, "package.json");
|
|
1128
1147
|
try {
|
|
1129
|
-
const pkgRaw = await
|
|
1148
|
+
const pkgRaw = await fsPromises4.readFile(pkgPath, "utf8");
|
|
1130
1149
|
const pkg = JSON.parse(pkgRaw);
|
|
1131
1150
|
if (isMonorepo) {
|
|
1132
1151
|
pkg.name = "web";
|
|
@@ -1136,7 +1155,7 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1136
1155
|
onlyBuiltDependencies: ["esbuild"]
|
|
1137
1156
|
};
|
|
1138
1157
|
}
|
|
1139
|
-
await
|
|
1158
|
+
await fsPromises4.writeFile(pkgPath, JSON.stringify(pkg, null, 2), "utf8");
|
|
1140
1159
|
} catch {
|
|
1141
1160
|
}
|
|
1142
1161
|
const aliasSpinner = spinner2();
|
|
@@ -1147,12 +1166,12 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1147
1166
|
silent: true
|
|
1148
1167
|
});
|
|
1149
1168
|
const tsconfigPaths = [
|
|
1150
|
-
|
|
1151
|
-
|
|
1169
|
+
path3.join(webDir, "tsconfig.json"),
|
|
1170
|
+
path3.join(webDir, "tsconfig.app.json")
|
|
1152
1171
|
];
|
|
1153
1172
|
for (const tsPath of tsconfigPaths) {
|
|
1154
1173
|
try {
|
|
1155
|
-
let content = await
|
|
1174
|
+
let content = await fsPromises4.readFile(tsPath, "utf8");
|
|
1156
1175
|
if (content.includes('"compilerOptions"')) {
|
|
1157
1176
|
if (!content.includes('"paths"')) {
|
|
1158
1177
|
content = content.replace(
|
|
@@ -1163,7 +1182,7 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1163
1182
|
"@/*": ["./src/*"]
|
|
1164
1183
|
},`
|
|
1165
1184
|
);
|
|
1166
|
-
await
|
|
1185
|
+
await fsPromises4.writeFile(tsPath, content, "utf8");
|
|
1167
1186
|
}
|
|
1168
1187
|
} else {
|
|
1169
1188
|
content = content.replace(
|
|
@@ -1176,14 +1195,14 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1176
1195
|
}
|
|
1177
1196
|
},`
|
|
1178
1197
|
);
|
|
1179
|
-
await
|
|
1198
|
+
await fsPromises4.writeFile(tsPath, content, "utf8");
|
|
1180
1199
|
}
|
|
1181
1200
|
} catch {
|
|
1182
1201
|
}
|
|
1183
1202
|
}
|
|
1184
|
-
const viteConfigPath =
|
|
1203
|
+
const viteConfigPath = path3.join(webDir, "vite.config.ts");
|
|
1185
1204
|
try {
|
|
1186
|
-
let content = await
|
|
1205
|
+
let content = await fsPromises4.readFile(viteConfigPath, "utf8");
|
|
1187
1206
|
if (!content.includes("import path from 'path'")) {
|
|
1188
1207
|
content = "import path from 'path';\n" + content;
|
|
1189
1208
|
}
|
|
@@ -1198,7 +1217,7 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1198
1217
|
}`
|
|
1199
1218
|
);
|
|
1200
1219
|
}
|
|
1201
|
-
await
|
|
1220
|
+
await fsPromises4.writeFile(viteConfigPath, content, "utf8");
|
|
1202
1221
|
} catch {
|
|
1203
1222
|
}
|
|
1204
1223
|
aliasSpinner.stop(
|
|
@@ -1242,9 +1261,9 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1242
1261
|
silent: true
|
|
1243
1262
|
});
|
|
1244
1263
|
s.message("Configuring Vite plugins and Tailwind CSS imports...");
|
|
1245
|
-
const viteConfigPath =
|
|
1264
|
+
const viteConfigPath = path3.join(webDir, "vite.config.ts");
|
|
1246
1265
|
try {
|
|
1247
|
-
let content = await
|
|
1266
|
+
let content = await fsPromises4.readFile(viteConfigPath, "utf8");
|
|
1248
1267
|
const hasReactCompiler = content.includes("reactCompilerPreset") || content.includes("@rolldown/plugin-babel") || content.includes("babel({");
|
|
1249
1268
|
if (hasReactCompiler) {
|
|
1250
1269
|
content = [
|
|
@@ -1271,7 +1290,7 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1271
1290
|
"});",
|
|
1272
1291
|
""
|
|
1273
1292
|
].join("\n");
|
|
1274
|
-
await
|
|
1293
|
+
await fsPromises4.writeFile(viteConfigPath, content, "utf8");
|
|
1275
1294
|
} else if (!content.includes("@tailwindcss/vite")) {
|
|
1276
1295
|
content = "import tailwindcss from '@tailwindcss/vite';\n" + content;
|
|
1277
1296
|
if (content.includes("plugins: [react()]")) {
|
|
@@ -1290,13 +1309,13 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1290
1309
|
"$1\n tailwindcss(),\n $2"
|
|
1291
1310
|
);
|
|
1292
1311
|
}
|
|
1293
|
-
await
|
|
1312
|
+
await fsPromises4.writeFile(viteConfigPath, content, "utf8");
|
|
1294
1313
|
}
|
|
1295
1314
|
} catch {
|
|
1296
1315
|
}
|
|
1297
|
-
const indexCssPath =
|
|
1316
|
+
const indexCssPath = path3.join(webDir, "src", "index.css");
|
|
1298
1317
|
try {
|
|
1299
|
-
await
|
|
1318
|
+
await fsPromises4.writeFile(
|
|
1300
1319
|
indexCssPath,
|
|
1301
1320
|
'@import "tailwindcss";\n',
|
|
1302
1321
|
"utf8"
|
|
@@ -1330,7 +1349,7 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1330
1349
|
handleCancel(enteredPreset);
|
|
1331
1350
|
presetCode = enteredPreset.trim();
|
|
1332
1351
|
}
|
|
1333
|
-
const args = ["
|
|
1352
|
+
const args = ["shadcn@latest", "init"];
|
|
1334
1353
|
if (presetCode) {
|
|
1335
1354
|
args.push("--preset", presetCode);
|
|
1336
1355
|
}
|
|
@@ -1338,7 +1357,8 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1338
1357
|
console.log(
|
|
1339
1358
|
pc7.cyan("\nStarting interactive shadcn UI initialization...")
|
|
1340
1359
|
);
|
|
1341
|
-
await
|
|
1360
|
+
await runInteractiveCommand("bunx", args, webDir);
|
|
1361
|
+
await removeBunLockfiles(webDir, projectPath);
|
|
1342
1362
|
console.log(
|
|
1343
1363
|
pc7.green(
|
|
1344
1364
|
isMonorepo ? `
|
|
@@ -1362,8 +1382,8 @@ async function setupReact(projectPath, isMonorepo = true) {
|
|
|
1362
1382
|
// src/modules/git/git.ts
|
|
1363
1383
|
import { confirm as confirm2, spinner as spinner3 } from "@clack/prompts";
|
|
1364
1384
|
import pc8 from "picocolors";
|
|
1365
|
-
import
|
|
1366
|
-
import
|
|
1385
|
+
import fsPromises5 from "fs/promises";
|
|
1386
|
+
import path4 from "path";
|
|
1367
1387
|
async function promptGit() {
|
|
1368
1388
|
return await confirm2({
|
|
1369
1389
|
message: "Do you want to initialize a local Git repository?",
|
|
@@ -1408,8 +1428,8 @@ async function gitInit(projectPath) {
|
|
|
1408
1428
|
"Thumbs.db",
|
|
1409
1429
|
""
|
|
1410
1430
|
].join("\n");
|
|
1411
|
-
await
|
|
1412
|
-
|
|
1431
|
+
await fsPromises5.writeFile(
|
|
1432
|
+
path4.join(projectPath, ".gitignore"),
|
|
1413
1433
|
gitignore,
|
|
1414
1434
|
"utf8"
|
|
1415
1435
|
);
|
|
@@ -1436,10 +1456,10 @@ Error details: ${error.message || error}`));
|
|
|
1436
1456
|
}
|
|
1437
1457
|
|
|
1438
1458
|
// src/modules/workspace/readme.ts
|
|
1439
|
-
import
|
|
1440
|
-
import
|
|
1459
|
+
import fsPromises6 from "fs/promises";
|
|
1460
|
+
import path5 from "path";
|
|
1441
1461
|
async function setupReadme(projectPath, workspaceName, options = {}) {
|
|
1442
|
-
const readmePath =
|
|
1462
|
+
const readmePath = path5.join(projectPath, "README.md");
|
|
1443
1463
|
let dockerDocs = [];
|
|
1444
1464
|
if (options.hasDocker) {
|
|
1445
1465
|
if (options.hasDockerScripts) {
|
|
@@ -1558,14 +1578,15 @@ async function setupReadme(projectPath, workspaceName, options = {}) {
|
|
|
1558
1578
|
"*Generated with love by [Morax Scaffolder CLI](https://github.com/Elitedv/morax).*",
|
|
1559
1579
|
""
|
|
1560
1580
|
].join("\n");
|
|
1561
|
-
await
|
|
1581
|
+
await fsPromises6.writeFile(readmePath, readmeContent, "utf8");
|
|
1562
1582
|
}
|
|
1563
1583
|
|
|
1564
1584
|
// src/standalone/react-runner.ts
|
|
1565
1585
|
async function runReactScaffolder(name, projectPath) {
|
|
1566
1586
|
const finalProjectPath = await setupReact(projectPath, false);
|
|
1567
|
-
await setupReadme(finalProjectPath,
|
|
1587
|
+
await setupReadme(finalProjectPath, path6.basename(finalProjectPath));
|
|
1568
1588
|
await runGitSetup(finalProjectPath);
|
|
1589
|
+
await removeBunLockfiles(finalProjectPath);
|
|
1569
1590
|
const installSpinner = spinner4();
|
|
1570
1591
|
installSpinner.start("Running final package installation...");
|
|
1571
1592
|
try {
|
|
@@ -1578,67 +1599,46 @@ async function runReactScaffolder(name, projectPath) {
|
|
|
1578
1599
|
console.error(pc9.red(`
|
|
1579
1600
|
Error details: ${error.message || error}`));
|
|
1580
1601
|
}
|
|
1581
|
-
endCli(
|
|
1602
|
+
endCli(path6.basename(finalProjectPath), finalProjectPath);
|
|
1582
1603
|
}
|
|
1583
1604
|
|
|
1584
1605
|
// src/standalone/next-runner.ts
|
|
1585
|
-
import
|
|
1606
|
+
import path9 from "path";
|
|
1586
1607
|
import { spinner as spinner5 } from "@clack/prompts";
|
|
1587
1608
|
import pc12 from "picocolors";
|
|
1588
1609
|
|
|
1589
1610
|
// src/modules/apps/web/nextjs.ts
|
|
1590
1611
|
import { confirm as confirm3 } from "@clack/prompts";
|
|
1591
1612
|
import pc10 from "picocolors";
|
|
1592
|
-
import
|
|
1593
|
-
import
|
|
1594
|
-
import { spawn as spawn3 } from "child_process";
|
|
1595
|
-
function runInteractiveCommand3(command, args, cwd) {
|
|
1596
|
-
return new Promise((resolve, reject) => {
|
|
1597
|
-
const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
|
|
1598
|
-
const child = spawn3(fullCommand, [], {
|
|
1599
|
-
cwd,
|
|
1600
|
-
stdio: "inherit",
|
|
1601
|
-
shell: true,
|
|
1602
|
-
env: { ...process.env, NODE_NO_WARNINGS: "1" }
|
|
1603
|
-
});
|
|
1604
|
-
child.on("close", (code) => {
|
|
1605
|
-
if (code === 0) {
|
|
1606
|
-
resolve();
|
|
1607
|
-
} else {
|
|
1608
|
-
reject(new Error(`Command "${fullCommand}" exited with code ${code}`));
|
|
1609
|
-
}
|
|
1610
|
-
});
|
|
1611
|
-
child.on("error", (err) => {
|
|
1612
|
-
reject(err);
|
|
1613
|
-
});
|
|
1614
|
-
});
|
|
1615
|
-
}
|
|
1613
|
+
import fsPromises7 from "fs/promises";
|
|
1614
|
+
import path7 from "path";
|
|
1616
1615
|
async function setupNextjs(projectPath, isMonorepo = true) {
|
|
1617
|
-
const appsDir = isMonorepo ?
|
|
1618
|
-
const targetName = isMonorepo ? "web" :
|
|
1619
|
-
const webDir =
|
|
1616
|
+
const appsDir = isMonorepo ? path7.join(projectPath, "apps") : path7.dirname(projectPath);
|
|
1617
|
+
const targetName = isMonorepo ? "web" : path7.basename(projectPath);
|
|
1618
|
+
const webDir = path7.join(appsDir, targetName);
|
|
1620
1619
|
try {
|
|
1621
|
-
await
|
|
1620
|
+
await fsPromises7.rm(webDir, { recursive: true, force: true });
|
|
1622
1621
|
} catch {
|
|
1623
1622
|
}
|
|
1624
1623
|
console.log(pc10.cyan("\nStarting interactive Next.js application setup..."));
|
|
1625
|
-
await
|
|
1626
|
-
"
|
|
1627
|
-
["
|
|
1624
|
+
await runInteractiveCommand(
|
|
1625
|
+
"bunx",
|
|
1626
|
+
["create-next-app@latest", targetName],
|
|
1628
1627
|
appsDir
|
|
1629
1628
|
);
|
|
1629
|
+
await removeBunLockfiles(webDir, projectPath);
|
|
1630
1630
|
if (isMonorepo) {
|
|
1631
1631
|
try {
|
|
1632
|
-
await
|
|
1632
|
+
await fsPromises7.rm(path7.join(webDir, ".git"), {
|
|
1633
1633
|
recursive: true,
|
|
1634
1634
|
force: true
|
|
1635
1635
|
});
|
|
1636
1636
|
} catch {
|
|
1637
1637
|
}
|
|
1638
1638
|
}
|
|
1639
|
-
const webPkgPath =
|
|
1639
|
+
const webPkgPath = path7.join(webDir, "package.json");
|
|
1640
1640
|
try {
|
|
1641
|
-
const webPkgRaw = await
|
|
1641
|
+
const webPkgRaw = await fsPromises7.readFile(webPkgPath, "utf8");
|
|
1642
1642
|
const webPkg = JSON.parse(webPkgRaw);
|
|
1643
1643
|
if (isMonorepo) {
|
|
1644
1644
|
webPkg.name = "web";
|
|
@@ -1648,7 +1648,7 @@ async function setupNextjs(projectPath, isMonorepo = true) {
|
|
|
1648
1648
|
onlyBuiltDependencies: ["sharp"]
|
|
1649
1649
|
};
|
|
1650
1650
|
}
|
|
1651
|
-
await
|
|
1651
|
+
await fsPromises7.writeFile(
|
|
1652
1652
|
webPkgPath,
|
|
1653
1653
|
JSON.stringify(webPkg, null, 2),
|
|
1654
1654
|
"utf8"
|
|
@@ -1661,52 +1661,28 @@ async function setupNextjs(projectPath, isMonorepo = true) {
|
|
|
1661
1661
|
// src/modules/apps/web/shadcn.ts
|
|
1662
1662
|
import { confirm as confirm4 } from "@clack/prompts";
|
|
1663
1663
|
import pc11 from "picocolors";
|
|
1664
|
-
import
|
|
1665
|
-
import
|
|
1666
|
-
import { spawn as spawn4 } from "child_process";
|
|
1664
|
+
import fsPromises8 from "fs/promises";
|
|
1665
|
+
import path8 from "path";
|
|
1667
1666
|
async function promptShadcn() {
|
|
1668
1667
|
return await confirm4({
|
|
1669
1668
|
message: "Do you want to setup shadcn UI in your Next.js website (apps/web)?",
|
|
1670
1669
|
initialValue: true
|
|
1671
1670
|
});
|
|
1672
1671
|
}
|
|
1673
|
-
function runInteractiveCommand4(command, args, cwd) {
|
|
1674
|
-
return new Promise((resolve, reject) => {
|
|
1675
|
-
const child = spawn4(command, args, {
|
|
1676
|
-
cwd,
|
|
1677
|
-
stdio: "inherit",
|
|
1678
|
-
shell: true,
|
|
1679
|
-
env: { ...process.env, NODE_NO_WARNINGS: "1" }
|
|
1680
|
-
});
|
|
1681
|
-
child.on("close", (code) => {
|
|
1682
|
-
if (code === 0) {
|
|
1683
|
-
resolve();
|
|
1684
|
-
} else {
|
|
1685
|
-
reject(
|
|
1686
|
-
new Error(
|
|
1687
|
-
`Command "${command} ${args.join(" ")}" exited with code ${code}`
|
|
1688
|
-
)
|
|
1689
|
-
);
|
|
1690
|
-
}
|
|
1691
|
-
});
|
|
1692
|
-
child.on("error", (err) => {
|
|
1693
|
-
reject(err);
|
|
1694
|
-
});
|
|
1695
|
-
});
|
|
1696
|
-
}
|
|
1697
1672
|
async function setupShadcn(projectPath, isMonorepo = true) {
|
|
1698
|
-
const webDir = isMonorepo ?
|
|
1673
|
+
const webDir = isMonorepo ? path8.join(projectPath, "apps", "web") : projectPath;
|
|
1699
1674
|
console.log(pc11.cyan("\nStarting interactive shadcn UI initialization..."));
|
|
1700
|
-
await
|
|
1701
|
-
"
|
|
1702
|
-
["
|
|
1675
|
+
await runInteractiveCommand(
|
|
1676
|
+
"bunx",
|
|
1677
|
+
["shadcn@latest", "init", "--template", "next"],
|
|
1703
1678
|
webDir
|
|
1704
1679
|
);
|
|
1680
|
+
await removeBunLockfiles(webDir, projectPath);
|
|
1705
1681
|
}
|
|
1706
1682
|
async function runShadcnSetup(projectPath, isMonorepo = true) {
|
|
1707
|
-
const webDir = isMonorepo ?
|
|
1683
|
+
const webDir = isMonorepo ? path8.join(projectPath, "apps", "web") : projectPath;
|
|
1708
1684
|
try {
|
|
1709
|
-
await
|
|
1685
|
+
await fsPromises8.access(webDir);
|
|
1710
1686
|
} catch {
|
|
1711
1687
|
return;
|
|
1712
1688
|
}
|
|
@@ -1734,8 +1710,9 @@ async function runShadcnSetup(projectPath, isMonorepo = true) {
|
|
|
1734
1710
|
async function runNextScaffolder(name, projectPath) {
|
|
1735
1711
|
const finalProjectPath = await setupNextjs(projectPath, false);
|
|
1736
1712
|
await runShadcnSetup(finalProjectPath, false);
|
|
1737
|
-
await setupReadme(finalProjectPath,
|
|
1713
|
+
await setupReadme(finalProjectPath, path9.basename(finalProjectPath));
|
|
1738
1714
|
await runGitSetup(finalProjectPath);
|
|
1715
|
+
await removeBunLockfiles(finalProjectPath);
|
|
1739
1716
|
const installSpinner = spinner5();
|
|
1740
1717
|
installSpinner.start("Running final package installation...");
|
|
1741
1718
|
try {
|
|
@@ -1748,20 +1725,20 @@ async function runNextScaffolder(name, projectPath) {
|
|
|
1748
1725
|
console.error(pc12.red(`
|
|
1749
1726
|
Error details: ${error.message || error}`));
|
|
1750
1727
|
}
|
|
1751
|
-
endCli(
|
|
1728
|
+
endCli(path9.basename(finalProjectPath), finalProjectPath);
|
|
1752
1729
|
}
|
|
1753
1730
|
|
|
1754
1731
|
// src/modules/workspace/directories.ts
|
|
1755
1732
|
import { spinner as spinner6 } from "@clack/prompts";
|
|
1756
|
-
import
|
|
1757
|
-
import
|
|
1733
|
+
import fsPromises10 from "fs/promises";
|
|
1734
|
+
import path11 from "path";
|
|
1758
1735
|
import pc13 from "picocolors";
|
|
1759
1736
|
|
|
1760
1737
|
// src/modules/workspace/config.ts
|
|
1761
|
-
import
|
|
1762
|
-
import
|
|
1738
|
+
import fsPromises9 from "fs/promises";
|
|
1739
|
+
import path10 from "path";
|
|
1763
1740
|
async function generateWorkspaceConfig(name, directories, projectPath) {
|
|
1764
|
-
await
|
|
1741
|
+
await fsPromises9.mkdir(projectPath, { recursive: true });
|
|
1765
1742
|
const defaultOnlyBuiltDeps = [
|
|
1766
1743
|
"esbuild",
|
|
1767
1744
|
"@biomejs/biome",
|
|
@@ -1779,14 +1756,14 @@ async function generateWorkspaceConfig(name, directories, projectPath) {
|
|
|
1779
1756
|
),
|
|
1780
1757
|
""
|
|
1781
1758
|
].join("\n");
|
|
1782
|
-
await
|
|
1783
|
-
|
|
1759
|
+
await fsPromises9.writeFile(
|
|
1760
|
+
path10.join(projectPath, "pnpm-workspace.yaml"),
|
|
1784
1761
|
workspaceYamlContent,
|
|
1785
1762
|
"utf8"
|
|
1786
1763
|
);
|
|
1787
1764
|
await runCommand("pnpm init", { cwd: projectPath, silent: true });
|
|
1788
|
-
const packageJsonPath =
|
|
1789
|
-
const packageJsonRaw = await
|
|
1765
|
+
const packageJsonPath = path10.join(projectPath, "package.json");
|
|
1766
|
+
const packageJsonRaw = await fsPromises9.readFile(packageJsonPath, "utf8");
|
|
1790
1767
|
const pkg = JSON.parse(packageJsonRaw);
|
|
1791
1768
|
pkg.name = name;
|
|
1792
1769
|
pkg.description = "High-performance monorepo workspace generated by Morax";
|
|
@@ -1801,15 +1778,12 @@ async function generateWorkspaceConfig(name, directories, projectPath) {
|
|
|
1801
1778
|
} catch {
|
|
1802
1779
|
pkg.packageManager = "pnpm@latest";
|
|
1803
1780
|
}
|
|
1804
|
-
pkg.pnpm = {
|
|
1805
|
-
onlyBuiltDependencies: defaultOnlyBuiltDeps
|
|
1806
|
-
};
|
|
1807
1781
|
pkg.workspaces = directories.map((dir) => `${dir}/*`);
|
|
1808
1782
|
pkg.scripts = {
|
|
1809
1783
|
dev: "pnpm -r --parallel dev"
|
|
1810
1784
|
};
|
|
1811
1785
|
delete pkg.main;
|
|
1812
|
-
await
|
|
1786
|
+
await fsPromises9.writeFile(
|
|
1813
1787
|
packageJsonPath,
|
|
1814
1788
|
JSON.stringify(pkg, null, 2),
|
|
1815
1789
|
"utf8"
|
|
@@ -1819,10 +1793,10 @@ async function generateWorkspaceConfig(name, directories, projectPath) {
|
|
|
1819
1793
|
// src/modules/workspace/directories.ts
|
|
1820
1794
|
async function createDirectories(directories, projectPath) {
|
|
1821
1795
|
for (const dir of directories) {
|
|
1822
|
-
const dirPath =
|
|
1823
|
-
await
|
|
1824
|
-
await
|
|
1825
|
-
|
|
1796
|
+
const dirPath = path11.join(projectPath, dir);
|
|
1797
|
+
await fsPromises10.mkdir(dirPath, { recursive: true });
|
|
1798
|
+
await fsPromises10.writeFile(
|
|
1799
|
+
path11.join(dirPath, ".gitkeep"),
|
|
1826
1800
|
`# Placeholder to ensure git tracks the empty ${dir}/ folder
|
|
1827
1801
|
`,
|
|
1828
1802
|
"utf8"
|
|
@@ -1851,11 +1825,11 @@ import { multiselect as multiselect2, select as select4, spinner as spinner7 } f
|
|
|
1851
1825
|
import pc14 from "picocolors";
|
|
1852
1826
|
|
|
1853
1827
|
// src/modules/workspace/docs.ts
|
|
1854
|
-
import
|
|
1855
|
-
import
|
|
1828
|
+
import fsPromises11 from "fs/promises";
|
|
1829
|
+
import path12 from "path";
|
|
1856
1830
|
async function setupProjectDocs(projectPath, options) {
|
|
1857
|
-
const docsDir =
|
|
1858
|
-
await
|
|
1831
|
+
const docsDir = path12.join(projectPath, "docs");
|
|
1832
|
+
await fsPromises11.mkdir(docsDir, { recursive: true });
|
|
1859
1833
|
const {
|
|
1860
1834
|
projectName,
|
|
1861
1835
|
hasServer,
|
|
@@ -1913,8 +1887,8 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
1913
1887
|
"Internal workspace dependencies are linked using pnpm workspace protocols (`workspace:*`).",
|
|
1914
1888
|
""
|
|
1915
1889
|
].join("\n");
|
|
1916
|
-
await
|
|
1917
|
-
|
|
1890
|
+
await fsPromises11.writeFile(
|
|
1891
|
+
path12.join(docsDir, "ARCHITECTURE.md"),
|
|
1918
1892
|
architectureMd,
|
|
1919
1893
|
"utf8"
|
|
1920
1894
|
);
|
|
@@ -1952,7 +1926,7 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
1952
1926
|
"```",
|
|
1953
1927
|
""
|
|
1954
1928
|
].join("\n");
|
|
1955
|
-
await
|
|
1929
|
+
await fsPromises11.writeFile(path12.join(docsDir, "DATABASE.md"), dbMd, "utf8");
|
|
1956
1930
|
}
|
|
1957
1931
|
if (hasServer) {
|
|
1958
1932
|
const serverMd = [
|
|
@@ -1975,8 +1949,8 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
1975
1949
|
"```",
|
|
1976
1950
|
""
|
|
1977
1951
|
].join("\n");
|
|
1978
|
-
await
|
|
1979
|
-
|
|
1952
|
+
await fsPromises11.writeFile(
|
|
1953
|
+
path12.join(docsDir, "SERVER.md"),
|
|
1980
1954
|
serverMd,
|
|
1981
1955
|
"utf8"
|
|
1982
1956
|
);
|
|
@@ -2011,7 +1985,7 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
2011
1985
|
"2. Update the corresponding schema in `packages/env/src/schema/*.ts`.",
|
|
2012
1986
|
""
|
|
2013
1987
|
].join("\n");
|
|
2014
|
-
await
|
|
1988
|
+
await fsPromises11.writeFile(path12.join(docsDir, "ENV.md"), envMd, "utf8");
|
|
2015
1989
|
}
|
|
2016
1990
|
if (hasDocker) {
|
|
2017
1991
|
const dockerMd = [
|
|
@@ -2059,8 +2033,8 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
2059
2033
|
"Docker Compose automatically loads root variables using `--env-file .env`.",
|
|
2060
2034
|
""
|
|
2061
2035
|
].join("\n");
|
|
2062
|
-
await
|
|
2063
|
-
|
|
2036
|
+
await fsPromises11.writeFile(
|
|
2037
|
+
path12.join(docsDir, "DOCKER.md"),
|
|
2064
2038
|
dockerMd,
|
|
2065
2039
|
"utf8"
|
|
2066
2040
|
);
|
|
@@ -2082,7 +2056,7 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
2082
2056
|
"```",
|
|
2083
2057
|
""
|
|
2084
2058
|
].join("\n");
|
|
2085
|
-
await
|
|
2059
|
+
await fsPromises11.writeFile(path12.join(docsDir, "WEB.md"), webMd, "utf8");
|
|
2086
2060
|
}
|
|
2087
2061
|
if (hasAuth) {
|
|
2088
2062
|
const authMd = [
|
|
@@ -2125,13 +2099,13 @@ async function setupProjectDocs(projectPath, options) {
|
|
|
2125
2099
|
"- `verification`: Email verification and password reset tokens",
|
|
2126
2100
|
""
|
|
2127
2101
|
].join("\n");
|
|
2128
|
-
await
|
|
2102
|
+
await fsPromises11.writeFile(path12.join(docsDir, "AUTH.md"), authMd, "utf8");
|
|
2129
2103
|
}
|
|
2130
2104
|
}
|
|
2131
2105
|
|
|
2132
2106
|
// src/modules/workspace/agents.ts
|
|
2133
|
-
import
|
|
2134
|
-
import
|
|
2107
|
+
import fsPromises12 from "fs/promises";
|
|
2108
|
+
import path13 from "path";
|
|
2135
2109
|
function generateClaudeMd(options) {
|
|
2136
2110
|
const {
|
|
2137
2111
|
projectName,
|
|
@@ -2321,21 +2295,21 @@ function generateAgentsMd(options) {
|
|
|
2321
2295
|
async function setupAgentDocs(projectPath, options) {
|
|
2322
2296
|
const claudeContent = generateClaudeMd(options);
|
|
2323
2297
|
const agentsContent = generateAgentsMd(options);
|
|
2324
|
-
await
|
|
2325
|
-
|
|
2298
|
+
await fsPromises12.writeFile(
|
|
2299
|
+
path13.join(projectPath, "CLAUDE.md"),
|
|
2326
2300
|
claudeContent,
|
|
2327
2301
|
"utf8"
|
|
2328
2302
|
);
|
|
2329
|
-
await
|
|
2330
|
-
|
|
2303
|
+
await fsPromises12.writeFile(
|
|
2304
|
+
path13.join(projectPath, "AGENTS.md"),
|
|
2331
2305
|
agentsContent,
|
|
2332
2306
|
"utf8"
|
|
2333
2307
|
);
|
|
2334
2308
|
}
|
|
2335
2309
|
|
|
2336
2310
|
// src/modules/workspace/license.ts
|
|
2337
|
-
import
|
|
2338
|
-
import
|
|
2311
|
+
import fsPromises13 from "fs/promises";
|
|
2312
|
+
import path14 from "path";
|
|
2339
2313
|
function getLicenseText(licenseType, year, author) {
|
|
2340
2314
|
switch (licenseType) {
|
|
2341
2315
|
case "MIT":
|
|
@@ -2464,19 +2438,19 @@ For more information, please refer to <https://unlicense.org>
|
|
|
2464
2438
|
async function setupLicense(projectPath, licenseType, author) {
|
|
2465
2439
|
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
2466
2440
|
const licenseContent = getLicenseText(licenseType, year, author);
|
|
2467
|
-
await
|
|
2468
|
-
|
|
2441
|
+
await fsPromises13.writeFile(
|
|
2442
|
+
path14.join(projectPath, "LICENSE"),
|
|
2469
2443
|
licenseContent,
|
|
2470
2444
|
"utf8"
|
|
2471
2445
|
);
|
|
2472
2446
|
}
|
|
2473
2447
|
|
|
2474
2448
|
// src/modules/workspace/scripts.ts
|
|
2475
|
-
import
|
|
2476
|
-
import
|
|
2449
|
+
import fsPromises14 from "fs/promises";
|
|
2450
|
+
import path15 from "path";
|
|
2477
2451
|
async function setupDockerScripts(projectPath, options = {}) {
|
|
2478
|
-
const scriptsDir =
|
|
2479
|
-
await
|
|
2452
|
+
const scriptsDir = path15.join(projectPath, "scripts");
|
|
2453
|
+
await fsPromises14.mkdir(scriptsDir, { recursive: true });
|
|
2480
2454
|
const hasPostgres = !!options.postgres;
|
|
2481
2455
|
const hasRedis = !!options.redis;
|
|
2482
2456
|
const validActions = ["infra-up", "infra-down"];
|
|
@@ -2528,8 +2502,8 @@ async function setupDockerScripts(projectPath, options = {}) {
|
|
|
2528
2502
|
"esac",
|
|
2529
2503
|
""
|
|
2530
2504
|
);
|
|
2531
|
-
await
|
|
2532
|
-
|
|
2505
|
+
await fsPromises14.writeFile(
|
|
2506
|
+
path15.join(scriptsDir, "command.sh"),
|
|
2533
2507
|
shellLines.join("\n"),
|
|
2534
2508
|
{ encoding: "utf8", mode: 493 }
|
|
2535
2509
|
);
|
|
@@ -2647,8 +2621,8 @@ async function promptAndSetupExtras(projectPath, options) {
|
|
|
2647
2621
|
// src/modules/skills/index.ts
|
|
2648
2622
|
import { confirm as confirm5 } from "@clack/prompts";
|
|
2649
2623
|
import pc15 from "picocolors";
|
|
2650
|
-
import
|
|
2651
|
-
import
|
|
2624
|
+
import fsPromises15 from "fs/promises";
|
|
2625
|
+
import path16 from "path";
|
|
2652
2626
|
async function promptSkills() {
|
|
2653
2627
|
const result = await confirm5({
|
|
2654
2628
|
message: "Install AI Agent Skills (skills.sh)?",
|
|
@@ -2658,31 +2632,31 @@ async function promptSkills() {
|
|
|
2658
2632
|
return result;
|
|
2659
2633
|
}
|
|
2660
2634
|
async function moveRulesToAgentRoot(projectPath) {
|
|
2661
|
-
const targetRulesDir =
|
|
2635
|
+
const targetRulesDir = path16.join(projectPath, ".agents", "rules");
|
|
2662
2636
|
const sourceCandidates = [
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2637
|
+
path16.join(projectPath, ".agents", "skills", "rules"),
|
|
2638
|
+
path16.join(projectPath, ".agent", "skills", "rules"),
|
|
2639
|
+
path16.join(projectPath, ".agent", "rules")
|
|
2666
2640
|
];
|
|
2667
2641
|
let moved = false;
|
|
2668
2642
|
for (const sourceDir of sourceCandidates) {
|
|
2669
2643
|
try {
|
|
2670
|
-
await
|
|
2644
|
+
await fsPromises15.access(sourceDir);
|
|
2671
2645
|
} catch {
|
|
2672
2646
|
continue;
|
|
2673
2647
|
}
|
|
2674
|
-
await
|
|
2648
|
+
await fsPromises15.mkdir(targetRulesDir, { recursive: true });
|
|
2675
2649
|
try {
|
|
2676
|
-
const entries = await
|
|
2650
|
+
const entries = await fsPromises15.readdir(sourceDir);
|
|
2677
2651
|
for (const entry of entries) {
|
|
2678
|
-
const srcPath =
|
|
2679
|
-
const destPath =
|
|
2680
|
-
await
|
|
2652
|
+
const srcPath = path16.join(sourceDir, entry);
|
|
2653
|
+
const destPath = path16.join(targetRulesDir, entry);
|
|
2654
|
+
await fsPromises15.cp(srcPath, destPath, {
|
|
2681
2655
|
recursive: true,
|
|
2682
2656
|
force: true
|
|
2683
2657
|
});
|
|
2684
2658
|
}
|
|
2685
|
-
await
|
|
2659
|
+
await fsPromises15.rm(sourceDir, { recursive: true, force: true });
|
|
2686
2660
|
moved = true;
|
|
2687
2661
|
} catch (err) {
|
|
2688
2662
|
console.log(
|
|
@@ -2693,17 +2667,17 @@ async function moveRulesToAgentRoot(projectPath) {
|
|
|
2693
2667
|
);
|
|
2694
2668
|
}
|
|
2695
2669
|
}
|
|
2696
|
-
const agentDir =
|
|
2670
|
+
const agentDir = path16.join(projectPath, ".agent");
|
|
2697
2671
|
try {
|
|
2698
|
-
const remaining = await
|
|
2672
|
+
const remaining = await fsPromises15.readdir(agentDir);
|
|
2699
2673
|
if (remaining.length === 0) {
|
|
2700
|
-
await
|
|
2674
|
+
await fsPromises15.rm(agentDir, { recursive: true, force: true });
|
|
2701
2675
|
} else if (remaining.length === 1 && remaining[0] === "skills") {
|
|
2702
|
-
const skillsRemaining = await
|
|
2703
|
-
|
|
2676
|
+
const skillsRemaining = await fsPromises15.readdir(
|
|
2677
|
+
path16.join(agentDir, "skills")
|
|
2704
2678
|
);
|
|
2705
2679
|
if (skillsRemaining.length === 0) {
|
|
2706
|
-
await
|
|
2680
|
+
await fsPromises15.rm(agentDir, { recursive: true, force: true });
|
|
2707
2681
|
}
|
|
2708
2682
|
}
|
|
2709
2683
|
} catch {
|
|
@@ -2734,22 +2708,22 @@ async function installSkills(projectPath) {
|
|
|
2734
2708
|
);
|
|
2735
2709
|
}
|
|
2736
2710
|
await moveRulesToAgentRoot(projectPath);
|
|
2737
|
-
const claudeDir =
|
|
2711
|
+
const claudeDir = path16.join(projectPath, ".claude");
|
|
2738
2712
|
try {
|
|
2739
|
-
await
|
|
2713
|
+
await fsPromises15.rm(claudeDir, { recursive: true, force: true });
|
|
2740
2714
|
} catch {
|
|
2741
2715
|
}
|
|
2742
|
-
const gitignorePath =
|
|
2716
|
+
const gitignorePath = path16.join(projectPath, ".gitignore");
|
|
2743
2717
|
try {
|
|
2744
2718
|
let gitignoreContent = "";
|
|
2745
2719
|
try {
|
|
2746
|
-
gitignoreContent = await
|
|
2720
|
+
gitignoreContent = await fsPromises15.readFile(gitignorePath, "utf8");
|
|
2747
2721
|
} catch {
|
|
2748
2722
|
gitignoreContent = "";
|
|
2749
2723
|
}
|
|
2750
2724
|
if (!gitignoreContent.includes(".agents")) {
|
|
2751
2725
|
const entry = gitignoreContent ? "\n# AI Agent Skills & Tooling\n.agents/\n.agent/\n" : "# AI Agent Skills & Tooling\n.agents/\n.agent/\n";
|
|
2752
|
-
await
|
|
2726
|
+
await fsPromises15.appendFile(gitignorePath, entry, "utf8");
|
|
2753
2727
|
}
|
|
2754
2728
|
} catch {
|
|
2755
2729
|
}
|
|
@@ -2762,8 +2736,8 @@ async function promptAndInstallSkills(projectPath) {
|
|
|
2762
2736
|
}
|
|
2763
2737
|
|
|
2764
2738
|
// src/modules/workspace/env.ts
|
|
2765
|
-
import
|
|
2766
|
-
import
|
|
2739
|
+
import fsPromises16 from "fs/promises";
|
|
2740
|
+
import path17 from "path";
|
|
2767
2741
|
async function setupRootEnv(projectPath, options = {}) {
|
|
2768
2742
|
const envLines = [
|
|
2769
2743
|
"# ==============================================================================",
|
|
@@ -2838,13 +2812,13 @@ async function setupRootEnv(projectPath, options = {}) {
|
|
|
2838
2812
|
}
|
|
2839
2813
|
}
|
|
2840
2814
|
const envContent = envLines.join("\n");
|
|
2841
|
-
await
|
|
2842
|
-
|
|
2815
|
+
await fsPromises16.writeFile(
|
|
2816
|
+
path17.join(projectPath, ".env"),
|
|
2843
2817
|
envContent,
|
|
2844
2818
|
"utf8"
|
|
2845
2819
|
);
|
|
2846
|
-
await
|
|
2847
|
-
|
|
2820
|
+
await fsPromises16.writeFile(
|
|
2821
|
+
path17.join(projectPath, ".env.example"),
|
|
2848
2822
|
envContent,
|
|
2849
2823
|
"utf8"
|
|
2850
2824
|
);
|
|
@@ -2853,15 +2827,21 @@ async function setupRootEnv(projectPath, options = {}) {
|
|
|
2853
2827
|
// src/modules/git/husky.ts
|
|
2854
2828
|
import { confirm as confirm6, spinner as spinner8 } from "@clack/prompts";
|
|
2855
2829
|
import pc16 from "picocolors";
|
|
2856
|
-
import
|
|
2857
|
-
import
|
|
2830
|
+
import fsPromises17 from "fs/promises";
|
|
2831
|
+
import path18 from "path";
|
|
2858
2832
|
async function setupHusky(projectPath) {
|
|
2859
|
-
await runCommand("pnpm add -D -E husky -w", {
|
|
2860
|
-
|
|
2861
|
-
|
|
2833
|
+
await runCommand("pnpm add -D -E husky -w", {
|
|
2834
|
+
cwd: projectPath,
|
|
2835
|
+
silent: true
|
|
2836
|
+
});
|
|
2837
|
+
await runCommand("pnpm exec husky init", {
|
|
2838
|
+
cwd: projectPath,
|
|
2839
|
+
silent: true
|
|
2840
|
+
});
|
|
2841
|
+
const preCommitPath = path18.join(projectPath, ".husky", "pre-commit");
|
|
2862
2842
|
let hookContent = "";
|
|
2863
2843
|
try {
|
|
2864
|
-
hookContent = await
|
|
2844
|
+
hookContent = await fsPromises17.readFile(preCommitPath, "utf8");
|
|
2865
2845
|
} catch {
|
|
2866
2846
|
hookContent = "pnpm test";
|
|
2867
2847
|
}
|
|
@@ -2869,9 +2849,9 @@ async function setupHusky(projectPath) {
|
|
|
2869
2849
|
if (!hookContent.includes("git add .")) {
|
|
2870
2850
|
hookContent = hookContent.trim() + "\ngit add .\n";
|
|
2871
2851
|
}
|
|
2872
|
-
await
|
|
2852
|
+
await fsPromises17.writeFile(preCommitPath, hookContent, "utf8");
|
|
2873
2853
|
try {
|
|
2874
|
-
await
|
|
2854
|
+
await fsPromises17.chmod(preCommitPath, 493);
|
|
2875
2855
|
} catch {
|
|
2876
2856
|
}
|
|
2877
2857
|
}
|
|
@@ -2893,8 +2873,8 @@ Error details: ${error.message || error}`));
|
|
|
2893
2873
|
// src/modules/git/lefthook.ts
|
|
2894
2874
|
import { spinner as spinner9 } from "@clack/prompts";
|
|
2895
2875
|
import pc17 from "picocolors";
|
|
2896
|
-
import
|
|
2897
|
-
import
|
|
2876
|
+
import fsPromises18 from "fs/promises";
|
|
2877
|
+
import path19 from "path";
|
|
2898
2878
|
async function setupLefthook(projectPath, hasFormatter, hasLinter) {
|
|
2899
2879
|
await runCommand("pnpm add -D lefthook -w", {
|
|
2900
2880
|
cwd: projectPath,
|
|
@@ -2924,17 +2904,17 @@ async function setupLefthook(projectPath, hasFormatter, hasLinter) {
|
|
|
2924
2904
|
...commands,
|
|
2925
2905
|
""
|
|
2926
2906
|
].join("\n");
|
|
2927
|
-
await
|
|
2928
|
-
|
|
2907
|
+
await fsPromises18.writeFile(
|
|
2908
|
+
path19.join(projectPath, "lefthook.yml"),
|
|
2929
2909
|
lefthookConfig,
|
|
2930
2910
|
"utf8"
|
|
2931
2911
|
);
|
|
2932
|
-
const rootPackagePath =
|
|
2933
|
-
const rootPackageRaw = await
|
|
2912
|
+
const rootPackagePath = path19.join(projectPath, "package.json");
|
|
2913
|
+
const rootPackageRaw = await fsPromises18.readFile(rootPackagePath, "utf8");
|
|
2934
2914
|
const rootPkg = JSON.parse(rootPackageRaw);
|
|
2935
2915
|
rootPkg.scripts = rootPkg.scripts || {};
|
|
2936
2916
|
rootPkg.scripts.prepare = "lefthook install";
|
|
2937
|
-
await
|
|
2917
|
+
await fsPromises18.writeFile(
|
|
2938
2918
|
rootPackagePath,
|
|
2939
2919
|
JSON.stringify(rootPkg, null, 2),
|
|
2940
2920
|
"utf8"
|
|
@@ -2962,8 +2942,8 @@ Error details: ${error.message || error}`));
|
|
|
2962
2942
|
// src/modules/quality/biome.ts
|
|
2963
2943
|
import { spinner as spinner10 } from "@clack/prompts";
|
|
2964
2944
|
import pc18 from "picocolors";
|
|
2965
|
-
import
|
|
2966
|
-
import
|
|
2945
|
+
import fsPromises19 from "fs/promises";
|
|
2946
|
+
import path20 from "path";
|
|
2967
2947
|
async function setupBiome(projectPath, options) {
|
|
2968
2948
|
await runCommand("pnpm add -D -E @biomejs/biome -w", {
|
|
2969
2949
|
cwd: projectPath,
|
|
@@ -2992,8 +2972,8 @@ async function setupBiome(projectPath, options) {
|
|
|
2992
2972
|
}
|
|
2993
2973
|
}
|
|
2994
2974
|
};
|
|
2995
|
-
await
|
|
2996
|
-
|
|
2975
|
+
await fsPromises19.writeFile(
|
|
2976
|
+
path20.join(projectPath, "biome.json"),
|
|
2997
2977
|
JSON.stringify(biomeConfig, null, 2),
|
|
2998
2978
|
"utf8"
|
|
2999
2979
|
);
|
|
@@ -3004,8 +2984,8 @@ async function setupBiome(projectPath, options) {
|
|
|
3004
2984
|
});
|
|
3005
2985
|
} catch {
|
|
3006
2986
|
}
|
|
3007
|
-
const rootPackagePath =
|
|
3008
|
-
const rootPackageRaw = await
|
|
2987
|
+
const rootPackagePath = path20.join(projectPath, "package.json");
|
|
2988
|
+
const rootPackageRaw = await fsPromises19.readFile(rootPackagePath, "utf8");
|
|
3009
2989
|
const rootPkg = JSON.parse(rootPackageRaw);
|
|
3010
2990
|
rootPkg.scripts = rootPkg.scripts || {};
|
|
3011
2991
|
if (options.linter) {
|
|
@@ -3018,7 +2998,7 @@ async function setupBiome(projectPath, options) {
|
|
|
3018
2998
|
if (options.linter && options.formatter) {
|
|
3019
2999
|
rootPkg.scripts.check = "biome check --write .";
|
|
3020
3000
|
}
|
|
3021
|
-
await
|
|
3001
|
+
await fsPromises19.writeFile(
|
|
3022
3002
|
rootPackagePath,
|
|
3023
3003
|
JSON.stringify(rootPkg, null, 2),
|
|
3024
3004
|
"utf8"
|
|
@@ -3042,8 +3022,8 @@ Error details: ${error.message || error}`));
|
|
|
3042
3022
|
// src/modules/quality/oxlint.ts
|
|
3043
3023
|
import { spinner as spinner11 } from "@clack/prompts";
|
|
3044
3024
|
import pc19 from "picocolors";
|
|
3045
|
-
import
|
|
3046
|
-
import
|
|
3025
|
+
import fsPromises20 from "fs/promises";
|
|
3026
|
+
import path21 from "path";
|
|
3047
3027
|
async function setupOxlint(projectPath) {
|
|
3048
3028
|
await runCommand("pnpm add -D -E oxlint -w", {
|
|
3049
3029
|
cwd: projectPath,
|
|
@@ -3060,19 +3040,19 @@ async function setupOxlint(projectPath) {
|
|
|
3060
3040
|
"no-debugger": "error"
|
|
3061
3041
|
}
|
|
3062
3042
|
};
|
|
3063
|
-
await
|
|
3064
|
-
|
|
3043
|
+
await fsPromises20.writeFile(
|
|
3044
|
+
path21.join(projectPath, ".oxlintrc.json"),
|
|
3065
3045
|
JSON.stringify(oxlintConfig, null, 2),
|
|
3066
3046
|
"utf8"
|
|
3067
3047
|
);
|
|
3068
|
-
const rootPackagePath =
|
|
3069
|
-
const rootPackageContent = await
|
|
3048
|
+
const rootPackagePath = path21.join(projectPath, "package.json");
|
|
3049
|
+
const rootPackageContent = await fsPromises20.readFile(rootPackagePath, "utf8");
|
|
3070
3050
|
const rootPkg = JSON.parse(rootPackageContent);
|
|
3071
3051
|
rootPkg.scripts = {
|
|
3072
3052
|
...rootPkg.scripts || {},
|
|
3073
3053
|
lint: "oxlint ."
|
|
3074
3054
|
};
|
|
3075
|
-
await
|
|
3055
|
+
await fsPromises20.writeFile(
|
|
3076
3056
|
rootPackagePath,
|
|
3077
3057
|
JSON.stringify(rootPkg, null, 2),
|
|
3078
3058
|
"utf8"
|
|
@@ -3097,10 +3077,13 @@ Error details: ${error.message || error}`));
|
|
|
3097
3077
|
// src/modules/quality/prettier.ts
|
|
3098
3078
|
import { confirm as confirm7, spinner as spinner12 } from "@clack/prompts";
|
|
3099
3079
|
import pc20 from "picocolors";
|
|
3100
|
-
import
|
|
3101
|
-
import
|
|
3080
|
+
import fsPromises21 from "fs/promises";
|
|
3081
|
+
import path22 from "path";
|
|
3102
3082
|
async function setupPrettier(projectPath) {
|
|
3103
|
-
await runCommand("pnpm add -D -E prettier -w", {
|
|
3083
|
+
await runCommand("pnpm add -D -E prettier -w", {
|
|
3084
|
+
cwd: projectPath,
|
|
3085
|
+
silent: true
|
|
3086
|
+
});
|
|
3104
3087
|
const prettierConfig = {
|
|
3105
3088
|
semi: true,
|
|
3106
3089
|
singleQuote: true,
|
|
@@ -3108,8 +3091,8 @@ async function setupPrettier(projectPath) {
|
|
|
3108
3091
|
tabWidth: 2,
|
|
3109
3092
|
printWidth: 80
|
|
3110
3093
|
};
|
|
3111
|
-
await
|
|
3112
|
-
|
|
3094
|
+
await fsPromises21.writeFile(
|
|
3095
|
+
path22.join(projectPath, ".prettierrc"),
|
|
3113
3096
|
JSON.stringify(prettierConfig, null, 2),
|
|
3114
3097
|
"utf8"
|
|
3115
3098
|
);
|
|
@@ -3121,19 +3104,19 @@ async function setupPrettier(projectPath) {
|
|
|
3121
3104
|
"pnpm-lock.yaml",
|
|
3122
3105
|
""
|
|
3123
3106
|
].join("\n");
|
|
3124
|
-
await
|
|
3125
|
-
|
|
3107
|
+
await fsPromises21.writeFile(
|
|
3108
|
+
path22.join(projectPath, ".prettierignore"),
|
|
3126
3109
|
prettierIgnore,
|
|
3127
3110
|
"utf8"
|
|
3128
3111
|
);
|
|
3129
|
-
const rootPackagePath =
|
|
3130
|
-
const rootPackageRaw = await
|
|
3112
|
+
const rootPackagePath = path22.join(projectPath, "package.json");
|
|
3113
|
+
const rootPackageRaw = await fsPromises21.readFile(rootPackagePath, "utf8");
|
|
3131
3114
|
const pkg = JSON.parse(rootPackageRaw);
|
|
3132
3115
|
pkg.scripts = {
|
|
3133
3116
|
...pkg.scripts || {},
|
|
3134
3117
|
format: "prettier --write ."
|
|
3135
3118
|
};
|
|
3136
|
-
await
|
|
3119
|
+
await fsPromises21.writeFile(
|
|
3137
3120
|
rootPackagePath,
|
|
3138
3121
|
JSON.stringify(pkg, null, 2),
|
|
3139
3122
|
"utf8"
|
|
@@ -3157,14 +3140,14 @@ Error details: ${error.message || error}`));
|
|
|
3157
3140
|
// src/modules/packages/typescript.ts
|
|
3158
3141
|
import { spinner as spinner13 } from "@clack/prompts";
|
|
3159
3142
|
import pc21 from "picocolors";
|
|
3160
|
-
import
|
|
3161
|
-
import
|
|
3143
|
+
import fsPromises22 from "fs/promises";
|
|
3144
|
+
import path23 from "path";
|
|
3162
3145
|
async function setupTypescript(projectPath) {
|
|
3163
|
-
const tsDir =
|
|
3164
|
-
await
|
|
3146
|
+
const tsDir = path23.join(projectPath, "packages", "typescript");
|
|
3147
|
+
await fsPromises22.mkdir(tsDir, { recursive: true });
|
|
3165
3148
|
await runCommand("pnpm init", { cwd: tsDir, silent: true });
|
|
3166
|
-
const tsPackagePath =
|
|
3167
|
-
const tsPackageRaw = await
|
|
3149
|
+
const tsPackagePath = path23.join(tsDir, "package.json");
|
|
3150
|
+
const tsPackageRaw = await fsPromises22.readFile(tsPackagePath, "utf8");
|
|
3168
3151
|
const tsPkg = JSON.parse(tsPackageRaw);
|
|
3169
3152
|
tsPkg.name = "@config/typescript";
|
|
3170
3153
|
tsPkg.version = "1.0.0";
|
|
@@ -3175,7 +3158,7 @@ async function setupTypescript(projectPath) {
|
|
|
3175
3158
|
delete tsPkg.keywords;
|
|
3176
3159
|
delete tsPkg.author;
|
|
3177
3160
|
delete tsPkg.license;
|
|
3178
|
-
await
|
|
3161
|
+
await fsPromises22.writeFile(
|
|
3179
3162
|
tsPackagePath,
|
|
3180
3163
|
JSON.stringify(tsPkg, null, 2),
|
|
3181
3164
|
"utf8"
|
|
@@ -3194,16 +3177,16 @@ async function setupTypescript(projectPath) {
|
|
|
3194
3177
|
isolatedModules: true
|
|
3195
3178
|
}
|
|
3196
3179
|
};
|
|
3197
|
-
await
|
|
3198
|
-
|
|
3180
|
+
await fsPromises22.writeFile(
|
|
3181
|
+
path23.join(tsDir, "tsconfig.json"),
|
|
3199
3182
|
JSON.stringify(tsconfigContent, null, 2),
|
|
3200
3183
|
"utf8"
|
|
3201
3184
|
);
|
|
3202
3185
|
}
|
|
3203
3186
|
async function runTypescriptSetup(projectPath) {
|
|
3204
|
-
const packagesDir =
|
|
3187
|
+
const packagesDir = path23.join(projectPath, "packages");
|
|
3205
3188
|
try {
|
|
3206
|
-
await
|
|
3189
|
+
await fsPromises22.access(packagesDir);
|
|
3207
3190
|
} catch {
|
|
3208
3191
|
return;
|
|
3209
3192
|
}
|
|
@@ -3225,14 +3208,14 @@ Error details: ${error.message || error}`));
|
|
|
3225
3208
|
}
|
|
3226
3209
|
|
|
3227
3210
|
// src/modules/apps/server/index.ts
|
|
3228
|
-
import
|
|
3229
|
-
import
|
|
3211
|
+
import fsPromises29 from "fs/promises";
|
|
3212
|
+
import path32 from "path";
|
|
3230
3213
|
import { spinner as spinner16 } from "@clack/prompts";
|
|
3231
3214
|
import pc24 from "picocolors";
|
|
3232
3215
|
|
|
3233
3216
|
// src/modules/apps/server/frameworks/express/index.ts
|
|
3234
|
-
import
|
|
3235
|
-
import
|
|
3217
|
+
import fsPromises23 from "fs/promises";
|
|
3218
|
+
import path24 from "path";
|
|
3236
3219
|
|
|
3237
3220
|
// src/modules/apps/server/frameworks/express/package.ts
|
|
3238
3221
|
function getExpressDependencies() {
|
|
@@ -3398,13 +3381,13 @@ function renderExpressBunTemplate(hasDb) {
|
|
|
3398
3381
|
// src/modules/apps/server/frameworks/express/index.ts
|
|
3399
3382
|
async function setupExpress(options) {
|
|
3400
3383
|
const { projectPath, runtime, linter, orm } = options;
|
|
3401
|
-
const serverDir =
|
|
3402
|
-
const srcDir =
|
|
3384
|
+
const serverDir = path24.join(projectPath, "apps", "server");
|
|
3385
|
+
const srcDir = path24.join(serverDir, "src");
|
|
3403
3386
|
const hasDb = orm !== "none";
|
|
3404
|
-
await
|
|
3387
|
+
await fsPromises23.mkdir(srcDir, { recursive: true });
|
|
3405
3388
|
await runCommand("pnpm init", { cwd: serverDir, silent: true });
|
|
3406
|
-
const serverPackagePath =
|
|
3407
|
-
const serverPackageRaw = await
|
|
3389
|
+
const serverPackagePath = path24.join(serverDir, "package.json");
|
|
3390
|
+
const serverPackageRaw = await fsPromises23.readFile(serverPackagePath, "utf8");
|
|
3408
3391
|
const serverPkg = JSON.parse(serverPackageRaw);
|
|
3409
3392
|
serverPkg.name = "server";
|
|
3410
3393
|
serverPkg.version = "1.0.0";
|
|
@@ -3424,7 +3407,7 @@ async function setupExpress(options) {
|
|
|
3424
3407
|
delete serverPkg.keywords;
|
|
3425
3408
|
delete serverPkg.author;
|
|
3426
3409
|
delete serverPkg.license;
|
|
3427
|
-
await
|
|
3410
|
+
await fsPromises23.writeFile(
|
|
3428
3411
|
serverPackagePath,
|
|
3429
3412
|
JSON.stringify(serverPkg, null, 2),
|
|
3430
3413
|
"utf8"
|
|
@@ -3437,8 +3420,8 @@ async function setupExpress(options) {
|
|
|
3437
3420
|
},
|
|
3438
3421
|
include: ["src/**/*"]
|
|
3439
3422
|
};
|
|
3440
|
-
await
|
|
3441
|
-
|
|
3423
|
+
await fsPromises23.writeFile(
|
|
3424
|
+
path24.join(serverDir, "tsconfig.json"),
|
|
3442
3425
|
JSON.stringify(tsconfigContent, null, 2),
|
|
3443
3426
|
"utf8"
|
|
3444
3427
|
);
|
|
@@ -3453,32 +3436,32 @@ async function setupExpress(options) {
|
|
|
3453
3436
|
"});",
|
|
3454
3437
|
""
|
|
3455
3438
|
].join("\n");
|
|
3456
|
-
await
|
|
3457
|
-
|
|
3439
|
+
await fsPromises23.writeFile(
|
|
3440
|
+
path24.join(serverDir, "tsdown.config.ts"),
|
|
3458
3441
|
tsdownConfigContent,
|
|
3459
3442
|
"utf8"
|
|
3460
3443
|
);
|
|
3461
3444
|
const deps = getExpressDependencies();
|
|
3462
3445
|
await runCommand(`pnpm add ${deps.join(" ")}`, {
|
|
3463
3446
|
cwd: serverDir,
|
|
3464
|
-
silent:
|
|
3447
|
+
silent: true
|
|
3465
3448
|
});
|
|
3466
3449
|
const devDeps = getExpressDevDependencies(runtime);
|
|
3467
3450
|
await runCommand(`pnpm add -D ${devDeps.join(" ")}`, {
|
|
3468
3451
|
cwd: serverDir,
|
|
3469
|
-
silent:
|
|
3452
|
+
silent: true
|
|
3470
3453
|
});
|
|
3471
3454
|
const indexTsContent = runtime === "bun" ? renderExpressBunTemplate(hasDb) : renderExpressNodeTemplate(hasDb);
|
|
3472
|
-
await
|
|
3473
|
-
|
|
3455
|
+
await fsPromises23.writeFile(
|
|
3456
|
+
path24.join(srcDir, "index.ts"),
|
|
3474
3457
|
indexTsContent,
|
|
3475
3458
|
"utf8"
|
|
3476
3459
|
);
|
|
3477
3460
|
}
|
|
3478
3461
|
|
|
3479
3462
|
// src/modules/apps/server/frameworks/hono/index.ts
|
|
3480
|
-
import
|
|
3481
|
-
import
|
|
3463
|
+
import fsPromises24 from "fs/promises";
|
|
3464
|
+
import path25 from "path";
|
|
3482
3465
|
|
|
3483
3466
|
// src/modules/apps/server/frameworks/hono/package.ts
|
|
3484
3467
|
function getHonoDependencies(runtime) {
|
|
@@ -3649,13 +3632,13 @@ function renderHonoBunTemplate(hasDb) {
|
|
|
3649
3632
|
// src/modules/apps/server/frameworks/hono/index.ts
|
|
3650
3633
|
async function setupHono(options) {
|
|
3651
3634
|
const { projectPath, runtime, linter, orm } = options;
|
|
3652
|
-
const serverDir =
|
|
3653
|
-
const srcDir =
|
|
3635
|
+
const serverDir = path25.join(projectPath, "apps", "server");
|
|
3636
|
+
const srcDir = path25.join(serverDir, "src");
|
|
3654
3637
|
const hasDb = orm !== "none";
|
|
3655
|
-
await
|
|
3638
|
+
await fsPromises24.mkdir(srcDir, { recursive: true });
|
|
3656
3639
|
await runCommand("pnpm init", { cwd: serverDir, silent: true });
|
|
3657
|
-
const serverPackagePath =
|
|
3658
|
-
const serverPackageRaw = await
|
|
3640
|
+
const serverPackagePath = path25.join(serverDir, "package.json");
|
|
3641
|
+
const serverPackageRaw = await fsPromises24.readFile(serverPackagePath, "utf8");
|
|
3659
3642
|
const serverPkg = JSON.parse(serverPackageRaw);
|
|
3660
3643
|
serverPkg.name = "server";
|
|
3661
3644
|
serverPkg.version = "1.0.0";
|
|
@@ -3675,7 +3658,7 @@ async function setupHono(options) {
|
|
|
3675
3658
|
delete serverPkg.keywords;
|
|
3676
3659
|
delete serverPkg.author;
|
|
3677
3660
|
delete serverPkg.license;
|
|
3678
|
-
await
|
|
3661
|
+
await fsPromises24.writeFile(
|
|
3679
3662
|
serverPackagePath,
|
|
3680
3663
|
JSON.stringify(serverPkg, null, 2),
|
|
3681
3664
|
"utf8"
|
|
@@ -3688,8 +3671,8 @@ async function setupHono(options) {
|
|
|
3688
3671
|
},
|
|
3689
3672
|
include: ["src/**/*"]
|
|
3690
3673
|
};
|
|
3691
|
-
await
|
|
3692
|
-
|
|
3674
|
+
await fsPromises24.writeFile(
|
|
3675
|
+
path25.join(serverDir, "tsconfig.json"),
|
|
3693
3676
|
JSON.stringify(tsconfigContent, null, 2),
|
|
3694
3677
|
"utf8"
|
|
3695
3678
|
);
|
|
@@ -3704,24 +3687,24 @@ async function setupHono(options) {
|
|
|
3704
3687
|
"});",
|
|
3705
3688
|
""
|
|
3706
3689
|
].join("\n");
|
|
3707
|
-
await
|
|
3708
|
-
|
|
3690
|
+
await fsPromises24.writeFile(
|
|
3691
|
+
path25.join(serverDir, "tsdown.config.ts"),
|
|
3709
3692
|
tsdownConfigContent,
|
|
3710
3693
|
"utf8"
|
|
3711
3694
|
);
|
|
3712
3695
|
const deps = getHonoDependencies(runtime);
|
|
3713
3696
|
await runCommand(`pnpm add ${deps.join(" ")}`, {
|
|
3714
3697
|
cwd: serverDir,
|
|
3715
|
-
silent:
|
|
3698
|
+
silent: true
|
|
3716
3699
|
});
|
|
3717
3700
|
const devDeps = getHonoDevDependencies(runtime);
|
|
3718
3701
|
await runCommand(`pnpm add -D ${devDeps.join(" ")}`, {
|
|
3719
3702
|
cwd: serverDir,
|
|
3720
|
-
silent:
|
|
3703
|
+
silent: true
|
|
3721
3704
|
});
|
|
3722
3705
|
const indexTsContent = runtime === "bun" ? renderHonoBunTemplate(hasDb) : renderHonoNodeTemplate(hasDb);
|
|
3723
|
-
await
|
|
3724
|
-
|
|
3706
|
+
await fsPromises24.writeFile(
|
|
3707
|
+
path25.join(srcDir, "index.ts"),
|
|
3725
3708
|
indexTsContent,
|
|
3726
3709
|
"utf8"
|
|
3727
3710
|
);
|
|
@@ -3782,13 +3765,13 @@ async function promptServerDeployment(framework) {
|
|
|
3782
3765
|
}
|
|
3783
3766
|
|
|
3784
3767
|
// src/modules/apps/server/deployment/docker/index.ts
|
|
3785
|
-
import
|
|
3768
|
+
import path28 from "path";
|
|
3786
3769
|
import { spinner as spinner14 } from "@clack/prompts";
|
|
3787
3770
|
import pc22 from "picocolors";
|
|
3788
3771
|
|
|
3789
3772
|
// src/modules/apps/server/deployment/docker/express-docker.ts
|
|
3790
|
-
import
|
|
3791
|
-
import
|
|
3773
|
+
import fsPromises25 from "fs/promises";
|
|
3774
|
+
import path26 from "path";
|
|
3792
3775
|
function getExpressDockerfile(runtime) {
|
|
3793
3776
|
if (runtime === "bun") {
|
|
3794
3777
|
return [
|
|
@@ -3854,8 +3837,8 @@ function getExpressDockerfile(runtime) {
|
|
|
3854
3837
|
}
|
|
3855
3838
|
async function setupExpressDocker(serverDir, runtime) {
|
|
3856
3839
|
const dockerfileContent = getExpressDockerfile(runtime);
|
|
3857
|
-
await
|
|
3858
|
-
|
|
3840
|
+
await fsPromises25.writeFile(
|
|
3841
|
+
path26.join(serverDir, "Dockerfile"),
|
|
3859
3842
|
dockerfileContent,
|
|
3860
3843
|
"utf8"
|
|
3861
3844
|
);
|
|
@@ -3866,16 +3849,16 @@ async function setupExpressDocker(serverDir, runtime) {
|
|
|
3866
3849
|
".env.local",
|
|
3867
3850
|
""
|
|
3868
3851
|
].join("\n");
|
|
3869
|
-
await
|
|
3870
|
-
|
|
3852
|
+
await fsPromises25.writeFile(
|
|
3853
|
+
path26.join(serverDir, ".dockerignore"),
|
|
3871
3854
|
dockerignoreContent,
|
|
3872
3855
|
"utf8"
|
|
3873
3856
|
);
|
|
3874
3857
|
}
|
|
3875
3858
|
|
|
3876
3859
|
// src/modules/apps/server/deployment/docker/hono-docker.ts
|
|
3877
|
-
import
|
|
3878
|
-
import
|
|
3860
|
+
import fsPromises26 from "fs/promises";
|
|
3861
|
+
import path27 from "path";
|
|
3879
3862
|
function getHonoDockerfile(runtime) {
|
|
3880
3863
|
if (runtime === "bun") {
|
|
3881
3864
|
return [
|
|
@@ -3941,8 +3924,8 @@ function getHonoDockerfile(runtime) {
|
|
|
3941
3924
|
}
|
|
3942
3925
|
async function setupHonoDocker(serverDir, runtime) {
|
|
3943
3926
|
const dockerfileContent = getHonoDockerfile(runtime);
|
|
3944
|
-
await
|
|
3945
|
-
|
|
3927
|
+
await fsPromises26.writeFile(
|
|
3928
|
+
path27.join(serverDir, "Dockerfile"),
|
|
3946
3929
|
dockerfileContent,
|
|
3947
3930
|
"utf8"
|
|
3948
3931
|
);
|
|
@@ -3953,8 +3936,8 @@ async function setupHonoDocker(serverDir, runtime) {
|
|
|
3953
3936
|
".env.local",
|
|
3954
3937
|
""
|
|
3955
3938
|
].join("\n");
|
|
3956
|
-
await
|
|
3957
|
-
|
|
3939
|
+
await fsPromises26.writeFile(
|
|
3940
|
+
path27.join(serverDir, ".dockerignore"),
|
|
3958
3941
|
dockerignoreContent,
|
|
3959
3942
|
"utf8"
|
|
3960
3943
|
);
|
|
@@ -3963,7 +3946,7 @@ async function setupHonoDocker(serverDir, runtime) {
|
|
|
3963
3946
|
// src/modules/apps/server/deployment/docker/index.ts
|
|
3964
3947
|
async function setupDockerDeployment(options) {
|
|
3965
3948
|
const { projectPath, framework, runtime } = options;
|
|
3966
|
-
const serverDir =
|
|
3949
|
+
const serverDir = path28.join(projectPath, "apps", "server");
|
|
3967
3950
|
const frameworkLabel = framework === "express" ? "Express" : "Hono";
|
|
3968
3951
|
const runtimeLabel = runtime === "bun" ? "Bun" : "Node.js";
|
|
3969
3952
|
const s = spinner14();
|
|
@@ -3988,13 +3971,13 @@ async function setupDockerDeployment(options) {
|
|
|
3988
3971
|
}
|
|
3989
3972
|
|
|
3990
3973
|
// src/modules/apps/server/deployment/vercel/index.ts
|
|
3991
|
-
import
|
|
3974
|
+
import path31 from "path";
|
|
3992
3975
|
import { spinner as spinner15 } from "@clack/prompts";
|
|
3993
3976
|
import pc23 from "picocolors";
|
|
3994
3977
|
|
|
3995
3978
|
// src/modules/apps/server/deployment/vercel/express-vercel.ts
|
|
3996
|
-
import
|
|
3997
|
-
import
|
|
3979
|
+
import fsPromises27 from "fs/promises";
|
|
3980
|
+
import path29 from "path";
|
|
3998
3981
|
async function setupExpressVercel(serverDir, _runtime) {
|
|
3999
3982
|
const vercelConfig = {
|
|
4000
3983
|
version: 2,
|
|
@@ -4011,16 +3994,16 @@ async function setupExpressVercel(serverDir, _runtime) {
|
|
|
4011
3994
|
}
|
|
4012
3995
|
]
|
|
4013
3996
|
};
|
|
4014
|
-
await
|
|
4015
|
-
|
|
3997
|
+
await fsPromises27.writeFile(
|
|
3998
|
+
path29.join(serverDir, "vercel.json"),
|
|
4016
3999
|
JSON.stringify(vercelConfig, null, 2),
|
|
4017
4000
|
"utf8"
|
|
4018
4001
|
);
|
|
4019
4002
|
}
|
|
4020
4003
|
|
|
4021
4004
|
// src/modules/apps/server/deployment/vercel/hono-vercel.ts
|
|
4022
|
-
import
|
|
4023
|
-
import
|
|
4005
|
+
import fsPromises28 from "fs/promises";
|
|
4006
|
+
import path30 from "path";
|
|
4024
4007
|
async function setupHonoVercel(serverDir, runtime) {
|
|
4025
4008
|
const vercelConfig = {
|
|
4026
4009
|
version: 2,
|
|
@@ -4037,8 +4020,8 @@ async function setupHonoVercel(serverDir, runtime) {
|
|
|
4037
4020
|
}
|
|
4038
4021
|
]
|
|
4039
4022
|
};
|
|
4040
|
-
await
|
|
4041
|
-
|
|
4023
|
+
await fsPromises28.writeFile(
|
|
4024
|
+
path30.join(serverDir, "vercel.json"),
|
|
4042
4025
|
JSON.stringify(vercelConfig, null, 2),
|
|
4043
4026
|
"utf8"
|
|
4044
4027
|
);
|
|
@@ -4047,9 +4030,9 @@ async function setupHonoVercel(serverDir, runtime) {
|
|
|
4047
4030
|
cwd: serverDir,
|
|
4048
4031
|
silent: true
|
|
4049
4032
|
});
|
|
4050
|
-
const indexTsPath =
|
|
4033
|
+
const indexTsPath = path30.join(serverDir, "src", "index.ts");
|
|
4051
4034
|
try {
|
|
4052
|
-
let content = await
|
|
4035
|
+
let content = await fsPromises28.readFile(indexTsPath, "utf8");
|
|
4053
4036
|
if (!content.includes("@hono/node-server")) {
|
|
4054
4037
|
content = "import { getRequestListener } from '@hono/node-server';\n" + content;
|
|
4055
4038
|
}
|
|
@@ -4059,7 +4042,7 @@ async function setupHonoVercel(serverDir, runtime) {
|
|
|
4059
4042
|
"export default process.env.VERCEL\n ? getRequestListener(app.fetch)\n : {\n port,\n fetch: app.fetch,\n };"
|
|
4060
4043
|
);
|
|
4061
4044
|
}
|
|
4062
|
-
await
|
|
4045
|
+
await fsPromises28.writeFile(indexTsPath, content, "utf8");
|
|
4063
4046
|
} catch {
|
|
4064
4047
|
}
|
|
4065
4048
|
}
|
|
@@ -4068,7 +4051,7 @@ async function setupHonoVercel(serverDir, runtime) {
|
|
|
4068
4051
|
// src/modules/apps/server/deployment/vercel/index.ts
|
|
4069
4052
|
async function setupVercelDeployment(options) {
|
|
4070
4053
|
const { projectPath, framework, runtime } = options;
|
|
4071
|
-
const serverDir =
|
|
4054
|
+
const serverDir = path31.join(projectPath, "apps", "server");
|
|
4072
4055
|
const frameworkLabel = framework === "express" ? "Express" : "Hono";
|
|
4073
4056
|
const s = spinner15();
|
|
4074
4057
|
s.start(
|
|
@@ -4102,9 +4085,9 @@ async function setupServerDeployment(options) {
|
|
|
4102
4085
|
|
|
4103
4086
|
// src/modules/apps/server/index.ts
|
|
4104
4087
|
async function runServerSetup(projectPath, framework, linter = "none", orm = "none", runtime = "node") {
|
|
4105
|
-
const appsDir =
|
|
4088
|
+
const appsDir = path32.join(projectPath, "apps");
|
|
4106
4089
|
try {
|
|
4107
|
-
await
|
|
4090
|
+
await fsPromises29.access(appsDir);
|
|
4108
4091
|
} catch {
|
|
4109
4092
|
return;
|
|
4110
4093
|
}
|
|
@@ -4175,8 +4158,8 @@ async function addWeb(projectPath) {
|
|
|
4175
4158
|
}
|
|
4176
4159
|
|
|
4177
4160
|
// src/modules/packages/env/index.ts
|
|
4178
|
-
import
|
|
4179
|
-
import
|
|
4161
|
+
import fsPromises30 from "fs/promises";
|
|
4162
|
+
import path33 from "path";
|
|
4180
4163
|
import { confirm as confirm8, spinner as spinner17 } from "@clack/prompts";
|
|
4181
4164
|
import pc25 from "picocolors";
|
|
4182
4165
|
|
|
@@ -4540,13 +4523,13 @@ async function promptEnv() {
|
|
|
4540
4523
|
}
|
|
4541
4524
|
async function addDependencyToPackage(pkgJsonPath, depName, depVersion) {
|
|
4542
4525
|
try {
|
|
4543
|
-
const raw = await
|
|
4526
|
+
const raw = await fsPromises30.readFile(pkgJsonPath, "utf8");
|
|
4544
4527
|
const pkg = JSON.parse(raw);
|
|
4545
4528
|
pkg.dependencies = {
|
|
4546
4529
|
...pkg.dependencies || {},
|
|
4547
4530
|
[depName]: depVersion
|
|
4548
4531
|
};
|
|
4549
|
-
await
|
|
4532
|
+
await fsPromises30.writeFile(
|
|
4550
4533
|
pkgJsonPath,
|
|
4551
4534
|
JSON.stringify(pkg, null, 2),
|
|
4552
4535
|
"utf8"
|
|
@@ -4555,11 +4538,11 @@ async function addDependencyToPackage(pkgJsonPath, depName, depVersion) {
|
|
|
4555
4538
|
}
|
|
4556
4539
|
}
|
|
4557
4540
|
async function updateDbForEnv(projectPath, dialect) {
|
|
4558
|
-
const dbDir =
|
|
4559
|
-
const clientFile =
|
|
4560
|
-
const drizzleConfigFile =
|
|
4541
|
+
const dbDir = path33.join(projectPath, "packages", "db");
|
|
4542
|
+
const clientFile = path33.join(dbDir, "src", "client.ts");
|
|
4543
|
+
const drizzleConfigFile = path33.join(dbDir, "drizzle.config.ts");
|
|
4561
4544
|
try {
|
|
4562
|
-
const content = await
|
|
4545
|
+
const content = await fsPromises30.readFile(clientFile, "utf8");
|
|
4563
4546
|
let newContent = "";
|
|
4564
4547
|
if (content.includes("drizzle-orm/libsql")) {
|
|
4565
4548
|
newContent = [
|
|
@@ -4617,7 +4600,7 @@ async function updateDbForEnv(projectPath, dialect) {
|
|
|
4617
4600
|
].join("\n");
|
|
4618
4601
|
}
|
|
4619
4602
|
if (newContent) {
|
|
4620
|
-
await
|
|
4603
|
+
await fsPromises30.writeFile(clientFile, newContent, "utf8");
|
|
4621
4604
|
}
|
|
4622
4605
|
} catch {
|
|
4623
4606
|
}
|
|
@@ -4639,14 +4622,14 @@ async function updateDbForEnv(projectPath, dialect) {
|
|
|
4639
4622
|
"});",
|
|
4640
4623
|
""
|
|
4641
4624
|
].join("\n");
|
|
4642
|
-
await
|
|
4625
|
+
await fsPromises30.writeFile(drizzleConfigFile, newDrizzleConfig, "utf8");
|
|
4643
4626
|
} catch {
|
|
4644
4627
|
}
|
|
4645
4628
|
}
|
|
4646
4629
|
async function updateServerEntryForEnv(projectPath) {
|
|
4647
|
-
const indexFile =
|
|
4630
|
+
const indexFile = path33.join(projectPath, "apps", "server", "src", "index.ts");
|
|
4648
4631
|
try {
|
|
4649
|
-
let content = await
|
|
4632
|
+
let content = await fsPromises30.readFile(indexFile, "utf8");
|
|
4650
4633
|
if (!content.includes("@repo/env")) {
|
|
4651
4634
|
content = "import { env } from '@repo/env';\n" + content;
|
|
4652
4635
|
}
|
|
@@ -4662,7 +4645,7 @@ async function updateServerEntryForEnv(projectPath) {
|
|
|
4662
4645
|
/app\.use\('\*', cors\(\)\);/,
|
|
4663
4646
|
"app.use('*', cors({ origin: env.server.CORS_ORIGIN }));"
|
|
4664
4647
|
);
|
|
4665
|
-
await
|
|
4648
|
+
await fsPromises30.writeFile(indexFile, content, "utf8");
|
|
4666
4649
|
} catch {
|
|
4667
4650
|
}
|
|
4668
4651
|
}
|
|
@@ -4677,13 +4660,13 @@ async function setupEnvPackage(options) {
|
|
|
4677
4660
|
webFramework
|
|
4678
4661
|
} = options;
|
|
4679
4662
|
const hasWebEnv = webFramework !== "skip" || Boolean(hasAuth);
|
|
4680
|
-
const envDir =
|
|
4681
|
-
const srcDir =
|
|
4682
|
-
const schemaDir =
|
|
4683
|
-
await
|
|
4663
|
+
const envDir = path33.join(projectPath, "packages", "env");
|
|
4664
|
+
const srcDir = path33.join(envDir, "src");
|
|
4665
|
+
const schemaDir = path33.join(srcDir, "schema");
|
|
4666
|
+
await fsPromises30.mkdir(schemaDir, { recursive: true });
|
|
4684
4667
|
const pkgContent = getEnvPackageJson(options);
|
|
4685
|
-
await
|
|
4686
|
-
|
|
4668
|
+
await fsPromises30.writeFile(
|
|
4669
|
+
path33.join(envDir, "package.json"),
|
|
4687
4670
|
JSON.stringify(pkgContent, null, 2),
|
|
4688
4671
|
"utf8"
|
|
4689
4672
|
);
|
|
@@ -4695,56 +4678,56 @@ async function setupEnvPackage(options) {
|
|
|
4695
4678
|
},
|
|
4696
4679
|
include: ["src/**/*"]
|
|
4697
4680
|
};
|
|
4698
|
-
await
|
|
4699
|
-
|
|
4681
|
+
await fsPromises30.writeFile(
|
|
4682
|
+
path33.join(envDir, "tsconfig.json"),
|
|
4700
4683
|
JSON.stringify(tsconfig, null, 2),
|
|
4701
4684
|
"utf8"
|
|
4702
4685
|
);
|
|
4703
4686
|
const createEnvCode = renderCreateEnvTemplate();
|
|
4704
|
-
await
|
|
4705
|
-
|
|
4687
|
+
await fsPromises30.writeFile(
|
|
4688
|
+
path33.join(srcDir, "create-env.ts"),
|
|
4706
4689
|
createEnvCode,
|
|
4707
4690
|
"utf8"
|
|
4708
4691
|
);
|
|
4709
4692
|
if (hasDb) {
|
|
4710
4693
|
const dbCode = renderDbEnvTemplate(options);
|
|
4711
|
-
await
|
|
4694
|
+
await fsPromises30.writeFile(path33.join(schemaDir, "db.ts"), dbCode, "utf8");
|
|
4712
4695
|
}
|
|
4713
4696
|
if (hasDocker) {
|
|
4714
4697
|
const dockerCode = renderDockerEnvTemplate(options);
|
|
4715
|
-
await
|
|
4716
|
-
|
|
4698
|
+
await fsPromises30.writeFile(
|
|
4699
|
+
path33.join(schemaDir, "docker.ts"),
|
|
4717
4700
|
dockerCode,
|
|
4718
4701
|
"utf8"
|
|
4719
4702
|
);
|
|
4720
4703
|
}
|
|
4721
4704
|
if (hasServer || hasDb) {
|
|
4722
4705
|
const serverCode = renderServerEnvTemplate(options);
|
|
4723
|
-
await
|
|
4724
|
-
|
|
4706
|
+
await fsPromises30.writeFile(
|
|
4707
|
+
path33.join(schemaDir, "server.ts"),
|
|
4725
4708
|
serverCode,
|
|
4726
4709
|
"utf8"
|
|
4727
4710
|
);
|
|
4728
4711
|
}
|
|
4729
4712
|
if (hasAuth) {
|
|
4730
4713
|
const authCode = renderAuthEnvTemplate(options);
|
|
4731
|
-
await
|
|
4732
|
-
|
|
4714
|
+
await fsPromises30.writeFile(
|
|
4715
|
+
path33.join(schemaDir, "auth.ts"),
|
|
4733
4716
|
authCode,
|
|
4734
4717
|
"utf8"
|
|
4735
4718
|
);
|
|
4736
4719
|
}
|
|
4737
4720
|
if (hasWebEnv) {
|
|
4738
4721
|
const webCode = renderWebEnvTemplate(options);
|
|
4739
|
-
await
|
|
4722
|
+
await fsPromises30.writeFile(path33.join(schemaDir, "web.ts"), webCode, "utf8");
|
|
4740
4723
|
}
|
|
4741
4724
|
const checkCode = renderCheckEnvTemplate(options);
|
|
4742
|
-
await
|
|
4725
|
+
await fsPromises30.writeFile(path33.join(srcDir, "check.ts"), checkCode, "utf8");
|
|
4743
4726
|
const indexCode = renderIndexEnvTemplate(options);
|
|
4744
|
-
await
|
|
4727
|
+
await fsPromises30.writeFile(path33.join(srcDir, "index.ts"), indexCode, "utf8");
|
|
4745
4728
|
if (hasDb) {
|
|
4746
4729
|
await addDependencyToPackage(
|
|
4747
|
-
|
|
4730
|
+
path33.join(projectPath, "packages", "db", "package.json"),
|
|
4748
4731
|
"@repo/env",
|
|
4749
4732
|
"workspace:*"
|
|
4750
4733
|
);
|
|
@@ -4752,7 +4735,7 @@ async function setupEnvPackage(options) {
|
|
|
4752
4735
|
}
|
|
4753
4736
|
if (hasServer) {
|
|
4754
4737
|
await addDependencyToPackage(
|
|
4755
|
-
|
|
4738
|
+
path33.join(projectPath, "apps", "server", "package.json"),
|
|
4756
4739
|
"@repo/env",
|
|
4757
4740
|
"workspace:*"
|
|
4758
4741
|
);
|
|
@@ -4760,21 +4743,21 @@ async function setupEnvPackage(options) {
|
|
|
4760
4743
|
}
|
|
4761
4744
|
if (hasAuth) {
|
|
4762
4745
|
await addDependencyToPackage(
|
|
4763
|
-
|
|
4746
|
+
path33.join(projectPath, "packages", "auth", "package.json"),
|
|
4764
4747
|
"@repo/env",
|
|
4765
4748
|
"workspace:*"
|
|
4766
4749
|
);
|
|
4767
4750
|
}
|
|
4768
4751
|
if (webFramework !== "skip") {
|
|
4769
|
-
const appsDir =
|
|
4752
|
+
const appsDir = path33.join(projectPath, "apps");
|
|
4770
4753
|
try {
|
|
4771
|
-
const entries = await
|
|
4754
|
+
const entries = await fsPromises30.readdir(appsDir, {
|
|
4772
4755
|
withFileTypes: true
|
|
4773
4756
|
});
|
|
4774
4757
|
for (const entry of entries) {
|
|
4775
4758
|
if (entry.isDirectory() && entry.name !== "server") {
|
|
4776
4759
|
await addDependencyToPackage(
|
|
4777
|
-
|
|
4760
|
+
path33.join(appsDir, entry.name, "package.json"),
|
|
4778
4761
|
"@repo/env",
|
|
4779
4762
|
"workspace:*"
|
|
4780
4763
|
);
|
|
@@ -4803,8 +4786,8 @@ Error details: ${error.message || error}`));
|
|
|
4803
4786
|
}
|
|
4804
4787
|
|
|
4805
4788
|
// src/modules/packages/auth/index.ts
|
|
4806
|
-
import
|
|
4807
|
-
import
|
|
4789
|
+
import fsPromises31 from "fs/promises";
|
|
4790
|
+
import path34 from "path";
|
|
4808
4791
|
import { confirm as confirm9, spinner as spinner18 } from "@clack/prompts";
|
|
4809
4792
|
import pc26 from "picocolors";
|
|
4810
4793
|
async function promptAuth() {
|
|
@@ -4820,11 +4803,11 @@ async function setupAuth(options) {
|
|
|
4820
4803
|
const s = spinner18();
|
|
4821
4804
|
s.start("Configuring shared Better Auth package (@repo/auth)...");
|
|
4822
4805
|
try {
|
|
4823
|
-
const authDir =
|
|
4824
|
-
const authSrcDir =
|
|
4825
|
-
await
|
|
4826
|
-
const authLibDir =
|
|
4827
|
-
await
|
|
4806
|
+
const authDir = path34.join(projectPath, "packages", "auth");
|
|
4807
|
+
const authSrcDir = path34.join(authDir, "src");
|
|
4808
|
+
await fsPromises31.mkdir(authSrcDir, { recursive: true });
|
|
4809
|
+
const authLibDir = path34.join(authSrcDir, "lib");
|
|
4810
|
+
await fsPromises31.mkdir(authLibDir, { recursive: true });
|
|
4828
4811
|
const authPkg = {
|
|
4829
4812
|
name: "@repo/auth",
|
|
4830
4813
|
version: "1.0.0",
|
|
@@ -4860,8 +4843,8 @@ async function setupAuth(options) {
|
|
|
4860
4843
|
typescript: "^5.7.3"
|
|
4861
4844
|
}
|
|
4862
4845
|
};
|
|
4863
|
-
await
|
|
4864
|
-
|
|
4846
|
+
await fsPromises31.writeFile(
|
|
4847
|
+
path34.join(authDir, "package.json"),
|
|
4865
4848
|
JSON.stringify(authPkg, null, 2),
|
|
4866
4849
|
"utf8"
|
|
4867
4850
|
);
|
|
@@ -4873,8 +4856,8 @@ async function setupAuth(options) {
|
|
|
4873
4856
|
},
|
|
4874
4857
|
include: ["src/**/*"]
|
|
4875
4858
|
};
|
|
4876
|
-
await
|
|
4877
|
-
|
|
4859
|
+
await fsPromises31.writeFile(
|
|
4860
|
+
path34.join(authDir, "tsconfig.json"),
|
|
4878
4861
|
JSON.stringify(tsconfig, null, 2),
|
|
4879
4862
|
"utf8"
|
|
4880
4863
|
);
|
|
@@ -4918,8 +4901,8 @@ async function setupAuth(options) {
|
|
|
4918
4901
|
`export const isProduction = ${isProdExpr};`,
|
|
4919
4902
|
""
|
|
4920
4903
|
);
|
|
4921
|
-
await
|
|
4922
|
-
|
|
4904
|
+
await fsPromises31.writeFile(
|
|
4905
|
+
path34.join(authLibDir, "origins.ts"),
|
|
4923
4906
|
originsLibLines.join("\n"),
|
|
4924
4907
|
"utf8"
|
|
4925
4908
|
);
|
|
@@ -4989,8 +4972,8 @@ async function setupAuth(options) {
|
|
|
4989
4972
|
"export type Auth = typeof auth;",
|
|
4990
4973
|
""
|
|
4991
4974
|
);
|
|
4992
|
-
await
|
|
4993
|
-
|
|
4975
|
+
await fsPromises31.writeFile(
|
|
4976
|
+
path34.join(authLibDir, "auth.ts"),
|
|
4994
4977
|
authLibLines.join("\n"),
|
|
4995
4978
|
"utf8"
|
|
4996
4979
|
);
|
|
@@ -5001,8 +4984,8 @@ async function setupAuth(options) {
|
|
|
5001
4984
|
"export { origins, trustedOrigins, isProduction } from './lib/origins.js';",
|
|
5002
4985
|
""
|
|
5003
4986
|
].join("\n");
|
|
5004
|
-
await
|
|
5005
|
-
|
|
4987
|
+
await fsPromises31.writeFile(
|
|
4988
|
+
path34.join(authSrcDir, "origins.ts"),
|
|
5006
4989
|
originsReexport,
|
|
5007
4990
|
"utf8"
|
|
5008
4991
|
);
|
|
@@ -5015,14 +4998,14 @@ async function setupAuth(options) {
|
|
|
5015
4998
|
"export { origins, trustedOrigins, isProduction } from './lib/origins.js';",
|
|
5016
4999
|
""
|
|
5017
5000
|
].join("\n");
|
|
5018
|
-
await
|
|
5019
|
-
|
|
5001
|
+
await fsPromises31.writeFile(
|
|
5002
|
+
path34.join(authSrcDir, "index.ts"),
|
|
5020
5003
|
authIndexContent,
|
|
5021
5004
|
"utf8"
|
|
5022
5005
|
);
|
|
5023
|
-
const dbDir =
|
|
5024
|
-
const schemaDir =
|
|
5025
|
-
await
|
|
5006
|
+
const dbDir = path34.join(projectPath, "packages", "db");
|
|
5007
|
+
const schemaDir = path34.join(dbDir, "src", "schema");
|
|
5008
|
+
await fsPromises31.mkdir(schemaDir, { recursive: true });
|
|
5026
5009
|
let authSchemaContent;
|
|
5027
5010
|
if (isSqlite) {
|
|
5028
5011
|
authSchemaContent = [
|
|
@@ -5145,43 +5128,43 @@ async function setupAuth(options) {
|
|
|
5145
5128
|
""
|
|
5146
5129
|
].join("\n");
|
|
5147
5130
|
}
|
|
5148
|
-
await
|
|
5149
|
-
|
|
5131
|
+
await fsPromises31.writeFile(
|
|
5132
|
+
path34.join(schemaDir, "auth.ts"),
|
|
5150
5133
|
authSchemaContent,
|
|
5151
5134
|
"utf8"
|
|
5152
5135
|
);
|
|
5153
|
-
const schemaIndexPath =
|
|
5136
|
+
const schemaIndexPath = path34.join(schemaDir, "index.ts");
|
|
5154
5137
|
try {
|
|
5155
|
-
const existing = await
|
|
5138
|
+
const existing = await fsPromises31.readFile(schemaIndexPath, "utf8");
|
|
5156
5139
|
if (!existing.includes("from './auth.js'") && !existing.includes("from './auth'")) {
|
|
5157
5140
|
const updated = `${existing}
|
|
5158
5141
|
export * from './auth.js';
|
|
5159
5142
|
`;
|
|
5160
|
-
await
|
|
5143
|
+
await fsPromises31.writeFile(schemaIndexPath, updated, "utf8");
|
|
5161
5144
|
}
|
|
5162
5145
|
} catch {
|
|
5163
5146
|
}
|
|
5164
5147
|
if (hasServer && serverFramework !== "none") {
|
|
5165
|
-
const serverDir =
|
|
5166
|
-
const serverPkgPath =
|
|
5148
|
+
const serverDir = path34.join(projectPath, "apps", "server");
|
|
5149
|
+
const serverPkgPath = path34.join(serverDir, "package.json");
|
|
5167
5150
|
try {
|
|
5168
|
-
const rawPkg = await
|
|
5151
|
+
const rawPkg = await fsPromises31.readFile(serverPkgPath, "utf8");
|
|
5169
5152
|
const pkg = JSON.parse(rawPkg);
|
|
5170
5153
|
pkg.dependencies = pkg.dependencies || {};
|
|
5171
5154
|
pkg.dependencies["@repo/auth"] = "workspace:*";
|
|
5172
5155
|
if (serverFramework === "express") {
|
|
5173
5156
|
pkg.dependencies["better-auth"] = "^1.1.21";
|
|
5174
5157
|
}
|
|
5175
|
-
await
|
|
5158
|
+
await fsPromises31.writeFile(
|
|
5176
5159
|
serverPkgPath,
|
|
5177
5160
|
JSON.stringify(pkg, null, 2),
|
|
5178
5161
|
"utf8"
|
|
5179
5162
|
);
|
|
5180
5163
|
} catch {
|
|
5181
5164
|
}
|
|
5182
|
-
const serverIndexPath =
|
|
5165
|
+
const serverIndexPath = path34.join(serverDir, "src", "index.ts");
|
|
5183
5166
|
try {
|
|
5184
|
-
let content = await
|
|
5167
|
+
let content = await fsPromises31.readFile(serverIndexPath, "utf8");
|
|
5185
5168
|
if (serverFramework === "express") {
|
|
5186
5169
|
if (!content.includes("@repo/auth")) {
|
|
5187
5170
|
content = content.replace(
|
|
@@ -5196,7 +5179,7 @@ export * from './auth.js';
|
|
|
5196
5179
|
"app.use(express.json());",
|
|
5197
5180
|
"// Mount Better Auth endpoints (/api/auth/*)\napp.all('/api/auth/*', toNodeHandler(auth));\n\napp.use(express.json());"
|
|
5198
5181
|
);
|
|
5199
|
-
await
|
|
5182
|
+
await fsPromises31.writeFile(serverIndexPath, content, "utf8");
|
|
5200
5183
|
}
|
|
5201
5184
|
} else if (serverFramework === "hono") {
|
|
5202
5185
|
if (!content.includes("@repo/auth")) {
|
|
@@ -5212,7 +5195,7 @@ export * from './auth.js';
|
|
|
5212
5195
|
"const app = new Hono();",
|
|
5213
5196
|
"const app = new Hono();\n\n// Mount Better Auth API handler\napp.on(['POST', 'GET'], '/api/auth/**', (c) => {\n return auth.handler(c.req.raw);\n});"
|
|
5214
5197
|
);
|
|
5215
|
-
await
|
|
5198
|
+
await fsPromises31.writeFile(serverIndexPath, content, "utf8");
|
|
5216
5199
|
}
|
|
5217
5200
|
}
|
|
5218
5201
|
} catch {
|
|
@@ -5226,11 +5209,11 @@ export * from './auth.js';
|
|
|
5226
5209
|
""
|
|
5227
5210
|
].join("\n");
|
|
5228
5211
|
for (const envFileName of [".env", ".env.example"]) {
|
|
5229
|
-
const envFilePath =
|
|
5212
|
+
const envFilePath = path34.join(projectPath, envFileName);
|
|
5230
5213
|
try {
|
|
5231
|
-
const raw = await
|
|
5214
|
+
const raw = await fsPromises31.readFile(envFilePath, "utf8");
|
|
5232
5215
|
if (!raw.includes("BETTER_AUTH_SECRET")) {
|
|
5233
|
-
await
|
|
5216
|
+
await fsPromises31.appendFile(
|
|
5234
5217
|
envFilePath,
|
|
5235
5218
|
`
|
|
5236
5219
|
${envLinesToAdd}`,
|
|
@@ -5255,8 +5238,8 @@ Error details: ${error.message || error}`));
|
|
|
5255
5238
|
// src/modules/docker/index.ts
|
|
5256
5239
|
import { spinner as spinner19 } from "@clack/prompts";
|
|
5257
5240
|
import pc27 from "picocolors";
|
|
5258
|
-
import
|
|
5259
|
-
import
|
|
5241
|
+
import fsPromises32 from "fs/promises";
|
|
5242
|
+
import path35 from "path";
|
|
5260
5243
|
async function setupDocker(projectPath, options) {
|
|
5261
5244
|
if (!options.postgres && !options.redis) {
|
|
5262
5245
|
return;
|
|
@@ -5264,8 +5247,8 @@ async function setupDocker(projectPath, options) {
|
|
|
5264
5247
|
const s = spinner19();
|
|
5265
5248
|
s.start("Configuring root Docker infrastructure in docker/...");
|
|
5266
5249
|
try {
|
|
5267
|
-
const dockerDir =
|
|
5268
|
-
await
|
|
5250
|
+
const dockerDir = path35.join(projectPath, "docker");
|
|
5251
|
+
await fsPromises32.mkdir(dockerDir, { recursive: true });
|
|
5269
5252
|
const safeName = options.projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5270
5253
|
const services = [];
|
|
5271
5254
|
const volumes = [];
|
|
@@ -5327,8 +5310,8 @@ async function setupDocker(projectPath, options) {
|
|
|
5327
5310
|
volumes.join("\n"),
|
|
5328
5311
|
""
|
|
5329
5312
|
].join("\n");
|
|
5330
|
-
await
|
|
5331
|
-
|
|
5313
|
+
await fsPromises32.writeFile(
|
|
5314
|
+
path35.join(dockerDir, "docker-compose.yml"),
|
|
5332
5315
|
composeContent,
|
|
5333
5316
|
"utf8"
|
|
5334
5317
|
);
|
|
@@ -5354,7 +5337,7 @@ async function runWorkspaceScaffolder(options = {}) {
|
|
|
5354
5337
|
await runPreflightChecks();
|
|
5355
5338
|
const isMonorepo = !options.react && !options.next;
|
|
5356
5339
|
const name = await promptWorkspaceName(isMonorepo);
|
|
5357
|
-
const projectPath =
|
|
5340
|
+
const projectPath = path36.join(process.cwd(), name);
|
|
5358
5341
|
await checkTargetDirectory(projectPath, name);
|
|
5359
5342
|
if (options.react) {
|
|
5360
5343
|
await runReactScaffolder(name, projectPath);
|
|
@@ -5501,6 +5484,7 @@ async function runWorkspaceScaffolder(options = {}) {
|
|
|
5501
5484
|
}
|
|
5502
5485
|
});
|
|
5503
5486
|
await promptAndInstallSkills(projectPath);
|
|
5487
|
+
await removeBunLockfiles(projectPath);
|
|
5504
5488
|
const s = spinner20();
|
|
5505
5489
|
s.start("Running final workspace package installation...");
|
|
5506
5490
|
try {
|
|
@@ -5528,6 +5512,8 @@ Error details: ${error.message || error}`));
|
|
|
5528
5512
|
}
|
|
5529
5513
|
|
|
5530
5514
|
// src/index.ts
|
|
5515
|
+
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ""} --no-deprecation`.trim();
|
|
5516
|
+
process.env.NODE_NO_WARNINGS = "1";
|
|
5531
5517
|
async function main() {
|
|
5532
5518
|
const isReactOnly = process.argv.includes("--react") || process.argv.includes("-r");
|
|
5533
5519
|
const isNextOnly = process.argv.includes("--nextjs") || process.argv.includes("--next") || process.argv.includes("-n");
|