create-better-fullstack 2.0.0 → 2.0.2

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,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { d as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-BMniWIbd.mjs";
2
+ import { a as getEffectiveStack, i as writeBtsConfig, l as getGraphSummary, n as readBtsConfig, p as getLatestCLIVersion, t as previewBtsConfigUpdate } from "./bts-config-Bg1Qea9Y.mjs";
3
3
  import z from "zod";
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";
4
+ import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CATEGORY_ORDER, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, DotnetApiSchema, DotnetAuthSchema, DotnetCachingSchema, DotnetDeploySchema, DotnetJobQueueSchema, DotnetObservabilitySchema, DotnetOrmSchema, DotnetRealtimeSchema, DotnetTestingSchema, DotnetValidationSchema, DotnetWebFrameworkSchema, EcosystemSchema, EffectSchema, ElixirApiSchema, ElixirAuthSchema, ElixirCachingSchema, ElixirDeploySchema, ElixirEmailSchema, ElixirHttpSchema, ElixirJobsSchema, ElixirJsonSchema, ElixirLibrariesSchema, ElixirObservabilitySchema, ElixirOrmSchema, ElixirQualitySchema, ElixirRealtimeSchema, ElixirTestingSchema, ElixirValidationSchema, ElixirWebFrameworkSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoAuthSchema, GoCachingSchema, GoCliSchema, GoConfigSchema, GoLoggingSchema, GoMessageQueueSchema, GoObservabilitySchema, GoOrmSchema, GoRealtimeSchema, GoTestingSchema, GoWebFrameworkSchema, I18nSchema, JavaApiSchema, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaLoggingSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LoggingSchema, MobileDeepLinkingSchema, MobileNavigationSchema, MobileOTASchema, MobilePushSchema, MobileStorageSchema, MobileTestingSchema, MobileUISchema, OPTION_CATEGORY_METADATA, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonApiSchema, PythonAuthSchema, PythonCachingSchema, PythonCliSchema, PythonGraphqlSchema, PythonObservabilitySchema, PythonOrmSchema, PythonQualitySchema, PythonRealtimeSchema, PythonTaskQueueSchema, PythonTestingSchema, PythonValidationSchema, PythonWebFrameworkSchema, RateLimitSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustMessageQueueSchema, RustObservabilitySchema, RustOrmSchema, RustRealtimeSchema, RustTemplatingSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility, formatStackPartSpec, getCategoryOrderForEcosystem, legacyProjectConfigToStackParts } 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, 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.
9
+ const INSTRUCTIONS = `Better-Fullstack scaffolds fullstack projects across TypeScript, React Native, Rust, Go, Python, Java, .NET, 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.
@@ -21,10 +21,10 @@ For existing projects:
21
21
 
22
22
  CRITICAL RULES:
23
23
  - Dependency installation is ALWAYS skipped in MCP mode (timeout risk). After scaffolding, tell the user to run install manually.
24
- - Array fields: "frontend", "addons", "examples", "aiDocs", "rustLibraries", "pythonAi", "javaLibraries", and "javaTestingLibraries". Most other option fields are strings.
24
+ - Array fields: "frontend", "addons", "examples", "aiDocs", "rustLibraries", "pythonAi", "pythonTesting", "pythonCli", "goTesting", "javaLibraries", "javaTestingLibraries", "dotnetTesting", "dotnetObservability", and "elixirLibraries". 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 web-specific fields (web frontend, backend, orm, etc.) are IGNORED for react-native/rust/python/go/java/elixir ecosystems.
27
+ - TypeScript web-specific fields (web frontend, backend, orm, etc.) are IGNORED for react-native/rust/python/go/java/dotnet/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 {
@@ -43,13 +43,14 @@ function getGuidance() {
43
43
  python: "Backend/AI: web framework (fastapi/django), ORM (sqlalchemy/sqlmodel), AI/ML integrations, task queues.",
44
44
  go: "Backend/CLI: web framework (gin/echo), ORM (gorm/sqlc), gRPC, CLI tools, logging.",
45
45
  java: "Backend/API: Spring Boot with Maven or Gradle Wrapper, optional Spring Data JPA, Spring Security, app libraries, and Java testing libraries.",
46
+ dotnet: "Backend/API: ASP.NET Core Minimal APIs, MVC, or Blazor with EF Core/Dapper, Identity/Auth0, SignalR, xUnit, and Docker-ready output.",
46
47
  elixir: "Phoenix: Phoenix or Phoenix LiveView with Ecto SQL, PostgreSQL-ready config, REST or Absinthe, Channels/Presence, Oban, and Mix releases/Docker."
47
48
  },
48
49
  fieldRules: {
49
50
  projectName: "kebab-case directory name. Required for bfs_create_project.",
50
51
  ecosystem: "Must be set first. Determines which other fields are relevant.",
51
52
  frontend: "ARRAY of strings. TypeScript only. Supports multiple frontends in one monorepo. Use [] for API-only.",
52
- arrayFields: "Use arrays for frontend, addons, examples, aiDocs, rustLibraries, pythonAi, javaLibraries, and javaTestingLibraries. Use [] for \"none\" on multi-select fields.",
53
+ arrayFields: "Use arrays for frontend, addons, examples, aiDocs, rustLibraries, pythonAi, pythonTesting, pythonCli, goTesting, javaLibraries, javaTestingLibraries, dotnetTesting, dotnetObservability, and elixirLibraries. Use [] for \"none\" on multi-select fields.",
53
54
  backend: "String. \"self\" means fullstack mode (Next.js/Vinext/TanStack Start/Nuxt/Astro API routes). \"none\" for frontend-only.",
54
55
  runtime: "\"bun\" or \"node\". Must be \"none\" when backend is \"self\" or \"convex\".",
55
56
  addons: "ARRAY of strings. Monorepo tools, code quality, desktop (tauri), browser extensions (wxt), etc.",
@@ -82,245 +83,89 @@ function getGuidance() {
82
83
  ]
83
84
  };
84
85
  }
85
- const SCHEMA_MAP = {
86
- ecosystem: EcosystemSchema,
87
- database: DatabaseSchema,
88
- orm: ORMSchema,
89
- backend: BackendSchema,
90
- runtime: RuntimeSchema,
91
- frontend: FrontendSchema,
92
- api: APISchema,
93
- auth: AuthSchema,
94
- payments: PaymentsSchema,
95
- email: EmailSchema,
96
- fileUpload: FileUploadSchema,
97
- effect: EffectSchema,
98
- ai: AISchema,
99
- stateManagement: StateManagementSchema,
100
- forms: FormsSchema,
101
- validation: ValidationSchema,
102
- testing: TestingSchema,
103
- cssFramework: CSSFrameworkSchema,
104
- uiLibrary: UILibrarySchema,
105
- realtime: RealtimeSchema,
106
- jobQueue: JobQueueSchema,
107
- animation: AnimationSchema,
108
- logging: LoggingSchema,
109
- observability: ObservabilitySchema,
110
- featureFlags: FeatureFlagsSchema,
111
- analytics: AnalyticsSchema,
112
- cms: CMSSchema,
113
- caching: CachingSchema,
114
- i18n: I18nSchema,
115
- search: SearchSchema,
116
- fileStorage: FileStorageSchema,
117
- mobileNavigation: MobileNavigationSchema,
118
- mobileUI: MobileUISchema,
119
- mobileStorage: MobileStorageSchema,
120
- mobileTesting: MobileTestingSchema,
121
- mobilePush: MobilePushSchema,
122
- mobileOTA: MobileOTASchema,
123
- mobileDeepLinking: MobileDeepLinkingSchema,
124
- addons: AddonsSchema,
125
- examples: ExamplesSchema,
126
- packageManager: PackageManagerSchema,
127
- dbSetup: DatabaseSetupSchema,
128
- webDeploy: WebDeploySchema,
129
- serverDeploy: ServerDeploySchema,
130
- astroIntegration: AstroIntegrationSchema,
131
- rustWebFramework: RustWebFrameworkSchema,
132
- rustFrontend: RustFrontendSchema,
133
- rustOrm: RustOrmSchema,
134
- rustApi: RustApiSchema,
135
- rustCli: RustCliSchema,
136
- rustLibraries: RustLibrariesSchema,
137
- rustLogging: RustLoggingSchema,
138
- rustErrorHandling: RustErrorHandlingSchema,
139
- rustCaching: RustCachingSchema,
140
- rustAuth: RustAuthSchema,
141
- pythonWebFramework: PythonWebFrameworkSchema,
142
- pythonOrm: PythonOrmSchema,
143
- pythonValidation: PythonValidationSchema,
144
- pythonAi: PythonAiSchema,
145
- pythonAuth: PythonAuthSchema,
146
- pythonApi: PythonApiSchema,
147
- pythonTaskQueue: PythonTaskQueueSchema,
148
- pythonGraphql: PythonGraphqlSchema,
149
- pythonQuality: PythonQualitySchema,
150
- goWebFramework: GoWebFrameworkSchema,
151
- goOrm: GoOrmSchema,
152
- goApi: GoApiSchema,
153
- goCli: GoCliSchema,
154
- goLogging: GoLoggingSchema,
155
- goAuth: GoAuthSchema,
156
- javaWebFramework: JavaWebFrameworkSchema,
157
- javaBuildTool: JavaBuildToolSchema,
158
- javaOrm: JavaOrmSchema,
159
- javaAuth: JavaAuthSchema,
160
- javaLibraries: JavaLibrariesSchema,
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
86
+ const MCP_ECOSYSTEMS = new Set(EcosystemSchema.options);
87
+ const MCP_SHARED_SCHEMA_KEYS = [
88
+ "ecosystem",
89
+ "packageManager",
90
+ "addons",
91
+ "examples",
92
+ "webDeploy",
93
+ "serverDeploy",
94
+ "dbSetup"
95
+ ];
96
+ const MCP_SHARED_COMPATIBILITY_KEYS = [
97
+ ...MCP_SHARED_SCHEMA_KEYS,
98
+ "projectName",
99
+ "git",
100
+ "install",
101
+ "aiDocs"
102
+ ];
103
+ const MCP_LEGACY_CATEGORY_KEYS = {
104
+ webFrontend: ["frontend"],
105
+ nativeFrontend: ["frontend"],
106
+ backendLibraries: ["effect"],
107
+ codeQuality: ["addons"],
108
+ documentation: ["addons"],
109
+ appPlatforms: ["addons"]
177
110
  };
178
- const ECOSYSTEM_CATEGORIES = {
179
- typescript: [
180
- "database",
181
- "orm",
182
- "backend",
183
- "runtime",
184
- "frontend",
185
- "api",
186
- "auth",
187
- "payments",
188
- "email",
189
- "fileUpload",
190
- "effect",
191
- "ai",
192
- "stateManagement",
193
- "forms",
194
- "validation",
195
- "testing",
196
- "cssFramework",
197
- "uiLibrary",
198
- "realtime",
199
- "jobQueue",
200
- "animation",
201
- "logging",
202
- "observability",
203
- "featureFlags",
204
- "analytics",
205
- "cms",
206
- "caching",
207
- "i18n",
208
- "search",
209
- "fileStorage",
210
- "astroIntegration"
211
- ],
212
- "react-native": [
213
- "frontend",
214
- "auth",
215
- "mobileNavigation",
216
- "mobileUI",
217
- "mobileStorage",
218
- "mobileTesting",
219
- "mobilePush",
220
- "mobileOTA",
221
- "mobileDeepLinking"
222
- ],
223
- rust: [
224
- "rustWebFramework",
225
- "rustFrontend",
226
- "rustOrm",
227
- "rustApi",
228
- "rustCli",
229
- "rustLibraries",
230
- "rustLogging",
231
- "rustErrorHandling",
232
- "rustCaching",
233
- "rustAuth",
234
- "email",
235
- "observability",
236
- "caching",
237
- "search"
238
- ],
239
- python: [
240
- "pythonWebFramework",
241
- "pythonOrm",
242
- "pythonValidation",
243
- "pythonAi",
244
- "pythonAuth",
245
- "pythonApi",
246
- "pythonTaskQueue",
247
- "pythonGraphql",
248
- "pythonQuality",
249
- "email",
250
- "observability",
251
- "caching",
252
- "search"
253
- ],
254
- go: [
255
- "goWebFramework",
256
- "goOrm",
257
- "goApi",
258
- "goCli",
259
- "goLogging",
260
- "goAuth",
261
- "auth",
262
- "email",
263
- "observability",
264
- "caching",
265
- "search"
266
- ],
267
- java: [
268
- "javaWebFramework",
269
- "javaBuildTool",
270
- "javaOrm",
271
- "javaAuth",
272
- "javaLibraries",
273
- "javaTestingLibraries",
274
- "email",
275
- "observability",
276
- "caching",
277
- "search"
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
- ],
296
- shared: [
297
- "ecosystem",
298
- "packageManager",
299
- "addons",
300
- "examples",
301
- "webDeploy",
302
- "serverDeploy",
303
- "dbSetup"
304
- ]
111
+ const MCP_SCHEMA_EXCLUDED_CATEGORIES = new Set([
112
+ "webFrontend",
113
+ "nativeFrontend",
114
+ "backendLibraries",
115
+ "codeQuality",
116
+ "documentation",
117
+ "appPlatforms",
118
+ "aiDocs",
119
+ "git",
120
+ "install",
121
+ "versionChannel",
122
+ "shadcnBase",
123
+ "shadcnStyle",
124
+ "shadcnIconLibrary",
125
+ "shadcnColorTheme",
126
+ "shadcnBaseColor",
127
+ "shadcnFont",
128
+ "shadcnRadius"
129
+ ]);
130
+ const MCP_SCHEMA_OPTION_OVERRIDES = {
131
+ ecosystem: EcosystemSchema.options,
132
+ frontend: FrontendSchema.options,
133
+ backend: BackendSchema.options,
134
+ addons: AddonsSchema.options,
135
+ examples: ExamplesSchema.options,
136
+ effect: EffectSchema.options
305
137
  };
138
+ const MCP_ALL_SCHEMA_KEYS = ["ecosystem", ...CATEGORY_ORDER.flatMap((category) => MCP_LEGACY_CATEGORY_KEYS[category] ?? [category]).filter((key, index, keys) => keys.indexOf(key) === index)].filter((key) => getMcpSchemaOptionValues(key).length > 0);
139
+ function isMcpEcosystem(ecosystem) {
140
+ return MCP_ECOSYSTEMS.has(ecosystem);
141
+ }
142
+ function getMcpSchemaOptionValues(key) {
143
+ const override = MCP_SCHEMA_OPTION_OVERRIDES[key];
144
+ if (override) return [...override];
145
+ const categories = key in OPTION_CATEGORY_METADATA && !MCP_SCHEMA_EXCLUDED_CATEGORIES.has(key) ? [key] : [];
146
+ return [...new Set(categories.flatMap((category) => OPTION_CATEGORY_METADATA[category].options.map((option) => option.id)))];
147
+ }
148
+ function getMcpCategoryKeysForEcosystem(ecosystem) {
149
+ const keys = getCategoryOrderForEcosystem(ecosystem).flatMap((category) => MCP_LEGACY_CATEGORY_KEYS[category] ?? [category]);
150
+ return [...new Set(keys.filter((key) => getMcpSchemaOptionValues(key).length > 0))];
151
+ }
152
+ function getMcpSchemaKeysForEcosystem(ecosystem) {
153
+ return new Set([...getMcpCategoryKeysForEcosystem(ecosystem), ...MCP_SHARED_SCHEMA_KEYS]);
154
+ }
306
155
  function getSchemaOptions(category, ecosystem) {
307
156
  if (category) {
308
- const schema = SCHEMA_MAP[category];
309
- if (!schema) return { error: `Unknown category: ${category}. Available: ${Object.keys(SCHEMA_MAP).join(", ")}` };
310
- if (schema instanceof z.ZodEnum) return {
311
- category,
312
- options: schema.options
313
- };
157
+ const options = getMcpSchemaOptionValues(category);
158
+ if (options.length === 0) return { error: `Unknown category: ${category}. Available: ${MCP_ALL_SCHEMA_KEYS.join(", ")}` };
314
159
  return {
315
160
  category,
316
- description: "Schema exists but is not a simple enum."
161
+ options
317
162
  };
318
163
  }
319
- const allowedKeys = ecosystem && ECOSYSTEM_CATEGORIES[ecosystem] ? new Set([...ECOSYSTEM_CATEGORIES[ecosystem], ...ECOSYSTEM_CATEGORIES.shared]) : null;
164
+ const allowedKeys = ecosystem && isMcpEcosystem(ecosystem) ? getMcpSchemaKeysForEcosystem(ecosystem) : null;
320
165
  const result = {};
321
- for (const [key, schema] of Object.entries(SCHEMA_MAP)) {
166
+ for (const key of MCP_ALL_SCHEMA_KEYS) {
322
167
  if (allowedKeys && !allowedKeys.has(key)) continue;
323
- if (schema instanceof z.ZodEnum) result[key] = schema.options;
168
+ result[key] = getMcpSchemaOptionValues(key);
324
169
  }
325
170
  return result;
326
171
  }
@@ -345,14 +190,8 @@ function filterCompatibilityResult(result, ecosystem) {
345
190
  adjustedStack: null,
346
191
  changes
347
192
  };
348
- const relevantKeys = new Set([
349
- ...ECOSYSTEM_CATEGORIES[ecosystem] ?? ECOSYSTEM_CATEGORIES.typescript,
350
- ...ECOSYSTEM_CATEGORIES.shared,
351
- "projectName",
352
- "git",
353
- "install",
354
- "aiDocs"
355
- ]);
193
+ const relevantEcosystem = isMcpEcosystem(ecosystem) ? ecosystem : "typescript";
194
+ const relevantKeys = new Set([...getMcpCategoryKeysForEcosystem(relevantEcosystem), ...MCP_SHARED_COMPATIBILITY_KEYS]);
356
195
  const filtered = {};
357
196
  for (const [key, value] of Object.entries(adjustedStack)) if (relevantKeys.has(key)) filtered[key] = value;
358
197
  return {
@@ -360,35 +199,185 @@ function filterCompatibilityResult(result, ecosystem) {
360
199
  changes
361
200
  };
362
201
  }
202
+ const MCP_CODE_QUALITY_ADDONS = new Set([
203
+ "biome",
204
+ "oxlint",
205
+ "ultracite",
206
+ "lefthook",
207
+ "husky",
208
+ "ruler"
209
+ ]);
210
+ const MCP_DOCUMENTATION_ADDONS = new Set(["starlight", "fumadocs"]);
211
+ const MCP_COMPATIBILITY_DEFAULTS = {
212
+ astroIntegration: "none",
213
+ runtime: "bun",
214
+ backend: "hono",
215
+ database: "none",
216
+ orm: "none",
217
+ dbSetup: "none",
218
+ auth: "none",
219
+ payments: "none",
220
+ email: "none",
221
+ fileUpload: "none",
222
+ logging: "none",
223
+ observability: "none",
224
+ featureFlags: "none",
225
+ analytics: "none",
226
+ backendLibraries: "none",
227
+ stateManagement: "none",
228
+ forms: "none",
229
+ validation: "none",
230
+ testing: "none",
231
+ realtime: "none",
232
+ jobQueue: "none",
233
+ caching: "none",
234
+ rateLimit: "none",
235
+ i18n: "none",
236
+ animation: "none",
237
+ cssFramework: "tailwind",
238
+ uiLibrary: "none",
239
+ shadcnBase: "radix",
240
+ shadcnStyle: "nova",
241
+ shadcnIconLibrary: "lucide",
242
+ shadcnColorTheme: "neutral",
243
+ shadcnBaseColor: "neutral",
244
+ shadcnFont: "inter",
245
+ shadcnRadius: "default",
246
+ cms: "none",
247
+ search: "none",
248
+ fileStorage: "none",
249
+ mobileUI: "none",
250
+ mobileStorage: "none",
251
+ mobileTesting: "none",
252
+ mobilePush: "none",
253
+ mobileOTA: "none",
254
+ packageManager: "bun",
255
+ versionChannel: "stable",
256
+ examples: [],
257
+ aiSdk: "none",
258
+ aiDocs: ["claude-md"],
259
+ git: "true",
260
+ install: "false",
261
+ api: "none",
262
+ webDeploy: "none",
263
+ serverDeploy: "none",
264
+ yolo: "false",
265
+ rustWebFramework: "none",
266
+ rustFrontend: "none",
267
+ rustOrm: "none",
268
+ rustApi: "none",
269
+ rustCli: "none",
270
+ rustLibraries: [],
271
+ rustLogging: "none",
272
+ rustErrorHandling: "none",
273
+ rustCaching: "none",
274
+ rustAuth: "none",
275
+ rustRealtime: "none",
276
+ rustMessageQueue: "none",
277
+ rustObservability: "none",
278
+ rustTemplating: "none",
279
+ pythonWebFramework: "none",
280
+ pythonOrm: "none",
281
+ pythonValidation: "none",
282
+ pythonAi: [],
283
+ pythonAuth: "none",
284
+ pythonApi: "none",
285
+ pythonTaskQueue: "none",
286
+ pythonGraphql: "none",
287
+ pythonQuality: "none",
288
+ pythonTesting: [],
289
+ pythonCaching: "none",
290
+ pythonRealtime: "none",
291
+ pythonObservability: "none",
292
+ pythonCli: [],
293
+ goWebFramework: "none",
294
+ goOrm: "none",
295
+ goApi: "none",
296
+ goCli: "none",
297
+ goLogging: "none",
298
+ goAuth: "none",
299
+ goTesting: [],
300
+ goRealtime: "none",
301
+ goMessageQueue: "none",
302
+ goCaching: "none",
303
+ goConfig: "none",
304
+ goObservability: "none",
305
+ javaWebFramework: "spring-boot",
306
+ javaBuildTool: "maven",
307
+ javaOrm: "none",
308
+ javaAuth: "none",
309
+ javaApi: "none",
310
+ javaLogging: "none",
311
+ javaLibraries: [],
312
+ javaTestingLibraries: ["junit5"],
313
+ dotnetWebFramework: "aspnet-minimal",
314
+ dotnetOrm: "ef-core",
315
+ dotnetAuth: "aspnet-identity",
316
+ dotnetApi: "minimal-api",
317
+ dotnetTesting: ["xunit"],
318
+ dotnetJobQueue: "none",
319
+ dotnetRealtime: "signalr",
320
+ dotnetObservability: ["serilog"],
321
+ dotnetValidation: "none",
322
+ dotnetCaching: "none",
323
+ dotnetDeploy: "docker",
324
+ elixirWebFramework: "phoenix",
325
+ elixirOrm: "ecto-sql",
326
+ elixirAuth: "none",
327
+ elixirApi: "rest",
328
+ elixirRealtime: "channels",
329
+ elixirJobs: "none",
330
+ elixirValidation: "ecto-changesets",
331
+ elixirHttp: "req",
332
+ elixirJson: "jason",
333
+ elixirEmail: "none",
334
+ elixirCaching: "none",
335
+ elixirObservability: "telemetry",
336
+ elixirTesting: "ex_unit",
337
+ elixirQuality: "credo",
338
+ elixirDeploy: "none",
339
+ elixirLibraries: []
340
+ };
341
+ const { backendLibraries: _backendLibrariesDefault, aiSdk: _aiSdkDefault, git: _compatibilityGitDefault, install: _compatibilityInstallDefault, yolo: _yoloDefault, ...MCP_PROJECT_COMPATIBILITY_DEFAULTS } = MCP_COMPATIBILITY_DEFAULTS;
342
+ const MCP_PROJECT_CONFIG_DEFAULTS = {
343
+ ...MCP_PROJECT_COMPATIBILITY_DEFAULTS,
344
+ addons: [],
345
+ effect: "none",
346
+ ai: "none"
347
+ };
348
+ function cloneMcpInputDefault(value) {
349
+ return Array.isArray(value) ? [...value] : value;
350
+ }
351
+ function applyMcpInputDefaults(defaults, input) {
352
+ return Object.fromEntries(Object.entries(defaults).map(([key, fallback]) => [key, input[key] ?? cloneMcpInputDefault(fallback)]));
353
+ }
354
+ function getMcpCompatibilityDefaults(input) {
355
+ return applyMcpInputDefaults(MCP_COMPATIBILITY_DEFAULTS, input);
356
+ }
357
+ function getMcpProjectConfigDefaults(input) {
358
+ return applyMcpInputDefaults(MCP_PROJECT_CONFIG_DEFAULTS, input);
359
+ }
363
360
  function buildProjectConfig(input, overrides) {
364
361
  const projectName = input.projectName ?? "my-project";
365
362
  const ecosystem = input.ecosystem ?? "typescript";
366
- const frontend = input.frontend ?? (ecosystem === "react-native" ? ["native-bare"] : ["tanstack-router"]);
363
+ const frontend = input.frontend ?? (ecosystem === "react-native" ? ["native-bare"] : ecosystem === "typescript" ? ["tanstack-router"] : ["none"]);
367
364
  const hasNativeFrontend = frontend.some((item) => item.startsWith("native-"));
368
365
  const hasMobileProject = ecosystem === "react-native" || hasNativeFrontend;
366
+ const defaults = getMcpProjectConfigDefaults(input);
369
367
  return {
370
368
  projectName,
371
369
  projectDir: overrides?.projectDir ?? "/virtual",
372
370
  relativePath: overrides ? `./${projectName}` : "./virtual",
373
371
  ecosystem,
374
372
  frontend,
375
- backend: input.backend ?? (ecosystem === "react-native" ? "none" : "hono"),
376
- runtime: input.runtime ?? (ecosystem === "react-native" ? "none" : "bun"),
377
- database: input.database ?? "none",
378
- orm: input.orm ?? "none",
379
- api: input.api ?? "none",
380
- auth: input.auth ?? "none",
381
- payments: input.payments ?? "none",
382
- email: input.email ?? "none",
383
- fileUpload: input.fileUpload ?? "none",
384
- effect: input.effect ?? "none",
385
- ai: input.ai ?? "none",
386
- stateManagement: input.stateManagement ?? "none",
387
- forms: input.forms ?? "none",
388
- validation: input.validation ?? "none",
389
- testing: input.testing ?? "none",
390
- cssFramework: input.cssFramework ?? (ecosystem === "react-native" ? "none" : "tailwind"),
391
- uiLibrary: input.uiLibrary ?? "none",
373
+ ...defaults,
374
+ backend: input.backend ?? (ecosystem === "react-native" ? "none" : defaults.backend),
375
+ runtime: input.runtime ?? (ecosystem === "react-native" ? "none" : defaults.runtime),
376
+ cssFramework: input.cssFramework ?? (ecosystem === "react-native" ? "none" : defaults.cssFramework),
377
+ mobileNavigation: input.mobileNavigation ?? (hasMobileProject ? "expo-router" : "none"),
378
+ mobileDeepLinking: input.mobileDeepLinking ?? (hasMobileProject ? "expo-linking" : "none"),
379
+ astroIntegration: "none",
380
+ versionChannel: "stable",
392
381
  shadcnBase: "radix",
393
382
  shadcnStyle: "nova",
394
383
  shadcnIconLibrary: "lucide",
@@ -396,82 +385,9 @@ function buildProjectConfig(input, overrides) {
396
385
  shadcnBaseColor: "neutral",
397
386
  shadcnFont: "inter",
398
387
  shadcnRadius: "default",
399
- realtime: input.realtime ?? "none",
400
- jobQueue: input.jobQueue ?? "none",
401
- animation: input.animation ?? "none",
402
- logging: input.logging ?? "none",
403
- observability: input.observability ?? "none",
404
- featureFlags: input.featureFlags ?? "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"),
413
- cms: input.cms ?? "none",
414
- caching: input.caching ?? "none",
415
- i18n: input.i18n ?? "none",
416
- search: input.search ?? "none",
417
- fileStorage: input.fileStorage ?? "none",
418
- addons: input.addons ?? [],
419
- examples: input.examples ?? [],
420
- packageManager: input.packageManager ?? "bun",
421
- versionChannel: "stable",
422
- webDeploy: input.webDeploy ?? "none",
423
- serverDeploy: input.serverDeploy ?? "none",
424
- dbSetup: input.dbSetup ?? "none",
425
- astroIntegration: "none",
426
- git: !!overrides,
427
- install: false,
428
388
  aiDocs: ["claude-md"],
429
- rustWebFramework: input.rustWebFramework ?? "none",
430
- rustFrontend: input.rustFrontend ?? "none",
431
- rustOrm: input.rustOrm ?? "none",
432
- rustApi: input.rustApi ?? "none",
433
- rustCli: input.rustCli ?? "none",
434
- rustLibraries: input.rustLibraries ?? [],
435
- rustLogging: input.rustLogging ?? "none",
436
- rustErrorHandling: input.rustErrorHandling ?? "none",
437
- rustCaching: input.rustCaching ?? "none",
438
- rustAuth: input.rustAuth ?? "none",
439
- pythonWebFramework: input.pythonWebFramework ?? "none",
440
- pythonOrm: input.pythonOrm ?? "none",
441
- pythonValidation: input.pythonValidation ?? "none",
442
- pythonAi: input.pythonAi ?? [],
443
- pythonAuth: input.pythonAuth ?? "none",
444
- pythonApi: input.pythonApi ?? "none",
445
- pythonTaskQueue: input.pythonTaskQueue ?? "none",
446
- pythonGraphql: input.pythonGraphql ?? "none",
447
- pythonQuality: input.pythonQuality ?? "none",
448
- goWebFramework: input.goWebFramework ?? "none",
449
- goOrm: input.goOrm ?? "none",
450
- goApi: input.goApi ?? "none",
451
- goCli: input.goCli ?? "none",
452
- goLogging: input.goLogging ?? "none",
453
- goAuth: input.goAuth ?? "none",
454
- javaWebFramework: input.javaWebFramework ?? "spring-boot",
455
- javaBuildTool: input.javaBuildTool ?? "maven",
456
- javaOrm: input.javaOrm ?? "none",
457
- javaAuth: input.javaAuth ?? "none",
458
- javaLibraries: input.javaLibraries ?? [],
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"
389
+ git: !!overrides,
390
+ install: false
475
391
  };
476
392
  }
477
393
  function sanitizePath(input) {
@@ -486,15 +402,9 @@ function buildCompatibilityInput(input) {
486
402
  const addons = input.addons ?? [];
487
403
  const ecosystem = input.ecosystem ?? "typescript";
488
404
  const hasMobileProject = ecosystem === "react-native" || nativeFrontend.length > 0;
489
- const codeQuality = addons.filter((a) => [
490
- "biome",
491
- "oxlint",
492
- "ultracite",
493
- "lefthook",
494
- "husky",
495
- "ruler"
496
- ].includes(a));
497
- const documentation = addons.filter((a) => ["starlight", "fumadocs"].includes(a));
405
+ const defaults = getMcpCompatibilityDefaults(input);
406
+ const codeQuality = addons.filter((a) => MCP_CODE_QUALITY_ADDONS.has(a));
407
+ const documentation = addons.filter((a) => MCP_DOCUMENTATION_ADDONS.has(a));
498
408
  const appPlatforms = addons.filter((a) => ![
499
409
  ...codeQuality,
500
410
  ...documentation,
@@ -505,109 +415,13 @@ function buildCompatibilityInput(input) {
505
415
  projectName: input.projectName ?? null,
506
416
  webFrontend,
507
417
  nativeFrontend,
508
- astroIntegration: input.astroIntegration ?? "none",
509
- runtime: input.runtime ?? "bun",
510
- backend: input.backend ?? "hono",
511
- database: input.database ?? "none",
512
- orm: input.orm ?? "none",
513
- dbSetup: input.dbSetup ?? "none",
514
- auth: input.auth ?? "none",
515
- payments: input.payments ?? "none",
516
- email: input.email ?? "none",
517
- fileUpload: input.fileUpload ?? "none",
518
- logging: input.logging ?? "none",
519
- observability: input.observability ?? "none",
520
- featureFlags: input.featureFlags ?? "none",
521
- analytics: input.analytics ?? "none",
522
- backendLibraries: "none",
523
- stateManagement: input.stateManagement ?? "none",
524
- forms: input.forms ?? "none",
525
- validation: input.validation ?? "none",
526
- testing: input.testing ?? "none",
527
- realtime: input.realtime ?? "none",
528
- jobQueue: input.jobQueue ?? "none",
529
- caching: input.caching ?? "none",
530
- i18n: input.i18n ?? "none",
531
- animation: input.animation ?? "none",
532
- cssFramework: input.cssFramework ?? "tailwind",
533
- uiLibrary: input.uiLibrary ?? "none",
534
- shadcnBase: input.shadcnBase ?? "radix",
535
- shadcnStyle: input.shadcnStyle ?? "nova",
536
- shadcnIconLibrary: input.shadcnIconLibrary ?? "lucide",
537
- shadcnColorTheme: input.shadcnColorTheme ?? "neutral",
538
- shadcnBaseColor: input.shadcnBaseColor ?? "neutral",
539
- shadcnFont: input.shadcnFont ?? "inter",
540
- shadcnRadius: input.shadcnRadius ?? "default",
541
- cms: input.cms ?? "none",
542
- search: input.search ?? "none",
543
- fileStorage: input.fileStorage ?? "none",
418
+ ...defaults,
544
419
  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
420
  mobileDeepLinking: input.mobileDeepLinking ?? (hasMobileProject ? "expo-linking" : "none"),
551
421
  codeQuality,
552
422
  documentation,
553
423
  appPlatforms,
554
- packageManager: input.packageManager ?? "bun",
555
- versionChannel: "stable",
556
- examples: input.examples ?? [],
557
- aiSdk: input.ai ?? "none",
558
- aiDocs: input.aiDocs ?? ["claude-md"],
559
- git: "true",
560
- install: "false",
561
- api: input.api ?? "none",
562
- webDeploy: input.webDeploy ?? "none",
563
- serverDeploy: input.serverDeploy ?? "none",
564
- yolo: "false",
565
- rustWebFramework: input.rustWebFramework ?? "none",
566
- rustFrontend: input.rustFrontend ?? "none",
567
- rustOrm: input.rustOrm ?? "none",
568
- rustApi: input.rustApi ?? "none",
569
- rustCli: input.rustCli ?? "none",
570
- rustLibraries: input.rustLibraries ?? [],
571
- rustLogging: input.rustLogging ?? "none",
572
- rustErrorHandling: input.rustErrorHandling ?? "none",
573
- rustCaching: input.rustCaching ?? "none",
574
- rustAuth: input.rustAuth ?? "none",
575
- pythonWebFramework: input.pythonWebFramework ?? "none",
576
- pythonOrm: input.pythonOrm ?? "none",
577
- pythonValidation: input.pythonValidation ?? "none",
578
- pythonAi: input.pythonAi ?? [],
579
- pythonAuth: input.pythonAuth ?? "none",
580
- pythonApi: input.pythonApi ?? "none",
581
- pythonTaskQueue: input.pythonTaskQueue ?? "none",
582
- pythonGraphql: input.pythonGraphql ?? "none",
583
- pythonQuality: input.pythonQuality ?? "none",
584
- goWebFramework: input.goWebFramework ?? "none",
585
- goOrm: input.goOrm ?? "none",
586
- goApi: input.goApi ?? "none",
587
- goCli: input.goCli ?? "none",
588
- goLogging: input.goLogging ?? "none",
589
- goAuth: input.goAuth ?? "none",
590
- javaWebFramework: input.javaWebFramework ?? "spring-boot",
591
- javaBuildTool: input.javaBuildTool ?? "maven",
592
- javaOrm: input.javaOrm ?? "none",
593
- javaAuth: input.javaAuth ?? "none",
594
- javaLibraries: input.javaLibraries ?? [],
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"
424
+ aiSdk: input.ai ?? defaults.aiSdk
611
425
  };
612
426
  }
613
427
  function summarizeTree(tree) {
@@ -626,6 +440,19 @@ function summarizeTree(tree) {
626
440
  files: paths
627
441
  };
628
442
  }
443
+ function getMcpGraphPreview(config) {
444
+ const stackParts = config.stackParts?.length ? config.stackParts : legacyProjectConfigToStackParts(config);
445
+ const graphSummary = stackParts.length > 0 ? getGraphSummary({ stackParts }) : void 0;
446
+ const effectiveStack = stackParts.length > 0 ? getEffectiveStack({ stackParts }) : void 0;
447
+ const stackPartSpecs = stackParts.filter((part) => part.source !== "provided").map((part) => formatStackPartSpec(part, stackParts));
448
+ return {
449
+ ...graphSummary ? {
450
+ graphSummary,
451
+ effectiveStack
452
+ } : {},
453
+ stackPartSpecs
454
+ };
455
+ }
629
456
  const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
630
457
 
631
458
  ## Backend Constraints
@@ -764,51 +591,21 @@ async function startMcpServer() {
764
591
  text: JSON.stringify(result, null, 2)
765
592
  }] };
766
593
  });
767
- 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({
768
- ecosystem: EcosystemSchema.describe("Language ecosystem"),
769
- frontend: z.array(z.string()).optional().describe("Web frontend frameworks (TypeScript only)"),
770
- backend: z.string().optional().describe("Backend framework"),
771
- runtime: z.string().optional().describe("JavaScript runtime"),
772
- database: z.string().optional().describe("Database type"),
773
- orm: z.string().optional().describe("ORM"),
774
- api: z.string().optional().describe("API layer"),
775
- auth: z.string().optional().describe("Auth provider"),
776
- payments: z.string().optional().describe("Payments provider"),
777
- email: EmailSchema.optional().describe("Email provider"),
778
- fileUpload: FileUploadSchema.optional().describe("File upload provider"),
779
- ai: AISchema.optional().describe("AI SDK"),
780
- stateManagement: StateManagementSchema.optional().describe("State management"),
781
- forms: FormsSchema.optional().describe("Forms library"),
782
- validation: ValidationSchema.optional().describe("Validation library"),
783
- testing: TestingSchema.optional().describe("Testing framework"),
784
- realtime: RealtimeSchema.optional().describe("Realtime library"),
785
- jobQueue: JobQueueSchema.optional().describe("Job queue"),
786
- animation: AnimationSchema.optional().describe("Animation library"),
787
- logging: LoggingSchema.optional().describe("Logging library"),
788
- observability: ObservabilitySchema.optional().describe("Observability provider"),
789
- featureFlags: FeatureFlagsSchema.optional().describe("Feature flags provider"),
790
- analytics: AnalyticsSchema.optional().describe("Analytics provider"),
791
- cms: CMSSchema.optional().describe("CMS"),
792
- caching: CachingSchema.optional().describe("Caching solution"),
793
- i18n: I18nSchema.optional().describe("Internationalization library"),
794
- search: SearchSchema.optional().describe("Search engine"),
795
- fileStorage: FileStorageSchema.optional().describe("File storage"),
594
+ const mobileInputSchema = {
796
595
  mobileNavigation: MobileNavigationSchema.optional().describe("Mobile navigation"),
797
596
  mobileUI: MobileUISchema.optional().describe("Mobile UI"),
798
597
  mobileStorage: MobileStorageSchema.optional().describe("Mobile storage"),
799
598
  mobileTesting: MobileTestingSchema.optional().describe("Mobile testing"),
800
599
  mobilePush: MobilePushSchema.optional().describe("Mobile push notifications"),
801
600
  mobileOTA: MobileOTASchema.optional().describe("Mobile OTA updates"),
802
- mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking"),
601
+ mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking")
602
+ };
603
+ const deploymentInputSchema = {
803
604
  dbSetup: DatabaseSetupSchema.optional().describe("Database hosting provider"),
804
605
  webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
805
- serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
806
- astroIntegration: AstroIntegrationSchema.optional().describe("Astro UI framework integration"),
807
- uiLibrary: z.string().optional().describe("UI component library"),
808
- cssFramework: z.string().optional().describe("CSS framework"),
809
- addons: z.array(AddonsSchema).optional().describe("Addon list"),
810
- examples: z.array(ExamplesSchema).optional().describe("Example templates"),
811
- packageManager: PackageManagerSchema.optional().describe("Package manager"),
606
+ serverDeploy: ServerDeploySchema.optional().describe("Server deployment target")
607
+ };
608
+ const crossEcosystemInputSchema = {
812
609
  rustWebFramework: RustWebFrameworkSchema.optional().describe("Rust web framework"),
813
610
  rustFrontend: RustFrontendSchema.optional().describe("Rust frontend (WASM)"),
814
611
  rustOrm: RustOrmSchema.optional().describe("Rust ORM"),
@@ -819,6 +616,10 @@ async function startMcpServer() {
819
616
  rustErrorHandling: RustErrorHandlingSchema.optional().describe("Rust error handling library"),
820
617
  rustCaching: RustCachingSchema.optional().describe("Rust caching library"),
821
618
  rustAuth: RustAuthSchema.optional().describe("Rust authentication library"),
619
+ rustRealtime: RustRealtimeSchema.optional().describe("Rust realtime library"),
620
+ rustMessageQueue: RustMessageQueueSchema.optional().describe("Rust message queue"),
621
+ rustObservability: RustObservabilitySchema.optional().describe("Rust observability"),
622
+ rustTemplating: RustTemplatingSchema.optional().describe("Rust template engine"),
822
623
  pythonWebFramework: PythonWebFrameworkSchema.optional().describe("Python web framework"),
823
624
  pythonOrm: PythonOrmSchema.optional().describe("Python ORM"),
824
625
  pythonValidation: PythonValidationSchema.optional().describe("Python validation"),
@@ -828,18 +629,42 @@ async function startMcpServer() {
828
629
  pythonTaskQueue: PythonTaskQueueSchema.optional().describe("Python task queue"),
829
630
  pythonGraphql: PythonGraphqlSchema.optional().describe("Python GraphQL framework"),
830
631
  pythonQuality: PythonQualitySchema.optional().describe("Python code quality"),
632
+ pythonTesting: z.array(PythonTestingSchema).optional().describe("Python testing libraries"),
633
+ pythonCaching: PythonCachingSchema.optional().describe("Python caching library"),
634
+ pythonRealtime: PythonRealtimeSchema.optional().describe("Python realtime library"),
635
+ pythonObservability: PythonObservabilitySchema.optional().describe("Python observability"),
636
+ pythonCli: z.array(PythonCliSchema).optional().describe("Python CLI tooling"),
831
637
  goWebFramework: GoWebFrameworkSchema.optional().describe("Go web framework"),
832
638
  goOrm: GoOrmSchema.optional().describe("Go ORM"),
833
639
  goApi: GoApiSchema.optional().describe("Go API layer"),
834
640
  goCli: GoCliSchema.optional().describe("Go CLI framework"),
835
641
  goLogging: GoLoggingSchema.optional().describe("Go logging library"),
836
642
  goAuth: GoAuthSchema.optional().describe("Go authentication library"),
643
+ goTesting: z.array(GoTestingSchema).optional().describe("Go testing libraries"),
644
+ goRealtime: GoRealtimeSchema.optional().describe("Go realtime/WebSocket library"),
645
+ goMessageQueue: GoMessageQueueSchema.optional().describe("Go message queue"),
646
+ goCaching: GoCachingSchema.optional().describe("Go caching library"),
647
+ goConfig: GoConfigSchema.optional().describe("Go config management"),
648
+ goObservability: GoObservabilitySchema.optional().describe("Go observability"),
837
649
  javaWebFramework: JavaWebFrameworkSchema.optional().describe("Java web framework"),
838
650
  javaBuildTool: JavaBuildToolSchema.optional().describe("Java build tool"),
839
651
  javaOrm: JavaOrmSchema.optional().describe("Java ORM"),
840
652
  javaAuth: JavaAuthSchema.optional().describe("Java authentication library"),
653
+ javaApi: JavaApiSchema.optional().describe("Java API layer"),
654
+ javaLogging: JavaLoggingSchema.optional().describe("Java logging configuration"),
841
655
  javaLibraries: z.array(JavaLibrariesSchema).optional().describe("Java application libraries"),
842
656
  javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
657
+ dotnetWebFramework: DotnetWebFrameworkSchema.optional().describe(".NET web framework"),
658
+ dotnetOrm: DotnetOrmSchema.optional().describe(".NET ORM/data access"),
659
+ dotnetAuth: DotnetAuthSchema.optional().describe(".NET authentication library"),
660
+ dotnetApi: DotnetApiSchema.optional().describe(".NET API style"),
661
+ dotnetTesting: z.array(DotnetTestingSchema).optional().describe(".NET testing libraries"),
662
+ dotnetJobQueue: DotnetJobQueueSchema.optional().describe(".NET jobs and scheduling"),
663
+ dotnetRealtime: DotnetRealtimeSchema.optional().describe(".NET realtime feature"),
664
+ dotnetObservability: z.array(DotnetObservabilitySchema).optional().describe(".NET observability/logging libraries"),
665
+ dotnetValidation: DotnetValidationSchema.optional().describe(".NET validation"),
666
+ dotnetCaching: DotnetCachingSchema.optional().describe(".NET caching library"),
667
+ dotnetDeploy: DotnetDeploySchema.optional().describe(".NET deployment target"),
843
668
  elixirWebFramework: ElixirWebFrameworkSchema.optional().describe("Elixir web framework"),
844
669
  elixirOrm: ElixirOrmSchema.optional().describe("Elixir persistence layer"),
845
670
  elixirAuth: ElixirAuthSchema.optional().describe("Elixir authentication"),
@@ -854,7 +679,48 @@ async function startMcpServer() {
854
679
  elixirObservability: ElixirObservabilitySchema.optional().describe("Elixir observability"),
855
680
  elixirTesting: ElixirTestingSchema.optional().describe("Elixir testing library"),
856
681
  elixirQuality: ElixirQualitySchema.optional().describe("Elixir code quality/security"),
857
- elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target")
682
+ elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target"),
683
+ elixirLibraries: z.array(ElixirLibrariesSchema).optional().describe("Elixir libraries")
684
+ };
685
+ 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({
686
+ ecosystem: EcosystemSchema.describe("Language ecosystem"),
687
+ frontend: z.array(z.string()).optional().describe("Web frontend frameworks (TypeScript only)"),
688
+ backend: z.string().optional().describe("Backend framework"),
689
+ runtime: z.string().optional().describe("JavaScript runtime"),
690
+ database: z.string().optional().describe("Database type"),
691
+ orm: z.string().optional().describe("ORM"),
692
+ api: z.string().optional().describe("API layer"),
693
+ auth: z.string().optional().describe("Auth provider"),
694
+ payments: z.string().optional().describe("Payments provider"),
695
+ email: EmailSchema.optional().describe("Email provider"),
696
+ fileUpload: FileUploadSchema.optional().describe("File upload provider"),
697
+ ai: AISchema.optional().describe("AI SDK"),
698
+ stateManagement: StateManagementSchema.optional().describe("State management"),
699
+ forms: FormsSchema.optional().describe("Forms library"),
700
+ validation: ValidationSchema.optional().describe("Validation library"),
701
+ testing: TestingSchema.optional().describe("Testing framework"),
702
+ realtime: RealtimeSchema.optional().describe("Realtime library"),
703
+ jobQueue: JobQueueSchema.optional().describe("Job queue"),
704
+ animation: AnimationSchema.optional().describe("Animation library"),
705
+ logging: LoggingSchema.optional().describe("Logging library"),
706
+ observability: ObservabilitySchema.optional().describe("Observability provider"),
707
+ featureFlags: FeatureFlagsSchema.optional().describe("Feature flags provider"),
708
+ analytics: AnalyticsSchema.optional().describe("Analytics provider"),
709
+ cms: CMSSchema.optional().describe("CMS"),
710
+ caching: CachingSchema.optional().describe("Caching solution"),
711
+ rateLimit: RateLimitSchema.optional().describe("Rate limiting solution"),
712
+ i18n: I18nSchema.optional().describe("Internationalization library"),
713
+ search: SearchSchema.optional().describe("Search engine"),
714
+ fileStorage: FileStorageSchema.optional().describe("File storage"),
715
+ ...mobileInputSchema,
716
+ ...deploymentInputSchema,
717
+ astroIntegration: AstroIntegrationSchema.optional().describe("Astro UI framework integration"),
718
+ uiLibrary: z.string().optional().describe("UI component library"),
719
+ cssFramework: z.string().optional().describe("CSS framework"),
720
+ addons: z.array(AddonsSchema).optional().describe("Addon list"),
721
+ examples: z.array(ExamplesSchema).optional().describe("Example templates"),
722
+ packageManager: PackageManagerSchema.optional().describe("Package manager"),
723
+ ...crossEcosystemInputSchema
858
724
  }), async (input) => {
859
725
  try {
860
726
  const filtered = filterCompatibilityResult(analyzeStackCompatibility(buildCompatibilityInput(input)), input.ecosystem);
@@ -902,81 +768,32 @@ async function startMcpServer() {
902
768
  featureFlags: FeatureFlagsSchema.optional().describe("Feature flag provider"),
903
769
  search: SearchSchema.optional().describe("Search engine"),
904
770
  caching: CachingSchema.optional().describe("Caching solution"),
771
+ rateLimit: RateLimitSchema.optional().describe("Rate limiting solution"),
905
772
  i18n: I18nSchema.optional().describe("Internationalization (i18n) library"),
906
773
  cms: CMSSchema.optional().describe("CMS"),
907
774
  fileStorage: FileStorageSchema.optional().describe("File storage"),
908
- mobileNavigation: MobileNavigationSchema.optional().describe("Mobile navigation"),
909
- mobileUI: MobileUISchema.optional().describe("Mobile UI"),
910
- mobileStorage: MobileStorageSchema.optional().describe("Mobile storage"),
911
- mobileTesting: MobileTestingSchema.optional().describe("Mobile testing"),
912
- mobilePush: MobilePushSchema.optional().describe("Mobile push notifications"),
913
- mobileOTA: MobileOTASchema.optional().describe("Mobile OTA updates"),
914
- mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking"),
775
+ ...mobileInputSchema,
915
776
  fileUpload: FileUploadSchema.optional().describe("File upload"),
916
- webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
917
- serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
918
- dbSetup: DatabaseSetupSchema.optional().describe("Database hosting provider"),
919
- rustWebFramework: RustWebFrameworkSchema.optional().describe("Rust web framework"),
920
- rustFrontend: RustFrontendSchema.optional().describe("Rust frontend (WASM)"),
921
- rustOrm: RustOrmSchema.optional().describe("Rust ORM"),
922
- rustApi: RustApiSchema.optional().describe("Rust API layer"),
923
- rustCli: RustCliSchema.optional().describe("Rust CLI framework"),
924
- rustLibraries: z.array(RustLibrariesSchema).optional().describe("Rust libraries"),
925
- rustLogging: RustLoggingSchema.optional().describe("Rust logging library"),
926
- rustErrorHandling: RustErrorHandlingSchema.optional().describe("Rust error handling library"),
927
- rustCaching: RustCachingSchema.optional().describe("Rust caching library"),
928
- rustAuth: RustAuthSchema.optional().describe("Rust authentication library"),
929
- pythonWebFramework: PythonWebFrameworkSchema.optional().describe("Python web framework"),
930
- pythonOrm: PythonOrmSchema.optional().describe("Python ORM"),
931
- pythonValidation: PythonValidationSchema.optional().describe("Python validation"),
932
- pythonAi: z.array(PythonAiSchema).optional().describe("Python AI libraries"),
933
- pythonAuth: PythonAuthSchema.optional().describe("Python auth library"),
934
- pythonApi: PythonApiSchema.optional().describe("Python API framework"),
935
- pythonTaskQueue: PythonTaskQueueSchema.optional().describe("Python task queue"),
936
- pythonGraphql: PythonGraphqlSchema.optional().describe("Python GraphQL framework"),
937
- pythonQuality: PythonQualitySchema.optional().describe("Python code quality"),
938
- goWebFramework: GoWebFrameworkSchema.optional().describe("Go web framework"),
939
- goOrm: GoOrmSchema.optional().describe("Go ORM"),
940
- goApi: GoApiSchema.optional().describe("Go API layer"),
941
- goCli: GoCliSchema.optional().describe("Go CLI framework"),
942
- goLogging: GoLoggingSchema.optional().describe("Go logging library"),
943
- goAuth: GoAuthSchema.optional().describe("Go authentication library"),
944
- javaWebFramework: JavaWebFrameworkSchema.optional().describe("Java web framework"),
945
- javaBuildTool: JavaBuildToolSchema.optional().describe("Java build tool"),
946
- javaOrm: JavaOrmSchema.optional().describe("Java ORM"),
947
- javaAuth: JavaAuthSchema.optional().describe("Java authentication library"),
948
- javaLibraries: z.array(JavaLibrariesSchema).optional().describe("Java application libraries"),
949
- javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
950
- elixirWebFramework: ElixirWebFrameworkSchema.optional().describe("Elixir web framework"),
951
- elixirOrm: ElixirOrmSchema.optional().describe("Elixir persistence layer"),
952
- elixirAuth: ElixirAuthSchema.optional().describe("Elixir authentication"),
953
- elixirApi: ElixirApiSchema.optional().describe("Elixir API layer"),
954
- elixirRealtime: ElixirRealtimeSchema.optional().describe("Elixir realtime feature"),
955
- elixirJobs: ElixirJobsSchema.optional().describe("Elixir jobs and scheduling"),
956
- elixirValidation: ElixirValidationSchema.optional().describe("Elixir validation/data"),
957
- elixirHttp: ElixirHttpSchema.optional().describe("Elixir HTTP client"),
958
- elixirJson: ElixirJsonSchema.optional().describe("Elixir JSON library"),
959
- elixirEmail: ElixirEmailSchema.optional().describe("Elixir email library"),
960
- elixirCaching: ElixirCachingSchema.optional().describe("Elixir caching library"),
961
- elixirObservability: ElixirObservabilitySchema.optional().describe("Elixir observability"),
962
- elixirTesting: ElixirTestingSchema.optional().describe("Elixir testing library"),
963
- elixirQuality: ElixirQualitySchema.optional().describe("Elixir code quality/security"),
964
- elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target")
777
+ ...deploymentInputSchema,
778
+ ...crossEcosystemInputSchema
965
779
  };
966
780
  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) => {
967
781
  try {
968
782
  const { generateVirtualProject, EMBEDDED_TEMPLATES } = await import("@better-fullstack/template-generator");
783
+ const config = buildProjectConfig(input);
969
784
  const result = await generateVirtualProject({
970
- config: buildProjectConfig(input),
785
+ config,
971
786
  templates: EMBEDDED_TEMPLATES
972
787
  });
973
788
  if (result.success && result.tree) {
974
789
  const summary = summarizeTree(result.tree);
790
+ const graphPreview = getMcpGraphPreview(config);
975
791
  return { content: [{
976
792
  type: "text",
977
793
  text: JSON.stringify({
978
794
  success: true,
979
- ...summary
795
+ ...summary,
796
+ ...graphPreview
980
797
  }, null, 2)
981
798
  }] };
982
799
  }
@@ -1028,9 +845,10 @@ async function startMcpServer() {
1028
845
  };
1029
846
  await writeTreeToFilesystem(result.tree, projectDir);
1030
847
  await writeBtsConfig(config);
848
+ const graphPreview = getMcpGraphPreview(config);
1031
849
  let addonWarnings = [];
1032
850
  if (config.addons.length > 0 && config.addons[0] !== "none") {
1033
- const { setupAddons } = await import("./addons-setup-Ca069cmy.mjs");
851
+ const { setupAddons } = await import("./addons-setup-CV5uZyhH.mjs");
1034
852
  addonWarnings = await setupAddons(config);
1035
853
  }
1036
854
  const installCmd = getInstallCommand(input.ecosystem ?? "typescript", projectName, input.packageManager, input.javaBuildTool, input.javaWebFramework);
@@ -1040,6 +858,7 @@ async function startMcpServer() {
1040
858
  success: true,
1041
859
  projectDirectory: projectDir,
1042
860
  fileCount: result.tree.fileCount,
861
+ ...graphPreview,
1043
862
  ...addonWarnings.length > 0 ? { addonWarnings } : {},
1044
863
  message: `Project created at ${projectDir}. Tell the user to run: ${installCmd}`
1045
864
  }, null, 2)
@@ -1076,6 +895,13 @@ async function startMcpServer() {
1076
895
  const existingAddons = new Set(config.addons ?? []);
1077
896
  const newAddons = (addons ?? []).filter((a) => a !== "none" && !existingAddons.has(a));
1078
897
  const mergedAddons = [...new Set([...config.addons ?? [], ...newAddons])];
898
+ const updatePreview = previewBtsConfigUpdate(config, {
899
+ addons: mergedAddons,
900
+ webDeploy: webDeploy ?? config.webDeploy,
901
+ serverDeploy: serverDeploy ?? config.serverDeploy
902
+ });
903
+ const existingGraphPreview = getMcpGraphPreview(config);
904
+ const proposedGraphPreview = getMcpGraphPreview(updatePreview);
1079
905
  const compatResult = analyzeStackCompatibility(buildCompatibilityInput({
1080
906
  ...config,
1081
907
  addons: mergedAddons,
@@ -1091,12 +917,18 @@ async function startMcpServer() {
1091
917
  ecosystem: config.ecosystem,
1092
918
  frontend: config.frontend,
1093
919
  backend: config.backend,
1094
- addons: config.addons
920
+ addons: config.addons,
921
+ graphSummary: existingGraphPreview.graphSummary,
922
+ effectiveStack: existingGraphPreview.effectiveStack,
923
+ stackPartSpecs: existingGraphPreview.stackPartSpecs
1095
924
  },
1096
925
  proposedAdditions: {
1097
926
  newAddons,
1098
927
  webDeploy: webDeploy ?? null,
1099
- serverDeploy: serverDeploy ?? null
928
+ serverDeploy: serverDeploy ?? null,
929
+ graphSummary: proposedGraphPreview.graphSummary,
930
+ effectiveStack: proposedGraphPreview.effectiveStack,
931
+ stackPartSpecs: proposedGraphPreview.stackPartSpecs
1100
932
  },
1101
933
  alreadyPresent: (addons ?? []).filter((a) => existingAddons.has(a)),
1102
934
  ...compatibilityWarnings ? { compatibilityWarnings } : {}
@@ -1132,6 +964,7 @@ async function startMcpServer() {
1132
964
  });
1133
965
  if (result?.success) {
1134
966
  const existingConfig = await readBtsConfig(safePath);
967
+ const graphPreview = existingConfig ? getMcpGraphPreview(existingConfig) : void 0;
1135
968
  const installCmd = getInstallCommand(existingConfig?.ecosystem ?? "typescript", safePath.split("/").pop() ?? "project", input.packageManager, existingConfig?.javaBuildTool, existingConfig?.javaWebFramework);
1136
969
  return { content: [{
1137
970
  type: "text",
@@ -1139,6 +972,7 @@ async function startMcpServer() {
1139
972
  success: true,
1140
973
  addedAddons: result.addedAddons,
1141
974
  projectDir: result.projectDir,
975
+ ...graphPreview,
1142
976
  message: `Added ${result.addedAddons.join(", ")} to project. Tell the user to run: ${installCmd}`
1143
977
  }, null, 2)
1144
978
  }] };
@@ -1193,4 +1027,4 @@ async function startMcpServer() {
1193
1027
  startMcpServer();
1194
1028
 
1195
1029
  //#endregion
1196
- export { startMcpServer as t };
1030
+ export { startMcpServer as n, getMcpGraphPreview as t };