create-better-fullstack 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,399 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { f as types_exports, m as DEFAULT_CONFIG } from "./bts-config-Bg1Qea9Y.mjs";
3
- import { a as CLIError, c as exitWithError, d as isFirstPrompt, f as isSilent, h as setLastPromptShownUI, m as setIsFirstPrompt$1, s as exitCancelled } from "./addons-setup-HSghQS7c.mjs";
2
+ import { A as types_exports, d as setLastPromptShownUI, r as exitCancelled, s as isFirstPrompt, u as setIsFirstPrompt$1, y as DEFAULT_CONFIG } from "./errors-D9yiiGVq.mjs";
3
+ import { m as validateAddonCompatibility, r as getCompatibleAddons } from "./compatibility-rules-D7zYNVjC.mjs";
4
4
  import { log, spinner } from "@clack/prompts";
5
5
  import pc from "picocolors";
6
6
  import fs from "fs-extra";
7
7
  import path from "node:path";
8
- import { allowedApisForFrontends, getAIFrontendCompatibilityIssue, getApiFrontendCompatibilityIssue, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getUnsupportedWebDeployFrontend, hasDockerComposeCompatibleFrontend, hasWebStyling, isBackendUtilsCompatibleBackend, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
9
- import gradient from "gradient-string";
10
8
  import consola from "consola";
11
9
  import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
12
10
  import { $ } from "execa";
13
11
 
14
- //#region src/utils/render-title.ts
15
- const TITLE_TEXT = `
16
- ██████╗ ███████╗████████╗████████╗███████╗██████╗
17
- ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗
18
- ██████╔╝█████╗ ██║ ██║ █████╗ ██████╔╝
19
- ██╔══██╗██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗
20
- ██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║
21
- ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
22
-
23
- ███████╗██╗ ██╗██╗ ██╗ ███████╗████████╗ █████╗ ██████╗██╗ ██╗
24
- ██╔════╝██║ ██║██║ ██║ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝
25
- █████╗ ██║ ██║██║ ██║ ███████╗ ██║ ███████║██║ █████╔╝
26
- ██╔══╝ ██║ ██║██║ ██║ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗
27
- ██║ ╚██████╔╝███████╗███████╗███████║ ██║ ██║ ██║╚██████╗██║ ██╗
28
- ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
29
- `;
30
- const monochromeTheme = {
31
- white: "#FFFFFF",
32
- lightGray: "#E5E5E5",
33
- gray: "#A3A3A3",
34
- darkGray: "#737373"
35
- };
36
- const renderTitle = () => {
37
- const terminalWidth = process.stdout.columns || 80;
38
- const titleLines = TITLE_TEXT.split("\n");
39
- if (terminalWidth < Math.max(...titleLines.map((line) => line.length))) console.log(gradient(Object.values(monochromeTheme)).multiline(`Better Fullstack`));
40
- else console.log(gradient(Object.values(monochromeTheme)).multiline(TITLE_TEXT));
41
- };
42
-
43
- //#endregion
44
- //#region src/utils/error-formatter.ts
45
- function getCategoryTitle(category) {
46
- return {
47
- incompatibility: "Incompatible Options",
48
- "invalid-selection": "Invalid Selection",
49
- "missing-requirement": "Missing Requirement",
50
- constraint: "Constraint Violation"
51
- }[category];
52
- }
53
- function displayStructuredError(error) {
54
- if (isSilent()) throw new CLIError(error.message);
55
- const lines = [];
56
- lines.push(pc.bold(pc.red(getCategoryTitle(error.category))));
57
- lines.push("");
58
- lines.push(error.message);
59
- if (error.provided && Object.keys(error.provided).length > 0) {
60
- lines.push("");
61
- lines.push(pc.dim("You provided:"));
62
- for (const [key, value] of Object.entries(error.provided)) {
63
- const displayValue = Array.isArray(value) ? value.join(", ") : value;
64
- lines.push(` ${pc.cyan("--" + key)} ${displayValue}`);
65
- }
66
- }
67
- if (error.suggestions.length > 0) {
68
- lines.push("");
69
- lines.push(pc.dim("Suggestions:"));
70
- for (const suggestion of error.suggestions) lines.push(` ${pc.green("•")} ${suggestion}`);
71
- }
72
- consola.box({
73
- title: pc.red("Error"),
74
- message: lines.join("\n"),
75
- style: { borderColor: "red" }
76
- });
77
- process.exit(1);
78
- }
79
- function incompatibilityError(opts) {
80
- return displayStructuredError({
81
- category: "incompatibility",
82
- ...opts
83
- });
84
- }
85
- function invalidSelectionError(opts) {
86
- return displayStructuredError({
87
- category: "invalid-selection",
88
- ...opts
89
- });
90
- }
91
- function missingRequirementError(opts) {
92
- return displayStructuredError({
93
- category: "missing-requirement",
94
- ...opts
95
- });
96
- }
97
- function constraintError(opts) {
98
- return displayStructuredError({
99
- category: "constraint",
100
- ...opts
101
- });
102
- }
103
-
104
- //#endregion
105
- //#region src/utils/compatibility-rules.ts
106
- function isWebFrontend$1(value) {
107
- return isWebFrontend(value);
108
- }
109
- function splitFrontends$1(values = []) {
110
- return splitFrontends(values);
111
- }
112
- function ensureSingleWebAndNative(frontends) {
113
- const { web, native } = splitFrontends$1(frontends);
114
- if (web.length > 1) invalidSelectionError({
115
- message: "Only one web framework can be selected per project.",
116
- provided: { frontend: web },
117
- suggestions: ["Keep one web framework and remove the others", "Use separate projects for multiple web frameworks"]
118
- });
119
- if (native.length > 1) invalidSelectionError({
120
- message: "Only one native framework can be selected per project.",
121
- provided: { frontend: native },
122
- suggestions: ["Keep one native framework and remove the others", "Choose: native-bare, native-uniwind, or native-unistyles"]
123
- });
124
- }
125
- const FULLSTACK_FRONTENDS = [
126
- "next",
127
- "vinext",
128
- "tanstack-start",
129
- "astro",
130
- "nuxt",
131
- "svelte",
132
- "solid-start"
133
- ];
134
- function validateSelfBackendCompatibility(providedFlags, options, config) {
135
- const backend = config.backend || options.backend;
136
- const frontends = config.frontend || options.frontend || [];
137
- if (backend === "self") {
138
- const { web, native } = splitFrontends$1(frontends);
139
- if (!(web.length === 1 && FULLSTACK_FRONTENDS.includes(web[0]))) exitWithError("Backend 'self' (fullstack) only supports Next.js, Vinext, TanStack Start, Astro, Nuxt, SvelteKit, or SolidStart frontends. Please use --frontend next, --frontend vinext, --frontend tanstack-start, --frontend astro, --frontend nuxt, --frontend svelte, or --frontend solid-start.");
140
- if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
141
- }
142
- const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS.includes(f));
143
- if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) only supports Next.js, Vinext, TanStack Start, Astro, Nuxt, SvelteKit, or SolidStart frontends. Please use --frontend next, --frontend vinext, --frontend tanstack-start, --frontend astro, --frontend nuxt, --frontend svelte, --frontend solid-start, or choose a different backend.");
144
- }
145
- const WORKERS_COMPATIBLE_BACKENDS = [
146
- "hono",
147
- "nitro",
148
- "fets"
149
- ];
150
- function validateWorkersCompatibility(providedFlags, options, config) {
151
- if (providedFlags.has("runtime") && options.runtime === "workers" && config.backend && !WORKERS_COMPATIBLE_BACKENDS.includes(config.backend)) incompatibilityError({
152
- message: "In Better-Fullstack, Cloudflare Workers runtime is currently supported only with compatible backends (Hono, Nitro, or Fets).",
153
- provided: {
154
- runtime: "workers",
155
- backend: config.backend
156
- },
157
- suggestions: [
158
- "Use --backend hono",
159
- "Use --backend nitro",
160
- "Use --backend fets",
161
- "Choose a different runtime (node, bun)"
162
- ]
163
- });
164
- if (providedFlags.has("backend") && config.backend && !WORKERS_COMPATIBLE_BACKENDS.includes(config.backend) && config.runtime === "workers") incompatibilityError({
165
- message: `In Better-Fullstack, backend '${config.backend}' is currently not available with Cloudflare Workers runtime.`,
166
- provided: {
167
- backend: config.backend,
168
- runtime: "workers"
169
- },
170
- suggestions: ["Use --backend hono, --backend nitro, or --backend fets", "Choose a different runtime (node, bun)"]
171
- });
172
- if (providedFlags.has("runtime") && options.runtime === "workers" && config.database === "mongodb") incompatibilityError({
173
- message: "In Better-Fullstack, Cloudflare Workers runtime is currently not available with MongoDB.",
174
- provided: {
175
- runtime: "workers",
176
- database: "mongodb"
177
- },
178
- suggestions: ["Use a different database (postgres, sqlite, mysql)", "Choose a different runtime (node, bun)"]
179
- });
180
- if (providedFlags.has("runtime") && options.runtime === "workers" && config.dbSetup === "docker") incompatibilityError({
181
- message: "In Better-Fullstack, Cloudflare Workers runtime is currently not available with Docker database setup.",
182
- provided: {
183
- runtime: "workers",
184
- "db-setup": "docker"
185
- },
186
- suggestions: ["Use --db-setup d1 for SQLite", "Choose a different runtime (node, bun)"]
187
- });
188
- if (providedFlags.has("database") && config.database === "mongodb" && config.runtime === "workers") incompatibilityError({
189
- message: "In Better-Fullstack, MongoDB is currently not available with Cloudflare Workers runtime.",
190
- provided: {
191
- database: "mongodb",
192
- runtime: "workers"
193
- },
194
- suggestions: ["Use a different database (postgres, sqlite, mysql)", "Choose a different runtime (node, bun)"]
195
- });
196
- }
197
- function validateApiFrontendCompatibility(api, frontends = [], astroIntegration) {
198
- const issue = getApiFrontendCompatibilityIssue(api, frontends, astroIntegration);
199
- if (!issue) return;
200
- incompatibilityError({
201
- message: issue.message,
202
- provided: issue.provided ?? {},
203
- suggestions: issue.suggestions ?? []
204
- });
205
- }
206
- function isFrontendAllowedWithBackend$1(frontend, backend, auth) {
207
- return isFrontendAllowedWithBackend(frontend, backend, auth);
208
- }
209
- function allowedApisForFrontends$1(frontends = [], astroIntegration) {
210
- return allowedApisForFrontends(frontends, astroIntegration);
211
- }
212
- function isExampleAIAllowed$1(backend, frontends = []) {
213
- return isExampleAIAllowed(backend, frontends);
214
- }
215
- function isExampleChatSdkAllowed$1(backend, frontends = [], runtime) {
216
- return isExampleChatSdkAllowed(backend, frontends, runtime);
217
- }
218
- function requiresChatSdkVercelAI(backend, frontends = [], runtime) {
219
- return requiresChatSdkVercelAIForSelection(backend, frontends, runtime);
220
- }
221
- function validateWebDeployRequiresWebFrontend(webDeploy, hasWebFrontendFlag) {
222
- if (webDeploy && webDeploy !== "none" && !hasWebFrontendFlag) exitWithError("'--web-deploy' requires a web frontend. Please select a web frontend or set '--web-deploy none'.");
223
- }
224
- function validateWebDeployFrontendTemplates(webDeploy, frontends = []) {
225
- const blocked = getUnsupportedWebDeployFrontend(webDeploy, frontends);
226
- if (blocked) exitWithError(`${webDeploy === "render" ? "Render" : "Netlify"} deployment is not yet wired up for the '${blocked}' frontend. Choose a different web deploy target or frontend.`);
227
- }
228
- function validateServerDeployRequiresBackend(serverDeploy, backend, hasGraphBackend = false) {
229
- if (serverDeploy && serverDeploy !== "none" && !hasGraphBackend && (!backend || backend === "none")) exitWithError("'--server-deploy' requires a backend. Please select a backend or set '--server-deploy none'.");
230
- }
231
- function validateAddonCompatibility$1(addon, frontend, _auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database) {
232
- const baseCompatibility = validateAddonCompatibility(addon, frontend, _auth);
233
- if (!baseCompatibility.isCompatible) return baseCompatibility;
234
- if (addon === "backend-utils") {
235
- if (ecosystem !== void 0 && ecosystem !== "typescript") return {
236
- isCompatible: false,
237
- reason: "Backend Utils requires a TypeScript server stack"
238
- };
239
- if (backend !== void 0 && !isBackendUtilsCompatibleBackend(backend)) return {
240
- isCompatible: false,
241
- reason: "Backend Utils requires a Hono, Express, Fastify, Elysia, feTS, or NestJS backend"
242
- };
243
- }
244
- if (addon === "docker-compose") {
245
- if (backend === "convex") return {
246
- isCompatible: false,
247
- reason: "docker-compose is not compatible with Convex backend (managed service)"
248
- };
249
- if (runtime === "workers") return {
250
- isCompatible: false,
251
- reason: "docker-compose is not compatible with Cloudflare Workers runtime"
252
- };
253
- if (ecosystem === "typescript" && !hasDockerComposeCompatibleFrontend(frontend)) return {
254
- isCompatible: false,
255
- reason: "Docker Compose currently supports Next.js, Vinext, TanStack Router, React Router, React Vite, Solid, or Astro"
256
- };
257
- if (ecosystem === "typescript" && backend === "self" && !frontend.includes("next") && !frontend.includes("vinext")) return {
258
- isCompatible: false,
259
- reason: "Docker Compose self-backend support currently requires Next.js or Vinext"
260
- };
261
- if (ecosystem === "rust" && rustFrontend && rustFrontend !== "none") return {
262
- isCompatible: false,
263
- reason: "Docker Compose for Rust currently supports server-only projects"
264
- };
265
- if (ecosystem === "java" && javaWebFramework && javaWebFramework !== "spring-boot") return {
266
- isCompatible: false,
267
- reason: "Docker Compose for Java currently requires Spring Boot"
268
- };
269
- if (ecosystem === "python" && database && database !== "none" && database !== "sqlite" && database !== "postgres") return {
270
- isCompatible: false,
271
- reason: "Docker Compose for Python ORM projects currently supports SQLite defaults or Postgres"
272
- };
273
- }
274
- return { isCompatible: true };
275
- }
276
- function getCompatibleAddons$1(allAddons, frontend, existingAddons = [], auth, backend, runtime) {
277
- return getCompatibleAddons(allAddons, frontend, existingAddons, auth).filter((addon) => {
278
- const { isCompatible } = validateAddonCompatibility$1(addon, frontend, auth, backend, runtime);
279
- return isCompatible;
280
- });
281
- }
282
- function validateAddonsAgainstFrontends(addons = [], frontends = [], auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database) {
283
- if (addons.includes("nx") && addons.includes("turborepo")) exitWithError("Nx and Turborepo are alternative workspace runners. Choose one addon.");
284
- for (const addon of addons) {
285
- if (addon === "none") continue;
286
- const { isCompatible, reason } = validateAddonCompatibility$1(addon, frontends, auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database);
287
- if (!isCompatible) exitWithError(`Incompatible addon/frontend combination: ${reason}`);
288
- }
289
- }
290
- function validatePaymentsCompatibility(payments, auth, _backend, frontends = []) {
291
- if (!payments || payments === "none") return;
292
- if (payments === "dodo" && frontends.includes("react-vite")) exitWithError("Dodo Payments are not yet supported for React + Vite projects.");
293
- if (payments === "polar") {
294
- if (!auth || auth === "none" || auth !== "better-auth" && auth !== "better-auth-organizations") exitWithError("Polar payments requires Better Auth. Please use '--auth better-auth' or choose a different payments provider.");
295
- const { web } = splitFrontends$1(frontends);
296
- if (web.length === 0 && frontends.length > 0) exitWithError("Polar payments requires a web frontend or no frontend. Please select a web frontend or choose a different payments provider.");
297
- }
298
- }
299
- function validateExamplesCompatibility(examples, backend, frontend, runtime, ai) {
300
- const examplesArr = examples ?? [];
301
- if (examplesArr.length === 0 || examplesArr.includes("none")) return;
302
- if (examplesArr.includes("tanstack-showcase")) {
303
- const showcaseFrontends = ["tanstack-router", "tanstack-start"];
304
- if (!(frontend ?? []).some((f) => showcaseFrontends.includes(f))) exitWithError("The 'tanstack-showcase' example requires TanStack Router or TanStack Start frontend.");
305
- }
306
- if (examplesArr.includes("ai") && (frontend ?? []).includes("solid")) exitWithError("The 'ai' example is not compatible with the Solid frontend.");
307
- if (examplesArr.includes("ai") && (frontend ?? []).includes("solid-start")) exitWithError("The 'ai' example is not compatible with the SolidStart frontend.");
308
- if (examplesArr.includes("ai") && backend === "convex") {
309
- const frontendArr = frontend ?? [];
310
- const includesNuxt = frontendArr.includes("nuxt");
311
- const includesSvelte = frontendArr.includes("svelte");
312
- if (includesNuxt || includesSvelte) exitWithError("The 'ai' example with Convex backend only supports React-based frontends (Next.js, TanStack Router, TanStack Start, React Router, React + Vite). Svelte and Nuxt are not supported with Convex AI.");
313
- }
314
- if (examplesArr.includes("chat-sdk")) {
315
- const frontendArr = frontend ?? [];
316
- if (frontendArr.includes("react-vite")) exitWithError("The 'chat-sdk' example is not yet supported for React + Vite projects.");
317
- if (!isExampleChatSdkAllowed$1(backend, frontendArr, runtime)) {
318
- if (backend === "none") exitWithError("The 'chat-sdk' example requires a backend.");
319
- if (backend === "convex") exitWithError("The 'chat-sdk' example is not supported with the Convex backend in v1. Use self backend (Next.js, TanStack Start, Nuxt) or Hono with Node runtime.");
320
- if (backend === "self") exitWithError("The 'chat-sdk' example with self backend only supports Next.js, TanStack Start, or Nuxt frontends in v1.");
321
- if (backend === "hono" && runtime !== "node") exitWithError("The 'chat-sdk' example with Hono requires '--runtime node' in v1 (Bun/Workers not supported yet).");
322
- exitWithError("The 'chat-sdk' example is only supported with self backend (Next.js, TanStack Start, Nuxt) or Hono with Node runtime in v1.");
323
- }
324
- if (requiresChatSdkVercelAI(backend, frontendArr, runtime) && ai && ai !== "vercel-ai") exitWithError("The 'chat-sdk' example requires '--ai vercel-ai' for the selected stack in v1 (Nuxt Discord and Hono GitHub profiles).");
325
- }
326
- }
327
- /**
328
- * Validates that TanStack AI is only used with compatible frontends (React or Solid).
329
- * Server-side @tanstack/ai core works anywhere, but client adapters only exist for React and Solid.
330
- */
331
- function validateAIFrontendCompatibility(ai, frontends = []) {
332
- const issue = getAIFrontendCompatibilityIssue(ai, frontends);
333
- if (!issue) return;
334
- exitWithError(issue.message);
335
- }
336
- /**
337
- * Validates that a UI library is compatible with the selected frontend(s)
338
- */
339
- function validateUILibraryFrontendCompatibility(uiLibrary, frontends = [], astroIntegration) {
340
- if (!uiLibrary || uiLibrary === "none") return;
341
- const { web } = splitFrontends$1(frontends);
342
- if (web.length === 0) return;
343
- const compatible = getCompatibleUILibraries(frontends, astroIntegration);
344
- if (!compatible.includes(uiLibrary)) {
345
- const isAstroNonReact = web.includes("astro") && astroIntegration !== "react";
346
- const supportsAstroReact = getCompatibleUILibraries(["astro"], "react").includes(uiLibrary);
347
- if (isAstroNonReact && supportsAstroReact) {
348
- incompatibilityError({
349
- message: `UI library '${uiLibrary}' requires React.`,
350
- provided: {
351
- "ui-library": uiLibrary,
352
- "astro-integration": astroIntegration || "none"
353
- },
354
- suggestions: ["Use --astro-integration react", "Choose a different UI library (daisyui, ark-ui)"]
355
- });
356
- return;
357
- }
358
- incompatibilityError({
359
- message: `UI library '${uiLibrary}' is not compatible with the selected frontend.`,
360
- provided: {
361
- "ui-library": uiLibrary,
362
- frontend: frontends
363
- },
364
- suggestions: [`Supported choices for this stack: ${compatible.join(", ")}`, "Choose a different UI library"]
365
- });
366
- }
367
- }
368
- /**
369
- * Validates that a UI library is compatible with the selected CSS framework
370
- */
371
- function validateUILibraryCSSFrameworkCompatibility(uiLibrary, cssFramework) {
372
- if (!uiLibrary || uiLibrary === "none") return;
373
- if (!cssFramework) return;
374
- const supported = getCompatibleCSSFrameworks(uiLibrary);
375
- if (!supported.includes(cssFramework)) exitWithError(`UI library '${uiLibrary}' is not compatible with '${cssFramework}' CSS framework. Supported CSS frameworks: ${supported.join(", ")}`);
376
- }
377
- /**
378
- * Gets list of UI libraries compatible with the selected frontend(s)
379
- */
380
- function getCompatibleUILibraries$1(frontends = [], astroIntegration) {
381
- return getCompatibleUILibraries(frontends, astroIntegration);
382
- }
383
- /**
384
- * Gets list of CSS frameworks compatible with the selected UI library
385
- */
386
- function getCompatibleCSSFrameworks$1(uiLibrary) {
387
- return getCompatibleCSSFrameworks(uiLibrary);
388
- }
389
- /**
390
- * Checks if a frontend has web styling (excludes native-only frontends)
391
- */
392
- function hasWebStyling$1(frontends = []) {
393
- return hasWebStyling(frontends);
394
- }
395
-
396
- //#endregion
397
12
  //#region src/utils/navigation.ts
