phos 1.0.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.
Files changed (116) hide show
  1. package/.eslintignore +3 -0
  2. package/AGENTS.md +172 -0
  3. package/CHANGELOG.md +184 -0
  4. package/LICENSE +21 -0
  5. package/README.md +279 -0
  6. package/bun.lock +125 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +255 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/generators/backends/elysia.d.ts +3 -0
  12. package/dist/generators/backends/elysia.d.ts.map +1 -0
  13. package/dist/generators/backends/elysia.js +135 -0
  14. package/dist/generators/backends/elysia.js.map +1 -0
  15. package/dist/generators/backends/fastapi.d.ts +3 -0
  16. package/dist/generators/backends/fastapi.d.ts.map +1 -0
  17. package/dist/generators/backends/fastapi.js +158 -0
  18. package/dist/generators/backends/fastapi.js.map +1 -0
  19. package/dist/generators/frontends/astro.d.ts +3 -0
  20. package/dist/generators/frontends/astro.d.ts.map +1 -0
  21. package/dist/generators/frontends/astro.js +303 -0
  22. package/dist/generators/frontends/astro.js.map +1 -0
  23. package/dist/generators/frontends/nextjs.d.ts +3 -0
  24. package/dist/generators/frontends/nextjs.d.ts.map +1 -0
  25. package/dist/generators/frontends/nextjs.js +274 -0
  26. package/dist/generators/frontends/nextjs.js.map +1 -0
  27. package/dist/generators/frontends/svelte.d.ts +3 -0
  28. package/dist/generators/frontends/svelte.d.ts.map +1 -0
  29. package/dist/generators/frontends/svelte.js +324 -0
  30. package/dist/generators/frontends/svelte.js.map +1 -0
  31. package/dist/generators/monorepo.d.ts +3 -0
  32. package/dist/generators/monorepo.d.ts.map +1 -0
  33. package/dist/generators/monorepo.js +320 -0
  34. package/dist/generators/monorepo.js.map +1 -0
  35. package/dist/generators/single.d.ts +3 -0
  36. package/dist/generators/single.d.ts.map +1 -0
  37. package/dist/generators/single.js +229 -0
  38. package/dist/generators/single.js.map +1 -0
  39. package/dist/utils/helpers.d.ts +38 -0
  40. package/dist/utils/helpers.d.ts.map +1 -0
  41. package/dist/utils/helpers.js +109 -0
  42. package/dist/utils/helpers.js.map +1 -0
  43. package/package.json +46 -0
  44. package/src/cli.ts +500 -0
  45. package/src/generators/backends/elysia.ts +45 -0
  46. package/src/generators/backends/fastapi.ts +71 -0
  47. package/src/generators/frontends/astro.ts +37 -0
  48. package/src/generators/frontends/nextjs.ts +37 -0
  49. package/src/generators/frontends/svelte.ts +38 -0
  50. package/src/generators/monorepo.ts +529 -0
  51. package/src/generators/single.ts +465 -0
  52. package/src/templates/backend/elysia/README.md +15 -0
  53. package/src/templates/backend/elysia/package.json +26 -0
  54. package/src/templates/backend/elysia/src/api/user_api.ts +0 -0
  55. package/src/templates/backend/elysia/src/db.ts +17 -0
  56. package/src/templates/backend/elysia/src/index.ts +68 -0
  57. package/src/templates/backend/elysia/src/service/user_service.ts +0 -0
  58. package/src/templates/backend/elysia/src/sql/user_sql.ts +0 -0
  59. package/src/templates/backend/elysia/src/types/user_type.ts +0 -0
  60. package/src/templates/backend/elysia/tsconfig.json +103 -0
  61. package/src/templates/backend/fastapi/.pylintrc +2 -0
  62. package/src/templates/backend/fastapi/README.md +33 -0
  63. package/src/templates/backend/fastapi/pyproject.toml +9 -0
  64. package/src/templates/backend/fastapi/pyproject_prettier.toml +20 -0
  65. package/src/templates/backend/fastapi/requirements.txt +15 -0
  66. package/src/templates/backend/fastapi/setup.sh +23 -0
  67. package/src/templates/backend/fastapi/src/api/user_api.py +0 -0
  68. package/src/templates/backend/fastapi/src/db.py +31 -0
  69. package/src/templates/backend/fastapi/src/main.py +53 -0
  70. package/src/templates/backend/fastapi/src/service/user_service.py +0 -0
  71. package/src/templates/backend/fastapi/src/sql/user_sql.py +0 -0
  72. package/src/templates/backend/fastapi/src/types/user_type.py +0 -0
  73. package/src/templates/frontend/astro/README.md +46 -0
  74. package/src/templates/frontend/astro/astro.config.mjs +5 -0
  75. package/src/templates/frontend/astro/package.json +28 -0
  76. package/src/templates/frontend/astro/public/favicon.ico +0 -0
  77. package/src/templates/frontend/astro/public/favicon.svg +9 -0
  78. package/src/templates/frontend/astro/src/assets/astro.svg +1 -0
  79. package/src/templates/frontend/astro/src/assets/background.svg +1 -0
  80. package/src/templates/frontend/astro/src/components/Welcome.astro +5 -0
  81. package/src/templates/frontend/astro/src/layouts/Layout.astro +23 -0
  82. package/src/templates/frontend/astro/src/pages/index.astro +8 -0
  83. package/src/templates/frontend/astro/tsconfig.json +5 -0
  84. package/src/templates/frontend/nextjs/README.md +36 -0
  85. package/src/templates/frontend/nextjs/app/favicon.ico +0 -0
  86. package/src/templates/frontend/nextjs/app/globals.css +26 -0
  87. package/src/templates/frontend/nextjs/app/layout.tsx +34 -0
  88. package/src/templates/frontend/nextjs/app/page.tsx +16 -0
  89. package/src/templates/frontend/nextjs/eslint.config.mjs +18 -0
  90. package/src/templates/frontend/nextjs/next.config.ts +7 -0
  91. package/src/templates/frontend/nextjs/package.json +28 -0
  92. package/src/templates/frontend/nextjs/postcss.config.mjs +7 -0
  93. package/src/templates/frontend/nextjs/public/file.svg +1 -0
  94. package/src/templates/frontend/nextjs/public/globe.svg +1 -0
  95. package/src/templates/frontend/nextjs/public/next.svg +1 -0
  96. package/src/templates/frontend/nextjs/public/vercel.svg +1 -0
  97. package/src/templates/frontend/nextjs/public/window.svg +1 -0
  98. package/src/templates/frontend/nextjs/tsconfig.json +34 -0
  99. package/src/templates/frontend/svelte/.prettierignore +9 -0
  100. package/src/templates/frontend/svelte/.prettierrc +19 -0
  101. package/src/templates/frontend/svelte/README.md +42 -0
  102. package/src/templates/frontend/svelte/eslint.config.js +39 -0
  103. package/src/templates/frontend/svelte/package.json +39 -0
  104. package/src/templates/frontend/svelte/src/app.d.ts +13 -0
  105. package/src/templates/frontend/svelte/src/app.html +11 -0
  106. package/src/templates/frontend/svelte/src/lib/assets/favicon.svg +1 -0
  107. package/src/templates/frontend/svelte/src/lib/index.ts +1 -0
  108. package/src/templates/frontend/svelte/src/routes/+layout.svelte +9 -0
  109. package/src/templates/frontend/svelte/src/routes/+page.svelte +2 -0
  110. package/src/templates/frontend/svelte/src/routes/layout.css +2 -0
  111. package/src/templates/frontend/svelte/static/robots.txt +3 -0
  112. package/src/templates/frontend/svelte/svelte.config.js +13 -0
  113. package/src/templates/frontend/svelte/tsconfig.json +20 -0
  114. package/src/templates/frontend/svelte/vite.config.ts +5 -0
  115. package/src/utils/helpers.ts +198 -0
  116. package/tsconfig.json +24 -0
