create-better-fullstack 1.7.1 → 1.8.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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./bts-config-bOXo9tbL.mjs";
2
+ import "./bts-config-YcroedMK.mjs";
3
3
  import { t as startMcpServer } from "./mcp-entry.mjs";
4
4
 
5
5
  export { startMcpServer };
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-bOXo9tbL.mjs";
2
+ import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-YcroedMK.mjs";
3
3
  import z from "zod";
4
- import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, EcosystemSchema, EffectSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoAuthSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, I18nSchema, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LoggingSchema, OPTION_CATEGORY_METADATA, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonApiSchema, PythonAuthSchema, PythonGraphqlSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility } from "@better-fullstack/types";
4
+ import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, EcosystemSchema, EffectSchema, ElixirApiSchema, ElixirAuthSchema, ElixirCachingSchema, ElixirDeploySchema, ElixirEmailSchema, ElixirHttpSchema, ElixirJobsSchema, ElixirJsonSchema, ElixirObservabilitySchema, ElixirOrmSchema, ElixirQualitySchema, ElixirRealtimeSchema, ElixirTestingSchema, ElixirValidationSchema, ElixirWebFrameworkSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoAuthSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, I18nSchema, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LoggingSchema, MobileDeepLinkingSchema, MobileNavigationSchema, MobileOTASchema, MobilePushSchema, MobileStorageSchema, MobileTestingSchema, MobileUISchema, OPTION_CATEGORY_METADATA, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonApiSchema, PythonAuthSchema, PythonGraphqlSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility } from "@better-fullstack/types";
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
 
8
8
  //#region src/mcp.ts
9
- const INSTRUCTIONS = `Better-Fullstack scaffolds fullstack projects across TypeScript, Rust, Go, Python, and Java ecosystems with ${Object.values(OPTION_CATEGORY_METADATA).reduce((sum, metadata) => sum + metadata.options.length, 0)} configurable options.
9
+ const INSTRUCTIONS = `Better-Fullstack scaffolds fullstack projects across TypeScript, React Native, Rust, Go, Python, Java, and Elixir ecosystems with ${Object.values(OPTION_CATEGORY_METADATA).reduce((sum, metadata) => sum + metadata.options.length, 0)} configurable options.
10
10
 
11
11
  RECOMMENDED WORKFLOW:
12
12
  1. Call bfs_get_guidance to understand field semantics, required fields, and workflow rules.
@@ -24,7 +24,7 @@ CRITICAL RULES:
24
24
  - Array fields: "frontend", "addons", "examples", "aiDocs", "rustLibraries", "pythonAi", "javaLibraries", and "javaTestingLibraries". Most other option fields are strings.
25
25
  - "none" means "skip this feature entirely", not "use the default".
26
26
  - Always specify "ecosystem" first — it determines which other fields are relevant.