398
13
  const GO_BACK_SYMBOL = Symbol("clack:goBack");
399
14
  function isGoBack(value) {
@@ -732,10 +347,18 @@ function getAddonDisplay(addon) {
732
347
  label = "Backend Utils";
733
348
  hint = "asyncHandler, ApiResponse & global error handler for your server";
734
349
  break;
350
+ case "devcontainer":
351
+ label = "DevContainer";
352
+ hint = "VS Code container config with stack-aware ports and extensions";
353
+ break;
735
354
  case "docker-compose":
736
355
  label = "Docker Compose";
737
356
  hint = "Containerize your app for deployment";
738
357
  break;
358
+ case "github-actions":
359
+ label = "GitHub Actions";
360
+ hint = "Ship a CI workflow (install, lint, type-check, build)";
361
+ break;
739
362
  default:
740
363
  label = addon;
741
364
  hint = `Add ${addon}`;
@@ -749,6 +372,7 @@ const ADDON_GROUPS = {
749
372
  Tooling: [
750
373
  "turborepo",
751
374
  "nx",
375
+ "github-actions",
752
376
  "biome",
753
377
  "oxlint",
754
378
  "ultracite",
@@ -762,6 +386,7 @@ const ADDON_GROUPS = {
762
386
  "opentui",
763
387
  "wxt",
764
388
  "ruler",
389
+ "devcontainer",
765
390
  "docker-compose"
766
391
  ],
767
392
  Integrations: [
@@ -786,10 +411,10 @@ function getAddonGroup(addon) {
786
411
  return Object.entries(ADDON_GROUPS).find(([, addons]) => addons.includes(addon))?.[0];
787
412
  }
788
413
  function validateAddonCompatibilityForPrompt(addon, frontends, auth, backend, runtime) {
789
- return validateAddonCompatibility$1(addon, frontends, auth, backend, runtime);
414
+ return validateAddonCompatibility(addon, frontends, auth, backend, runtime);
790
415
  }
791
416
  function getCompatibleAddonsForPrompt(allAddons, frontends, existingAddons = [], auth, backend, runtime) {
792
- return getCompatibleAddons$1(allAddons, frontends, existingAddons, auth, backend, runtime);
417
+ return getCompatibleAddons(allAddons, frontends, existingAddons, auth, backend, runtime);
793
418
  }
794
419
  async function getAddonsChoice(addons, frontends, auth, backend, runtime) {
795
420
  if (addons !== void 0) return addons;
@@ -1021,6 +646,9 @@ async function applyDependencyVersionChannel(projectDir, channel) {
1021
646
 
1022
647
  //#endregion
1023
648
  //#region src/helpers/core/install-dependencies.ts
649
+ function toErrorMessage(error) {
650
+ return error instanceof Error ? error.message : String(error);
651
+ }
1024
652
  function getInstallEnvironment(packageManager) {
1025
653
  if (packageManager === "yarn") return {
1026
654
  YARN_ENABLE_HARDENED_MODE: "0",
@@ -1033,6 +661,7 @@ function getInstallArgs(packageManager) {
1033
661
  }
1034
662
  async function installDependencies({ projectDir, packageManager }) {
1035
663
  const s = spinner();
664
+ const step = "Install dependencies";
1036
665
  try {
1037
666
  s.start(`Running ${packageManager} install...`);
1038
667
  const installArgs = getInstallArgs(packageManager);
@@ -1045,13 +674,24 @@ async function installDependencies({ projectDir, packageManager }) {
1045
674
  stderr: "inherit"
1046
675
  })`${packageManager} ${installArgs}`;
1047
676
  s.stop("Dependencies installed successfully");
677
+ return {
678
+ step,
679
+ success: true
680
+ };
1048
681
  } catch (error) {
1049
682
  s.stop(pc.red("Failed to install dependencies"));
1050
- if (error instanceof Error) consola.error(pc.red(`Installation error: ${error.message}`));
683
+ const errorMessage = toErrorMessage(error);
684
+ consola.error(pc.red(`Installation error: ${errorMessage}`));
685
+ return {
686
+ step,
687
+ success: false,
688
+ errorMessage
689
+ };
1051
690
  }
1052
691
  }
1053
692
  async function runCargoBuild({ projectDir }) {
1054
693
  const s = spinner();
694
+ const step = "Cargo build";
1055
695
  try {
1056
696
  s.start("Running cargo build...");
1057
697
  await $({
@@ -1059,13 +699,24 @@ async function runCargoBuild({ projectDir }) {
1059
699
  stderr: "inherit"
1060
700
  })`cargo build`;
1061
701
  s.stop("Cargo build completed");
702
+ return {
703
+ step,
704
+ success: true
705
+ };
1062
706
  } catch (error) {
1063
707
  s.stop(pc.red("Cargo build failed"));
1064
- if (error instanceof Error) consola.error(pc.red(`Cargo build error: ${error.message}`));
708
+ const errorMessage = toErrorMessage(error);
709
+ consola.error(pc.red(`Cargo build error: ${errorMessage}`));
710
+ return {
711
+ step,
712
+ success: false,
713
+ errorMessage
714
+ };
1065
715
  }
1066
716
  }
1067
717
  async function runUvSync({ projectDir }) {
1068
718
  const s = spinner();
719
+ const step = "uv sync (Python dependencies)";
1069
720
  try {
1070
721
  s.start("Running uv sync...");
1071
722
  await $({
@@ -1073,13 +724,24 @@ async function runUvSync({ projectDir }) {
1073
724
  stderr: "inherit"
1074
725
  })`uv sync`;
1075
726
  s.stop("Python dependencies installed successfully");
727
+ return {
728
+ step,
729
+ success: true
730
+ };
1076
731
  } catch (error) {
1077
732
  s.stop(pc.red("uv sync failed"));
1078
- if (error instanceof Error) consola.error(pc.red(`uv sync error: ${error.message}`));
733
+ const errorMessage = toErrorMessage(error);
734
+ consola.error(pc.red(`uv sync error: ${errorMessage}`));
735
+ return {
736
+ step,
737
+ success: false,
738
+ errorMessage
739
+ };
1079
740
  }
1080
741
  }
1081
742
  async function runGoModTidy({ projectDir }) {
1082
743
  const s = spinner();
744
+ const step = "go mod tidy";
1083
745
  try {
1084
746
  s.start("Running go mod tidy...");
1085
747
  await $({
@@ -1087,14 +749,25 @@ async function runGoModTidy({ projectDir }) {
1087
749
  stderr: "inherit"
1088
750
  })`go mod tidy`;
1089
751
  s.stop("Go dependencies installed successfully");
752
+ return {
753
+ step,
754
+ success: true
755
+ };
1090
756
  } catch (error) {
1091
757
  s.stop(pc.red("go mod tidy failed"));
1092
- if (error instanceof Error) consola.error(pc.red(`go mod tidy error: ${error.message}`));
758
+ const errorMessage = toErrorMessage(error);
759
+ consola.error(pc.red(`go mod tidy error: ${errorMessage}`));
760
+ return {
761
+ step,
762
+ success: false,
763
+ errorMessage
764
+ };
1093
765
  }
1094
766
  }
1095
767
  async function runMavenTests({ projectDir }) {
1096
768
  const s = spinner();
1097
769
  const mvnw = process.platform === "win32" ? "mvnw.cmd" : "./mvnw";
770
+ const step = "Maven tests";
1098
771
  try {
1099
772
  s.start("Running Maven tests...");
1100
773
  await $({
@@ -1102,14 +775,25 @@ async function runMavenTests({ projectDir }) {
1102
775
  stderr: "inherit"
1103
776
  })`${mvnw} test`;
1104
777
  s.stop("Maven tests completed");
778
+ return {
779
+ step,
780
+ success: true
781
+ };
1105
782
  } catch (error) {
1106
783
  s.stop(pc.red("Maven tests failed"));
1107
- if (error instanceof Error) consola.error(pc.red(`Maven test error: ${error.message}`));
784
+ const errorMessage = toErrorMessage(error);
785
+ consola.error(pc.red(`Maven test error: ${errorMessage}`));
786
+ return {
787
+ step,
788
+ success: false,
789
+ errorMessage
790
+ };
1108
791
  }
1109
792
  }
1110
793
  async function runGradleTests({ projectDir }) {
1111
794
  const s = spinner();
1112
795
  const gradlew = process.platform === "win32" ? "gradlew.bat" : "./gradlew";
796
+ const step = "Gradle tests";
1113
797
  try {
1114
798
  s.start("Running Gradle tests...");
1115
799
  await $({
@@ -1117,13 +801,24 @@ async function runGradleTests({ projectDir }) {
1117
801
  stderr: "inherit"
1118
802
  })`${gradlew} test`;
1119
803
  s.stop("Gradle tests completed");
804
+ return {
805
+ step,
806
+ success: true
807
+ };
1120
808
  } catch (error) {
1121
809
  s.stop(pc.red("Gradle tests failed"));
1122
- if (error instanceof Error) consola.error(pc.red(`Gradle test error: ${error.message}`));
810
+ const errorMessage = toErrorMessage(error);
811
+ consola.error(pc.red(`Gradle test error: ${errorMessage}`));
812
+ return {
813
+ step,
814
+ success: false,
815
+ errorMessage
816
+ };
1123
817
  }
1124
818
  }
1125
819
  async function runMixCompile({ projectDir }) {
1126
820
  const s = spinner();
821
+ const step = "mix deps.get / compile";
1127
822
  try {
1128
823
  s.start("Running mix deps.get and mix compile...");
1129
824
  await $({
@@ -1135,11 +830,21 @@ async function runMixCompile({ projectDir }) {
1135
830
  stderr: "inherit"
1136
831
  })`mix compile`;
1137
832
  s.stop("Elixir dependencies installed and project compiled");
833
+ return {
834
+ step,
835
+ success: true
836
+ };
1138
837
  } catch (error) {
1139
838
  s.stop(pc.red("mix compile failed"));
1140
- if (error instanceof Error) consola.error(pc.red(`Mix error: ${error.message}`));
839
+ const errorMessage = toErrorMessage(error);
840
+ consola.error(pc.red(`Mix error: ${errorMessage}`));
841
+ return {
842
+ step,
843
+ success: false,
844
+ errorMessage
845
+ };
1141
846
  }
1142
847
  }
1143
848
 
1144
849
  //#endregion
1145
- export { validateAddonsAgainstFrontends as A, validateWorkersCompatibility as B, isExampleAIAllowed$1 as C, requiresChatSdkVercelAI as D, isWebFrontend$1 as E, validateServerDeployRequiresBackend as F, incompatibilityError as H, validateUILibraryCSSFrameworkCompatibility as I, validateUILibraryFrontendCompatibility as L, validateExamplesCompatibility as M, validatePaymentsCompatibility as N, splitFrontends$1 as O, validateSelfBackendCompatibility as P, validateWebDeployFrontendTemplates as R, hasWebStyling$1 as S, isFrontendAllowedWithBackend$1 as T, missingRequirementError as U, constraintError as V, renderTitle as W, isGoBack as _, runMavenTests as a, getCompatibleCSSFrameworks$1 as b, applyDependencyVersionChannel as c, isCancel$1 as d, navigableConfirm as f, GO_BACK_SYMBOL as g, setIsFirstPrompt as h, runGradleTests as i, validateApiFrontendCompatibility as j, validateAIFrontendCompatibility as k, getAddonsChoice as l, navigableSelect as m, runCargoBuild as n, runMixCompile as o, navigableMultiselect as p, runGoModTidy as r, runUvSync as s, installDependencies as t, getAddonsToAdd as u, allowedApisForFrontends$1 as v, isExampleChatSdkAllowed$1 as w, getCompatibleUILibraries$1 as x, ensureSingleWebAndNative as y, validateWebDeployRequiresWebFrontend as z };
850
+ export { isGoBack as _, runMavenTests as a, applyDependencyVersionChannel as c, isCancel$1 as d, navigableConfirm as f, GO_BACK_SYMBOL as g, setIsFirstPrompt as h, runGradleTests as i, getAddonsChoice as l, navigableSelect as m, runCargoBuild as n, runMixCompile as o, navigableMultiselect as p, runGoModTidy as r, runUvSync as s, installDependencies as t, getAddonsToAdd as u };
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import "./errors-D9yiiGVq.mjs";
3
+ import "./config-validation-C4glouQh.mjs";
4
+ import "./compatibility-rules-D7zYNVjC.mjs";
5
+ import { i as startMcpServer, n as MCP_STACK_UPDATE_SCHEMA, r as getMcpGraphPreview, t as MCP_PLAN_CREATE_SCHEMA } from "./mcp-entry.mjs";
6
+
7
+ export { startMcpServer };