@@ -0,0 +1,109 @@
1
+ import fs from 'fs-extra';
2
+ import Handlebars from 'handlebars';
3
+ import pc from 'picocolors';
4
+ import { execSync } from 'child_process';
5
+ import { resolve, join } from 'path';
6
+ export async function createDirectory(dirPath) {
7
+ await fs.ensureDir(dirPath);
8
+ }
9
+ export async function writeFile(filePath, content) {
10
+ await fs.ensureFile(filePath);
11
+ await fs.writeFile(filePath, content, 'utf-8');
12
+ }
13
+ export async function copyTemplate(templatePath, outputPath, data) {
14
+ const files = await fs.readdir(templatePath, { withFileTypes: true });
15
+ for (const file of files) {
16
+ const srcPath = join(templatePath, file.name);
17
+ const destPath = join(outputPath, file.name);
18
+ if (file.isDirectory()) {
19
+ await createDirectory(destPath);
20
+ await copyTemplate(srcPath, destPath, data);
21
+ }
22
+ else {
23
+ let content = await fs.readFile(srcPath, 'utf-8');
24
+ const template = Handlebars.compile(content);
25
+ const rendered = template(data);
26
+ await writeFile(destPath, rendered);
27
+ }
28
+ }
29
+ }
30
+ export function getPackageManagerInstallCmd(packageManager) {
31
+ switch (packageManager) {
32
+ case 'npm':
33
+ return 'npm install';
34
+ case 'yarn':
35
+ return 'yarn';
36
+ case 'pnpm':
37
+ return 'pnpm install';
38
+ case 'bun':
39
+ return 'bun install';
40
+ default:
41
+ return 'npm install';
42
+ }
43
+ }
44
+ export function getPackageManagerRunCmd(packageManager, script) {
45
+ switch (packageManager) {
46
+ case 'npm':
47
+ return `npm run ${script}`;
48
+ case 'yarn':
49
+ return `yarn ${script}`;
50
+ case 'pnpm':
51
+ return `pnpm run ${script}`;
52
+ case 'bun':
53
+ return `bun run ${script}`;
54
+ default:
55
+ return `npm run ${script}`;
56
+ }
57
+ }
58
+ export function logStep(message) {
59
+ console.log(pc.cyan(` ${message}`));
60
+ }
61
+ export function logSuccess(message) {
62
+ console.log(pc.green(` ✅ ${message}`));
63
+ }
64
+ export function logInfo(message) {
65
+ console.log(pc.blue(` ℹ️ ${message}`));
66
+ }
67
+ export async function installDependencies(projectPath, packageManager) {
68
+ try {
69
+ logStep(`Installing dependencies with ${packageManager}...`);
70
+ execSync(getPackageManagerInstallCmd(packageManager), {
71
+ cwd: projectPath,
72
+ stdio: 'inherit',
73
+ });
74
+ logSuccess('Dependencies installed');
75
+ }
76
+ catch (error) {
77
+ throw new Error(`Failed to install dependencies: ${error}`);
78
+ }
79
+ }
80
+ export async function initializeGit(projectPath) {
81
+ try {
82
+ logStep('Initializing Git repository...');
83
+ execSync('git init', { cwd: projectPath, stdio: 'inherit' });
84
+ execSync('git add .', { cwd: projectPath, stdio: 'inherit' });
85
+ execSync('git commit -m "Initial commit from Phos"', {
86
+ cwd: projectPath,
87
+ stdio: 'inherit',
88
+ });
89
+ logSuccess('Git repository initialized');
90
+ }
91
+ catch (error) {
92
+ throw new Error(`Failed to initialize Git: ${error}`);
93
+ }
94
+ }
95
+ export function getProjectPath(projectName) {
96
+ return resolve(process.cwd(), projectName);
97
+ }
98
+ export function capitalize(str) {
99
+ return str.charAt(0).toUpperCase() + str.slice(1);
100
+ }
101
+ export function toKebabCase(str) {
102
+ return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
103
+ }
104
+ export function toPascalCase(str) {
105
+ return str
106
+ .replace(/[-_](.)/g, (_, c) => c.toUpperCase())
107
+ .replace(/^(.)/, c => c.toUpperCase());
108
+ }
109
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "phos",
3
+ "version": "1.0.0",
4
+ "description": "Full-stack interactive project generator CLI - Phos",
5
+ "type": "module",
6
+ "bin": {
7
+ "phos": "dist/cli.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node dist/cli.js",
11
+ "dev": "tsx src/cli.ts",
12
+ "build": "tsc"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "generator",
17
+ "scaffold",
18
+ "create",
19
+ "phos"
20
+ ],
21
+ "author": "DotJumpDot",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@clack/prompts": "^1.0.0",
25
+ "commander": "^14.0.2",
26
+ "fs-extra": "^11.3.3",
27
+ "handlebars": "^4.7.8",
28
+ "picocolors": "^1.1.1"
29
+ },
30
+ "devDependencies": {
31
+ "@types/fs-extra": "^11.0.4",
32
+ "@types/node": "^20.11.0",
33
+ "tsx": "^4.19.2",
34
+ "typescript": "^5.7.3"
35
+ },
36
+ "main": "./dist/cli.js",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/DotJumpDot/Phos.git"
40
+ },
41
+ "types": "./dist/cli.d.ts",
42
+ "bugs": {
43
+ "url": "https://github.com/DotJumpDot/Phos/issues"
44
+ },
45
+ "homepage": "https://github.com/DotJumpDot/Phos#readme"
46
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,500 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import { intro, outro, select, text, confirm, multiselect, note } from "@clack/prompts";
5
+ import pc from "picocolors";
6
+ import { existsSync } from "fs";
7
+ import { resolve } from "path";
8
+ import { generateMonorepo } from "@/generators/monorepo.js";
9
+ import { generateSingle } from "@/generators/single.js";
10
+
11
+ const program = new Command();
12
+
13
+ program.name("phos").description("Full-stack interactive project generator CLI").version("1.0.0");
14
+
15
+ program
16
+ .command("create")
17
+ .description("Create a new project")
18
+ .action(async () => {
19
+ intro(pc.bgCyan(pc.black(" Phos ")));
20
+
21
+ const projectName = await text({
22
+ message: "Project name",
23
+ placeholder: "my-awesome-app",
24
+ validate: (value) => {
25
+ if (!value) return "Project name is required";
26
+ if (!/^[a-z0-9-]+$/.test(value)) {
27
+ return "Project name must be lowercase letters, numbers, and hyphens only";
28
+ }
29
+ const projectPath = resolve(process.cwd(), value);
30
+ if (existsSync(projectPath)) {
31
+ return `Directory "${value}" already exists`;
32
+ }
33
+ return undefined;
34
+ },
35
+ });
36
+
37
+ if (typeof projectName !== "string" || !projectName) {
38
+ outro(pc.red("Project creation cancelled"));
39
+ process.exit(0);
40
+ }
41
+
42
+ const projectType = await select({
43
+ message: "Select project type",
44
+ options: [
45
+ { value: "monorepo", label: "Monorepo" },
46
+ { value: "single", label: "Single repo" },
47
+ ],
48
+ });
49
+
50
+ if (typeof projectType !== "string") {
51
+ outro(pc.red("Project creation cancelled"));
52
+ process.exit(0);
53
+ }
54
+
55
+ const projectTypeTyped = projectType as "monorepo" | "single";
56
+
57
+ let backendFramework: "elysia" | "fastapi" | undefined;
58
+ let frontendFramework: "astro" | "svelte" | "nextjs" | undefined;
59
+ let selectedFramework: "elysia" | "fastapi" | "astro" | "svelte" | "nextjs" | undefined;
60
+ let packageManager: "npm" | "yarn" | "pnpm" | "bun" | "venv" | "pip";
61
+ let useTypeScript: boolean;
62
+ let addESLint: boolean;
63
+ let addPrettier: boolean;
64
+ let cssFramework: "none" | "tailwind" | "scss" | "css-modules" = "none";
65
+ let uiComponents: "none" | "shadcn" | "radix" = "none";
66
+ let testing: "none" | "vitest" | "playwright" | "both" = "none";
67
+
68
+ if (projectTypeTyped === "monorepo") {
69
+ backendFramework = (await select({
70
+ message: "Select Backend Framework",
71
+ options: [
72
+ { value: "elysia", label: "Elysia" },
73
+ { value: "fastapi", label: "FastAPI" },
74
+ ],
75
+ })) as "elysia" | "fastapi";
76
+
77
+ if (typeof backendFramework !== "string") {
78
+ outro(pc.red("Project creation cancelled"));
79
+ process.exit(0);
80
+ }
81
+
82
+ packageManager = (await select({
83
+ message:
84
+ backendFramework === "fastapi"
85
+ ? "Select Python Environment"
86
+ : "Select Backend package manager",
87
+ options:
88
+ backendFramework === "fastapi"
89
+ ? [
90
+ { value: "venv", label: "venv (virtual environment)" },
91
+ { value: "pip", label: "pip (system)" },
92
+ ]
93
+ : [
94
+ { value: "npm", label: "npm" },
95
+ { value: "yarn", label: "yarn" },
96
+ { value: "pnpm", label: "pnpm" },
97
+ { value: "bun", label: "bun" },
98
+ ],
99
+ })) as "npm" | "yarn" | "pnpm" | "bun" | "venv" | "pip";
100
+
101
+ if (typeof packageManager !== "string") {
102
+ outro(pc.red("Project creation cancelled"));
103
+ process.exit(0);
104
+ }
105
+
106
+ useTypeScript =
107
+ backendFramework === "fastapi"
108
+ ? false
109
+ : ((await confirm({
110
+ message: "Backend: Use TypeScript?",
111
+ initialValue: true,
112
+ })) as boolean);
113
+
114
+ if (typeof useTypeScript !== "boolean") {
115
+ outro(pc.red("Project creation cancelled"));
116
+ process.exit(0);
117
+ }
118
+
119
+ addESLint = (await confirm({
120
+ message: "Backend: Add ESLint?",
121
+ initialValue: true,
122
+ })) as boolean;
123
+
124
+ if (typeof addESLint !== "boolean") {
125
+ outro(pc.red("Project creation cancelled"));
126
+ process.exit(0);
127
+ }
128
+
129
+ addPrettier =
130
+ backendFramework === "fastapi"
131
+ ? false
132
+ : ((await confirm({
133
+ message: "Backend: Add Prettier?",
134
+ initialValue: true,
135
+ })) as boolean);
136
+
137
+ if (typeof addPrettier !== "boolean") {
138
+ outro(pc.red("Project creation cancelled"));
139
+ process.exit(0);
140
+ }
141
+
142
+ frontendFramework = (await select({
143
+ message: "Select Frontend Framework",
144
+ options: [
145
+ { value: "astro", label: "Astro" },
146
+ { value: "svelte", label: "Svelte" },
147
+ { value: "nextjs", label: "NextJS" },
148
+ ],
149
+ })) as "astro" | "svelte" | "nextjs";
150
+
151
+ if (typeof frontendFramework !== "string") {
152
+ outro(pc.red("Project creation cancelled"));
153
+ process.exit(0);
154
+ }
155
+
156
+ const frontendPackageManager = await select({
157
+ message: "Select Frontend package manager",
158
+ options: [
159
+ { value: "npm", label: "npm" },
160
+ { value: "yarn", label: "yarn" },
161
+ { value: "pnpm", label: "pnpm" },
162
+ { value: "bun", label: "bun" },
163
+ ],
164
+ });
165
+
166
+ if (typeof frontendPackageManager !== "string") {
167
+ outro(pc.red("Project creation cancelled"));
168
+ process.exit(0);
169
+ }
170
+
171
+ const frontendUseTypeScript = await confirm({
172
+ message: "Frontend: Use TypeScript?",
173
+ initialValue: true,
174
+ });
175
+
176
+ if (typeof frontendUseTypeScript !== "boolean") {
177
+ outro(pc.red("Project creation cancelled"));
178
+ process.exit(0);
179
+ }
180
+
181
+ const frontendAddESLint = await confirm({
182
+ message: "Frontend: Add ESLint?",
183
+ initialValue: true,
184
+ });
185
+
186
+ if (typeof frontendAddESLint !== "boolean") {
187
+ outro(pc.red("Project creation cancelled"));
188
+ process.exit(0);
189
+ }
190
+
191
+ const frontendAddPrettier = await confirm({
192
+ message: "Frontend: Add Prettier?",
193
+ initialValue: true,
194
+ });
195
+
196
+ if (typeof frontendAddPrettier !== "boolean") {
197
+ outro(pc.red("Project creation cancelled"));
198
+ process.exit(0);
199
+ }
200
+
201
+ cssFramework = (await select({
202
+ message: "Select CSS Framework",
203
+ options: [
204
+ { value: "none", label: "No" },
205
+ { value: "tailwind", label: "Tailwind CSS" },
206
+ { value: "scss", label: "SCSS" },
207
+ { value: "css-modules", label: "CSS Modules" },
208
+ ],
209
+ })) as "none" | "tailwind" | "scss" | "css-modules";
210
+
211
+ if (typeof cssFramework !== "string") {
212
+ outro(pc.red("Project creation cancelled"));
213
+ process.exit(0);
214
+ }
215
+
216
+ uiComponents = (await select({
217
+ message: "Add UI Components?",
218
+ options: [
219
+ { value: "none", label: "No" },
220
+ { value: "shadcn", label: "shadcn/ui" },
221
+ { value: "radix", label: "Radix UI" },
222
+ ],
223
+ })) as "none" | "shadcn" | "radix";
224
+
225
+ if (typeof uiComponents !== "string") {
226
+ outro(pc.red("Project creation cancelled"));
227
+ process.exit(0);
228
+ }
229
+
230
+ testing = (await select({
231
+ message: "Add Testing?",
232
+ options: [
233
+ { value: "none", label: "No" },
234
+ { value: "vitest", label: "Vitest" },
235
+ { value: "playwright", label: "Playwright" },
236
+ { value: "both", label: "Vitest + Playwright" },
237
+ ],
238
+ })) as "none" | "vitest" | "playwright" | "both";
239
+
240
+ if (typeof testing !== "string") {
241
+ outro(pc.red("Project creation cancelled"));
242
+ process.exit(0);
243
+ }
244
+ } else {
245
+ selectedFramework = (await select({
246
+ message: "Select What Framework u want to set up?",
247
+ options: [
248
+ { value: "elysia", label: "ElysiaJS" },
249
+ { value: "fastapi", label: "FastAPI" },
250
+ { value: "svelte", label: "Svelte" },
251
+ { value: "nextjs", label: "NextJS" },
252
+ { value: "astro", label: "Astro" },
253
+ ],
254
+ })) as "elysia" | "fastapi" | "svelte" | "nextjs" | "astro";
255
+
256
+ if (typeof selectedFramework !== "string") {
257
+ outro(pc.red("Project creation cancelled"));
258
+ process.exit(0);
259
+ }
260
+
261
+ if (selectedFramework === "elysia" || selectedFramework === "fastapi") {
262
+ backendFramework = selectedFramework as "elysia" | "fastapi";
263
+ packageManager = (await select({
264
+ message:
265
+ selectedFramework === "fastapi"
266
+ ? "Select Python Environment"
267
+ : "Select Backend package manager",
268
+ options:
269
+ selectedFramework === "fastapi"
270
+ ? [
271
+ { value: "venv", label: "venv (virtual environment)" },
272
+ { value: "pip", label: "pip (system)" },
273
+ ]
274
+ : [
275
+ { value: "npm", label: "npm" },
276
+ { value: "yarn", label: "yarn" },
277
+ { value: "pnpm", label: "pnpm" },
278
+ { value: "bun", label: "bun" },
279
+ ],
280
+ })) as "npm" | "yarn" | "pnpm" | "bun" | "venv" | "pip";
281
+
282
+ if (typeof packageManager !== "string") {
283
+ outro(pc.red("Project creation cancelled"));
284
+ process.exit(0);
285
+ }
286
+
287
+ useTypeScript =
288
+ selectedFramework === "fastapi"
289
+ ? false
290
+ : ((await confirm({
291
+ message: "Backend: Use TypeScript?",
292
+ initialValue: true,
293
+ })) as boolean);
294
+
295
+ if (typeof useTypeScript !== "boolean") {
296
+ outro(pc.red("Project creation cancelled"));
297
+ process.exit(0);
298
+ }
299
+
300
+ addESLint = (await confirm({
301
+ message: "Backend: Add ESLint?",
302
+ initialValue: true,
303
+ })) as boolean;
304
+
305
+ if (typeof addESLint !== "boolean") {
306
+ outro(pc.red("Project creation cancelled"));
307
+ process.exit(0);
308
+ }
309
+
310
+ addPrettier =
311
+ selectedFramework === "fastapi"
312
+ ? false
313
+ : ((await confirm({
314
+ message: "Backend: Add Prettier?",
315
+ initialValue: true,
316
+ })) as boolean);
317
+
318
+ if (typeof addPrettier !== "boolean") {
319
+ outro(pc.red("Project creation cancelled"));
320
+ process.exit(0);
321
+ }
322
+ } else {
323
+ frontendFramework = selectedFramework as "astro" | "svelte" | "nextjs";
324
+ packageManager = (await select({
325
+ message: "Select package manager",
326
+ options: [
327
+ { value: "npm", label: "npm" },
328
+ { value: "yarn", label: "yarn" },
329
+ { value: "pnpm", label: "pnpm" },
330
+ { value: "bun", label: "bun" },
331
+ ],
332
+ })) as "npm" | "yarn" | "pnpm" | "bun";
333
+
334
+ if (typeof packageManager !== "string") {
335
+ outro(pc.red("Project creation cancelled"));
336
+ process.exit(0);
337
+ }
338
+
339
+ useTypeScript = (await confirm({
340
+ message: "Use TypeScript?",
341
+ initialValue: true,
342
+ })) as boolean;
343
+
344
+ if (typeof useTypeScript !== "boolean") {
345
+ outro(pc.red("Project creation cancelled"));
346
+ process.exit(0);
347
+ }
348
+
349
+ addESLint = (await confirm({
350
+ message: "Add ESLint?",
351
+ initialValue: true,
352
+ })) as boolean;
353
+
354
+ if (typeof addESLint !== "boolean") {
355
+ outro(pc.red("Project creation cancelled"));
356
+ process.exit(0);
357
+ }
358
+
359
+ addPrettier = (await confirm({
360
+ message: "Add Prettier?",
361
+ initialValue: true,
362
+ })) as boolean;
363
+
364
+ if (typeof addPrettier !== "boolean") {
365
+ outro(pc.red("Project creation cancelled"));
366
+ process.exit(0);
367
+ }
368
+
369
+ cssFramework = (await select({
370
+ message: "Select CSS Framework",
371
+ options: [
372
+ { value: "none", label: "No" },
373
+ { value: "tailwind", label: "Tailwind CSS" },
374
+ { value: "scss", label: "SCSS" },
375
+ { value: "css-modules", label: "CSS Modules" },
376
+ ],
377
+ })) as "none" | "tailwind" | "scss" | "css-modules";
378
+
379
+ if (typeof cssFramework !== "string") {
380
+ outro(pc.red("Project creation cancelled"));
381
+ process.exit(0);
382
+ }
383
+
384
+ uiComponents = (await select({
385
+ message: "Add UI Components?",
386
+ options: [
387
+ { value: "none", label: "No" },
388
+ { value: "shadcn", label: "shadcn/ui" },
389
+ { value: "radix", label: "Radix UI" },
390
+ ],
391
+ })) as "none" | "shadcn" | "radix";
392
+
393
+ if (typeof uiComponents !== "string") {
394
+ outro(pc.red("Project creation cancelled"));
395
+ process.exit(0);
396
+ }
397
+
398
+ testing = (await select({
399
+ message: "Add Testing?",
400
+ options: [
401
+ { value: "none", label: "No" },
402
+ { value: "vitest", label: "Vitest" },
403
+ { value: "playwright", label: "Playwright" },
404
+ { value: "both", label: "Vitest + Playwright" },
405
+ ],
406
+ })) as "none" | "vitest" | "playwright" | "both";
407
+
408
+ if (typeof testing !== "string") {
409
+ outro(pc.red("Project creation cancelled"));
410
+ process.exit(0);
411
+ }
412
+ }
413
+ }
414
+
415
+ const initGit = await confirm({
416
+ message: "Initialize Git?",
417
+ initialValue: false,
418
+ });
419
+
420
+ if (typeof initGit !== "boolean") {
421
+ outro(pc.red("Project creation cancelled"));
422
+ process.exit(0);
423
+ }
424
+
425
+ const installDeps = await confirm({
426
+ message: "Install dependencies?",
427
+ initialValue: false,
428
+ });
429
+
430
+ if (typeof installDeps !== "boolean") {
431
+ outro(pc.red("Project creation cancelled"));
432
+ process.exit(0);
433
+ }
434
+
435
+ const config = {
436
+ projectName,
437
+ projectType: projectTypeTyped,
438
+ backend: backendFramework
439
+ ? {
440
+ framework: backendFramework,
441
+ packageManager: packageManager as "npm" | "yarn" | "pnpm" | "bun" | "venv" | "pip",
442
+ typescript: useTypeScript,
443
+ eslint: addESLint,
444
+ prettier: addPrettier,
445
+ }
446
+ : undefined,
447
+ frontend: frontendFramework
448
+ ? {
449
+ framework: frontendFramework,
450
+ packageManager: packageManager as "npm" | "yarn" | "pnpm" | "bun",
451
+ typescript: useTypeScript,
452
+ eslint: addESLint,
453
+ prettier: addPrettier,
454
+ cssFramework,
455
+ uiComponents,
456
+ testing,
457
+ }
458
+ : undefined,
459
+ git: initGit,
460
+ install: installDeps,
461
+ };
462
+
463
+ const summaryLines = [
464
+ `${pc.cyan("Project:")} ${projectName}`,
465
+ `${pc.cyan("Type:")} ${projectTypeTyped}`,
466
+ projectTypeTyped === "monorepo"
467
+ ? `${pc.cyan("Backend:")} ${backendFramework} (${packageManager})`
468
+ : "",
469
+ projectTypeTyped === "monorepo"
470
+ ? `${pc.cyan("Frontend:")} ${frontendFramework} (${packageManager})`
471
+ : "",
472
+ projectTypeTyped === "single"
473
+ ? `${pc.cyan("Framework:")} ${selectedFramework} (${packageManager})`
474
+ : "",
475
+ `${pc.cyan("TypeScript:")} ${useTypeScript ? "Yes" : "No"}`,
476
+ `${pc.cyan("ESLint:")} ${addESLint ? "Yes" : "No"}`,
477
+ `${pc.cyan("Prettier:")} ${addPrettier ? "Yes" : "No"}`,
478
+ frontendFramework ? `${pc.cyan("CSS:")} ${cssFramework}` : "",
479
+ frontendFramework ? `${pc.cyan("UI Components:")} ${uiComponents}` : "",
480
+ frontendFramework ? `${pc.cyan("Testing:")} ${testing}` : "",
481
+ `${pc.cyan("Git:")} ${initGit ? "Yes" : "No"}`,
482
+ `${pc.cyan("Install:")} ${installDeps ? "Yes" : "No"}`,
483
+ ].filter(Boolean);
484
+
485
+ note(`${pc.bold("Configuration Summary")}\n\n` + summaryLines.join("\n"), "Configuration");
486
+
487
+ try {
488
+ if (projectTypeTyped === "monorepo") {
489
+ await generateMonorepo(config);
490
+ } else {
491
+ await generateSingle(config);
492
+ }
493
+ outro(pc.green("✨ Project created successfully!"));
494
+ } catch (error) {
495
+ outro(pc.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
496
+ process.exit(1);
497
+ }
498
+ });
499
+
500
+ program.parse();