27
- - TypeScript-specific fields (frontend, backend, orm, etc.) are IGNORED for rust/python/go/java ecosystems.
27
+ - TypeScript web-specific fields (web frontend, backend, orm, etc.) are IGNORED for react-native/rust/python/go/java/elixir ecosystems.
28
28
  - The compatibility engine auto-adjusts invalid combinations — always call bfs_check_compatibility first to see adjustments.`;
29
29
  function getGuidance() {
30
30
  return {
@@ -37,18 +37,20 @@ function getGuidance() {
37
37
  "For existing projects: call bfs_plan_addition, then bfs_add_feature."
38
38
  ],
39
39
  ecosystems: {
40
- typescript: "Full-featured: frontend + backend + database + ORM + auth + payments + 20+ feature categories.",
40
+ typescript: "Full-featured web: frontend + backend + database + ORM + auth + payments + 20+ feature categories.",
41
+ "react-native": "Mobile: Expo/React Native frontend variants plus mobile navigation, UI, storage, testing, push, OTA, and deep linking.",
41
42
  rust: "Backend/CLI: web framework (axum/actix-web), ORM (sea-orm/sqlx), gRPC, GraphQL, CLI tools.",
42
43
  python: "Backend/AI: web framework (fastapi/django), ORM (sqlalchemy/sqlmodel), AI/ML integrations, task queues.",
43
44
  go: "Backend/CLI: web framework (gin/echo), ORM (gorm/sqlc), gRPC, CLI tools, logging.",
44
- java: "Backend/API: Spring Boot with Maven or Gradle Wrapper, optional Spring Data JPA, Spring Security, app libraries, and Java testing libraries."
45
+ java: "Backend/API: Spring Boot with Maven or Gradle Wrapper, optional Spring Data JPA, Spring Security, app libraries, and Java testing libraries.",
46
+ elixir: "Phoenix: Phoenix or Phoenix LiveView with Ecto SQL, PostgreSQL-ready config, REST or Absinthe, Channels/Presence, Oban, and Mix releases/Docker."
45
47
  },
46
48
  fieldRules: {
47
49
  projectName: "kebab-case directory name. Required for bfs_create_project.",
48
50
  ecosystem: "Must be set first. Determines which other fields are relevant.",
49
51
  frontend: "ARRAY of strings. TypeScript only. Supports multiple frontends in one monorepo. Use [] for API-only.",
50
52
  arrayFields: "Use arrays for frontend, addons, examples, aiDocs, rustLibraries, pythonAi, javaLibraries, and javaTestingLibraries. Use [] for \"none\" on multi-select fields.",
51
- backend: "String. \"self\" means fullstack mode (Next.js/TanStack Start/Nuxt/Astro API routes). \"none\" for frontend-only.",
53
+ backend: "String. \"self\" means fullstack mode (Next.js/Vinext/TanStack Start/Nuxt/Astro API routes). \"none\" for frontend-only.",
52
54
  runtime: "\"bun\" or \"node\". Must be \"none\" when backend is \"self\" or \"convex\".",
53
55
  addons: "ARRAY of strings. Monorepo tools, code quality, desktop (tauri), browser extensions (wxt), etc.",
54
56
  email: "String. TypeScript supports multiple providers; Rust, Python, Go, and Java currently support resend or none.",
@@ -58,17 +60,17 @@ function getGuidance() {
58
60
  ambiguityRules: [
59
61
  "If the user request leaves major stack choices unspecified, ASK the user before proceeding. Do not guess.",
60
62
  "Do not infer addons, examples, or optional features the user did not mention. Default strings to \"none\" and multi-select arrays to [].",
61
- "When the user says 'fullstack Next.js', use backend='self', frontend=['next'], runtime='none'.",
63
+ "When the user says 'fullstack Next.js', use backend='self', frontend=['next'], runtime='none'.\nWhen the user says 'fullstack Vinext', use backend='self', frontend=['vinext'], runtime='none'.",
62
64
  "When the user says 'React + Hono', use frontend=['tanstack-router'] (or ask which React framework), backend='hono'."
63
65
  ],
64
66
  criticalConstraints: [
65
- "tRPC (api='trpc') only works with React-based frontends: next, react-router, tanstack-router, tanstack-start.",
67
+ "tRPC (api='trpc') only works with React-based frontends: next, vinext, react-router, tanstack-router, tanstack-start.",
66
68
  "Use api='orpc' for svelte, solid, nuxt.",
67
69
  "Angular: use api='none' (has built-in HttpClient).",
68
70
  "Qwik: use backend='none', api='none' (built-in server).",
69
71
  "NestJS and AdonisJS backends require runtime='node'.",
70
72
  "Elysia backend requires runtime='bun'.",
71
- "backend='self' only works with: next, tanstack-start, astro, nuxt, svelte, solid-start.",
73
+ "backend='self' only works with: next, vinext, tanstack-start, astro, nuxt, svelte, solid-start.",
72
74
  "backend='convex' overrides: runtime=none, database=none, orm=none, api=none.",
73
75
  "TypeORM + better-auth: unsupported (no adapter). Use auth='none' or orm='drizzle'.",
74
76
  "Sequelize + better-auth: unsupported (no adapter). Use auth='none' or orm='drizzle'.",
@@ -112,6 +114,13 @@ const SCHEMA_MAP = {
112
114
  i18n: I18nSchema,
113
115
  search: SearchSchema,
114
116
  fileStorage: FileStorageSchema,
117
+ mobileNavigation: MobileNavigationSchema,
118
+ mobileUI: MobileUISchema,
119
+ mobileStorage: MobileStorageSchema,
120
+ mobileTesting: MobileTestingSchema,
121
+ mobilePush: MobilePushSchema,
122
+ mobileOTA: MobileOTASchema,
123
+ mobileDeepLinking: MobileDeepLinkingSchema,
115
124
  addons: AddonsSchema,
116
125
  examples: ExamplesSchema,
117
126
  packageManager: PackageManagerSchema,
@@ -149,7 +158,22 @@ const SCHEMA_MAP = {
149
158
  javaOrm: JavaOrmSchema,
150
159
  javaAuth: JavaAuthSchema,
151
160
  javaLibraries: JavaLibrariesSchema,
152
- javaTestingLibraries: JavaTestingLibrariesSchema
161
+ javaTestingLibraries: JavaTestingLibrariesSchema,
162
+ elixirWebFramework: ElixirWebFrameworkSchema,
163
+ elixirOrm: ElixirOrmSchema,
164
+ elixirAuth: ElixirAuthSchema,
165
+ elixirApi: ElixirApiSchema,
166
+ elixirRealtime: ElixirRealtimeSchema,
167
+ elixirJobs: ElixirJobsSchema,
168
+ elixirValidation: ElixirValidationSchema,
169
+ elixirHttp: ElixirHttpSchema,
170
+ elixirJson: ElixirJsonSchema,
171
+ elixirEmail: ElixirEmailSchema,
172
+ elixirCaching: ElixirCachingSchema,
173
+ elixirObservability: ElixirObservabilitySchema,
174
+ elixirTesting: ElixirTestingSchema,
175
+ elixirQuality: ElixirQualitySchema,
176
+ elixirDeploy: ElixirDeploySchema
153
177
  };
154
178
  const ECOSYSTEM_CATEGORIES = {
155
179
  typescript: [
@@ -185,6 +209,17 @@ const ECOSYSTEM_CATEGORIES = {
185
209
  "fileStorage",
186
210
  "astroIntegration"
187
211
  ],
212
+ "react-native": [
213
+ "frontend",
214
+ "auth",
215
+ "mobileNavigation",
216
+ "mobileUI",
217
+ "mobileStorage",
218
+ "mobileTesting",
219
+ "mobilePush",
220
+ "mobileOTA",
221
+ "mobileDeepLinking"
222
+ ],
188
223
  rust: [
189
224
  "rustWebFramework",
190
225
  "rustFrontend",
@@ -241,6 +276,23 @@ const ECOSYSTEM_CATEGORIES = {
241
276
  "caching",
242
277
  "search"
243
278
  ],
279
+ elixir: [
280
+ "elixirWebFramework",
281
+ "elixirOrm",
282
+ "elixirAuth",
283
+ "elixirApi",
284
+ "elixirRealtime",
285
+ "elixirJobs",
286
+ "elixirValidation",
287
+ "elixirHttp",
288
+ "elixirJson",
289
+ "elixirEmail",
290
+ "elixirCaching",
291
+ "elixirObservability",
292
+ "elixirTesting",
293
+ "elixirQuality",
294
+ "elixirDeploy"
295
+ ],
244
296
  shared: [
245
297
  "ecosystem",
246
298
  "packageManager",
@@ -277,12 +329,16 @@ function getInstallCommand(ecosystem, projectName, packageManager, javaBuildTool
277
329
  case "rust": return `cd ${projectName} && cargo build`;
278
330
  case "python": return `cd ${projectName} && uv sync`;
279
331
  case "go": return `cd ${projectName} && go mod tidy`;
332
+ case "elixir": return `cd ${projectName} && mix deps.get && mix compile && mix test`;
280
333
  case "java":
281
334
  if (javaWebFramework === "quarkus") return javaBuildTool === "gradle" ? `cd ${projectName} && ./gradlew test && ./gradlew quarkusDev` : `cd ${projectName} && ./mvnw test && ./mvnw quarkus:dev`;
282
335
  return javaBuildTool === "gradle" ? `cd ${projectName} && ./gradlew test && ./gradlew bootRun` : `cd ${projectName} && ./mvnw test && ./mvnw spring-boot:run`;
283
336
  default: return `cd ${projectName} && ${packageManager ?? "bun"} install`;
284
337
  }
285
338
  }
339
+ function mcpInputSchema(schema) {
340
+ return schema;
341
+ }
286
342
  function filterCompatibilityResult(result, ecosystem) {
287
343
  const { adjustedStack, changes } = result;
288
344
  if (!adjustedStack) return {
@@ -306,14 +362,18 @@ function filterCompatibilityResult(result, ecosystem) {
306
362
  }
307
363
  function buildProjectConfig(input, overrides) {
308
364
  const projectName = input.projectName ?? "my-project";
365
+ const ecosystem = input.ecosystem ?? "typescript";
366
+ const frontend = input.frontend ?? (ecosystem === "react-native" ? ["native-bare"] : ["tanstack-router"]);
367
+ const hasNativeFrontend = frontend.some((item) => item.startsWith("native-"));
368
+ const hasMobileProject = ecosystem === "react-native" || hasNativeFrontend;
309
369
  return {
310
370
  projectName,
311
371
  projectDir: overrides?.projectDir ?? "/virtual",
312
372
  relativePath: overrides ? `./${projectName}` : "./virtual",
313
- ecosystem: input.ecosystem ?? "typescript",
314
- frontend: input.frontend ?? ["tanstack-router"],
315
- backend: input.backend ?? "hono",
316
- runtime: input.runtime ?? "bun",
373
+ ecosystem,
374
+ frontend,
375
+ backend: input.backend ?? (ecosystem === "react-native" ? "none" : "hono"),
376
+ runtime: input.runtime ?? (ecosystem === "react-native" ? "none" : "bun"),
317
377
  database: input.database ?? "none",
318
378
  orm: input.orm ?? "none",
319
379
  api: input.api ?? "none",
@@ -321,13 +381,13 @@ function buildProjectConfig(input, overrides) {
321
381
  payments: input.payments ?? "none",
322
382
  email: input.email ?? "none",
323
383
  fileUpload: input.fileUpload ?? "none",
324
- effect: "none",
384
+ effect: input.effect ?? "none",
325
385
  ai: input.ai ?? "none",
326
386
  stateManagement: input.stateManagement ?? "none",
327
387
  forms: input.forms ?? "none",
328
388
  validation: input.validation ?? "none",
329
389
  testing: input.testing ?? "none",
330
- cssFramework: input.cssFramework ?? "tailwind",
390
+ cssFramework: input.cssFramework ?? (ecosystem === "react-native" ? "none" : "tailwind"),
331
391
  uiLibrary: input.uiLibrary ?? "none",
332
392
  shadcnBase: "radix",
333
393
  shadcnStyle: "nova",
@@ -342,7 +402,14 @@ function buildProjectConfig(input, overrides) {
342
402
  logging: input.logging ?? "none",
343
403
  observability: input.observability ?? "none",
344
404
  featureFlags: input.featureFlags ?? "none",
345
- analytics: "none",
405
+ analytics: input.analytics ?? "none",
406
+ mobileNavigation: input.mobileNavigation ?? (hasMobileProject ? "expo-router" : "none"),
407
+ mobileUI: input.mobileUI ?? "none",
408
+ mobileStorage: input.mobileStorage ?? "none",
409
+ mobileTesting: input.mobileTesting ?? "none",
410
+ mobilePush: input.mobilePush ?? "none",
411
+ mobileOTA: input.mobileOTA ?? "none",
412
+ mobileDeepLinking: input.mobileDeepLinking ?? (hasMobileProject ? "expo-linking" : "none"),
346
413
  cms: input.cms ?? "none",
347
414
  caching: input.caching ?? "none",
348
415
  i18n: input.i18n ?? "none",
@@ -389,7 +456,22 @@ function buildProjectConfig(input, overrides) {
389
456
  javaOrm: input.javaOrm ?? "none",
390
457
  javaAuth: input.javaAuth ?? "none",
391
458
  javaLibraries: input.javaLibraries ?? [],
392
- javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"]
459
+ javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"],
460
+ elixirWebFramework: input.elixirWebFramework ?? "phoenix",
461
+ elixirOrm: input.elixirOrm ?? "ecto-sql",
462
+ elixirAuth: input.elixirAuth ?? "none",
463
+ elixirApi: input.elixirApi ?? "rest",
464
+ elixirRealtime: input.elixirRealtime ?? "channels",
465
+ elixirJobs: input.elixirJobs ?? "none",
466
+ elixirValidation: input.elixirValidation ?? "ecto-changesets",
467
+ elixirHttp: input.elixirHttp ?? "req",
468
+ elixirJson: input.elixirJson ?? "jason",
469
+ elixirEmail: input.elixirEmail ?? "none",
470
+ elixirCaching: input.elixirCaching ?? "none",
471
+ elixirObservability: input.elixirObservability ?? "telemetry",
472
+ elixirTesting: input.elixirTesting ?? "ex_unit",
473
+ elixirQuality: input.elixirQuality ?? "credo",
474
+ elixirDeploy: input.elixirDeploy ?? "none"
393
475
  };
394
476
  }
395
477
  function sanitizePath(input) {
@@ -399,7 +481,11 @@ function sanitizePath(input) {
399
481
  }
400
482
  function buildCompatibilityInput(input) {
401
483
  const frontend = input.frontend;
484
+ const webFrontend = (frontend ?? []).filter((item) => !item.startsWith("native-"));
485
+ const nativeFrontend = (frontend ?? []).filter((item) => item.startsWith("native-"));
402
486
  const addons = input.addons ?? [];
487
+ const ecosystem = input.ecosystem ?? "typescript";
488
+ const hasMobileProject = ecosystem === "react-native" || nativeFrontend.length > 0;
403
489
  const codeQuality = addons.filter((a) => [
404
490
  "biome",
405
491
  "oxlint",
@@ -415,10 +501,10 @@ function buildCompatibilityInput(input) {
415
501
  "none"
416
502
  ].includes(a));
417
503
  return {
418
- ecosystem: input.ecosystem ?? "typescript",
504
+ ecosystem,
419
505
  projectName: input.projectName ?? null,
420
- webFrontend: frontend ?? [],
421
- nativeFrontend: [],
506
+ webFrontend,
507
+ nativeFrontend,
422
508
  astroIntegration: input.astroIntegration ?? "none",
423
509
  runtime: input.runtime ?? "bun",
424
510
  backend: input.backend ?? "hono",
@@ -455,6 +541,13 @@ function buildCompatibilityInput(input) {
455
541
  cms: input.cms ?? "none",
456
542
  search: input.search ?? "none",
457
543
  fileStorage: input.fileStorage ?? "none",
544
+ mobileNavigation: input.mobileNavigation ?? (hasMobileProject ? "expo-router" : "none"),
545
+ mobileUI: input.mobileUI ?? "none",
546
+ mobileStorage: input.mobileStorage ?? "none",
547
+ mobileTesting: input.mobileTesting ?? "none",
548
+ mobilePush: input.mobilePush ?? "none",
549
+ mobileOTA: input.mobileOTA ?? "none",
550
+ mobileDeepLinking: input.mobileDeepLinking ?? (hasMobileProject ? "expo-linking" : "none"),
458
551
  codeQuality,
459
552
  documentation,
460
553
  appPlatforms,
@@ -499,7 +592,22 @@ function buildCompatibilityInput(input) {
499
592
  javaOrm: input.javaOrm ?? "none",
500
593
  javaAuth: input.javaAuth ?? "none",
501
594
  javaLibraries: input.javaLibraries ?? [],
502
- javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"]
595
+ javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"],
596
+ elixirWebFramework: input.elixirWebFramework ?? "phoenix",
597
+ elixirOrm: input.elixirOrm ?? "ecto-sql",
598
+ elixirAuth: input.elixirAuth ?? "none",
599
+ elixirApi: input.elixirApi ?? "rest",
600
+ elixirRealtime: input.elixirRealtime ?? "channels",
601
+ elixirJobs: input.elixirJobs ?? "none",
602
+ elixirValidation: input.elixirValidation ?? "ecto-changesets",
603
+ elixirHttp: input.elixirHttp ?? "req",
604
+ elixirJson: input.elixirJson ?? "jason",
605
+ elixirEmail: input.elixirEmail ?? "none",
606
+ elixirCaching: input.elixirCaching ?? "none",
607
+ elixirObservability: input.elixirObservability ?? "telemetry",
608
+ elixirTesting: input.elixirTesting ?? "ex_unit",
609
+ elixirQuality: input.elixirQuality ?? "credo",
610
+ elixirDeploy: input.elixirDeploy ?? "none"
503
611
  };
504
612
  }
505
613
  function summarizeTree(tree) {
@@ -523,7 +631,7 @@ const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
523
631
  ## Backend Constraints
524
632
  - **Convex**: Forces runtime=none, database=none, orm=none, api=none, dbSetup=none, serverDeploy=none. Removes incompatible frontends (Solid, SolidStart, Astro).
525
633
  - **No backend (none)**: Clears auth, payments, database, orm, api, serverDeploy, search, fileStorage.
526
- - **Fullstack (backend='self')**: Sets runtime=none, serverDeploy=none. Only works with: next, tanstack-start, astro, nuxt, svelte, solid-start.
634
+ - **Fullstack (backend='self')**: Sets runtime=none, serverDeploy=none. Only works with: next, vinext, tanstack-start, astro, nuxt, svelte, solid-start.
527
635
 
528
636
  ## Runtime Constraints
529
637
  - NestJS and AdonisJS require runtime=node.
@@ -532,7 +640,7 @@ const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
532
640
  - backend=self or backend=convex requires runtime=none.
533
641
 
534
642
  ## API Constraints
535
- - tRPC only works with React-based frontends: next, react-router, tanstack-router, tanstack-start.
643
+ - tRPC only works with React-based frontends: next, vinext, react-router, tanstack-router, tanstack-start.
536
644
  - Use oRPC for svelte, solid, nuxt.
537
645
  - Angular: use api=none (has built-in HttpClient).
538
646
  - Qwik: use backend=none, api=none (built-in server, no external APIs).
@@ -559,7 +667,7 @@ const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
559
667
  - Java Sentry requires Maven or Gradle so the generated project can manage the SDK dependency.
560
668
 
561
669
  ## Ecosystem Isolation
562
- - Rust, Python, Go, and Java ecosystems are independent — TypeScript fields are ignored.
670
+ - Rust, Python, Go, Java, and Elixir ecosystems are independent — TypeScript fields are ignored.
563
671
  - Each ecosystem generates a standalone project with its own build system.
564
672
  `;
565
673
  const GETTING_STARTED_MD = `# Getting Started with Better-Fullstack MCP
@@ -628,24 +736,25 @@ async function startMcpServer() {
628
736
  instructions: INSTRUCTIONS,
629
737
  capabilities: { logging: {} }
630
738
  });
631
- server.tool("bfs_get_guidance", "Returns workflow rules, field semantics, ambiguity rules, and critical constraints. Call this FIRST before using other tools.", {}, async () => {
739
+ const registerTool = server.tool.bind(server);
740
+ registerTool("bfs_get_guidance", "Returns workflow rules, field semantics, ambiguity rules, and critical constraints. Call this FIRST before using other tools.", mcpInputSchema({}), async () => {
632
741
  const guidance = getGuidance();
633
742
  return { content: [{
634
743
  type: "text",
635
744
  text: JSON.stringify(guidance, null, 2)
636
745
  }] };
637
746
  });
638
- server.tool("bfs_get_schema", "Returns valid options for a specific category (e.g., 'database', 'frontend', 'backend') or ALL categories. Use ecosystem to filter to relevant categories only.", {
747
+ registerTool("bfs_get_schema", "Returns valid options for a specific category (e.g., 'database', 'frontend', 'backend') or ALL categories. Use ecosystem to filter to relevant categories only.", mcpInputSchema({
639
748
  category: z.string().optional().describe("Category name (e.g., 'database', 'orm', 'frontend'). Omit for all categories."),
640
749
  ecosystem: EcosystemSchema.optional().describe("Filter categories to this ecosystem (e.g., 'rust' returns only Rust + shared categories).")
641
- }, async ({ category, ecosystem }) => {
750
+ }), async ({ category, ecosystem }) => {
642
751
  const result = getSchemaOptions(category, ecosystem);
643
752
  return { content: [{
644
753
  type: "text",
645
754
  text: JSON.stringify(result, null, 2)
646
755
  }] };
647
756
  });
648
- server.tool("bfs_check_compatibility", "Validates a stack combination and returns auto-adjusted selections with warnings. Call BEFORE creating a project to avoid invalid combinations.", {
757
+ registerTool("bfs_check_compatibility", "Validates a stack combination and returns auto-adjusted selections with warnings. Call BEFORE creating a project to avoid invalid combinations.", mcpInputSchema({
649
758
  ecosystem: EcosystemSchema.describe("Language ecosystem"),
650
759
  frontend: z.array(z.string()).optional().describe("Web frontend frameworks (TypeScript only)"),
651
760
  backend: z.string().optional().describe("Backend framework"),
@@ -674,6 +783,13 @@ async function startMcpServer() {
674
783
  i18n: I18nSchema.optional().describe("Internationalization library"),
675
784
  search: SearchSchema.optional().describe("Search engine"),
676
785
  fileStorage: FileStorageSchema.optional().describe("File storage"),
786
+ mobileNavigation: MobileNavigationSchema.optional().describe("Mobile navigation"),
787
+ mobileUI: MobileUISchema.optional().describe("Mobile UI"),
788
+ mobileStorage: MobileStorageSchema.optional().describe("Mobile storage"),
789
+ mobileTesting: MobileTestingSchema.optional().describe("Mobile testing"),
790
+ mobilePush: MobilePushSchema.optional().describe("Mobile push notifications"),
791
+ mobileOTA: MobileOTASchema.optional().describe("Mobile OTA updates"),
792
+ mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking"),
677
793
  dbSetup: DatabaseSetupSchema.optional().describe("Database hosting provider"),
678
794
  webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
679
795
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
@@ -713,8 +829,23 @@ async function startMcpServer() {
713
829
  javaOrm: JavaOrmSchema.optional().describe("Java ORM"),
714
830
  javaAuth: JavaAuthSchema.optional().describe("Java authentication library"),
715
831
  javaLibraries: z.array(JavaLibrariesSchema).optional().describe("Java application libraries"),
716
- javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries")
717
- }, async (input) => {
832
+ javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
833
+ elixirWebFramework: ElixirWebFrameworkSchema.optional().describe("Elixir web framework"),
834
+ elixirOrm: ElixirOrmSchema.optional().describe("Elixir persistence layer"),
835
+ elixirAuth: ElixirAuthSchema.optional().describe("Elixir authentication"),
836
+ elixirApi: ElixirApiSchema.optional().describe("Elixir API layer"),
837
+ elixirRealtime: ElixirRealtimeSchema.optional().describe("Elixir realtime feature"),
838
+ elixirJobs: ElixirJobsSchema.optional().describe("Elixir jobs and scheduling"),
839
+ elixirValidation: ElixirValidationSchema.optional().describe("Elixir validation/data"),
840
+ elixirHttp: ElixirHttpSchema.optional().describe("Elixir HTTP client"),
841
+ elixirJson: ElixirJsonSchema.optional().describe("Elixir JSON library"),
842
+ elixirEmail: ElixirEmailSchema.optional().describe("Elixir email library"),
843
+ elixirCaching: ElixirCachingSchema.optional().describe("Elixir caching library"),
844
+ elixirObservability: ElixirObservabilitySchema.optional().describe("Elixir observability"),
845
+ elixirTesting: ElixirTestingSchema.optional().describe("Elixir testing library"),
846
+ elixirQuality: ElixirQualitySchema.optional().describe("Elixir code quality/security"),
847
+ elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target")
848
+ }), async (input) => {
718
849
  try {
719
850
  const filtered = filterCompatibilityResult(analyzeStackCompatibility(buildCompatibilityInput(input)), input.ecosystem);
720
851
  return { content: [{
@@ -764,6 +895,13 @@ async function startMcpServer() {
764
895
  i18n: I18nSchema.optional().describe("Internationalization (i18n) library"),
765
896
  cms: CMSSchema.optional().describe("CMS"),
766
897
  fileStorage: FileStorageSchema.optional().describe("File storage"),
898
+ mobileNavigation: MobileNavigationSchema.optional().describe("Mobile navigation"),
899
+ mobileUI: MobileUISchema.optional().describe("Mobile UI"),
900
+ mobileStorage: MobileStorageSchema.optional().describe("Mobile storage"),
901
+ mobileTesting: MobileTestingSchema.optional().describe("Mobile testing"),
902
+ mobilePush: MobilePushSchema.optional().describe("Mobile push notifications"),
903
+ mobileOTA: MobileOTASchema.optional().describe("Mobile OTA updates"),
904
+ mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking"),
767
905
  fileUpload: FileUploadSchema.optional().describe("File upload"),
768
906
  webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
769
907
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
@@ -798,9 +936,24 @@ async function startMcpServer() {
798
936
  javaOrm: JavaOrmSchema.optional().describe("Java ORM"),
799
937
  javaAuth: JavaAuthSchema.optional().describe("Java authentication library"),
800
938
  javaLibraries: z.array(JavaLibrariesSchema).optional().describe("Java application libraries"),
801
- javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries")
939
+ javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
940
+ elixirWebFramework: ElixirWebFrameworkSchema.optional().describe("Elixir web framework"),
941
+ elixirOrm: ElixirOrmSchema.optional().describe("Elixir persistence layer"),
942
+ elixirAuth: ElixirAuthSchema.optional().describe("Elixir authentication"),
943
+ elixirApi: ElixirApiSchema.optional().describe("Elixir API layer"),
944
+ elixirRealtime: ElixirRealtimeSchema.optional().describe("Elixir realtime feature"),
945
+ elixirJobs: ElixirJobsSchema.optional().describe("Elixir jobs and scheduling"),
946
+ elixirValidation: ElixirValidationSchema.optional().describe("Elixir validation/data"),
947
+ elixirHttp: ElixirHttpSchema.optional().describe("Elixir HTTP client"),
948
+ elixirJson: ElixirJsonSchema.optional().describe("Elixir JSON library"),
949
+ elixirEmail: ElixirEmailSchema.optional().describe("Elixir email library"),
950
+ elixirCaching: ElixirCachingSchema.optional().describe("Elixir caching library"),
951
+ elixirObservability: ElixirObservabilitySchema.optional().describe("Elixir observability"),
952
+ elixirTesting: ElixirTestingSchema.optional().describe("Elixir testing library"),
953
+ elixirQuality: ElixirQualitySchema.optional().describe("Elixir code quality/security"),
954
+ elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target")
802
955
  };
803
- server.tool("bfs_plan_project", "Dry-run: generates a project in-memory and returns the file tree WITHOUT writing to disk. Use this to preview what would be created.", planCreateSchema, async (input) => {
956
+ registerTool("bfs_plan_project", "Dry-run: generates a project in-memory and returns the file tree WITHOUT writing to disk. Use this to preview what would be created.", mcpInputSchema(planCreateSchema), async (input) => {
804
957
  try {
805
958
  const { generateVirtualProject, EMBEDDED_TEMPLATES } = await import("@better-fullstack/template-generator");
806
959
  const result = await generateVirtualProject({
@@ -837,10 +990,10 @@ async function startMcpServer() {
837
990
  };
838
991
  }
839
992
  });
840
- server.tool("bfs_create_project", "Creates a new fullstack project on disk. Dependencies are NOT installed (agent must tell user to install manually). Call bfs_plan_project first to preview.", {
993
+ registerTool("bfs_create_project", "Creates a new fullstack project on disk. Dependencies are NOT installed (agent must tell user to install manually). Call bfs_plan_project first to preview.", mcpInputSchema({
841
994
  ...planCreateSchema,
842
995
  projectName: z.string().describe("Project name (kebab-case). Will be the directory name.")
843
- }, async (input) => {
996
+ }), async (input) => {
844
997
  try {
845
998
  const { generateVirtualProject, EMBEDDED_TEMPLATES } = await import("@better-fullstack/template-generator");
846
999
  const { writeTreeToFilesystem } = await import("@better-fullstack/template-generator/fs-writer");
@@ -867,7 +1020,7 @@ async function startMcpServer() {
867
1020
  await writeBtsConfig(config);
868
1021
  let addonWarnings = [];
869
1022
  if (config.addons.length > 0 && config.addons[0] !== "none") {
870
- const { setupAddons } = await import("./addons-setup-BdKQJ1h6.mjs");
1023
+ const { setupAddons } = await import("./addons-setup-CJwQAWFg.mjs");
871
1024
  addonWarnings = await setupAddons(config);
872
1025
  }
873
1026
  const installCmd = getInstallCommand(input.ecosystem ?? "typescript", projectName, input.packageManager, input.javaBuildTool, input.javaWebFramework);
@@ -891,12 +1044,12 @@ async function startMcpServer() {
891
1044
  };
892
1045
  }
893
1046
  });
894
- server.tool("bfs_plan_addition", "Validates what would be added to an existing project. Reads the project config (bts.jsonc) and checks which addons are new.", {
1047
+ registerTool("bfs_plan_addition", "Validates what would be added to an existing project. Reads the project config (bts.jsonc) and checks which addons are new.", mcpInputSchema({
895
1048
  projectDir: z.string().describe("Absolute path to the existing project directory"),
896
1049
  addons: z.array(AddonsSchema).optional().describe("Addons to add"),
897
1050
  webDeploy: WebDeploySchema.optional().describe("Web deployment option"),
898
1051
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment option")
899
- }, async ({ projectDir, addons, webDeploy, serverDeploy }) => {
1052
+ }), async ({ projectDir, addons, webDeploy, serverDeploy }) => {
900
1053
  try {
901
1054
  const safePath = sanitizePath(projectDir);
902
1055
  const config = await readBtsConfig(safePath);
@@ -949,13 +1102,13 @@ async function startMcpServer() {
949
1102
  };
950
1103
  }
951
1104
  });
952
- server.tool("bfs_add_feature", "Adds addons/features to an existing Better-Fullstack project. Dependencies are NOT installed. Call bfs_plan_addition first to validate.", {
1105
+ registerTool("bfs_add_feature", "Adds addons/features to an existing Better-Fullstack project. Dependencies are NOT installed. Call bfs_plan_addition first to validate.", mcpInputSchema({
953
1106
  projectDir: z.string().describe("Absolute path to the existing project directory"),
954
1107
  addons: z.array(AddonsSchema).optional().describe("Addons to add"),
955
1108
  webDeploy: WebDeploySchema.optional().describe("Web deployment option"),
956
1109
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment option"),
957
1110
  packageManager: PackageManagerSchema.optional().describe("Package manager to use")
958
- }, async (input) => {
1111
+ }), async (input) => {
959
1112
  try {
960
1113
  const safePath = sanitizePath(input.projectDir);
961
1114
  const { add } = await import("./index.mjs");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "Scaffold production-ready fullstack apps in seconds. Pick your stack from 425 options — the CLI wires everything together.",
5
5
  "keywords": [
6
6
  "algolia",
@@ -127,11 +127,11 @@
127
127
  "prepublishOnly": "npm run build"
128
128
  },
129
129
  "dependencies": {
130
- "@better-fullstack/template-generator": "^1.7.1",
131
- "@better-fullstack/types": "^1.7.1",
130
+ "@better-fullstack/template-generator": "^1.8.1",
131
+ "@better-fullstack/types": "^1.8.1",
132
132
  "@clack/core": "^0.5.0",
133
- "@clack/prompts": "^1.3.0",
134
- "@orpc/server": "^1.14.2",
133
+ "@clack/prompts": "^1.4.0",
134
+ "@orpc/server": "^1.14.3",
135
135
  "consola": "^3.4.2",
136
136
  "env-paths": "^4.0.0",
137
137
  "execa": "^9.6.1",
@@ -146,13 +146,13 @@
146
146
  "trpc-cli": "^0.12.1",
147
147
  "ts-morph": "^27.0.2",
148
148
  "yaml": "^2.9.0",
149
- "zod": "4.3.6"
149
+ "zod": "4.4.3"
150
150
  },
151
151
  "devDependencies": {
152
- "@types/bun": "^1.3.13",
152
+ "@types/bun": "^1.3.14",
153
153
  "@types/fs-extra": "^11.0.4",
154
- "@types/node": "^25.6.2",
155
- "publint": "^0.3.20",
154
+ "@types/node": "^25.9.1",
155
+ "publint": "^0.3.21",
156
156
  "tsdown": "^0.18.2",
157
157
  "typescript": "^5.9.3"
158
158
  }
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./bts-config-bOXo9tbL.mjs";
3
- import { i as setupLefthook, n as setupBiome, r as setupHusky, t as setupAddons } from "./addons-setup-CGhYT2qC.mjs";
4
-
5
- export { setupAddons };