create-better-fullstack 2.1.8 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +4 -4
  2. package/dist/{add-handler-ztNjzoMN.mjs → add-handler-z4NCxoq6.mjs} +9 -8
  3. package/dist/addons-setup-COE1e1db.mjs +7 -0
  4. package/dist/{addons-setup-LaAj43NP.mjs → addons-setup-DKtiNexf.mjs} +1 -1
  5. package/dist/{analytics-DVltG11u.mjs → analytics-BD8hZvIj.mjs} +1 -1
  6. package/dist/{bts-config-DQVWvPDs.mjs → bts-config-Bwd6GB7B.mjs} +59 -0
  7. package/dist/cli.mjs +2 -2
  8. package/dist/command-exists-DtX9ldL8.mjs +15 -0
  9. package/dist/{config-processing-D9-F2Us9.mjs → config-processing-B-RT_mVE.mjs} +32 -3
  10. package/dist/{doctor-a4ca3SMd.mjs → doctor-LmNs-hDr.mjs} +4 -3
  11. package/dist/{file-formatter-gvmrpd-g.mjs → file-formatter-DxF56-mO.mjs} +550 -24
  12. package/dist/{gen-CCClL7Ve.mjs → gen-CQfQU0uZ.mjs} +1 -1
  13. package/dist/{generated-checks-BV9jol5h.mjs → generated-checks-BUcI5VM2.mjs} +55 -22
  14. package/dist/index.d.mts +741 -211
  15. package/dist/index.mjs +30 -9
  16. package/dist/{install-dependencies-RoUyaE8o.mjs → install-dependencies-CJiUklm3.mjs} +132 -23
  17. package/dist/{mcp-492OkjcS.mjs → mcp-BBammItk.mjs} +5 -5
  18. package/dist/mcp-entry.mjs +76 -236
  19. package/dist/{registry-DSf2CEaU.mjs → registry-D0JfLCoH.mjs} +1 -1
  20. package/dist/{run-T6g1jkfy.mjs → run-BAIeghcU.mjs} +1948 -318
  21. package/dist/run-CAl4L4uU.mjs +16 -0
  22. package/dist/scaffold-manifest-CQwvyttq.mjs +4 -0
  23. package/dist/{scaffold-manifest-Dyi0voqE.mjs → scaffold-manifest-Dr3Anmlf.mjs} +34 -5
  24. package/dist/{update-DJ8CI5KW.mjs → update-CnrBdWrh.mjs} +182 -25
  25. package/package.json +24 -7
  26. package/dist/addons-setup-DnLjAzTw.mjs +0 -7
  27. package/dist/run-CD8f7PHh.mjs +0 -15
  28. package/dist/scaffold-manifest-DGRyepdb.mjs +0 -4
  29. /package/dist/{update-deps-aD-iQw4U.mjs → update-deps-G3FgqBlW.mjs} +0 -0
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { _ as DEFAULT_UI_LIBRARY_BY_FRONTEND, b as types_exports, c as getGraphBackendDeployInstructions, d as getGraphSummary, g as DEFAULT_CONFIG, h as BUILDER_URL, i as readBtsConfigFromFile, l as getGraphBackendUrl, m as getLatestCLIVersion, o as writeBtsConfig, p as hasGraphPart, t as buildBtsConfigForPersistence, u as getGraphPart, v as getDefaultConfig, y as getUserPkgManager } from "./bts-config-DQVWvPDs.mjs";
2
+ import { _ as DEFAULT_UI_LIBRARY_BY_FRONTEND, b as types_exports, c as getGraphBackendDeployInstructions, d as getGraphSummary, g as DEFAULT_CONFIG, h as BUILDER_URL, i as readBtsConfigFromFile, l as getGraphBackendUrl, m as getLatestCLIVersion, o as writeBtsConfig, p as hasGraphPart, t as buildBtsConfigForPersistence, u as getGraphPart, v as getDefaultConfig, y as getUserPkgManager } from "./bts-config-Bwd6GB7B.mjs";
3
3
  import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
4
4
  import { a as handleError, c as isSilent, d as setLastPromptShownUI, i as exitWithError, l as runWithContextAsync, n as UserCancelledError, o as didLastPromptShowUI, r as exitCancelled, s as isFirstPrompt, t as CLIError, u as setIsFirstPrompt } from "./errors-ns_o2OKg.mjs";
5
5
  import { t as canPromptInteractively } from "./prompt-environment-BR0Kkw2W.mjs";
6
- import { a as trackProjectCreation, i as trackEvent, n as isTelemetryEnabled, o as getPersistedTelemetryPreference, r as maybeShowTelemetryNotice, s as setTelemetryPreference, t as hasTelemetryEnvOverride } from "./analytics-DVltG11u.mjs";
7
- import { _ as CreateCommandInputSchema, a as allowedApisForFrontends$1, c as getCompatibleUILibraries$1, d as isExampleChatSdkAllowed$1, f as isFrontendAllowedWithBackend$1, h as splitFrontends$1, i as validateFullConfig, l as hasWebStyling$1, m as requiresChatSdkVercelAI, n as formatProject, p as isWebFrontend$1, r as validateConfigForProgrammaticUse, s as getCompatibleCSSFrameworks$1, u as isExampleAIAllowed$1, v as CreateCommandOptionsSchema } from "./file-formatter-gvmrpd-g.mjs";
8
- import { _ as isGoBack, a as runMavenTests, c as applyDependencyVersionChannel, d as isCancel$1, f as navigableConfirm, g as GO_BACK_SYMBOL, h as setIsFirstPrompt$1, i as runGradleTests, l as getAddonsChoice, m as navigableSelect, n as runCargoBuild, o as runMixCompile, p as navigableMultiselect, r as runGoModTidy, s as runUvSync, t as installDependencies } from "./install-dependencies-RoUyaE8o.mjs";
9
- import { n as commandExists, t as runGeneratedChecks } from "./generated-checks-BV9jol5h.mjs";
10
- import { a as getTemplateConfig, i as validateArrayOptions, n as getProvidedFlags, o as getTemplateDescription, r as processFlags, s as generateReproducibleCommand, t as applyEffectBackendDefaults } from "./config-processing-D9-F2Us9.mjs";
11
- import { a as recordScaffoldManifest } from "./scaffold-manifest-Dyi0voqE.mjs";
12
- import { n as getPackageExecutionArgs, r as addPackageDependency, t as setupAddons } from "./addons-setup-LaAj43NP.mjs";
6
+ import { a as trackProjectCreation, i as trackEvent, n as isTelemetryEnabled, o as getPersistedTelemetryPreference, r as maybeShowTelemetryNotice, s as setTelemetryPreference, t as hasTelemetryEnvOverride } from "./analytics-BD8hZvIj.mjs";
7
+ import { C as CreateCommandInputSchema, _ as isExampleChatSdkAllowed$1, b as requiresChatSdkVercelAI, d as allowedApisForFrontends$1, g as isExampleAIAllowed$1, h as hasWebStyling$1, i as validateFullConfig, m as getCompatibleUILibraries$1, n as formatProject, p as getCompatibleCSSFrameworks$1, r as validateConfigForProgrammaticUse, u as resolveCompatibilityAdjustments, v as isFrontendAllowedWithBackend$1, w as CreateCommandOptionsSchema, x as splitFrontends$1, y as isWebFrontend$1 } from "./file-formatter-DxF56-mO.mjs";
8
+ import { _ as GO_BACK_SYMBOL, a as runMavenTests, c as applyDependencyVersionChannel, d as getAppPlatformsChoice, f as isCancel$1, g as setIsFirstPrompt$1, h as navigableSelect, i as runGradleTests, l as getAddonsChoice, m as navigableMultiselect, n as runCargoBuild, o as runMixCompile, p as navigableConfirm, r as runGoModTidy, s as runPythonInstall, t as installDependencies, v as isGoBack } from "./install-dependencies-CJiUklm3.mjs";
9
+ import { t as commandExists } from "./command-exists-DtX9ldL8.mjs";
10
+ import { a as getTemplateConfig, i as validateArrayOptions, n as getProvidedFlags, o as getTemplateDescription, r as processFlags, s as generateReproducibleCommand, t as applyEffectBackendDefaults } from "./config-processing-B-RT_mVE.mjs";
11
+ import { t as runGeneratedChecks } from "./generated-checks-BUcI5VM2.mjs";
12
+ import { n as collectStructuredBaselines, s as recordScaffoldManifest } from "./scaffold-manifest-Dr3Anmlf.mjs";
13
+ import { n as getPackageExecutionArgs, r as addPackageDependency, t as setupAddons } from "./addons-setup-DKtiNexf.mjs";
13
14
  import { cancel, confirm, intro, isCancel, log, note, outro, select, spinner, text } from "@clack/prompts";
14
15
  import { createRouterClient, os } from "@orpc/server";
15
16
  import pc from "picocolors";
@@ -269,6 +270,16 @@ const AI_PROMPT_OPTIONS = [
269
270
  label: "OpenAI Agents SDK",
270
271
  hint: "Official multi-agent framework with handoffs and guardrails"
271
272
  },
273
+ {
274
+ value: "openai-sdk",
275
+ label: "OpenAI SDK",
276
+ hint: "Official OpenAI JavaScript and TypeScript client"
277
+ },
278
+ {
279
+ value: "anthropic-sdk",
280
+ label: "Anthropic SDK",
281
+ hint: "Official Anthropic TypeScript client for Claude"
282
+ },
272
283
  {
273
284
  value: "google-adk",
274
285
  label: "Google ADK",
@@ -305,11 +316,14 @@ const AI_PROMPT_OPTIONS = [
305
316
  hint: "No AI SDK"
306
317
  }
307
318
  ];
308
- function resolveAIPrompt(ai) {
309
- return createStaticSinglePromptResolution(AI_PROMPT_OPTIONS, "none", ai);
319
+ function resolveAIPrompt(context = {}) {
320
+ return createStaticSinglePromptResolution(["none", "convex"].includes(context.backend ?? "") ? AI_PROMPT_OPTIONS.filter((option) => option.value !== "openai-sdk" && option.value !== "anthropic-sdk") : AI_PROMPT_OPTIONS, "none", context.ai);
310
321
  }
311
- async function getAIChoice(ai) {
312
- const resolution = resolveAIPrompt(ai);
322
+ async function getAIChoice(ai, backend) {
323
+ const resolution = resolveAIPrompt({
324
+ ai,
325
+ backend
326
+ });
313
327
  if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
314
328
  const response = await navigableSelect({
315
329
  message: "Select AI SDK",
@@ -574,6 +588,7 @@ function resolveAuthPrompt(context = {}) {
574
588
  { value: "auth0" },
575
589
  { value: "workos" },
576
590
  { value: "kinde" },
591
+ { value: "passport" },
577
592
  { value: "none" }
578
593
  ];
579
594
  const supportedOptions = (0, types_exports.getSupportedCapabilityOptions)("auth", {
@@ -854,6 +869,11 @@ const CMS_PROMPT_OPTIONS = [
854
869
  label: "Keystatic",
855
870
  hint: "Git-backed CMS for Markdown, JSON, and YAML content"
856
871
  },
872
+ {
873
+ value: "contentful",
874
+ label: "Contentful",
875
+ hint: "Hosted headless CMS with a typed JavaScript delivery client"
876
+ },
857
877
  {
858
878
  value: "none",
859
879
  label: "None",
@@ -861,28 +881,44 @@ const CMS_PROMPT_OPTIONS = [
861
881
  }
862
882
  ];
863
883
  function resolveCMSPrompt(context = {}) {
864
- if (context.backend === "none" || context.backend === "convex") return {
865
- shouldPrompt: false,
866
- mode: "single",
867
- options: [],
868
- autoValue: "none"
869
- };
884
+ const compatibleOptions = context.frontends?.some((frontend) => ["vanilla-vite", "vue"].includes(frontend)) ? CMS_PROMPT_OPTIONS.filter((option) => ["contentful", "none"].includes(option.value)) : CMS_PROMPT_OPTIONS;
885
+ if (context.backend === "none" || context.backend === "convex") {
886
+ const options = compatibleOptions.filter((option) => ["contentful", "none"].includes(option.value));
887
+ if ((context.frontends?.some((frontend) => frontend !== "none" && isWebFrontend$1(frontend)) ?? false) && (context.cms === void 0 || context.cms === "contentful")) return context.cms === "contentful" ? {
888
+ shouldPrompt: false,
889
+ mode: "single",
890
+ options,
891
+ autoValue: "contentful"
892
+ } : {
893
+ shouldPrompt: true,
894
+ mode: "single",
895
+ options,
896
+ initialValue: "none"
897
+ };
898
+ return {
899
+ shouldPrompt: false,
900
+ mode: "single",
901
+ options: [],
902
+ autoValue: "none"
903
+ };
904
+ }
870
905
  return context.cms !== void 0 ? {
871
906
  shouldPrompt: false,
872
907
  mode: "single",
873
- options: CMS_PROMPT_OPTIONS,
874
- autoValue: context.cms
908
+ options: compatibleOptions,
909
+ autoValue: compatibleOptions.some((option) => option.value === context.cms) ? context.cms : "none"
875
910
  } : {
876
911
  shouldPrompt: true,
877
912
  mode: "single",
878
- options: CMS_PROMPT_OPTIONS,
913
+ options: compatibleOptions,
879
914
  initialValue: "none"
880
915
  };
881
916
  }
882
- async function getCMSChoice(cms, backend) {
917
+ async function getCMSChoice(cms, backend, frontends) {
883
918
  const resolution = resolveCMSPrompt({
884
919
  cms,
885
- backend
920
+ backend,
921
+ frontends
886
922
  });
887
923
  if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
888
924
  const response = await navigableSelect({
@@ -914,6 +950,11 @@ const sharedServiceSection = {
914
950
  ]
915
951
  };
916
952
  const typescriptSections = [
953
+ {
954
+ id: "app-platforms",
955
+ label: "App Platforms",
956
+ promptKeys: ["appPlatforms"]
957
+ },
917
958
  {
918
959
  id: "ui-styling",
919
960
  label: "UI & Styling",
@@ -1030,7 +1071,8 @@ const CONFIG_SCOPE_REGISTRY = {
1030
1071
  promptKeys: [
1031
1072
  "mobileUI",
1032
1073
  "mobileStorage",
1033
- "mobileDeepLinking"
1074
+ "mobileDeepLinking",
1075
+ "mobileLibraries"
1034
1076
  ]
1035
1077
  },
1036
1078
  {
@@ -1118,17 +1160,25 @@ const CONFIG_SCOPE_REGISTRY = {
1118
1160
  },
1119
1161
  {
1120
1162
  id: "api-jobs",
1121
- label: "GraphQL, Tasks & CLI",
1163
+ label: "GraphQL, Queues & CLI",
1122
1164
  promptKeys: [
1123
1165
  "pythonGraphql",
1124
1166
  "pythonTaskQueue",
1167
+ "pythonMessageQueue",
1125
1168
  "pythonCli"
1126
1169
  ]
1127
1170
  },
1128
1171
  {
1129
1172
  id: "data-realtime",
1130
- label: "Caching & Realtime",
1131
- promptKeys: ["pythonCaching", "pythonRealtime"]
1173
+ label: "Data, Media & Integrations",
1174
+ promptKeys: [
1175
+ "pythonData",
1176
+ "pythonMedia",
1177
+ "pythonCloudSdk",
1178
+ "pythonHttpClient",
1179
+ "pythonCaching",
1180
+ "pythonRealtime"
1181
+ ]
1132
1182
  },
1133
1183
  {
1134
1184
  id: "quality",
@@ -1138,6 +1188,11 @@ const CONFIG_SCOPE_REGISTRY = {
1138
1188
  "pythonTesting",
1139
1189
  "pythonObservability"
1140
1190
  ]
1191
+ },
1192
+ {
1193
+ id: "runtime-tooling",
1194
+ label: "Server & Package Manager",
1195
+ promptKeys: ["pythonServer", "pythonPackageManager"]
1141
1196
  }
1142
1197
  ]
1143
1198
  },
@@ -1148,7 +1203,10 @@ const CONFIG_SCOPE_REGISTRY = {
1148
1203
  "dbSetup",
1149
1204
  "goOrm",
1150
1205
  "goApi",
1151
- "goAuth"
1206
+ "goAuth",
1207
+ "goValidation",
1208
+ "goMigrations",
1209
+ "goDI"
1152
1210
  ],
1153
1211
  sections: [
1154
1212
  sharedServiceSection,
@@ -1158,7 +1216,9 @@ const CONFIG_SCOPE_REGISTRY = {
1158
1216
  promptKeys: [
1159
1217
  "goCli",
1160
1218
  "goConfig",
1161
- "goLogging"
1219
+ "goLogging",
1220
+ "goTemplating",
1221
+ "goProtoTooling"
1162
1222
  ]
1163
1223
  },
1164
1224
  {
@@ -1172,8 +1232,12 @@ const CONFIG_SCOPE_REGISTRY = {
1172
1232
  },
1173
1233
  {
1174
1234
  id: "quality",
1175
- label: "Testing & Observability",
1176
- promptKeys: ["goTesting", "goObservability"]
1235
+ label: "Quality, Testing & Observability",
1236
+ promptKeys: [
1237
+ "goQuality",
1238
+ "goTesting",
1239
+ "goObservability"
1240
+ ]
1177
1241
  }
1178
1242
  ]
1179
1243
  },
@@ -1230,7 +1294,11 @@ const CONFIG_SCOPE_REGISTRY = {
1230
1294
  {
1231
1295
  id: "validation-deploy",
1232
1296
  label: "Validation & Deployment",
1233
- promptKeys: ["dotnetValidation", "dotnetDeploy"]
1297
+ promptKeys: [
1298
+ "dotnetValidation",
1299
+ "dotnetDeploy",
1300
+ "dotnetLibraries"
1301
+ ]
1234
1302
  }
1235
1303
  ]
1236
1304
  },
@@ -1269,13 +1337,27 @@ const CONFIG_SCOPE_REGISTRY = {
1269
1337
  promptKeys: [
1270
1338
  "elixirTesting",
1271
1339
  "elixirQuality",
1272
- "elixirObservability"
1340
+ "elixirObservability",
1341
+ "elixirDocumentation"
1342
+ ]
1343
+ },
1344
+ {
1345
+ id: "runtime",
1346
+ label: "Internationalization, Runtime & Clustering",
1347
+ promptKeys: [
1348
+ "elixirI18n",
1349
+ "elixirHttpServer",
1350
+ "elixirClustering"
1273
1351
  ]
1274
1352
  },
1275
1353
  {
1276
1354
  id: "deploy-libraries",
1277
1355
  label: "Deployment & Libraries",
1278
- promptKeys: ["elixirDeploy", "elixirLibraries"]
1356
+ promptKeys: [
1357
+ "elixirDeploy",
1358
+ "elixirApplicationFramework",
1359
+ "elixirLibraries"
1360
+ ]
1279
1361
  }
1280
1362
  ]
1281
1363
  }
@@ -1310,6 +1392,7 @@ function shouldAskConfigPromptKey(ecosystem, key, scope, selectedSectionIds) {
1310
1392
  }
1311
1393
  function getDefaultPromptValue(key) {
1312
1394
  if (key === "astroIntegration") return void 0;
1395
+ if (key === "appPlatforms") return [];
1313
1396
  const defaults = getDefaultConfig();
1314
1397
  if (key === "shadcnOptions") return {
1315
1398
  shadcnBase: defaults.shadcnBase,
@@ -1382,13 +1465,17 @@ const CSS_FRAMEWORK_OPTIONS = {
1382
1465
  label: "PostCSS Only",
1383
1466
  hint: "Minimal setup with just PostCSS"
1384
1467
  },
1468
+ "styled-components": {
1469
+ label: "styled-components",
1470
+ hint: "CSS-in-JS with tagged template literals for React"
1471
+ },
1385
1472
  none: {
1386
1473
  label: "None",
1387
1474
  hint: "Plain CSS without preprocessors"
1388
1475
  }
1389
1476
  };
1390
1477
  function resolveCSSFrameworkPrompt(context = {}) {
1391
- const compatibleFrameworks = getCompatibleCSSFrameworks$1(context.uiLibrary);
1478
+ const compatibleFrameworks = getCompatibleCSSFrameworks$1(context.uiLibrary, context.frontends);
1392
1479
  if (context.cssFramework !== void 0) return {
1393
1480
  shouldPrompt: false,
1394
1481
  mode: "single",
@@ -1397,7 +1484,7 @@ function resolveCSSFrameworkPrompt(context = {}) {
1397
1484
  label: CSS_FRAMEWORK_OPTIONS[fw].label,
1398
1485
  hint: CSS_FRAMEWORK_OPTIONS[fw].hint
1399
1486
  })),
1400
- autoValue: compatibleFrameworks.includes(context.cssFramework) ? context.cssFramework : compatibleFrameworks[0]
1487
+ autoValue: context.cssFramework
1401
1488
  };
1402
1489
  return {
1403
1490
  shouldPrompt: true,
@@ -1410,10 +1497,11 @@ function resolveCSSFrameworkPrompt(context = {}) {
1410
1497
  initialValue: compatibleFrameworks.includes("tailwind") ? "tailwind" : compatibleFrameworks[0]
1411
1498
  };
1412
1499
  }
1413
- async function getCSSFrameworkChoice(cssFramework, uiLibrary) {
1500
+ async function getCSSFrameworkChoice(cssFramework, uiLibrary, frontends) {
1414
1501
  const resolution = resolveCSSFrameworkPrompt({
1415
1502
  cssFramework,
1416
- uiLibrary
1503
+ uiLibrary,
1504
+ frontends
1417
1505
  });
1418
1506
  if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
1419
1507
  const selected = await navigableSelect({
@@ -1908,6 +1996,113 @@ const DEPLOY_OPTIONS$1 = [
1908
1996
  hint: "No .NET deploy target"
1909
1997
  }
1910
1998
  ];
1999
+ const LIBRARIES_OPTIONS = [
2000
+ {
2001
+ value: "automapper",
2002
+ label: "AutoMapper",
2003
+ hint: "Convention-based object mapping"
2004
+ },
2005
+ {
2006
+ value: "mediatr",
2007
+ label: "MediatR",
2008
+ hint: "In-process request and notification dispatch"
2009
+ },
2010
+ {
2011
+ value: "fastendpoints",
2012
+ label: "FastEndpoints",
2013
+ hint: "REPR-style endpoint framework"
2014
+ },
2015
+ {
2016
+ value: "api-versioning",
2017
+ label: "ASP.NET API Versioning",
2018
+ hint: "Versioned HTTP APIs"
2019
+ },
2020
+ {
2021
+ value: "scalar",
2022
+ label: "Scalar",
2023
+ hint: "Interactive OpenAPI reference UI"
2024
+ },
2025
+ {
2026
+ value: "polly",
2027
+ label: "Polly",
2028
+ hint: "Resilience and transient-fault handling"
2029
+ },
2030
+ {
2031
+ value: "masstransit",
2032
+ label: "MassTransit",
2033
+ hint: "Distributed messaging abstraction"
2034
+ },
2035
+ {
2036
+ value: "rebus",
2037
+ label: "Rebus",
2038
+ hint: "Service bus and message workflows"
2039
+ },
2040
+ {
2041
+ value: "coravel",
2042
+ label: "Coravel",
2043
+ hint: "Task scheduling and queuing"
2044
+ },
2045
+ {
2046
+ value: "magic-onion",
2047
+ label: "MagicOnion",
2048
+ hint: "Realtime RPC over gRPC"
2049
+ },
2050
+ {
2051
+ value: "prometheus-net",
2052
+ label: "prometheus-net",
2053
+ hint: "Prometheus metrics endpoint"
2054
+ },
2055
+ {
2056
+ value: "seq",
2057
+ label: "Seq",
2058
+ hint: "Structured log sink for Seq"
2059
+ },
2060
+ {
2061
+ value: "application-insights",
2062
+ label: "Application Insights",
2063
+ hint: "Azure application telemetry"
2064
+ },
2065
+ {
2066
+ value: "sentry",
2067
+ label: "Sentry",
2068
+ hint: "Error and performance monitoring"
2069
+ },
2070
+ {
2071
+ value: "mongodb-driver",
2072
+ label: "MongoDB Driver",
2073
+ hint: "Official MongoDB client"
2074
+ },
2075
+ {
2076
+ value: "nhibernate",
2077
+ label: "NHibernate",
2078
+ hint: "Mature object-relational mapper"
2079
+ },
2080
+ {
2081
+ value: "mapster",
2082
+ label: "Mapster",
2083
+ hint: "Fast object mapping with DI"
2084
+ },
2085
+ {
2086
+ value: "scrutor",
2087
+ label: "Scrutor",
2088
+ hint: "Assembly scanning and decoration"
2089
+ },
2090
+ {
2091
+ value: "refit",
2092
+ label: "Refit",
2093
+ hint: "Type-safe REST clients"
2094
+ },
2095
+ {
2096
+ value: "fluent-email",
2097
+ label: "FluentEmail",
2098
+ hint: "Fluent email composition"
2099
+ },
2100
+ {
2101
+ value: "none",
2102
+ label: "None",
2103
+ hint: "No additional .NET libraries"
2104
+ }
2105
+ ];
1911
2106
  const resolveDotnetWebFrameworkPrompt = (value) => createStaticSinglePromptResolution(WEB_FRAMEWORK_OPTIONS$1, "aspnet-minimal", value);
1912
2107
  const resolveDotnetOrmPrompt = (value) => createStaticSinglePromptResolution(ORM_OPTIONS$1, "ef-core", value);
1913
2108
  const resolveDotnetAuthPrompt = (value) => createStaticSinglePromptResolution(AUTH_OPTIONS$1, "aspnet-identity", value);
@@ -1918,6 +2113,7 @@ const resolveDotnetRealtimePrompt = (value) => createStaticSinglePromptResolutio
1918
2113
  const resolveDotnetObservabilityPrompt = (value) => createStaticMultiPromptResolution(OBSERVABILITY_OPTIONS$1, ["serilog"], value);
1919
2114
  const resolveDotnetCachingPrompt = (value) => createStaticSinglePromptResolution(CACHING_OPTIONS$1, "none", value);
1920
2115
  const resolveDotnetDeployPrompt = (value) => createStaticSinglePromptResolution(DEPLOY_OPTIONS$1, "docker", value);
2116
+ const resolveDotnetLibrariesPrompt = (value) => createStaticMultiPromptResolution(LIBRARIES_OPTIONS, [], value);
1921
2117
  const getDotnetWebFrameworkChoice = (value) => makeChoice$1("Select .NET web framework", WEB_FRAMEWORK_OPTIONS$1, "aspnet-minimal", value);
1922
2118
  const getDotnetOrmChoice = (value) => makeChoice$1("Select .NET data access", ORM_OPTIONS$1, "ef-core", value);
1923
2119
  const getDotnetAuthChoice = (value) => makeChoice$1("Select .NET auth", AUTH_OPTIONS$1, "aspnet-identity", value);
@@ -1929,6 +2125,91 @@ const getDotnetObservabilityChoice = (value) => makeMultiChoice$1("Select .NET o
1929
2125
  const getDotnetValidationChoice = (value) => makeChoice$1("Select .NET validation", VALIDATION_OPTIONS$1, "none", value);
1930
2126
  const getDotnetCachingChoice = (value) => makeChoice$1("Select .NET caching", CACHING_OPTIONS$1, "none", value);
1931
2127
  const getDotnetDeployChoice = (value) => makeChoice$1("Select .NET deploy target", DEPLOY_OPTIONS$1, "docker", value);
2128
+ const getDotnetLibrariesChoice = (value) => makeMultiChoice$1("Select .NET application libraries", LIBRARIES_OPTIONS, [], value);
2129
+
2130
+ //#endregion
2131
+ //#region src/prompts/ecosystem.ts
2132
+ const ECOSYSTEM_PROMPT_OPTIONS = [
2133
+ {
2134
+ value: "typescript",
2135
+ label: "TypeScript",
2136
+ hint: "Full-stack TypeScript web with React, Vue, Svelte, and more"
2137
+ },
2138
+ {
2139
+ value: "react-native",
2140
+ label: "React Native",
2141
+ hint: "Expo and React Native mobile apps with native integrations"
2142
+ },
2143
+ {
2144
+ value: "rust",
2145
+ label: "Rust",
2146
+ hint: "Rust ecosystem with Axum, Leptos, and more"
2147
+ },
2148
+ {
2149
+ value: "python",
2150
+ label: "Python",
2151
+ hint: "Python ecosystem with FastAPI, Django, and AI/ML tools"
2152
+ },
2153
+ {
2154
+ value: "go",
2155
+ label: "Go",
2156
+ hint: "Go ecosystem with Gin, Echo, GORM, and more"
2157
+ },
2158
+ {
2159
+ value: "java",
2160
+ label: "Java",
2161
+ hint: "Java ecosystem with Spring Boot, Maven, Gradle, and more"
2162
+ },
2163
+ {
2164
+ value: "dotnet",
2165
+ label: ".NET",
2166
+ hint: "ASP.NET Core ecosystem with Minimal APIs, EF Core, SignalR, and more"
2167
+ },
2168
+ {
2169
+ value: "elixir",
2170
+ label: "Elixir",
2171
+ hint: "Elixir ecosystem with Phoenix, LiveView, Ecto, and more"
2172
+ }
2173
+ ];
2174
+ async function getEcosystemChoice(ecosystem) {
2175
+ if (ecosystem !== void 0) return ecosystem;
2176
+ const response = await navigableSelect({
2177
+ message: "Select ecosystem",
2178
+ options: ECOSYSTEM_PROMPT_OPTIONS,
2179
+ initialValue: "typescript"
2180
+ });
2181
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2182
+ return response;
2183
+ }
2184
+
2185
+ //#endregion
2186
+ //#region src/prompts/effect.ts
2187
+ async function getEffectChoice(effect) {
2188
+ if (effect !== void 0) return effect;
2189
+ const response = await navigableSelect({
2190
+ message: "Select Effect services",
2191
+ options: [
2192
+ {
2193
+ value: "effect",
2194
+ label: "Effect Core",
2195
+ hint: "Add Effect services and layers to the selected stack"
2196
+ },
2197
+ {
2198
+ value: "effect-full",
2199
+ label: "Effect Platform + SQL",
2200
+ hint: "Core plus Platform, browser/server adapters, SQL, and Vitest integration"
2201
+ },
2202
+ {
2203
+ value: "none",
2204
+ label: "None",
2205
+ hint: "No additional Effect services"
2206
+ }
2207
+ ],
2208
+ initialValue: "none"
2209
+ });
2210
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2211
+ return response;
2212
+ }
1932
2213
 
1933
2214
  //#endregion
1934
2215
  //#region src/prompts/elixir-ecosystem.ts
@@ -1982,6 +2263,16 @@ const ORM_OPTIONS = [
1982
2263
  label: "Ecto",
1983
2264
  hint: "Ecto schemas and changesets without SQL repo wiring"
1984
2265
  },
2266
+ {
2267
+ value: "myxql",
2268
+ label: "MyXQL",
2269
+ hint: "Ecto SQL with MySQL and MariaDB"
2270
+ },
2271
+ {
2272
+ value: "ecto_sqlite3",
2273
+ label: "ecto_sqlite3",
2274
+ hint: "Embedded SQLite through Ecto SQL"
2275
+ },
1985
2276
  {
1986
2277
  value: "none",
1987
2278
  label: "None",
@@ -2004,6 +2295,11 @@ const AUTH_OPTIONS = [
2004
2295
  label: "Guardian",
2005
2296
  hint: "JWT authentication foundation"
2006
2297
  },
2298
+ {
2299
+ value: "pow",
2300
+ label: "Pow",
2301
+ hint: "Database-backed Phoenix authentication"
2302
+ },
2007
2303
  {
2008
2304
  value: "none",
2009
2305
  label: "None",
@@ -2026,6 +2322,11 @@ const API_OPTIONS = [
2026
2322
  label: "gRPC",
2027
2323
  hint: "grpc-elixir endpoint (run protoc codegen for stubs)"
2028
2324
  },
2325
+ {
2326
+ value: "open_api_spex",
2327
+ label: "OpenApiSpex",
2328
+ hint: "OpenAPI schemas, validation, and Swagger UI"
2329
+ },
2029
2330
  {
2030
2331
  value: "none",
2031
2332
  label: "None",
@@ -2043,6 +2344,21 @@ const LIBRARY_OPTIONS = [
2043
2344
  label: "Nx",
2044
2345
  hint: "Numerical Elixir: tensors and ML on the BEAM"
2045
2346
  },
2347
+ {
2348
+ value: "ex_aws",
2349
+ label: "ExAws",
2350
+ hint: "AWS clients including S3, SQS, and SNS"
2351
+ },
2352
+ {
2353
+ value: "floki",
2354
+ label: "Floki",
2355
+ hint: "HTML parsing and transformation"
2356
+ },
2357
+ {
2358
+ value: "rustler",
2359
+ label: "Rustler",
2360
+ hint: "Safe Rust native extensions for the BEAM"
2361
+ },
2046
2362
  {
2047
2363
  value: "none",
2048
2364
  label: "None",
@@ -2121,6 +2437,11 @@ const HTTP_OPTIONS = [
2121
2437
  label: "Finch",
2122
2438
  hint: "Pooled HTTP client"
2123
2439
  },
2440
+ {
2441
+ value: "tesla",
2442
+ label: "Tesla",
2443
+ hint: "Middleware-based HTTP client"
2444
+ },
2124
2445
  {
2125
2446
  value: "none",
2126
2447
  label: "None",
@@ -2136,15 +2457,23 @@ const JSON_OPTIONS = [{
2136
2457
  label: "None",
2137
2458
  hint: "No JSON library"
2138
2459
  }];
2139
- const EMAIL_OPTIONS = [{
2140
- value: "swoosh",
2141
- label: "Swoosh",
2142
- hint: "Phoenix email library"
2143
- }, {
2144
- value: "none",
2145
- label: "None",
2146
- hint: "No email library"
2147
- }];
2460
+ const EMAIL_OPTIONS = [
2461
+ {
2462
+ value: "swoosh",
2463
+ label: "Swoosh",
2464
+ hint: "Phoenix email library"
2465
+ },
2466
+ {
2467
+ value: "bamboo",
2468
+ label: "Bamboo",
2469
+ hint: "Adapter-based transactional email"
2470
+ },
2471
+ {
2472
+ value: "none",
2473
+ label: "None",
2474
+ hint: "No email library"
2475
+ }
2476
+ ];
2148
2477
  const CACHING_OPTIONS = [
2149
2478
  {
2150
2479
  value: "cachex",
@@ -2156,6 +2485,11 @@ const CACHING_OPTIONS = [
2156
2485
  label: "Nebulex",
2157
2486
  hint: "Cache abstraction"
2158
2487
  },
2488
+ {
2489
+ value: "redix",
2490
+ label: "Redix",
2491
+ hint: "Resilient Redis client"
2492
+ },
2159
2493
  {
2160
2494
  value: "none",
2161
2495
  label: "None",
@@ -2178,6 +2512,11 @@ const OBSERVABILITY_OPTIONS = [
2178
2512
  label: "PromEx",
2179
2513
  hint: "Prometheus metrics for Phoenix"
2180
2514
  },
2515
+ {
2516
+ value: "sentry",
2517
+ label: "Sentry",
2518
+ hint: "Exception and performance monitoring"
2519
+ },
2181
2520
  {
2182
2521
  value: "none",
2183
2522
  label: "None",
@@ -2205,6 +2544,16 @@ const TESTING_OPTIONS = [
2205
2544
  label: "Wallaby",
2206
2545
  hint: "Browser acceptance testing"
2207
2546
  },
2547
+ {
2548
+ value: "stream_data",
2549
+ label: "StreamData",
2550
+ hint: "Property-based testing with shrinking"
2551
+ },
2552
+ {
2553
+ value: "ex_machina",
2554
+ label: "ExMachina",
2555
+ hint: "Factories for Ecto-backed tests"
2556
+ },
2208
2557
  {
2209
2558
  value: "none",
2210
2559
  label: "None",
@@ -2227,12 +2576,75 @@ const QUALITY_OPTIONS = [
2227
2576
  label: "Sobelow",
2228
2577
  hint: "Phoenix security analysis"
2229
2578
  },
2579
+ {
2580
+ value: "excoveralls",
2581
+ label: "ExCoveralls",
2582
+ hint: "Coverage reports and CI integration"
2583
+ },
2584
+ {
2585
+ value: "mix_audit",
2586
+ label: "MixAudit",
2587
+ hint: "Audit Hex dependencies for vulnerabilities"
2588
+ },
2230
2589
  {
2231
2590
  value: "none",
2232
2591
  label: "None",
2233
2592
  hint: "No code quality tool"
2234
2593
  }
2235
2594
  ];
2595
+ const I18N_OPTIONS = [{
2596
+ value: "gettext",
2597
+ label: "Gettext",
2598
+ hint: "Canonical Phoenix localization"
2599
+ }, {
2600
+ value: "none",
2601
+ label: "None",
2602
+ hint: "No localization layer"
2603
+ }];
2604
+ const HTTP_SERVER_OPTIONS = [
2605
+ {
2606
+ value: "bandit",
2607
+ label: "Bandit",
2608
+ hint: "Modern pure-Elixir HTTP/WebSocket server"
2609
+ },
2610
+ {
2611
+ value: "cowboy",
2612
+ label: "Cowboy",
2613
+ hint: "Established Erlang HTTP server"
2614
+ },
2615
+ {
2616
+ value: "none",
2617
+ label: "None",
2618
+ hint: "No HTTP server dependency"
2619
+ }
2620
+ ];
2621
+ const APPLICATION_FRAMEWORK_OPTIONS = [{
2622
+ value: "ash",
2623
+ label: "Ash Framework",
2624
+ hint: "Resource-oriented application framework"
2625
+ }, {
2626
+ value: "none",
2627
+ label: "None",
2628
+ hint: "No application framework"
2629
+ }];
2630
+ const DOCUMENTATION_OPTIONS = [{
2631
+ value: "ex_doc",
2632
+ label: "ExDoc",
2633
+ hint: "Generate HTML and EPUB API documentation"
2634
+ }, {
2635
+ value: "none",
2636
+ label: "None",
2637
+ hint: "No documentation generator"
2638
+ }];
2639
+ const CLUSTERING_OPTIONS = [{
2640
+ value: "libcluster",
2641
+ label: "libcluster",
2642
+ hint: "Automatic BEAM cluster formation"
2643
+ }, {
2644
+ value: "none",
2645
+ label: "None",
2646
+ hint: "No cluster topology"
2647
+ }];
2236
2648
  const DEPLOY_OPTIONS = [
2237
2649
  {
2238
2650
  value: "docker",
@@ -2274,6 +2686,11 @@ const resolveElixirCachingPrompt = (value) => createStaticSinglePromptResolution
2274
2686
  const resolveElixirObservabilityPrompt = (value) => createStaticSinglePromptResolution(OBSERVABILITY_OPTIONS, "telemetry", value);
2275
2687
  const resolveElixirTestingPrompt = (value) => createStaticSinglePromptResolution(TESTING_OPTIONS, "ex_unit", value);
2276
2688
  const resolveElixirQualityPrompt = (value) => createStaticSinglePromptResolution(QUALITY_OPTIONS, "credo", value);
2689
+ const resolveElixirI18nPrompt = (value) => createStaticSinglePromptResolution(I18N_OPTIONS, "none", value);
2690
+ const resolveElixirHttpServerPrompt = (value) => createStaticSinglePromptResolution(HTTP_SERVER_OPTIONS, "cowboy", value);
2691
+ const resolveElixirApplicationFrameworkPrompt = (value) => createStaticSinglePromptResolution(APPLICATION_FRAMEWORK_OPTIONS, "none", value);
2692
+ const resolveElixirDocumentationPrompt = (value) => createStaticSinglePromptResolution(DOCUMENTATION_OPTIONS, "none", value);
2693
+ const resolveElixirClusteringPrompt = (value) => createStaticSinglePromptResolution(CLUSTERING_OPTIONS, "none", value);
2277
2694
  const resolveElixirDeployPrompt = (value) => createStaticSinglePromptResolution(DEPLOY_OPTIONS, "none", value);
2278
2695
  const getElixirWebFrameworkChoice = (value) => makeChoice("Select Elixir web framework", WEB_FRAMEWORK_OPTIONS, "phoenix", value);
2279
2696
  const getElixirOrmChoice = (value) => makeChoice("Select Elixir database layer", ORM_OPTIONS, "ecto-sql", value);
@@ -2289,93 +2706,14 @@ const getElixirCachingChoice = (value) => makeChoice("Select Elixir caching", CA
2289
2706
  const getElixirObservabilityChoice = (value) => makeChoice("Select Elixir observability", OBSERVABILITY_OPTIONS, "telemetry", value);
2290
2707
  const getElixirTestingChoice = (value) => makeChoice("Select Elixir testing", TESTING_OPTIONS, "ex_unit", value);
2291
2708
  const getElixirQualityChoice = (value) => makeChoice("Select Elixir code quality", QUALITY_OPTIONS, "credo", value);
2709
+ const getElixirI18nChoice = (value) => makeChoice("Select Elixir localization", I18N_OPTIONS, "none", value);
2710
+ const getElixirHttpServerChoice = (value) => makeChoice("Select Elixir HTTP server", HTTP_SERVER_OPTIONS, "cowboy", value);
2711
+ const getElixirApplicationFrameworkChoice = (value) => makeChoice("Select Elixir application framework", APPLICATION_FRAMEWORK_OPTIONS, "none", value);
2712
+ const getElixirDocumentationChoice = (value) => makeChoice("Select Elixir documentation", DOCUMENTATION_OPTIONS, "none", value);
2713
+ const getElixirClusteringChoice = (value) => makeChoice("Select Elixir clustering", CLUSTERING_OPTIONS, "none", value);
2292
2714
  const getElixirDeployChoice = (value) => makeChoice("Select Elixir deploy target", DEPLOY_OPTIONS, "none", value);
2293
2715
  const getElixirLibrariesChoice = (value) => makeMultiChoice("Select Elixir libraries", LIBRARY_OPTIONS, [], value);
2294
2716
 
2295
- //#endregion
2296
- //#region src/prompts/ecosystem.ts
2297
- const ECOSYSTEM_PROMPT_OPTIONS = [
2298
- {
2299
- value: "typescript",
2300
- label: "TypeScript",
2301
- hint: "Full-stack TypeScript web with React, Vue, Svelte, and more"
2302
- },
2303
- {
2304
- value: "react-native",
2305
- label: "React Native",
2306
- hint: "Expo and React Native mobile apps with native integrations"
2307
- },
2308
- {
2309
- value: "rust",
2310
- label: "Rust",
2311
- hint: "Rust ecosystem with Axum, Leptos, and more"
2312
- },
2313
- {
2314
- value: "python",
2315
- label: "Python",
2316
- hint: "Python ecosystem with FastAPI, Django, and AI/ML tools"
2317
- },
2318
- {
2319
- value: "go",
2320
- label: "Go",
2321
- hint: "Go ecosystem with Gin, Echo, GORM, and more"
2322
- },
2323
- {
2324
- value: "java",
2325
- label: "Java",
2326
- hint: "Java ecosystem with Spring Boot, Maven, Gradle, and more"
2327
- },
2328
- {
2329
- value: "dotnet",
2330
- label: ".NET",
2331
- hint: "ASP.NET Core ecosystem with Minimal APIs, EF Core, SignalR, and more"
2332
- },
2333
- {
2334
- value: "elixir",
2335
- label: "Elixir",
2336
- hint: "Elixir ecosystem with Phoenix, LiveView, Ecto, and more"
2337
- }
2338
- ];
2339
- async function getEcosystemChoice(ecosystem) {
2340
- if (ecosystem !== void 0) return ecosystem;
2341
- const response = await navigableSelect({
2342
- message: "Select ecosystem",
2343
- options: ECOSYSTEM_PROMPT_OPTIONS,
2344
- initialValue: "typescript"
2345
- });
2346
- if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2347
- return response;
2348
- }
2349
-
2350
- //#endregion
2351
- //#region src/prompts/effect.ts
2352
- async function getEffectChoice(effect) {
2353
- if (effect !== void 0) return effect;
2354
- const response = await navigableSelect({
2355
- message: "Select Effect services",
2356
- options: [
2357
- {
2358
- value: "effect",
2359
- label: "Effect Core",
2360
- hint: "Add Effect services and layers to the selected stack"
2361
- },
2362
- {
2363
- value: "effect-full",
2364
- label: "Effect Platform + SQL",
2365
- hint: "Core plus Platform, browser/server adapters, SQL, and Vitest integration"
2366
- },
2367
- {
2368
- value: "none",
2369
- label: "None",
2370
- hint: "No additional Effect services"
2371
- }
2372
- ],
2373
- initialValue: "none"
2374
- });
2375
- if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2376
- return response;
2377
- }
2378
-
2379
2717
  //#endregion
2380
2718
  //#region src/prompts/email.ts
2381
2719
  const EMAIL_PROMPT_OPTIONS = [
@@ -2695,6 +3033,16 @@ const WEB_FRONTEND_PROMPT_OPTIONS = [
2695
3033
  label: "React + Vite",
2696
3034
  hint: "Client-routed React SPA powered by Vite"
2697
3035
  },
3036
+ {
3037
+ value: "vanilla-vite",
3038
+ label: "Vite (Vanilla TypeScript)",
3039
+ hint: "Framework-free TypeScript, HTML, and CSS powered by Vite"
3040
+ },
3041
+ {
3042
+ value: "vue",
3043
+ label: "Vue 3 + Vite",
3044
+ hint: "Standalone Vue 3 SPA powered by Vite"
3045
+ },
2698
3046
  {
2699
3047
  value: "next",
2700
3048
  label: "Next.js",
@@ -2909,6 +3257,21 @@ const GO_WEB_FRAMEWORK_PROMPT_OPTIONS = [
2909
3257
  label: "net/http",
2910
3258
  hint: "Go 1.22+ standard-library routing (ServeMux), zero dependencies"
2911
3259
  },
3260
+ {
3261
+ value: "go-zero",
3262
+ label: "go-zero",
3263
+ hint: "API-first microservice framework with resilience and code generation"
3264
+ },
3265
+ {
3266
+ value: "kratos",
3267
+ label: "Kratos",
3268
+ hint: "Cloud-native HTTP/gRPC framework with middleware and lifecycle management"
3269
+ },
3270
+ {
3271
+ value: "httprouter",
3272
+ label: "HttpRouter",
3273
+ hint: "Minimal high-performance radix-tree HTTP router"
3274
+ },
2912
3275
  {
2913
3276
  value: "none",
2914
3277
  label: "None",
@@ -2936,6 +3299,11 @@ const GO_ORM_PROMPT_OPTIONS = [
2936
3299
  label: "Bun",
2937
3300
  hint: "SQL-first Go ORM by uptrace with a lightweight query builder"
2938
3301
  },
3302
+ {
3303
+ value: "sqlx",
3304
+ label: "sqlx",
3305
+ hint: "Lightweight database/sql extensions with named queries and struct scanning"
3306
+ },
2939
3307
  {
2940
3308
  value: "none",
2941
3309
  label: "None",
@@ -2953,6 +3321,21 @@ const GO_API_PROMPT_OPTIONS = [
2953
3321
  label: "gqlgen",
2954
3322
  hint: "Schema-first GraphQL server with code generation"
2955
3323
  },
3324
+ {
3325
+ value: "grpc-gateway",
3326
+ label: "grpc-gateway",
3327
+ hint: "REST/JSON gateway for protobuf-defined services"
3328
+ },
3329
+ {
3330
+ value: "connect-go",
3331
+ label: "Connect-Go",
3332
+ hint: "Protobuf RPC over gRPC, gRPC-Web, and HTTP/1.1"
3333
+ },
3334
+ {
3335
+ value: "oapi-codegen",
3336
+ label: "oapi-codegen",
3337
+ hint: "Generate typed Go clients and servers from OpenAPI contracts"
3338
+ },
2956
3339
  {
2957
3340
  value: "none",
2958
3341
  label: "None",
@@ -3024,6 +3407,11 @@ const GO_AUTH_PROMPT_OPTIONS = [
3024
3407
  label: "Goth",
3025
3408
  hint: "OAuth social login for 30+ providers (Google, GitHub, ...)"
3026
3409
  },
3410
+ {
3411
+ value: "oauth2",
3412
+ label: "golang.org/x/oauth2",
3413
+ hint: "Canonical OAuth2 client foundation for authorization-code and service flows"
3414
+ },
3027
3415
  {
3028
3416
  value: "none",
3029
3417
  label: "None",
@@ -3125,6 +3513,21 @@ const GO_TESTING_PROMPT_OPTIONS = [
3125
3513
  label: "GoMock",
3126
3514
  hint: "Interface mock generation via mockgen"
3127
3515
  },
3516
+ {
3517
+ value: "testcontainers",
3518
+ label: "Testcontainers for Go",
3519
+ hint: "Disposable real databases and services for integration tests"
3520
+ },
3521
+ {
3522
+ value: "ginkgo-gomega",
3523
+ label: "Ginkgo + Gomega",
3524
+ hint: "BDD test runner and expressive matcher library"
3525
+ },
3526
+ {
3527
+ value: "mockery",
3528
+ label: "mockery",
3529
+ hint: "Generate typed interface mocks with a reproducible project config"
3530
+ },
3128
3531
  {
3129
3532
  value: "none",
3130
3533
  label: "None",
@@ -3159,6 +3562,16 @@ const GO_MESSAGE_QUEUE_PROMPT_OPTIONS = [
3159
3562
  label: "Watermill",
3160
3563
  hint: "Event-driven framework over Kafka, RabbitMQ, Pub/Sub, and more"
3161
3564
  },
3565
+ {
3566
+ value: "kafka-go",
3567
+ label: "kafka-go",
3568
+ hint: "Idiomatic Kafka producer, consumer, and consumer-group client"
3569
+ },
3570
+ {
3571
+ value: "asynq",
3572
+ label: "Asynq",
3573
+ hint: "Redis-backed background jobs with retries, scheduling, and priorities"
3574
+ },
3162
3575
  {
3163
3576
  value: "none",
3164
3577
  label: "None",
@@ -3199,14 +3612,76 @@ const GO_CONFIG_PROMPT_OPTIONS = [
3199
3612
  hint: "Environment variables only"
3200
3613
  }
3201
3614
  ];
3202
- const GO_OBSERVABILITY_PROMPT_OPTIONS = [{
3203
- value: "opentelemetry",
3204
- label: "OpenTelemetry",
3205
- hint: "Official OTel SDK: traces and metrics with OTLP export"
3615
+ const GO_OBSERVABILITY_PROMPT_OPTIONS = [
3616
+ {
3617
+ value: "opentelemetry",
3618
+ label: "OpenTelemetry",
3619
+ hint: "Official OTel SDK: traces and metrics with OTLP export"
3620
+ },
3621
+ {
3622
+ value: "prometheus",
3623
+ label: "Prometheus",
3624
+ hint: "Standard Prometheus metrics collectors and HTTP exposition"
3625
+ },
3626
+ {
3627
+ value: "none",
3628
+ label: "None",
3629
+ hint: "No tracing/metrics SDK"
3630
+ }
3631
+ ];
3632
+ const GO_VALIDATION_PROMPT_OPTIONS = [{
3633
+ value: "validator",
3634
+ label: "go-playground/validator",
3635
+ hint: "Struct and field validation used by major Go web frameworks"
3206
3636
  }, {
3207
3637
  value: "none",
3208
3638
  label: "None",
3209
- hint: "No tracing/metrics SDK"
3639
+ hint: "No validation helper"
3640
+ }];
3641
+ const GO_QUALITY_PROMPT_OPTIONS = [{
3642
+ value: "golangci-lint",
3643
+ label: "golangci-lint",
3644
+ hint: "Fast multi-linter with a checked-in CI-ready configuration"
3645
+ }, {
3646
+ value: "none",
3647
+ label: "None",
3648
+ hint: "No additional quality tooling"
3649
+ }];
3650
+ const GO_MIGRATIONS_PROMPT_OPTIONS = [{
3651
+ value: "golang-migrate",
3652
+ label: "golang-migrate",
3653
+ hint: "Versioned database migrations across PostgreSQL, MySQL, SQLite, and more"
3654
+ }, {
3655
+ value: "none",
3656
+ label: "None",
3657
+ hint: "No migration tooling"
3658
+ }];
3659
+ const GO_TEMPLATING_PROMPT_OPTIONS = [{
3660
+ value: "templ",
3661
+ label: "templ",
3662
+ hint: "Type-safe Go-native HTML components and code generation"
3663
+ }, {
3664
+ value: "none",
3665
+ label: "None",
3666
+ hint: "No server-side templating"
3667
+ }];
3668
+ const GO_PROTO_TOOLING_PROMPT_OPTIONS = [{
3669
+ value: "buf",
3670
+ label: "Buf",
3671
+ hint: "Protobuf linting, breaking-change checks, dependencies, and generation"
3672
+ }, {
3673
+ value: "none",
3674
+ label: "None",
3675
+ hint: "No protobuf toolchain"
3676
+ }];
3677
+ const GO_DI_PROMPT_OPTIONS = [{
3678
+ value: "fx",
3679
+ label: "Uber Fx",
3680
+ hint: "Lifecycle-aware dependency injection for modular Go services"
3681
+ }, {
3682
+ value: "none",
3683
+ label: "None",
3684
+ hint: "No dependency injection framework"
3210
3685
  }];
3211
3686
  function resolveGoTestingPrompt(goTesting) {
3212
3687
  return createStaticMultiPromptResolution(GO_TESTING_PROMPT_OPTIONS, [], goTesting);
@@ -3293,6 +3768,90 @@ async function getGoObservabilityChoice(goObservability) {
3293
3768
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3294
3769
  return response;
3295
3770
  }
3771
+ function resolveGoValidationPrompt(goValidation) {
3772
+ return createStaticSinglePromptResolution(GO_VALIDATION_PROMPT_OPTIONS, "none", goValidation);
3773
+ }
3774
+ async function getGoValidationChoice(goValidation) {
3775
+ const resolution = resolveGoValidationPrompt(goValidation);
3776
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
3777
+ const response = await navigableSelect({
3778
+ message: "Select Go validation library",
3779
+ options: resolution.options,
3780
+ initialValue: resolution.initialValue
3781
+ });
3782
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3783
+ return response;
3784
+ }
3785
+ function resolveGoQualityPrompt(goQuality) {
3786
+ return createStaticSinglePromptResolution(GO_QUALITY_PROMPT_OPTIONS, "none", goQuality);
3787
+ }
3788
+ async function getGoQualityChoice(goQuality) {
3789
+ const resolution = resolveGoQualityPrompt(goQuality);
3790
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
3791
+ const response = await navigableSelect({
3792
+ message: "Select Go code quality tooling",
3793
+ options: resolution.options,
3794
+ initialValue: resolution.initialValue
3795
+ });
3796
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3797
+ return response;
3798
+ }
3799
+ function resolveGoMigrationsPrompt(goMigrations) {
3800
+ return createStaticSinglePromptResolution(GO_MIGRATIONS_PROMPT_OPTIONS, "none", goMigrations);
3801
+ }
3802
+ async function getGoMigrationsChoice(goMigrations) {
3803
+ const resolution = resolveGoMigrationsPrompt(goMigrations);
3804
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
3805
+ const response = await navigableSelect({
3806
+ message: "Select Go database migration tooling",
3807
+ options: resolution.options,
3808
+ initialValue: resolution.initialValue
3809
+ });
3810
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3811
+ return response;
3812
+ }
3813
+ function resolveGoTemplatingPrompt(goTemplating) {
3814
+ return createStaticSinglePromptResolution(GO_TEMPLATING_PROMPT_OPTIONS, "none", goTemplating);
3815
+ }
3816
+ async function getGoTemplatingChoice(goTemplating) {
3817
+ const resolution = resolveGoTemplatingPrompt(goTemplating);
3818
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
3819
+ const response = await navigableSelect({
3820
+ message: "Select Go templating library",
3821
+ options: resolution.options,
3822
+ initialValue: resolution.initialValue
3823
+ });
3824
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3825
+ return response;
3826
+ }
3827
+ function resolveGoProtoToolingPrompt(goProtoTooling) {
3828
+ return createStaticSinglePromptResolution(GO_PROTO_TOOLING_PROMPT_OPTIONS, "none", goProtoTooling);
3829
+ }
3830
+ async function getGoProtoToolingChoice(goProtoTooling) {
3831
+ const resolution = resolveGoProtoToolingPrompt(goProtoTooling);
3832
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
3833
+ const response = await navigableSelect({
3834
+ message: "Select Go protobuf tooling",
3835
+ options: resolution.options,
3836
+ initialValue: resolution.initialValue
3837
+ });
3838
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3839
+ return response;
3840
+ }
3841
+ function resolveGoDIPrompt(goDI) {
3842
+ return createStaticSinglePromptResolution(GO_DI_PROMPT_OPTIONS, "none", goDI);
3843
+ }
3844
+ async function getGoDIChoice(goDI) {
3845
+ const resolution = resolveGoDIPrompt(goDI);
3846
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
3847
+ const response = await navigableSelect({
3848
+ message: "Select Go dependency injection",
3849
+ options: resolution.options,
3850
+ initialValue: resolution.initialValue
3851
+ });
3852
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3853
+ return response;
3854
+ }
3296
3855
 
3297
3856
  //#endregion
3298
3857
  //#region src/prompts/i18n.ts
@@ -3378,7 +3937,7 @@ async function getinstallChoice(install, ecosystem, javaBuildTool) {
3378
3937
  return false;
3379
3938
  }
3380
3939
  const response$1 = await navigableConfirm({
3381
- message: "Run uv sync?",
3940
+ message: "Run uv sync --extra dev?",
3382
3941
  initialValue: DEFAULT_CONFIG.install
3383
3942
  });
3384
3943
  if (isCancel$1(response$1)) return exitCancelled("Operation cancelled");
@@ -3664,6 +4223,106 @@ const JAVA_LIBRARY_PROMPT_OPTIONS = [
3664
4223
  label: "OpenTelemetry",
3665
4224
  hint: "OpenTelemetry SDK with OTLP export"
3666
4225
  },
4226
+ {
4227
+ value: "spring-data-redis",
4228
+ label: "Spring Data Redis",
4229
+ hint: "Redis repositories and template-based data access"
4230
+ },
4231
+ {
4232
+ value: "spring-data-mongodb",
4233
+ label: "Spring Data MongoDB",
4234
+ hint: "MongoDB repositories and document mapping"
4235
+ },
4236
+ {
4237
+ value: "spring-data-elasticsearch",
4238
+ label: "Spring Data Elasticsearch",
4239
+ hint: "Elasticsearch repositories and search operations"
4240
+ },
4241
+ {
4242
+ value: "spring-data-neo4j",
4243
+ label: "Spring Data Neo4j",
4244
+ hint: "Neo4j graph mapping and repositories"
4245
+ },
4246
+ {
4247
+ value: "spring-data-cassandra",
4248
+ label: "Spring Data Cassandra",
4249
+ hint: "Apache Cassandra mapping and repositories"
4250
+ },
4251
+ {
4252
+ value: "spring-data-couchbase",
4253
+ label: "Spring Data Couchbase",
4254
+ hint: "Couchbase document mapping and repositories"
4255
+ },
4256
+ {
4257
+ value: "spring-data-jdbc",
4258
+ label: "Spring Data JDBC",
4259
+ hint: "Aggregate-oriented relational persistence without JPA"
4260
+ },
4261
+ {
4262
+ value: "spring-data-rest",
4263
+ label: "Spring Data REST",
4264
+ hint: "REST endpoints backed by Spring Data repositories"
4265
+ },
4266
+ {
4267
+ value: "spring-quartz",
4268
+ label: "Quartz Scheduler",
4269
+ hint: "Durable scheduling and background jobs"
4270
+ },
4271
+ {
4272
+ value: "spring-pulsar",
4273
+ label: "Spring for Apache Pulsar",
4274
+ hint: "Apache Pulsar producers, consumers, and listeners"
4275
+ },
4276
+ {
4277
+ value: "spring-integration",
4278
+ label: "Spring Integration",
4279
+ hint: "Enterprise integration flows and messaging adapters"
4280
+ },
4281
+ {
4282
+ value: "spring-websocket",
4283
+ label: "Spring WebSocket",
4284
+ hint: "Real-time bidirectional WebSocket messaging"
4285
+ },
4286
+ {
4287
+ value: "spring-rsocket",
4288
+ label: "Spring RSocket",
4289
+ hint: "Reactive messaging over the RSocket protocol"
4290
+ },
4291
+ {
4292
+ value: "spring-hateoas",
4293
+ label: "Spring HATEOAS",
4294
+ hint: "Hypermedia links and representations for REST APIs"
4295
+ },
4296
+ {
4297
+ value: "spring-session-redis",
4298
+ label: "Spring Session Redis",
4299
+ hint: "Distributed HTTP sessions backed by Redis"
4300
+ },
4301
+ {
4302
+ value: "spring-session-jdbc",
4303
+ label: "Spring Session JDBC",
4304
+ hint: "Database-backed HTTP sessions through JDBC"
4305
+ },
4306
+ {
4307
+ value: "spring-ldap",
4308
+ label: "Spring LDAP",
4309
+ hint: "LDAP directory access and authentication support"
4310
+ },
4311
+ {
4312
+ value: "spring-oauth2-client",
4313
+ label: "Spring OAuth2 Client",
4314
+ hint: "OAuth2 login and authorized client support"
4315
+ },
4316
+ {
4317
+ value: "spring-saml2",
4318
+ label: "Spring SAML2",
4319
+ hint: "SAML 2.0 relying-party authentication"
4320
+ },
4321
+ {
4322
+ value: "spring-restclient",
4323
+ label: "Spring REST Client",
4324
+ hint: "Synchronous HTTP client with Spring RestClient"
4325
+ },
3667
4326
  {
3668
4327
  value: "none",
3669
4328
  label: "None",
@@ -4065,6 +4724,113 @@ const MOBILE_DEEP_LINKING_OPTIONS = [{
4065
4724
  label: "None",
4066
4725
  hint: "Skip deep link helpers"
4067
4726
  }];
4727
+ const MOBILE_LIBRARIES_OPTIONS = [
4728
+ {
4729
+ value: "expo-sqlite",
4730
+ label: "Expo SQLite",
4731
+ hint: "Persistent SQLite database"
4732
+ },
4733
+ {
4734
+ value: "expo-camera",
4735
+ label: "Expo Camera",
4736
+ hint: "Camera preview and capture"
4737
+ },
4738
+ {
4739
+ value: "expo-image-picker",
4740
+ label: "Expo Image Picker",
4741
+ hint: "System media picker"
4742
+ },
4743
+ {
4744
+ value: "expo-location",
4745
+ label: "Expo Location",
4746
+ hint: "Geolocation and geocoding"
4747
+ },
4748
+ {
4749
+ value: "expo-sensors",
4750
+ label: "Expo Sensors",
4751
+ hint: "Device motion and sensors"
4752
+ },
4753
+ {
4754
+ value: "expo-file-system",
4755
+ label: "Expo File System",
4756
+ hint: "Local file access"
4757
+ },
4758
+ {
4759
+ value: "expo-image",
4760
+ label: "Expo Image",
4761
+ hint: "Performant image component"
4762
+ },
4763
+ {
4764
+ value: "expo-audio",
4765
+ label: "Expo Audio",
4766
+ hint: "Audio playback and recording"
4767
+ },
4768
+ {
4769
+ value: "expo-video",
4770
+ label: "Expo Video",
4771
+ hint: "Cross-platform video playback"
4772
+ },
4773
+ {
4774
+ value: "expo-contacts",
4775
+ label: "Expo Contacts",
4776
+ hint: "Device contacts access"
4777
+ },
4778
+ {
4779
+ value: "expo-calendar",
4780
+ label: "Expo Calendar",
4781
+ hint: "Device calendars and events"
4782
+ },
4783
+ {
4784
+ value: "expo-local-authentication",
4785
+ label: "Expo Local Authentication",
4786
+ hint: "Biometric authentication"
4787
+ },
4788
+ {
4789
+ value: "expo-sharing",
4790
+ label: "Expo Sharing",
4791
+ hint: "Native share sheet"
4792
+ },
4793
+ {
4794
+ value: "expo-clipboard",
4795
+ label: "Expo Clipboard",
4796
+ hint: "System clipboard access"
4797
+ },
4798
+ {
4799
+ value: "expo-task-manager",
4800
+ label: "Expo Task Manager",
4801
+ hint: "Background task registry"
4802
+ },
4803
+ {
4804
+ value: "expo-background-task",
4805
+ label: "Expo Background Task",
4806
+ hint: "Deferrable background work"
4807
+ },
4808
+ {
4809
+ value: "expo-maps",
4810
+ label: "Expo Maps",
4811
+ hint: "Native Apple and Google maps"
4812
+ },
4813
+ {
4814
+ value: "expo-brightness",
4815
+ label: "Expo Brightness",
4816
+ hint: "Screen brightness control"
4817
+ },
4818
+ {
4819
+ value: "expo-battery",
4820
+ label: "Expo Battery",
4821
+ hint: "Battery status monitoring"
4822
+ },
4823
+ {
4824
+ value: "expo-screen-capture",
4825
+ label: "Expo Screen Capture",
4826
+ hint: "Screen capture detection and prevention"
4827
+ },
4828
+ {
4829
+ value: "none",
4830
+ label: "None",
4831
+ hint: "No additional mobile libraries"
4832
+ }
4833
+ ];
4068
4834
  async function promptMobileOption(options, defaultValue, selected, message) {
4069
4835
  const resolution = createStaticSinglePromptResolution(options, defaultValue, selected);
4070
4836
  if (!resolution.shouldPrompt) return resolution.autoValue ?? defaultValue;
@@ -4098,6 +4864,9 @@ function resolveMobileOTAPrompt(mobileOTA) {
4098
4864
  function resolveMobileDeepLinkingPrompt(mobileDeepLinking) {
4099
4865
  return createStaticSinglePromptResolution(MOBILE_DEEP_LINKING_OPTIONS, "expo-linking", mobileDeepLinking);
4100
4866
  }
4867
+ function resolveMobileLibrariesPrompt(mobileLibraries) {
4868
+ return createStaticMultiPromptResolution(MOBILE_LIBRARIES_OPTIONS, [], mobileLibraries);
4869
+ }
4101
4870
  function getMobileNavigationChoice(mobileNavigation) {
4102
4871
  return promptMobileOption(MOBILE_NAVIGATION_OPTIONS, "expo-router", mobileNavigation, "Select mobile navigation");
4103
4872
  }
@@ -4119,6 +4888,19 @@ function getMobileOTAChoice(mobileOTA) {
4119
4888
  function getMobileDeepLinkingChoice(mobileDeepLinking) {
4120
4889
  return promptMobileOption(MOBILE_DEEP_LINKING_OPTIONS, "expo-linking", mobileDeepLinking, "Select mobile deep linking");
4121
4890
  }
4891
+ async function getMobileLibrariesChoice(mobileLibraries) {
4892
+ const resolution = resolveMobileLibrariesPrompt(mobileLibraries);
4893
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
4894
+ if (!canPromptInteractively()) return [];
4895
+ const response = await navigableMultiselect({
4896
+ message: "Select mobile application libraries",
4897
+ options: resolution.options,
4898
+ required: false,
4899
+ initialValues: resolution.initialValue
4900
+ });
4901
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
4902
+ return response.includes("none") ? [] : response;
4903
+ }
4122
4904
 
4123
4905
  //#endregion
4124
4906
  //#region src/prompts/package-manager.ts
@@ -4184,6 +4966,16 @@ const PYTHON_WEB_FRAMEWORK_PROMPT_OPTIONS = [
4184
4966
  label: "Starlette",
4185
4967
  hint: "Minimal ASGI toolkit that powers FastAPI — great for lean async apps"
4186
4968
  },
4969
+ {
4970
+ value: "aiohttp",
4971
+ label: "aiohttp",
4972
+ hint: "Async HTTP server and client framework"
4973
+ },
4974
+ {
4975
+ value: "streamlit",
4976
+ label: "Streamlit",
4977
+ hint: "Turn Python data scripts into interactive web apps"
4978
+ },
4187
4979
  {
4188
4980
  value: "none",
4189
4981
  label: "None",
@@ -4211,6 +5003,11 @@ const PYTHON_ORM_PROMPT_OPTIONS = [
4211
5003
  label: "Peewee",
4212
5004
  hint: "Small, expressive ORM for SQLite, MySQL, and PostgreSQL"
4213
5005
  },
5006
+ {
5007
+ value: "pymongo",
5008
+ label: "PyMongo",
5009
+ hint: "Official MongoDB driver for Python"
5010
+ },
4214
5011
  {
4215
5012
  value: "none",
4216
5013
  label: "None",
@@ -4281,6 +5078,31 @@ const PYTHON_AI_PROMPT_OPTIONS = [
4281
5078
  value: "smolagents",
4282
5079
  label: "smolagents",
4283
5080
  hint: "HuggingFace's minimal, hackable agent library"
5081
+ },
5082
+ {
5083
+ value: "pytorch",
5084
+ label: "PyTorch",
5085
+ hint: "Tensor computation and deep learning platform"
5086
+ },
5087
+ {
5088
+ value: "transformers",
5089
+ label: "Transformers",
5090
+ hint: "Hugging Face pretrained model toolkit"
5091
+ },
5092
+ {
5093
+ value: "scikit-learn",
5094
+ label: "scikit-learn",
5095
+ hint: "Classical machine learning algorithms and pipelines"
5096
+ },
5097
+ {
5098
+ value: "tensorflow",
5099
+ label: "TensorFlow",
5100
+ hint: "End-to-end machine learning platform"
5101
+ },
5102
+ {
5103
+ value: "mcp",
5104
+ label: "MCP Python SDK",
5105
+ hint: "Official Model Context Protocol SDK"
4284
5106
  }
4285
5107
  ];
4286
5108
  const PYTHON_AUTH_PROMPT_OPTIONS = [
@@ -4294,6 +5116,11 @@ const PYTHON_AUTH_PROMPT_OPTIONS = [
4294
5116
  label: "JWT (python-jose)",
4295
5117
  hint: "Simple JWT token creation and verification"
4296
5118
  },
5119
+ {
5120
+ value: "pyjwt",
5121
+ label: "PyJWT",
5122
+ hint: "Focused JSON Web Token encoding and decoding"
5123
+ },
4297
5124
  {
4298
5125
  value: "fastapi-users",
4299
5126
  label: "FastAPI Users",
@@ -4532,6 +5359,11 @@ const PYTHON_TESTING_PROMPT_OPTIONS = [
4532
5359
  label: "Hypothesis",
4533
5360
  hint: "Property-based testing that generates edge-case inputs"
4534
5361
  },
5362
+ {
5363
+ value: "pytest-cov",
5364
+ label: "pytest-cov",
5365
+ hint: "Coverage reporting for pytest"
5366
+ },
4535
5367
  {
4536
5368
  value: "none",
4537
5369
  label: "None",
@@ -4572,15 +5404,23 @@ const PYTHON_REALTIME_PROMPT_OPTIONS = [
4572
5404
  hint: "No realtime layer"
4573
5405
  }
4574
5406
  ];
4575
- const PYTHON_OBSERVABILITY_PROMPT_OPTIONS = [{
4576
- value: "opentelemetry",
4577
- label: "OpenTelemetry",
4578
- hint: "Official OTel SDK with OTLP export and auto-instrumentation"
4579
- }, {
4580
- value: "none",
4581
- label: "None",
4582
- hint: "No tracing/metrics SDK"
4583
- }];
5407
+ const PYTHON_OBSERVABILITY_PROMPT_OPTIONS = [
5408
+ {
5409
+ value: "opentelemetry",
5410
+ label: "OpenTelemetry",
5411
+ hint: "Official OTel SDK with OTLP export and auto-instrumentation"
5412
+ },
5413
+ {
5414
+ value: "prometheus-client",
5415
+ label: "Prometheus Client",
5416
+ hint: "Prometheus metrics instrumentation and exposition"
5417
+ },
5418
+ {
5419
+ value: "none",
5420
+ label: "None",
5421
+ hint: "No tracing/metrics SDK"
5422
+ }
5423
+ ];
4584
5424
  const PYTHON_CLI_PROMPT_OPTIONS = [
4585
5425
  {
4586
5426
  value: "typer",
@@ -4603,6 +5443,90 @@ const PYTHON_CLI_PROMPT_OPTIONS = [
4603
5443
  hint: "No CLI tooling"
4604
5444
  }
4605
5445
  ];
5446
+ const PYTHON_CLOUD_SDK_PROMPT_OPTIONS = [{
5447
+ value: "boto3",
5448
+ label: "Boto3",
5449
+ hint: "Official AWS SDK for Python"
5450
+ }, {
5451
+ value: "none",
5452
+ label: "None",
5453
+ hint: "No cloud SDK"
5454
+ }];
5455
+ const PYTHON_HTTP_CLIENT_PROMPT_OPTIONS = [{
5456
+ value: "requests",
5457
+ label: "Requests",
5458
+ hint: "Simple, widely adopted synchronous HTTP client"
5459
+ }, {
5460
+ value: "none",
5461
+ label: "None",
5462
+ hint: "No HTTP client"
5463
+ }];
5464
+ const PYTHON_DATA_PROMPT_OPTIONS = [
5465
+ {
5466
+ value: "numpy",
5467
+ label: "NumPy",
5468
+ hint: "N-dimensional arrays and numerical computing"
5469
+ },
5470
+ {
5471
+ value: "pandas",
5472
+ label: "pandas",
5473
+ hint: "DataFrames and data analysis tools"
5474
+ },
5475
+ {
5476
+ value: "scipy",
5477
+ label: "SciPy",
5478
+ hint: "Scientific algorithms for optimization, statistics, and signals"
5479
+ },
5480
+ {
5481
+ value: "none",
5482
+ label: "None",
5483
+ hint: "No data/scientific libraries"
5484
+ }
5485
+ ];
5486
+ const PYTHON_MEDIA_PROMPT_OPTIONS = [{
5487
+ value: "pillow",
5488
+ label: "Pillow",
5489
+ hint: "Image loading, processing, and export"
5490
+ }, {
5491
+ value: "none",
5492
+ label: "None",
5493
+ hint: "No media library"
5494
+ }];
5495
+ const PYTHON_SERVER_PROMPT_OPTIONS = [{
5496
+ value: "gunicorn",
5497
+ label: "Gunicorn",
5498
+ hint: "Production WSGI/ASGI process manager"
5499
+ }, {
5500
+ value: "none",
5501
+ label: "None",
5502
+ hint: "No production server"
5503
+ }];
5504
+ const PYTHON_PACKAGE_MANAGER_PROMPT_OPTIONS = [
5505
+ {
5506
+ value: "uv",
5507
+ label: "uv",
5508
+ hint: "Fast Python package and project manager"
5509
+ },
5510
+ {
5511
+ value: "poetry",
5512
+ label: "Poetry",
5513
+ hint: "Dependency management and packaging workflow"
5514
+ },
5515
+ {
5516
+ value: "none",
5517
+ label: "None",
5518
+ hint: "Do not configure a Python package manager"
5519
+ }
5520
+ ];
5521
+ const PYTHON_MESSAGE_QUEUE_PROMPT_OPTIONS = [{
5522
+ value: "confluent-kafka",
5523
+ label: "Confluent Kafka",
5524
+ hint: "High-performance Apache Kafka producer and consumer client"
5525
+ }, {
5526
+ value: "none",
5527
+ label: "None",
5528
+ hint: "No message queue client"
5529
+ }];
4606
5530
  function resolvePythonTestingPrompt(pythonTesting) {
4607
5531
  return createStaticMultiPromptResolution(PYTHON_TESTING_PROMPT_OPTIONS, [], pythonTesting);
4608
5532
  }
@@ -4675,6 +5599,105 @@ async function getPythonCliChoice(pythonCli) {
4675
5599
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
4676
5600
  return response.includes("none") ? [] : response;
4677
5601
  }
5602
+ function resolvePythonCloudSdkPrompt(value) {
5603
+ return createStaticSinglePromptResolution(PYTHON_CLOUD_SDK_PROMPT_OPTIONS, "none", value);
5604
+ }
5605
+ async function getPythonCloudSdkChoice(value) {
5606
+ const resolution = resolvePythonCloudSdkPrompt(value);
5607
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
5608
+ const response = await navigableSelect({
5609
+ message: "Select Python cloud SDK",
5610
+ options: resolution.options,
5611
+ initialValue: resolution.initialValue
5612
+ });
5613
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5614
+ return response;
5615
+ }
5616
+ function resolvePythonHttpClientPrompt(value) {
5617
+ return createStaticSinglePromptResolution(PYTHON_HTTP_CLIENT_PROMPT_OPTIONS, "none", value);
5618
+ }
5619
+ async function getPythonHttpClientChoice(value) {
5620
+ const resolution = resolvePythonHttpClientPrompt(value);
5621
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
5622
+ const response = await navigableSelect({
5623
+ message: "Select Python HTTP client",
5624
+ options: resolution.options,
5625
+ initialValue: resolution.initialValue
5626
+ });
5627
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5628
+ return response;
5629
+ }
5630
+ function resolvePythonDataPrompt(value) {
5631
+ return createStaticMultiPromptResolution(PYTHON_DATA_PROMPT_OPTIONS, [], value);
5632
+ }
5633
+ async function getPythonDataChoice(value) {
5634
+ const resolution = resolvePythonDataPrompt(value);
5635
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
5636
+ const response = await navigableMultiselect({
5637
+ message: "Select Python data and scientific libraries",
5638
+ options: resolution.options,
5639
+ required: false,
5640
+ initialValues: resolution.initialValue
5641
+ });
5642
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5643
+ return response.includes("none") ? [] : response;
5644
+ }
5645
+ function resolvePythonMediaPrompt(value) {
5646
+ return createStaticSinglePromptResolution(PYTHON_MEDIA_PROMPT_OPTIONS, "none", value);
5647
+ }
5648
+ async function getPythonMediaChoice(value) {
5649
+ const resolution = resolvePythonMediaPrompt(value);
5650
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
5651
+ const response = await navigableSelect({
5652
+ message: "Select Python media library",
5653
+ options: resolution.options,
5654
+ initialValue: resolution.initialValue
5655
+ });
5656
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5657
+ return response;
5658
+ }
5659
+ function resolvePythonServerPrompt(value) {
5660
+ return createStaticSinglePromptResolution(PYTHON_SERVER_PROMPT_OPTIONS, "none", value);
5661
+ }
5662
+ async function getPythonServerChoice(value) {
5663
+ const resolution = resolvePythonServerPrompt(value);
5664
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
5665
+ const response = await navigableSelect({
5666
+ message: "Select Python production server",
5667
+ options: resolution.options,
5668
+ initialValue: resolution.initialValue
5669
+ });
5670
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5671
+ return response;
5672
+ }
5673
+ function resolvePythonPackageManagerPrompt(value) {
5674
+ return createStaticSinglePromptResolution(PYTHON_PACKAGE_MANAGER_PROMPT_OPTIONS, "uv", value);
5675
+ }
5676
+ async function getPythonPackageManagerChoice(value) {
5677
+ const resolution = resolvePythonPackageManagerPrompt(value);
5678
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "uv";
5679
+ const response = await navigableSelect({
5680
+ message: "Select Python package manager",
5681
+ options: resolution.options,
5682
+ initialValue: resolution.initialValue
5683
+ });
5684
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5685
+ return response;
5686
+ }
5687
+ function resolvePythonMessageQueuePrompt(value) {
5688
+ return createStaticSinglePromptResolution(PYTHON_MESSAGE_QUEUE_PROMPT_OPTIONS, "none", value);
5689
+ }
5690
+ async function getPythonMessageQueueChoice(value) {
5691
+ const resolution = resolvePythonMessageQueuePrompt(value);
5692
+ if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
5693
+ const response = await navigableSelect({
5694
+ message: "Select Python message queue client",
5695
+ options: resolution.options,
5696
+ initialValue: resolution.initialValue
5697
+ });
5698
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
5699
+ return response;
5700
+ }
4678
5701
 
4679
5702
  //#endregion
4680
5703
  //#region src/prompts/rust-ecosystem.ts
@@ -4704,6 +5727,16 @@ const RUST_WEB_FRAMEWORK_PROMPT_OPTIONS = [
4704
5727
  label: "Loco",
4705
5728
  hint: "The Rails of Rust: opinionated full-stack framework (runs DB-free too)"
4706
5729
  },
5730
+ {
5731
+ value: "warp",
5732
+ label: "Warp",
5733
+ hint: "Composable, filter-based async web framework"
5734
+ },
5735
+ {
5736
+ value: "salvo",
5737
+ label: "Salvo",
5738
+ hint: "Batteries-included async framework with OpenAPI and HTTP/3 support"
5739
+ },
4707
5740
  {
4708
5741
  value: "none",
4709
5742
  label: "None",
@@ -4721,6 +5754,11 @@ const RUST_FRONTEND_PROMPT_OPTIONS = [
4721
5754
  label: "Dioxus",
4722
5755
  hint: "Fullstack, cross-platform UI library for Rust"
4723
5756
  },
5757
+ {
5758
+ value: "yew",
5759
+ label: "Yew",
5760
+ hint: "Mature React-like framework for client-side Rust/WASM applications"
5761
+ },
4724
5762
  {
4725
5763
  value: "none",
4726
5764
  label: "None",
@@ -4743,6 +5781,21 @@ const RUST_ORM_PROMPT_OPTIONS = [
4743
5781
  label: "Diesel",
4744
5782
  hint: "Safe, extensible ORM with compile-time query validation"
4745
5783
  },
5784
+ {
5785
+ value: "mongodb",
5786
+ label: "MongoDB Rust Driver",
5787
+ hint: "Official async MongoDB driver with typed BSON support"
5788
+ },
5789
+ {
5790
+ value: "rusqlite",
5791
+ label: "rusqlite",
5792
+ hint: "Ergonomic embedded SQLite access"
5793
+ },
5794
+ {
5795
+ value: "tokio-postgres",
5796
+ label: "tokio-postgres",
5797
+ hint: "Native asynchronous PostgreSQL client without an ORM"
5798
+ },
4746
5799
  {
4747
5800
  value: "none",
4748
5801
  label: "None",
@@ -4760,6 +5813,11 @@ const RUST_API_PROMPT_OPTIONS = [
4760
5813
  label: "async-graphql",
4761
5814
  hint: "High-performance GraphQL server library"
4762
5815
  },
5816
+ {
5817
+ value: "jsonrpsee",
5818
+ label: "jsonrpsee",
5819
+ hint: "Async JSON-RPC server and client framework"
5820
+ },
4763
5821
  {
4764
5822
  value: "none",
4765
5823
  label: "None",
@@ -4868,6 +5926,41 @@ const RUST_LIBRARIES_PROMPT_OPTIONS = [
4868
5926
  value: "insta",
4869
5927
  label: "Insta",
4870
5928
  hint: "Snapshot testing for Rust"
5929
+ },
5930
+ {
5931
+ value: "rand",
5932
+ label: "rand",
5933
+ hint: "Randomness, sampling, and test-data generation"
5934
+ },
5935
+ {
5936
+ value: "regex",
5937
+ label: "regex",
5938
+ hint: "Fast, safe regular expressions with linear-time matching"
5939
+ },
5940
+ {
5941
+ value: "rayon",
5942
+ label: "Rayon",
5943
+ hint: "Data parallelism for CPU-bound iterators and collections"
5944
+ },
5945
+ {
5946
+ value: "itertools",
5947
+ label: "Itertools",
5948
+ hint: "Additional iterator adaptors, grouping, and collection helpers"
5949
+ },
5950
+ {
5951
+ value: "rstest",
5952
+ label: "rstest",
5953
+ hint: "Fixture-based and parameterized Rust tests"
5954
+ },
5955
+ {
5956
+ value: "cargo-nextest",
5957
+ label: "cargo-nextest",
5958
+ hint: "Fast, isolated test runner with CI-friendly profiles"
5959
+ },
5960
+ {
5961
+ value: "cargo-audit",
5962
+ label: "cargo-audit",
5963
+ hint: "RustSec vulnerability auditing for Cargo dependencies"
4871
5964
  }
4872
5965
  ];
4873
5966
  const RUST_LOGGING_PROMPT_OPTIONS = [
@@ -5063,6 +6156,16 @@ async function getRustAuthChoice(rustAuth) {
5063
6156
  label: "Torii",
5064
6157
  hint: "Auth framework with passwords, sessions, and pluggable storage"
5065
6158
  },
6159
+ {
6160
+ value: "openidconnect",
6161
+ label: "OpenID Connect",
6162
+ hint: "Strongly typed OIDC discovery, authorization, and token flows"
6163
+ },
6164
+ {
6165
+ value: "tower-sessions",
6166
+ label: "tower-sessions",
6167
+ hint: "Tower and Axum session middleware with pluggable stores"
6168
+ },
5066
6169
  {
5067
6170
  value: "none",
5068
6171
  label: "None",
@@ -5096,15 +6199,28 @@ async function getRustMessageQueueChoice(rustMessageQueue) {
5096
6199
  if (rustMessageQueue !== void 0) return rustMessageQueue;
5097
6200
  const response = await navigableSelect({
5098
6201
  message: "Select Rust message queue",
5099
- options: [{
5100
- value: "lapin",
5101
- label: "Lapin",
5102
- hint: "Async RabbitMQ (AMQP) client"
5103
- }, {
5104
- value: "none",
5105
- label: "None",
5106
- hint: "No message queue"
5107
- }],
6202
+ options: [
6203
+ {
6204
+ value: "lapin",
6205
+ label: "Lapin",
6206
+ hint: "Async RabbitMQ (AMQP) client"
6207
+ },
6208
+ {
6209
+ value: "rdkafka",
6210
+ label: "rdkafka",
6211
+ hint: "High-performance Kafka client backed by librdkafka"
6212
+ },
6213
+ {
6214
+ value: "async-nats",
6215
+ label: "async-nats",
6216
+ hint: "Async NATS and JetStream client for cloud-native messaging"
6217
+ },
6218
+ {
6219
+ value: "none",
6220
+ label: "None",
6221
+ hint: "No message queue"
6222
+ }
6223
+ ],
5108
6224
  initialValue: "none"
5109
6225
  });
5110
6226
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
@@ -5114,15 +6230,23 @@ async function getRustObservabilityChoice(rustObservability) {
5114
6230
  if (rustObservability !== void 0) return rustObservability;
5115
6231
  const response = await navigableSelect({
5116
6232
  message: "Select Rust observability",
5117
- options: [{
5118
- value: "opentelemetry",
5119
- label: "OpenTelemetry",
5120
- hint: "Official OTel SDK with OTLP/HTTP export"
5121
- }, {
5122
- value: "none",
5123
- label: "None",
5124
- hint: "No tracing/metrics SDK"
5125
- }],
6233
+ options: [
6234
+ {
6235
+ value: "opentelemetry",
6236
+ label: "OpenTelemetry",
6237
+ hint: "Official OTel SDK with OTLP/HTTP export"
6238
+ },
6239
+ {
6240
+ value: "metrics",
6241
+ label: "metrics",
6242
+ hint: "Lightweight metrics facade with a Prometheus exporter"
6243
+ },
6244
+ {
6245
+ value: "none",
6246
+ label: "None",
6247
+ hint: "No tracing/metrics SDK"
6248
+ }
6249
+ ],
5126
6250
  initialValue: "none"
5127
6251
  });
5128
6252
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
@@ -5143,6 +6267,11 @@ async function getRustTemplatingChoice(rustTemplating) {
5143
6267
  label: "Tera",
5144
6268
  hint: "Runtime Jinja2-style templates with dynamic loading"
5145
6269
  },
6270
+ {
6271
+ value: "minijinja",
6272
+ label: "MiniJinja",
6273
+ hint: "Lightweight Jinja-compatible runtime template engine"
6274
+ },
5146
6275
  {
5147
6276
  value: "none",
5148
6277
  label: "None",
@@ -5852,6 +6981,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5852
6981
  const baseConfig = getDefaultConfig();
5853
6982
  const configScope = !hasMultiStackPromptFlags(flags) ? promptValue(await getConfigScopeChoice()) : "full";
5854
6983
  const typeScriptSections = configScope === "custom" ? promptValue(await getConfigSectionsChoice("typescript", [], [
6984
+ "app-platforms",
5855
6985
  "ui-styling",
5856
6986
  "deploy",
5857
6987
  "addons-examples"
@@ -5863,6 +6993,15 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5863
6993
  }));
5864
6994
  const frontendList = [frontend];
5865
6995
  const astroIntegration = frontend === "astro" ? promptValue(await getAstroIntegrationChoice(flags.astroIntegration)) : void 0;
6996
+ const nativeFrontend = promptValue(await navigableSelect({
6997
+ message: "Add a native mobile app? (React Native ecosystem)",
6998
+ options: [{
6999
+ value: "none",
7000
+ label: "None",
7001
+ hint: "web app only"
7002
+ }, ...NATIVE_FRONTEND_PROMPT_OPTIONS],
7003
+ initialValue: "none"
7004
+ }));
5866
7005
  const uiLibrary = hasWebStyling$1(frontendList) ? await scopedPromptValue("typescript", "uiLibrary", configScope, typeScriptSections, () => getUILibraryChoice(flags.uiLibrary, frontendList, astroIntegration)) : "none";
5867
7006
  const shadcnOptions = uiLibrary === "shadcn-ui" ? shouldAskConfigPromptKey("typescript", "shadcnOptions", configScope, typeScriptSections) ? promptValue(await getShadcnOptions({
5868
7007
  shadcnBase: flags.shadcnBase,
@@ -5873,10 +7012,16 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5873
7012
  shadcnFont: flags.shadcnFont,
5874
7013
  shadcnRadius: flags.shadcnRadius
5875
7014
  })) : getDefaultPromptValue("shadcnOptions") : void 0;
5876
- const cssFramework = hasWebStyling$1(frontendList) ? await scopedPromptValue("typescript", "cssFramework", configScope, typeScriptSections, () => getCSSFrameworkChoice(flags.cssFramework, uiLibrary)) : "none";
7015
+ const cssFramework = hasWebStyling$1(frontendList) ? await scopedPromptValue("typescript", "cssFramework", configScope, typeScriptSections, () => getCSSFrameworkChoice(flags.cssFramework, uiLibrary, frontendList)) : "none";
5877
7016
  const backendEcosystem = await selectBackendEcosystem();
5878
7017
  const backendSections = configScope === "custom" ? promptValue(await getConfigSectionsChoice(backendEcosystem)) : [];
5879
7018
  const stackPartSpecs = [`frontend:typescript:${frontend}`];
7019
+ if (nativeFrontend !== "none") {
7020
+ stackPartSpecs.push(`mobile:react-native:${nativeFrontend}`);
7021
+ stackPartSpecs.push("mobile.navigation:react-native:expo-router");
7022
+ if (nativeFrontend === "native-uniwind") stackPartSpecs.push("mobile.ui:react-native:uniwind");
7023
+ if (nativeFrontend === "native-unistyles") stackPartSpecs.push("mobile.ui:react-native:unistyles");
7024
+ }
5880
7025
  const backendChoices = {};
5881
7026
  let database = "none";
5882
7027
  let dbSetup = "none";
@@ -5898,6 +7043,16 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5898
7043
  const goCaching = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goCaching", configScope, backendSections, () => getGoCachingChoice(flags.goCaching));
5899
7044
  const goConfig = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goConfig", configScope, backendSections, () => getGoConfigChoice(flags.goConfig));
5900
7045
  const goObservability = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goObservability", configScope, backendSections, () => getGoObservabilityChoice(flags.goObservability));
7046
+ const goValidation = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goValidation", configScope, backendSections, () => getGoValidationChoice(flags.goValidation));
7047
+ const goQuality = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goQuality", configScope, backendSections, () => getGoQualityChoice(flags.goQuality));
7048
+ const goMigrations = goWebFramework === "none" || ![
7049
+ "sqlite",
7050
+ "postgres",
7051
+ "mysql"
7052
+ ].includes(database) ? "none" : await scopedPromptValue("go", "goMigrations", configScope, backendSections, () => getGoMigrationsChoice(flags.goMigrations));
7053
+ const goTemplating = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goTemplating", configScope, backendSections, () => getGoTemplatingChoice(flags.goTemplating));
7054
+ const goProtoTooling = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goProtoTooling", configScope, backendSections, () => getGoProtoToolingChoice(flags.goProtoTooling));
7055
+ const goDI = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goDI", configScope, backendSections, () => getGoDIChoice(flags.goDI));
5901
7056
  Object.assign(backendChoices, {
5902
7057
  goWebFramework,
5903
7058
  goOrm,
@@ -5910,7 +7065,13 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5910
7065
  goMessageQueue,
5911
7066
  goCaching,
5912
7067
  goConfig,
5913
- goObservability
7068
+ goObservability,
7069
+ goValidation,
7070
+ goQuality,
7071
+ goMigrations,
7072
+ goTemplating,
7073
+ goProtoTooling,
7074
+ goDI
5914
7075
  });
5915
7076
  if (goWebFramework !== "none") stackPartSpecs.push(`backend:go:${goWebFramework}`);
5916
7077
  if (goOrm !== "none") stackPartSpecs.push(`backend.orm:go:${goOrm}`);
@@ -5922,6 +7083,12 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5922
7083
  if (goCaching !== "none") stackPartSpecs.push(`backend.caching:go:${goCaching}`);
5923
7084
  if (goConfig !== "none") stackPartSpecs.push(`backend.config:go:${goConfig}`);
5924
7085
  if (goObservability !== "none") stackPartSpecs.push(`backend.observability:go:${goObservability}`);
7086
+ if (goValidation !== "none") stackPartSpecs.push(`backend.validation:go:${goValidation}`);
7087
+ if (goQuality !== "none") stackPartSpecs.push(`backend.codeQuality:go:${goQuality}`);
7088
+ if (goMigrations !== "none") stackPartSpecs.push(`backend.migrations:go:${goMigrations}`);
7089
+ if (goTemplating !== "none") stackPartSpecs.push(`backend.templating:go:${goTemplating}`);
7090
+ if (goProtoTooling !== "none") stackPartSpecs.push(`backend.buildTool:go:${goProtoTooling}`);
7091
+ if (goDI !== "none") stackPartSpecs.push(`backend.libraries:go:${goDI}`);
5925
7092
  }
5926
7093
  if (backendEcosystem === "rust") {
5927
7094
  const rustWebFramework = promptValue(await getRustWebFrameworkChoice(flags.rustWebFramework));
@@ -5987,6 +7154,13 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
5987
7154
  const pythonRealtime = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonRealtime", configScope, backendSections, () => getPythonRealtimeChoice(flags.pythonRealtime));
5988
7155
  const pythonObservability = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonObservability", configScope, backendSections, () => getPythonObservabilityChoice(flags.pythonObservability));
5989
7156
  const pythonCli = pythonWebFramework === "none" ? [] : await scopedPromptValue("python", "pythonCli", configScope, backendSections, () => getPythonCliChoice(flags.pythonCli));
7157
+ const pythonCloudSdk = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonCloudSdk", configScope, backendSections, () => getPythonCloudSdkChoice(flags.pythonCloudSdk));
7158
+ const pythonHttpClient = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonHttpClient", configScope, backendSections, () => getPythonHttpClientChoice(flags.pythonHttpClient));
7159
+ const pythonData = pythonWebFramework === "none" ? [] : await scopedPromptValue("python", "pythonData", configScope, backendSections, () => getPythonDataChoice(flags.pythonData));
7160
+ const pythonMedia = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonMedia", configScope, backendSections, () => getPythonMediaChoice(flags.pythonMedia));
7161
+ const pythonServer = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonServer", configScope, backendSections, () => getPythonServerChoice(flags.pythonServer));
7162
+ const pythonPackageManager = pythonWebFramework === "none" ? "uv" : await scopedPromptValue("python", "pythonPackageManager", configScope, backendSections, () => getPythonPackageManagerChoice(flags.pythonPackageManager));
7163
+ const pythonMessageQueue = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonMessageQueue", configScope, backendSections, () => getPythonMessageQueueChoice(flags.pythonMessageQueue));
5990
7164
  Object.assign(backendChoices, {
5991
7165
  pythonWebFramework,
5992
7166
  pythonOrm,
@@ -6000,7 +7174,14 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6000
7174
  pythonCaching,
6001
7175
  pythonRealtime,
6002
7176
  pythonObservability,
6003
- pythonCli
7177
+ pythonCli,
7178
+ pythonCloudSdk,
7179
+ pythonHttpClient,
7180
+ pythonData,
7181
+ pythonMedia,
7182
+ pythonServer,
7183
+ pythonPackageManager,
7184
+ pythonMessageQueue
6004
7185
  });
6005
7186
  if (pythonWebFramework !== "none") stackPartSpecs.push(`backend:python:${pythonWebFramework}`);
6006
7187
  if (pythonOrm !== "none") stackPartSpecs.push(`backend.orm:python:${pythonOrm}`);
@@ -6012,6 +7193,13 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6012
7193
  if (pythonRealtime !== "none") stackPartSpecs.push(`backend.realtime:python:${pythonRealtime}`);
6013
7194
  if (pythonObservability !== "none") stackPartSpecs.push(`backend.observability:python:${pythonObservability}`);
6014
7195
  for (const cli of pythonCli) if (cli !== "none") stackPartSpecs.push(`backend.cli:python:${cli}`);
7196
+ if (pythonCloudSdk !== "none") stackPartSpecs.push(`backend.cloudSdk:python:${pythonCloudSdk}`);
7197
+ if (pythonHttpClient !== "none") stackPartSpecs.push(`backend.httpClient:python:${pythonHttpClient}`);
7198
+ for (const data of pythonData) if (data !== "none") stackPartSpecs.push(`backend.data:python:${data}`);
7199
+ if (pythonMedia !== "none") stackPartSpecs.push(`backend.media:python:${pythonMedia}`);
7200
+ if (pythonServer !== "none") stackPartSpecs.push(`backend.server:python:${pythonServer}`);
7201
+ if (pythonPackageManager !== "none") stackPartSpecs.push(`backend.packageManager:python:${pythonPackageManager}`);
7202
+ if (pythonMessageQueue !== "none") stackPartSpecs.push(`backend.messageQueue:python:${pythonMessageQueue}`);
6015
7203
  }
6016
7204
  if (backendEcosystem === "java") {
6017
7205
  const javaWebFramework = promptValue(await getJavaWebFrameworkChoice(flags.javaWebFramework));
@@ -6063,6 +7251,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6063
7251
  const dotnetValidation = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetValidation", configScope, backendSections, () => getDotnetValidationChoice(flags.dotnetValidation));
6064
7252
  const dotnetCaching = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetCaching", configScope, backendSections, () => getDotnetCachingChoice(flags.dotnetCaching));
6065
7253
  const dotnetDeploy = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetDeploy", configScope, backendSections, () => getDotnetDeployChoice(flags.dotnetDeploy));
7254
+ const dotnetLibraries = dotnetWebFramework === "none" ? [] : await scopedPromptValue("dotnet", "dotnetLibraries", configScope, backendSections, () => getDotnetLibrariesChoice(flags.dotnetLibraries));
6066
7255
  Object.assign(backendChoices, {
6067
7256
  dotnetWebFramework,
6068
7257
  dotnetOrm,
@@ -6074,7 +7263,8 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6074
7263
  dotnetObservability,
6075
7264
  dotnetValidation,
6076
7265
  dotnetCaching,
6077
- dotnetDeploy
7266
+ dotnetDeploy,
7267
+ dotnetLibraries
6078
7268
  });
6079
7269
  if (dotnetWebFramework !== "none") stackPartSpecs.push(`backend:dotnet:${dotnetWebFramework}`);
6080
7270
  if (dotnetOrm !== "none") stackPartSpecs.push(`backend.orm:dotnet:${dotnetOrm}`);
@@ -6087,6 +7277,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6087
7277
  if (dotnetValidation !== "none") stackPartSpecs.push(`backend.validation:dotnet:${dotnetValidation}`);
6088
7278
  if (dotnetCaching !== "none") stackPartSpecs.push(`backend.caching:dotnet:${dotnetCaching}`);
6089
7279
  if (dotnetDeploy !== "none") stackPartSpecs.push(`backend.deploy:dotnet:${dotnetDeploy}`);
7280
+ for (const library of dotnetLibraries) if (library !== "none") stackPartSpecs.push(`backend.libraries:dotnet:${library}`);
6090
7281
  }
6091
7282
  if (backendEcosystem === "elixir") {
6092
7283
  const elixirWebFramework = promptValue(await getElixirWebFrameworkChoice(flags.elixirWebFramework));
@@ -6108,6 +7299,11 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6108
7299
  const elixirObservability = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirObservability", configScope, backendSections, () => getElixirObservabilityChoice(flags.elixirObservability));
6109
7300
  const elixirTesting = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirTesting", configScope, backendSections, () => getElixirTestingChoice(flags.elixirTesting));
6110
7301
  const elixirQuality = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirQuality", configScope, backendSections, () => getElixirQualityChoice(flags.elixirQuality));
7302
+ const elixirI18n = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirI18n", configScope, backendSections, () => getElixirI18nChoice(flags.elixirI18n));
7303
+ const elixirHttpServer = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirHttpServer", configScope, backendSections, () => getElixirHttpServerChoice(flags.elixirHttpServer));
7304
+ const elixirApplicationFramework = await scopedPromptValue("elixir", "elixirApplicationFramework", configScope, backendSections, () => getElixirApplicationFrameworkChoice(flags.elixirApplicationFramework));
7305
+ const elixirDocumentation = await scopedPromptValue("elixir", "elixirDocumentation", configScope, backendSections, () => getElixirDocumentationChoice(flags.elixirDocumentation));
7306
+ const elixirClustering = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirClustering", configScope, backendSections, () => getElixirClusteringChoice(flags.elixirClustering));
6111
7307
  const elixirDeploy = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirDeploy", configScope, backendSections, () => getElixirDeployChoice(flags.elixirDeploy));
6112
7308
  const elixirLibraries = elixirWebFramework === "none" ? [] : await scopedPromptValue("elixir", "elixirLibraries", configScope, backendSections, () => getElixirLibrariesChoice(flags.elixirLibraries));
6113
7309
  Object.assign(backendChoices, {
@@ -6125,6 +7321,11 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6125
7321
  elixirObservability,
6126
7322
  elixirTesting,
6127
7323
  elixirQuality,
7324
+ elixirI18n,
7325
+ elixirHttpServer,
7326
+ elixirApplicationFramework,
7327
+ elixirDocumentation,
7328
+ elixirClustering,
6128
7329
  elixirDeploy,
6129
7330
  elixirLibraries
6130
7331
  });
@@ -6138,13 +7339,19 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6138
7339
  if (elixirCaching !== "none") stackPartSpecs.push(`backend.caching:elixir:${elixirCaching}`);
6139
7340
  if (elixirObservability !== "none") stackPartSpecs.push(`backend.observability:elixir:${elixirObservability}`);
6140
7341
  if (elixirTesting !== "none") stackPartSpecs.push(`backend.testing:elixir:${elixirTesting}`);
7342
+ if (elixirI18n !== "none") stackPartSpecs.push(`backend.i18n:elixir:${elixirI18n}`);
7343
+ if (elixirHttpServer !== "none") stackPartSpecs.push(`backend.runtime:elixir:${elixirHttpServer}`);
7344
+ if (elixirApplicationFramework !== "none") stackPartSpecs.push(`backend.libraries:elixir:${elixirApplicationFramework}`);
7345
+ if (elixirDocumentation !== "none") stackPartSpecs.push(`backend.documentation:elixir:${elixirDocumentation}`);
7346
+ if (elixirClustering !== "none") stackPartSpecs.push(`backend.config:elixir:${elixirClustering}`);
6141
7347
  if (elixirDeploy !== "none") stackPartSpecs.push(`backend.deploy:elixir:${elixirDeploy}`);
6142
7348
  for (const library of elixirLibraries) if (library !== "none") stackPartSpecs.push(`backend.libraries:elixir:${library}`);
6143
7349
  }
6144
7350
  if (database !== "none") stackPartSpecs.push(`database:universal:${database}`);
6145
7351
  const stackParts = (0, types_exports.parseStackPartSpecs)(stackPartSpecs, "selected");
6146
7352
  const graphPartial = (0, types_exports.stackPartsToLegacyProjectConfigPartial)(stackParts);
6147
- const addons = await scopedPromptValue("typescript", "addons", configScope, typeScriptSections, () => getAddonsChoice(flags.addons, frontendList, "none", "none", "bun"));
7353
+ const appPlatforms = await scopedPromptValue("typescript", "appPlatforms", configScope, typeScriptSections, () => getAppPlatformsChoice(flags.addons, frontendList));
7354
+ const addons = await scopedPromptValue("typescript", "addons", configScope, typeScriptSections, () => getAddonsChoice(flags.addons, frontendList, "none", "none", "bun", "none"));
6148
7355
  const webDeploy = await scopedPromptValue("typescript", "webDeploy", configScope, typeScriptSections, () => getDeploymentChoice(flags.webDeploy, "bun", "none", frontendList));
6149
7356
  const serverDeploy = shouldAskConfigPromptKey("typescript", "serverDeploy", configScope, typeScriptSections) ? await selectServerDeployment(flags.serverDeploy) : getDefaultPromptValue("serverDeploy");
6150
7357
  const aiDocs = promptValue(await getAiDocsChoice(flags.aiDocs));
@@ -6160,7 +7367,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6160
7367
  projectDir,
6161
7368
  relativePath,
6162
7369
  ecosystem: "typescript",
6163
- frontend: frontendList,
7370
+ frontend: nativeFrontend === "none" ? frontendList : [...frontendList, nativeFrontend],
6164
7371
  backend: "none",
6165
7372
  runtime: "none",
6166
7373
  database,
@@ -6171,7 +7378,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
6171
7378
  uiLibrary,
6172
7379
  ...shadcnOptions,
6173
7380
  cssFramework,
6174
- addons,
7381
+ addons: Array.from(new Set([...appPlatforms, ...addons])),
6175
7382
  examples: [],
6176
7383
  dbSetup,
6177
7384
  webDeploy,
@@ -6413,42 +7620,6 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
6413
7620
  return response;
6414
7621
  }
6415
7622
 
6416
- //#endregion
6417
- //#region src/prompts/workspace-shape.ts
6418
- const SINGLE_APP_WEB_FRONTENDS = new Set(["next", "tanstack-start"]);
6419
- /**
6420
- * The flat single-app layout only makes sense for a "thin self" app: backend
6421
- * `self` with exactly one Next.js or TanStack Start web frontend. For anything
6422
- * else we never prompt and resolve to `monorepo` (the compatibility engine and
6423
- * generator also normalize non-qualifying stacks back to monorepo).
6424
- */
6425
- function stackCanUseSingleApp(backend, frontend) {
6426
- if (backend !== "self") return false;
6427
- const webFrontends = frontend.filter((f) => f && f !== "none");
6428
- if (webFrontends.length !== 1) return false;
6429
- return SINGLE_APP_WEB_FRONTENDS.has(webFrontends[0]);
6430
- }
6431
- async function getWorkspaceShapeChoice(workspaceShape, backend, frontend) {
6432
- if (!stackCanUseSingleApp(backend, frontend ?? [])) return "monorepo";
6433
- if (workspaceShape !== void 0) return workspaceShape;
6434
- if (!canPromptInteractively()) return "monorepo";
6435
- const response = await navigableSelect({
6436
- message: "Choose workspace layout",
6437
- options: [{
6438
- value: "monorepo",
6439
- label: "Monorepo",
6440
- hint: "apps/* + packages/* workspaces (recommended)"
6441
- }, {
6442
- value: "single-app",
6443
- label: "Single app",
6444
- hint: "Flat app at the repo root (no workspaces)"
6445
- }],
6446
- initialValue: "monorepo"
6447
- });
6448
- if (isCancel$1(response)) return exitCancelled("Operation cancelled");
6449
- return response;
6450
- }
6451
-
6452
7623
  //#endregion
6453
7624
  //#region src/prompts/payments.ts
6454
7625
  function resolvePaymentsPrompt(context = {}) {
@@ -6521,6 +7692,14 @@ function resolvePaymentsPrompt(context = {}) {
6521
7692
  label: "None",
6522
7693
  hint: "No payments integration"
6523
7694
  });
7695
+ if (context.backend !== "convex") {
7696
+ const insertAt = options.findIndex((option) => option.value === "dodo");
7697
+ options.splice(insertAt, 0, {
7698
+ value: "paypal",
7699
+ label: "PayPal",
7700
+ hint: "PayPal JavaScript SDK buttons with server-side Orders API helpers."
7701
+ });
7702
+ }
6524
7703
  if (isRevenueCatCompatible) options.push({
6525
7704
  value: "revenuecat",
6526
7705
  label: "RevenueCat",
@@ -6611,6 +7790,11 @@ const REALTIME_PROMPT_OPTIONS = [
6611
7790
  label: "Socket.IO",
6612
7791
  hint: "Real-time bidirectional communication with fallbacks"
6613
7792
  },
7793
+ {
7794
+ value: "ws",
7795
+ label: "ws",
7796
+ hint: "Lightweight standards-based WebSocket server and client"
7797
+ },
6614
7798
  {
6615
7799
  value: "partykit",
6616
7800
  label: "PartyKit",
@@ -6649,15 +7833,16 @@ function resolveRealtimePrompt(context = {}) {
6649
7833
  options: [],
6650
7834
  autoValue: "none"
6651
7835
  };
7836
+ const options = context.backend === "express" ? REALTIME_PROMPT_OPTIONS : REALTIME_PROMPT_OPTIONS.filter((option) => option.value !== "ws");
6652
7837
  return context.realtime !== void 0 ? {
6653
7838
  shouldPrompt: false,
6654
7839
  mode: "single",
6655
- options: REALTIME_PROMPT_OPTIONS,
7840
+ options,
6656
7841
  autoValue: context.realtime
6657
7842
  } : {
6658
7843
  shouldPrompt: true,
6659
7844
  mode: "single",
6660
- options: REALTIME_PROMPT_OPTIONS,
7845
+ options,
6661
7846
  initialValue: "none"
6662
7847
  };
6663
7848
  }
@@ -6845,6 +8030,11 @@ const TESTING_PROMPT_OPTIONS = [
6845
8030
  label: "Jest",
6846
8031
  hint: "Classic testing framework with wide ecosystem"
6847
8032
  },
8033
+ {
8034
+ value: "mocha",
8035
+ label: "Mocha",
8036
+ hint: "Flexible Node.js test framework with TypeScript support via tsx"
8037
+ },
6848
8038
  {
6849
8039
  value: "cypress",
6850
8040
  label: "Cypress",
@@ -6945,8 +8135,11 @@ const PROMPT_RESOLVER_REGISTRY = {
6945
8135
  },
6946
8136
  ai: {
6947
8137
  schemaValues: types_exports.AI_VALUES,
6948
- resolve: ({ value } = {}) => resolveAIPrompt(value),
6949
- coverageContexts: [{}]
8138
+ resolve: ({ value, backend } = {}) => resolveAIPrompt({
8139
+ ai: value,
8140
+ backend
8141
+ }),
8142
+ coverageContexts: [{ backend: "hono" }, { backend: "none" }]
6950
8143
  },
6951
8144
  animation: {
6952
8145
  schemaValues: types_exports.ANIMATION_VALUES,
@@ -6964,15 +8157,23 @@ const PROMPT_RESOLVER_REGISTRY = {
6964
8157
  auth: {
6965
8158
  schemaValues: types_exports.AUTH_VALUES,
6966
8159
  resolve: resolveAuthPrompt,
6967
- coverageContexts: [{
6968
- ecosystem: "typescript",
6969
- backend: "self",
6970
- frontend: ["next"]
6971
- }, {
6972
- ecosystem: "go",
6973
- backend: "none",
6974
- frontend: []
6975
- }]
8160
+ coverageContexts: [
8161
+ {
8162
+ ecosystem: "typescript",
8163
+ backend: "self",
8164
+ frontend: ["next"]
8165
+ },
8166
+ {
8167
+ ecosystem: "typescript",
8168
+ backend: "express",
8169
+ frontend: ["react-vite"]
8170
+ },
8171
+ {
8172
+ ecosystem: "go",
8173
+ backend: "none",
8174
+ frontend: []
8175
+ }
8176
+ ]
6976
8177
  },
6977
8178
  caching: {
6978
8179
  schemaValues: types_exports.CACHING_VALUES,
@@ -6987,12 +8188,32 @@ const PROMPT_RESOLVER_REGISTRY = {
6987
8188
  cms: {
6988
8189
  schemaValues: types_exports.CMS_VALUES,
6989
8190
  resolve: resolveCMSPrompt,
6990
- coverageContexts: [{ backend: "hono" }, { backend: "none" }]
8191
+ coverageContexts: [
8192
+ { backend: "hono" },
8193
+ {
8194
+ backend: "none",
8195
+ frontends: ["vue"]
8196
+ },
8197
+ {
8198
+ backend: "none",
8199
+ frontends: []
8200
+ }
8201
+ ]
6991
8202
  },
6992
8203
  cssFramework: {
6993
8204
  schemaValues: types_exports.CSS_FRAMEWORK_VALUES,
6994
8205
  resolve: resolveCSSFrameworkPrompt,
6995
- coverageContexts: [{}, { uiLibrary: "radix-ui" }]
8206
+ coverageContexts: [
8207
+ { frontends: ["react-vite"] },
8208
+ {
8209
+ uiLibrary: "none",
8210
+ frontends: ["vue"]
8211
+ },
8212
+ {
8213
+ uiLibrary: "radix-ui",
8214
+ frontends: ["react-vite"]
8215
+ }
8216
+ ]
6996
8217
  },
6997
8218
  database: {
6998
8219
  schemaValues: types_exports.DATABASE_VALUES,
@@ -7077,7 +8298,11 @@ const PROMPT_RESOLVER_REGISTRY = {
7077
8298
  realtime: {
7078
8299
  schemaValues: types_exports.REALTIME_VALUES,
7079
8300
  resolve: resolveRealtimePrompt,
7080
- coverageContexts: [{ backend: "hono" }, { backend: "none" }]
8301
+ coverageContexts: [
8302
+ { backend: "express" },
8303
+ { backend: "hono" },
8304
+ { backend: "none" }
8305
+ ]
7081
8306
  },
7082
8307
  runtime: {
7083
8308
  schemaValues: types_exports.RUNTIME_VALUES,
@@ -7129,6 +8354,11 @@ const PROMPT_RESOLVER_REGISTRY = {
7129
8354
  resolve: ({ value } = {}) => resolveMobileDeepLinkingPrompt(value),
7130
8355
  coverageContexts: [{}]
7131
8356
  },
8357
+ mobileLibraries: {
8358
+ schemaValues: types_exports.MOBILE_LIBRARIES_VALUES,
8359
+ resolve: ({ value } = {}) => resolveMobileLibrariesPrompt(value),
8360
+ coverageContexts: [{}, { value: ["none"] }]
8361
+ },
7132
8362
  uiLibrary: {
7133
8363
  schemaValues: types_exports.UI_LIBRARY_VALUES,
7134
8364
  resolve: resolveUILibraryPrompt,
@@ -7239,6 +8469,41 @@ const PROMPT_RESOLVER_REGISTRY = {
7239
8469
  resolve: ({ value } = {}) => resolvePythonQualityPrompt(value),
7240
8470
  coverageContexts: [{}]
7241
8471
  },
8472
+ pythonCloudSdk: {
8473
+ schemaValues: types_exports.PYTHON_CLOUD_SDK_VALUES,
8474
+ resolve: ({ value } = {}) => resolvePythonCloudSdkPrompt(value),
8475
+ coverageContexts: [{}]
8476
+ },
8477
+ pythonHttpClient: {
8478
+ schemaValues: types_exports.PYTHON_HTTP_CLIENT_VALUES,
8479
+ resolve: ({ value } = {}) => resolvePythonHttpClientPrompt(value),
8480
+ coverageContexts: [{}]
8481
+ },
8482
+ pythonData: {
8483
+ schemaValues: types_exports.PYTHON_DATA_VALUES,
8484
+ resolve: ({ value } = {}) => resolvePythonDataPrompt(value),
8485
+ coverageContexts: [{}, { value: ["none"] }]
8486
+ },
8487
+ pythonMedia: {
8488
+ schemaValues: types_exports.PYTHON_MEDIA_VALUES,
8489
+ resolve: ({ value } = {}) => resolvePythonMediaPrompt(value),
8490
+ coverageContexts: [{}]
8491
+ },
8492
+ pythonServer: {
8493
+ schemaValues: types_exports.PYTHON_SERVER_VALUES,
8494
+ resolve: ({ value } = {}) => resolvePythonServerPrompt(value),
8495
+ coverageContexts: [{}]
8496
+ },
8497
+ pythonPackageManager: {
8498
+ schemaValues: types_exports.PYTHON_PACKAGE_MANAGER_VALUES,
8499
+ resolve: ({ value } = {}) => resolvePythonPackageManagerPrompt(value),
8500
+ coverageContexts: [{}]
8501
+ },
8502
+ pythonMessageQueue: {
8503
+ schemaValues: types_exports.PYTHON_MESSAGE_QUEUE_VALUES,
8504
+ resolve: ({ value } = {}) => resolvePythonMessageQueuePrompt(value),
8505
+ coverageContexts: [{}]
8506
+ },
7242
8507
  goWebFramework: {
7243
8508
  schemaValues: types_exports.GO_WEB_FRAMEWORK_VALUES,
7244
8509
  resolve: ({ value } = {}) => resolveGoWebFrameworkPrompt(value),
@@ -7269,6 +8534,36 @@ const PROMPT_RESOLVER_REGISTRY = {
7269
8534
  resolve: ({ value } = {}) => resolveGoAuthPrompt(value),
7270
8535
  coverageContexts: [{}]
7271
8536
  },
8537
+ goValidation: {
8538
+ schemaValues: types_exports.GO_VALIDATION_VALUES,
8539
+ resolve: ({ value } = {}) => resolveGoValidationPrompt(value),
8540
+ coverageContexts: [{}]
8541
+ },
8542
+ goQuality: {
8543
+ schemaValues: types_exports.GO_QUALITY_VALUES,
8544
+ resolve: ({ value } = {}) => resolveGoQualityPrompt(value),
8545
+ coverageContexts: [{}]
8546
+ },
8547
+ goMigrations: {
8548
+ schemaValues: types_exports.GO_MIGRATIONS_VALUES,
8549
+ resolve: ({ value } = {}) => resolveGoMigrationsPrompt(value),
8550
+ coverageContexts: [{}]
8551
+ },
8552
+ goTemplating: {
8553
+ schemaValues: types_exports.GO_TEMPLATING_VALUES,
8554
+ resolve: ({ value } = {}) => resolveGoTemplatingPrompt(value),
8555
+ coverageContexts: [{}]
8556
+ },
8557
+ goProtoTooling: {
8558
+ schemaValues: types_exports.GO_PROTO_TOOLING_VALUES,
8559
+ resolve: ({ value } = {}) => resolveGoProtoToolingPrompt(value),
8560
+ coverageContexts: [{}]
8561
+ },
8562
+ goDI: {
8563
+ schemaValues: types_exports.GO_DI_VALUES,
8564
+ resolve: ({ value } = {}) => resolveGoDIPrompt(value),
8565
+ coverageContexts: [{}]
8566
+ },
7272
8567
  javaWebFramework: {
7273
8568
  schemaValues: types_exports.JAVA_WEB_FRAMEWORK_VALUES,
7274
8569
  resolve: ({ value } = {}) => resolveJavaWebFrameworkPrompt(value),
@@ -7349,6 +8644,11 @@ const PROMPT_RESOLVER_REGISTRY = {
7349
8644
  resolve: ({ value } = {}) => resolveDotnetDeployPrompt(value),
7350
8645
  coverageContexts: [{}]
7351
8646
  },
8647
+ dotnetLibraries: {
8648
+ schemaValues: types_exports.DOTNET_LIBRARIES_VALUES,
8649
+ resolve: ({ value } = {}) => resolveDotnetLibrariesPrompt(value),
8650
+ coverageContexts: [{}, { value: ["none"] }]
8651
+ },
7352
8652
  elixirWebFramework: {
7353
8653
  schemaValues: types_exports.ELIXIR_WEB_FRAMEWORK_VALUES,
7354
8654
  resolve: ({ value } = {}) => resolveElixirWebFrameworkPrompt(value),
@@ -7419,6 +8719,31 @@ const PROMPT_RESOLVER_REGISTRY = {
7419
8719
  resolve: ({ value } = {}) => resolveElixirQualityPrompt(value),
7420
8720
  coverageContexts: [{}]
7421
8721
  },
8722
+ elixirI18n: {
8723
+ schemaValues: types_exports.ELIXIR_I18N_VALUES,
8724
+ resolve: ({ value } = {}) => resolveElixirI18nPrompt(value),
8725
+ coverageContexts: [{}]
8726
+ },
8727
+ elixirHttpServer: {
8728
+ schemaValues: types_exports.ELIXIR_HTTP_SERVER_VALUES,
8729
+ resolve: ({ value } = {}) => resolveElixirHttpServerPrompt(value),
8730
+ coverageContexts: [{}]
8731
+ },
8732
+ elixirApplicationFramework: {
8733
+ schemaValues: types_exports.ELIXIR_APPLICATION_FRAMEWORK_VALUES,
8734
+ resolve: ({ value } = {}) => resolveElixirApplicationFrameworkPrompt(value),
8735
+ coverageContexts: [{}]
8736
+ },
8737
+ elixirDocumentation: {
8738
+ schemaValues: types_exports.ELIXIR_DOCUMENTATION_VALUES,
8739
+ resolve: ({ value } = {}) => resolveElixirDocumentationPrompt(value),
8740
+ coverageContexts: [{}]
8741
+ },
8742
+ elixirClustering: {
8743
+ schemaValues: types_exports.ELIXIR_CLUSTERING_VALUES,
8744
+ resolve: ({ value } = {}) => resolveElixirClusteringPrompt(value),
8745
+ coverageContexts: [{}]
8746
+ },
7422
8747
  elixirDeploy: {
7423
8748
  schemaValues: types_exports.ELIXIR_DEPLOY_VALUES,
7424
8749
  resolve: ({ value } = {}) => resolveElixirDeployPrompt(value),
@@ -7521,6 +8846,66 @@ async function getSearchChoice(search, backend, ecosystem) {
7521
8846
  return response;
7522
8847
  }
7523
8848
 
8849
+ //#endregion
8850
+ //#region src/prompts/server-deploy.ts
8851
+ async function getServerDeploymentChoice(deployment, runtime, backend, _webDeploy) {
8852
+ if (deployment !== void 0) return deployment;
8853
+ if (backend === "none" || backend === "convex") return "none";
8854
+ if (backend !== "hono") return "none";
8855
+ if (runtime === "workers") return "cloudflare";
8856
+ const response = await navigableSelect({
8857
+ message: "Select server deployment",
8858
+ options: getServerDeploymentOptions(runtime),
8859
+ initialValue: DEFAULT_CONFIG.serverDeploy
8860
+ });
8861
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
8862
+ return response;
8863
+ }
8864
+ function getServerDeploymentOptions(runtime) {
8865
+ return [
8866
+ {
8867
+ value: "none",
8868
+ label: "None",
8869
+ hint: "Skip server deployment setup"
8870
+ },
8871
+ {
8872
+ value: "railway",
8873
+ label: "Railway",
8874
+ hint: "Deploy with Railway cloud development platform"
8875
+ },
8876
+ {
8877
+ value: "fly",
8878
+ label: "Fly.io",
8879
+ hint: "Deploy globally with Fly.io edge platform"
8880
+ },
8881
+ {
8882
+ value: "render",
8883
+ label: "Render",
8884
+ hint: "Deploy with Render's Blueprint and Docker builds"
8885
+ },
8886
+ ...runtime === "node" ? [{
8887
+ value: "netlify",
8888
+ label: "Netlify",
8889
+ hint: "Deploy Hono APIs with Netlify Functions"
8890
+ }] : [],
8891
+ {
8892
+ value: "docker",
8893
+ label: "Docker",
8894
+ hint: "Container-based deployment with Dockerfile"
8895
+ },
8896
+ {
8897
+ value: "sst",
8898
+ label: "SST",
8899
+ hint: "Deploy to AWS with SST (Serverless Stack)"
8900
+ },
8901
+ {
8902
+ value: "vercel",
8903
+ label: "Vercel",
8904
+ hint: "Deploy to Vercel's edge network with zero config"
8905
+ }
8906
+ ];
8907
+ }
8908
+
7524
8909
  //#endregion
7525
8910
  //#region src/prompts/vector-db.ts
7526
8911
  const VECTOR_DB_PROMPT_OPTIONS = [
@@ -7593,64 +8978,40 @@ async function getVectorDbChoice(vectorDb, backend, ecosystem) {
7593
8978
  }
7594
8979
 
7595
8980
  //#endregion
7596
- //#region src/prompts/server-deploy.ts
7597
- async function getServerDeploymentChoice(deployment, runtime, backend, _webDeploy) {
7598
- if (deployment !== void 0) return deployment;
7599
- if (backend === "none" || backend === "convex") return "none";
7600
- if (backend !== "hono") return "none";
7601
- if (runtime === "workers") return "cloudflare";
8981
+ //#region src/prompts/workspace-shape.ts
8982
+ const SINGLE_APP_WEB_FRONTENDS = new Set(["next", "tanstack-start"]);
8983
+ /**
8984
+ * The flat single-app layout only makes sense for a "thin self" app: backend
8985
+ * `self` with exactly one Next.js or TanStack Start web frontend. For anything
8986
+ * else we never prompt and resolve to `monorepo` (the compatibility engine and
8987
+ * generator also normalize non-qualifying stacks back to monorepo).
8988
+ */
8989
+ function stackCanUseSingleApp(backend, frontend) {
8990
+ if (backend !== "self") return false;
8991
+ const webFrontends = frontend.filter((f) => f && f !== "none");
8992
+ if (webFrontends.length !== 1) return false;
8993
+ return SINGLE_APP_WEB_FRONTENDS.has(webFrontends[0]);
8994
+ }
8995
+ async function getWorkspaceShapeChoice(workspaceShape, backend, frontend) {
8996
+ if (!stackCanUseSingleApp(backend, frontend ?? [])) return "monorepo";
8997
+ if (workspaceShape !== void 0) return workspaceShape;
8998
+ if (!canPromptInteractively()) return "monorepo";
7602
8999
  const response = await navigableSelect({
7603
- message: "Select server deployment",
7604
- options: getServerDeploymentOptions(runtime),
7605
- initialValue: DEFAULT_CONFIG.serverDeploy
9000
+ message: "Choose workspace layout",
9001
+ options: [{
9002
+ value: "monorepo",
9003
+ label: "Monorepo",
9004
+ hint: "apps/* + packages/* workspaces (recommended)"
9005
+ }, {
9006
+ value: "single-app",
9007
+ label: "Single app",
9008
+ hint: "Flat app at the repo root (no workspaces)"
9009
+ }],
9010
+ initialValue: "monorepo"
7606
9011
  });
7607
9012
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
7608
9013
  return response;
7609
9014
  }
7610
- function getServerDeploymentOptions(runtime) {
7611
- return [
7612
- {
7613
- value: "none",
7614
- label: "None",
7615
- hint: "Skip server deployment setup"
7616
- },
7617
- {
7618
- value: "railway",
7619
- label: "Railway",
7620
- hint: "Deploy with Railway cloud development platform"
7621
- },
7622
- {
7623
- value: "fly",
7624
- label: "Fly.io",
7625
- hint: "Deploy globally with Fly.io edge platform"
7626
- },
7627
- {
7628
- value: "render",
7629
- label: "Render",
7630
- hint: "Deploy with Render's Blueprint and Docker builds"
7631
- },
7632
- ...runtime === "node" ? [{
7633
- value: "netlify",
7634
- label: "Netlify",
7635
- hint: "Deploy Hono APIs with Netlify Functions"
7636
- }] : [],
7637
- {
7638
- value: "docker",
7639
- label: "Docker",
7640
- hint: "Container-based deployment with Dockerfile"
7641
- },
7642
- {
7643
- value: "sst",
7644
- label: "SST",
7645
- hint: "Deploy to AWS with SST (Serverless Stack)"
7646
- },
7647
- {
7648
- value: "vercel",
7649
- label: "Vercel",
7650
- hint: "Deploy to Vercel's edge network with zero config"
7651
- }
7652
- ];
7653
- }
7654
9015
 
7655
9016
  //#endregion
7656
9017
  //#region src/prompts/config-prompts.ts
@@ -7674,6 +9035,7 @@ const CONFIG_PROMPT_ENTRY_KEY_MAP = {
7674
9035
  configSections: true,
7675
9036
  frontend: true,
7676
9037
  astroIntegration: true,
9038
+ appPlatforms: true,
7677
9039
  uiLibrary: true,
7678
9040
  shadcnOptions: true,
7679
9041
  cssFramework: true,
@@ -7718,6 +9080,7 @@ const CONFIG_PROMPT_ENTRY_KEY_MAP = {
7718
9080
  mobilePush: true,
7719
9081
  mobileOTA: true,
7720
9082
  mobileDeepLinking: true,
9083
+ mobileLibraries: true,
7721
9084
  rustWebFramework: true,
7722
9085
  rustFrontend: true,
7723
9086
  rustOrm: true,
@@ -7746,6 +9109,13 @@ const CONFIG_PROMPT_ENTRY_KEY_MAP = {
7746
9109
  pythonRealtime: true,
7747
9110
  pythonObservability: true,
7748
9111
  pythonCli: true,
9112
+ pythonCloudSdk: true,
9113
+ pythonHttpClient: true,
9114
+ pythonData: true,
9115
+ pythonMedia: true,
9116
+ pythonServer: true,
9117
+ pythonPackageManager: true,
9118
+ pythonMessageQueue: true,
7749
9119
  goWebFramework: true,
7750
9120
  goOrm: true,
7751
9121
  goApi: true,
@@ -7758,6 +9128,12 @@ const CONFIG_PROMPT_ENTRY_KEY_MAP = {
7758
9128
  goCaching: true,
7759
9129
  goConfig: true,
7760
9130
  goObservability: true,
9131
+ goValidation: true,
9132
+ goQuality: true,
9133
+ goMigrations: true,
9134
+ goTemplating: true,
9135
+ goProtoTooling: true,
9136
+ goDI: true,
7761
9137
  javaWebFramework: true,
7762
9138
  javaLanguage: true,
7763
9139
  javaBuildTool: true,
@@ -7778,6 +9154,7 @@ const CONFIG_PROMPT_ENTRY_KEY_MAP = {
7778
9154
  dotnetValidation: true,
7779
9155
  dotnetCaching: true,
7780
9156
  dotnetDeploy: true,
9157
+ dotnetLibraries: true,
7781
9158
  elixirWebFramework: true,
7782
9159
  elixirOrm: true,
7783
9160
  elixirAuth: true,
@@ -7792,6 +9169,11 @@ const CONFIG_PROMPT_ENTRY_KEY_MAP = {
7792
9169
  elixirObservability: true,
7793
9170
  elixirTesting: true,
7794
9171
  elixirQuality: true,
9172
+ elixirI18n: true,
9173
+ elixirHttpServer: true,
9174
+ elixirApplicationFramework: true,
9175
+ elixirDocumentation: true,
9176
+ elixirClustering: true,
7795
9177
  elixirDeploy: true,
7796
9178
  elixirLibraries: true,
7797
9179
  aiDocs: true,
@@ -7868,7 +9250,8 @@ function getPromptResolutionValue(key, results, flags) {
7868
9250
  },
7869
9251
  cssFramework: {
7870
9252
  cssFramework: flags.cssFramework,
7871
- uiLibrary: results.uiLibrary
9253
+ uiLibrary: results.uiLibrary,
9254
+ frontends
7872
9255
  },
7873
9256
  forms: {
7874
9257
  forms: flags.forms,
@@ -7977,6 +9360,10 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
7977
9360
  if (results.frontend?.includes("astro")) return getAstroIntegrationChoice(flags.astroIntegration);
7978
9361
  return Promise.resolve(void 0);
7979
9362
  },
9363
+ appPlatforms: ({ results }) => {
9364
+ if (results.ecosystem !== "typescript") return Promise.resolve([]);
9365
+ return getAppPlatformsChoice(flags.addons, results.frontend);
9366
+ },
7980
9367
  uiLibrary: ({ results }) => {
7981
9368
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
7982
9369
  if (hasWebStyling$1(results.frontend)) return getUILibraryChoice(flags.uiLibrary, results.frontend, results.astroIntegration);
@@ -7996,7 +9383,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
7996
9383
  },
7997
9384
  cssFramework: ({ results }) => {
7998
9385
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
7999
- if (hasWebStyling$1(results.frontend)) return getCSSFrameworkChoice(flags.cssFramework, results.uiLibrary);
9386
+ if (hasWebStyling$1(results.frontend)) return getCSSFrameworkChoice(flags.cssFramework, results.uiLibrary, results.frontend);
8000
9387
  return Promise.resolve("none");
8001
9388
  },
8002
9389
  backend: ({ results }) => {
@@ -8046,7 +9433,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8046
9433
  const nonTypeScriptAddons = (flags.addons ?? []).filter((addon) => addon === "docker-compose" || addon === "devcontainer" || addon === "github-actions");
8047
9434
  return Promise.resolve(nonTypeScriptAddons);
8048
9435
  }
8049
- return getAddonsChoice(flags.addons, results.frontend, results.auth, results.backend, results.runtime);
9436
+ return getAddonsChoice(flags.addons, results.frontend, results.auth, results.backend, results.runtime, results.api);
8050
9437
  },
8051
9438
  examples: ({ results }) => {
8052
9439
  if (results.ecosystem !== "typescript") return Promise.resolve([]);
@@ -8067,7 +9454,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8067
9454
  ai: ({ results }) => {
8068
9455
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
8069
9456
  if (flags.ai === void 0 && results.examples?.includes("chat-sdk") && requiresChatSdkVercelAI(results.backend, results.frontend, results.runtime)) return Promise.resolve("vercel-ai");
8070
- return getAIChoice(flags.ai);
9457
+ return getAIChoice(flags.ai, results.backend);
8071
9458
  },
8072
9459
  validation: ({ results }) => {
8073
9460
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
@@ -8120,7 +9507,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8120
9507
  },
8121
9508
  cms: ({ results }) => {
8122
9509
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
8123
- return getCMSChoice(flags.cms, results.backend);
9510
+ return getCMSChoice(flags.cms, results.backend, results.frontend);
8124
9511
  },
8125
9512
  caching: ({ results }) => {
8126
9513
  if (results.ecosystem === "react-native" || results.ecosystem === "elixir") return Promise.resolve("none");
@@ -8183,6 +9570,11 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8183
9570
  if (!results.frontend?.some((frontend) => frontend.startsWith("native-"))) return Promise.resolve("none");
8184
9571
  return getMobileDeepLinkingChoice(flags.mobileDeepLinking);
8185
9572
  },
9573
+ mobileLibraries: ({ results }) => {
9574
+ if (results.ecosystem !== "typescript" && results.ecosystem !== "react-native") return Promise.resolve([]);
9575
+ if (!results.frontend?.some((frontend) => frontend.startsWith("native-"))) return Promise.resolve([]);
9576
+ return getMobileLibrariesChoice(flags.mobileLibraries);
9577
+ },
8186
9578
  rustWebFramework: ({ results }) => {
8187
9579
  if (results.ecosystem !== "rust") return Promise.resolve("none");
8188
9580
  return getRustWebFrameworkChoice(flags.rustWebFramework);
@@ -8296,6 +9688,34 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8296
9688
  if (results.ecosystem !== "python") return Promise.resolve([]);
8297
9689
  return getPythonCliChoice(flags.pythonCli);
8298
9690
  },
9691
+ pythonCloudSdk: ({ results }) => {
9692
+ if (results.ecosystem !== "python") return Promise.resolve("none");
9693
+ return getPythonCloudSdkChoice(flags.pythonCloudSdk);
9694
+ },
9695
+ pythonHttpClient: ({ results }) => {
9696
+ if (results.ecosystem !== "python") return Promise.resolve("none");
9697
+ return getPythonHttpClientChoice(flags.pythonHttpClient);
9698
+ },
9699
+ pythonData: ({ results }) => {
9700
+ if (results.ecosystem !== "python") return Promise.resolve([]);
9701
+ return getPythonDataChoice(flags.pythonData);
9702
+ },
9703
+ pythonMedia: ({ results }) => {
9704
+ if (results.ecosystem !== "python") return Promise.resolve("none");
9705
+ return getPythonMediaChoice(flags.pythonMedia);
9706
+ },
9707
+ pythonServer: ({ results }) => {
9708
+ if (results.ecosystem !== "python") return Promise.resolve("none");
9709
+ return getPythonServerChoice(flags.pythonServer);
9710
+ },
9711
+ pythonPackageManager: ({ results }) => {
9712
+ if (results.ecosystem !== "python") return Promise.resolve("uv");
9713
+ return getPythonPackageManagerChoice(flags.pythonPackageManager);
9714
+ },
9715
+ pythonMessageQueue: ({ results }) => {
9716
+ if (results.ecosystem !== "python") return Promise.resolve("none");
9717
+ return getPythonMessageQueueChoice(flags.pythonMessageQueue);
9718
+ },
8299
9719
  goWebFramework: ({ results }) => {
8300
9720
  if (results.ecosystem !== "go") return Promise.resolve("none");
8301
9721
  return getGoWebFrameworkChoice(flags.goWebFramework);
@@ -8344,6 +9764,34 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8344
9764
  if (results.ecosystem !== "go") return Promise.resolve("none");
8345
9765
  return getGoObservabilityChoice(flags.goObservability);
8346
9766
  },
9767
+ goValidation: ({ results }) => {
9768
+ if (results.ecosystem !== "go") return Promise.resolve("none");
9769
+ return getGoValidationChoice(flags.goValidation);
9770
+ },
9771
+ goQuality: ({ results }) => {
9772
+ if (results.ecosystem !== "go") return Promise.resolve("none");
9773
+ return getGoQualityChoice(flags.goQuality);
9774
+ },
9775
+ goMigrations: ({ results }) => {
9776
+ if (results.ecosystem !== "go" || !results.database || ![
9777
+ "sqlite",
9778
+ "postgres",
9779
+ "mysql"
9780
+ ].includes(results.database)) return Promise.resolve("none");
9781
+ return getGoMigrationsChoice(flags.goMigrations);
9782
+ },
9783
+ goTemplating: ({ results }) => {
9784
+ if (results.ecosystem !== "go") return Promise.resolve("none");
9785
+ return getGoTemplatingChoice(flags.goTemplating);
9786
+ },
9787
+ goProtoTooling: ({ results }) => {
9788
+ if (results.ecosystem !== "go") return Promise.resolve("none");
9789
+ return getGoProtoToolingChoice(flags.goProtoTooling);
9790
+ },
9791
+ goDI: ({ results }) => {
9792
+ if (results.ecosystem !== "go") return Promise.resolve("none");
9793
+ return getGoDIChoice(flags.goDI);
9794
+ },
8347
9795
  javaWebFramework: ({ results }) => {
8348
9796
  if (results.ecosystem !== "java") return Promise.resolve("none");
8349
9797
  return getJavaWebFrameworkChoice(flags.javaWebFramework);
@@ -8453,6 +9901,11 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8453
9901
  if (results.dotnetWebFramework === "none") return Promise.resolve("none");
8454
9902
  return getDotnetDeployChoice(flags.dotnetDeploy);
8455
9903
  },
9904
+ dotnetLibraries: ({ results }) => {
9905
+ if (results.ecosystem !== "dotnet") return Promise.resolve([]);
9906
+ if (results.dotnetWebFramework === "none") return Promise.resolve([]);
9907
+ return getDotnetLibrariesChoice(flags.dotnetLibraries);
9908
+ },
8456
9909
  elixirWebFramework: ({ results }) => {
8457
9910
  if (results.ecosystem !== "elixir") return Promise.resolve("none");
8458
9911
  return getElixirWebFrameworkChoice(flags.elixirWebFramework);
@@ -8509,6 +9962,26 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8509
9962
  if (results.ecosystem !== "elixir") return Promise.resolve("none");
8510
9963
  return getElixirQualityChoice(flags.elixirQuality);
8511
9964
  },
9965
+ elixirI18n: ({ results }) => {
9966
+ if (results.ecosystem !== "elixir") return Promise.resolve("none");
9967
+ return getElixirI18nChoice(flags.elixirI18n);
9968
+ },
9969
+ elixirHttpServer: ({ results }) => {
9970
+ if (results.ecosystem !== "elixir") return Promise.resolve("none");
9971
+ return getElixirHttpServerChoice(flags.elixirHttpServer);
9972
+ },
9973
+ elixirApplicationFramework: ({ results }) => {
9974
+ if (results.ecosystem !== "elixir") return Promise.resolve("none");
9975
+ return getElixirApplicationFrameworkChoice(flags.elixirApplicationFramework);
9976
+ },
9977
+ elixirDocumentation: ({ results }) => {
9978
+ if (results.ecosystem !== "elixir") return Promise.resolve("none");
9979
+ return getElixirDocumentationChoice(flags.elixirDocumentation);
9980
+ },
9981
+ elixirClustering: ({ results }) => {
9982
+ if (results.ecosystem !== "elixir") return Promise.resolve("none");
9983
+ return getElixirClusteringChoice(flags.elixirClustering);
9984
+ },
8512
9985
  elixirDeploy: ({ results }) => {
8513
9986
  if (results.ecosystem !== "elixir") return Promise.resolve("none");
8514
9987
  return getElixirDeployChoice(flags.elixirDeploy);
@@ -8543,7 +10016,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8543
10016
  payments: result.payments,
8544
10017
  email: result.email,
8545
10018
  effect: result.effect,
8546
- addons: result.addons,
10019
+ addons: Array.from(new Set([...result.appPlatforms ?? [], ...result.addons])),
8547
10020
  examples: result.examples,
8548
10021
  git: result.git,
8549
10022
  packageManager: result.packageManager,
@@ -8580,6 +10053,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8580
10053
  mobilePush: result.mobilePush,
8581
10054
  mobileOTA: result.mobileOTA,
8582
10055
  mobileDeepLinking: result.mobileDeepLinking,
10056
+ mobileLibraries: result.mobileLibraries,
8583
10057
  ecosystem: result.ecosystem,
8584
10058
  rustWebFramework: result.rustWebFramework,
8585
10059
  rustFrontend: result.rustFrontend,
@@ -8609,6 +10083,13 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8609
10083
  pythonRealtime: result.pythonRealtime,
8610
10084
  pythonObservability: result.pythonObservability,
8611
10085
  pythonCli: result.pythonCli,
10086
+ pythonCloudSdk: result.pythonCloudSdk,
10087
+ pythonHttpClient: result.pythonHttpClient,
10088
+ pythonData: result.pythonData,
10089
+ pythonMedia: result.pythonMedia,
10090
+ pythonServer: result.pythonServer,
10091
+ pythonPackageManager: result.pythonPackageManager,
10092
+ pythonMessageQueue: result.pythonMessageQueue,
8612
10093
  goWebFramework: result.goWebFramework,
8613
10094
  goOrm: result.goOrm,
8614
10095
  goApi: result.goApi,
@@ -8621,6 +10102,12 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8621
10102
  goCaching: result.goCaching,
8622
10103
  goConfig: result.goConfig,
8623
10104
  goObservability: result.goObservability,
10105
+ goValidation: result.goValidation,
10106
+ goQuality: result.goQuality,
10107
+ goMigrations: result.goMigrations,
10108
+ goTemplating: result.goTemplating,
10109
+ goProtoTooling: result.goProtoTooling,
10110
+ goDI: result.goDI,
8624
10111
  javaWebFramework: result.javaWebFramework,
8625
10112
  javaLanguage: result.javaLanguage,
8626
10113
  javaBuildTool: result.javaBuildTool,
@@ -8641,6 +10128,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8641
10128
  dotnetValidation: result.dotnetValidation,
8642
10129
  dotnetCaching: result.dotnetCaching,
8643
10130
  dotnetDeploy: result.dotnetDeploy,
10131
+ dotnetLibraries: result.dotnetLibraries,
8644
10132
  elixirWebFramework: result.elixirWebFramework,
8645
10133
  elixirOrm: result.elixirOrm,
8646
10134
  elixirAuth: result.elixirAuth,
@@ -8655,6 +10143,11 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
8655
10143
  elixirObservability: result.elixirObservability,
8656
10144
  elixirTesting: result.elixirTesting,
8657
10145
  elixirQuality: result.elixirQuality,
10146
+ elixirI18n: result.elixirI18n,
10147
+ elixirHttpServer: result.elixirHttpServer,
10148
+ elixirApplicationFramework: result.elixirApplicationFramework,
10149
+ elixirDocumentation: result.elixirDocumentation,
10150
+ elixirClustering: result.elixirClustering,
8658
10151
  elixirDeploy: result.elixirDeploy,
8659
10152
  elixirLibraries: result.elixirLibraries,
8660
10153
  aiDocs: result.aiDocs
@@ -8905,6 +10398,11 @@ function displayConfig(config) {
8905
10398
  if (config.elixirObservability && config.elixirObservability !== "none") configDisplay.push(`${pc.blue("Elixir Observability:")} ${String(config.elixirObservability)}`);
8906
10399
  if (config.elixirTesting && config.elixirTesting !== "none") configDisplay.push(`${pc.blue("Elixir Testing:")} ${String(config.elixirTesting)}`);
8907
10400
  if (config.elixirQuality && config.elixirQuality !== "none") configDisplay.push(`${pc.blue("Elixir Quality:")} ${String(config.elixirQuality)}`);
10401
+ if (config.elixirI18n && config.elixirI18n !== "none") configDisplay.push(`${pc.blue("Elixir I18n:")} ${String(config.elixirI18n)}`);
10402
+ if (config.elixirHttpServer && config.elixirHttpServer !== "none") configDisplay.push(`${pc.blue("Elixir HTTP Server:")} ${String(config.elixirHttpServer)}`);
10403
+ if (config.elixirApplicationFramework && config.elixirApplicationFramework !== "none") configDisplay.push(`${pc.blue("Elixir Application Framework:")} ${String(config.elixirApplicationFramework)}`);
10404
+ if (config.elixirDocumentation && config.elixirDocumentation !== "none") configDisplay.push(`${pc.blue("Elixir Documentation:")} ${String(config.elixirDocumentation)}`);
10405
+ if (config.elixirClustering && config.elixirClustering !== "none") configDisplay.push(`${pc.blue("Elixir Clustering:")} ${String(config.elixirClustering)}`);
8908
10406
  if (config.elixirDeploy && config.elixirDeploy !== "none") configDisplay.push(`${pc.blue("Elixir Deploy:")} ${String(config.elixirDeploy)}`);
8909
10407
  }
8910
10408
  if (config.observability !== void 0) configDisplay.push(`${pc.blue("Observability:")} ${String(config.observability)}`);
@@ -8917,6 +10415,8 @@ function displayConfig(config) {
8917
10415
  if (config.mobilePush !== void 0) configDisplay.push(`${pc.blue("Mobile Push:")} ${String(config.mobilePush)}`);
8918
10416
  if (config.mobileOTA !== void 0) configDisplay.push(`${pc.blue("Mobile OTA:")} ${String(config.mobileOTA)}`);
8919
10417
  if (config.mobileDeepLinking !== void 0) configDisplay.push(`${pc.blue("Mobile Deep Linking:")} ${String(config.mobileDeepLinking)}`);
10418
+ if (config.mobileLibraries && config.mobileLibraries.length > 0) configDisplay.push(`${pc.blue("Mobile Libraries:")} ${config.mobileLibraries.join(", ")}`);
10419
+ if (config.dotnetLibraries && config.dotnetLibraries.length > 0) configDisplay.push(`${pc.blue(".NET Libraries:")} ${config.dotnetLibraries.join(", ")}`);
8920
10420
  if (config.caching !== void 0) configDisplay.push(`${pc.blue("Caching:")} ${String(config.caching)}`);
8921
10421
  if (config.i18n !== void 0) configDisplay.push(`${pc.blue("i18n:")} ${String(config.i18n)}`);
8922
10422
  if (config.cms !== void 0) configDisplay.push(`${pc.blue("CMS:")} ${String(config.cms)}`);
@@ -10694,7 +12194,11 @@ function displayRustInstructions(config) {
10694
12194
  if (rustWebFramework && rustWebFramework !== "none") output += `${pc.cyan("•")} Web Framework: ${{
10695
12195
  actix: "Actix Web",
10696
12196
  axum: "Axum",
10697
- rocket: "Rocket"
12197
+ rocket: "Rocket",
12198
+ poem: "Poem",
12199
+ loco: "Loco",
12200
+ warp: "Warp",
12201
+ salvo: "Salvo"
10698
12202
  }[rustWebFramework] || rustWebFramework}\n`;
10699
12203
  if (rustFrontend && rustFrontend !== "none") output += `${pc.cyan("•")} Frontend: ${{
10700
12204
  leptos: "Leptos",
@@ -10704,11 +12208,15 @@ function displayRustInstructions(config) {
10704
12208
  if (rustOrm && rustOrm !== "none") output += `${pc.cyan("•")} Database: ${{
10705
12209
  diesel: "Diesel",
10706
12210
  sqlx: "SQLx",
10707
- "sea-orm": "SeaORM"
12211
+ "sea-orm": "SeaORM",
12212
+ mongodb: "MongoDB Rust Driver",
12213
+ rusqlite: "rusqlite",
12214
+ "tokio-postgres": "tokio-postgres"
10708
12215
  }[rustOrm] || rustOrm}\n`;
10709
12216
  if (rustApi && rustApi !== "none") output += `${pc.cyan("•")} API: ${{
10710
12217
  "async-graphql": "async-graphql",
10711
- juniper: "Juniper"
12218
+ tonic: "Tonic",
12219
+ jsonrpsee: "jsonrpsee"
10712
12220
  }[rustApi] || rustApi}\n`;
10713
12221
  if (rustCli && rustCli !== "none") output += `${pc.cyan("•")} CLI: ${{
10714
12222
  clap: "Clap",
@@ -10744,7 +12252,7 @@ function displayRustInstructions(config) {
10744
12252
  consola$1.box(output);
10745
12253
  }
10746
12254
  function displayGoInstructions(config) {
10747
- const { relativePath, depsInstalled, goWebFramework, goOrm, goApi, goCli, goLogging, goAuth } = config;
12255
+ const { relativePath, depsInstalled, goWebFramework, goOrm, goApi, goCli, goLogging, goAuth, goTesting, goMessageQueue, goObservability, goValidation, goQuality, goMigrations, goTemplating, goProtoTooling, goDI } = config;
10748
12256
  const cdCmd = `cd ${relativePath}`;
10749
12257
  let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
10750
12258
  let stepCounter = 2;
@@ -10755,14 +12263,25 @@ function displayGoInstructions(config) {
10755
12263
  gin: "Gin",
10756
12264
  echo: "Echo",
10757
12265
  fiber: "Fiber",
10758
- chi: "Chi"
12266
+ chi: "Chi",
12267
+ stdlib: "net/http",
12268
+ "go-zero": "go-zero",
12269
+ kratos: "Kratos",
12270
+ httprouter: "HttpRouter"
10759
12271
  }[goWebFramework] || goWebFramework}\n`;
10760
12272
  if (goOrm && goOrm !== "none") output += `${pc.cyan("•")} Database: ${{
10761
12273
  gorm: "GORM",
10762
12274
  sqlc: "sqlc",
10763
- ent: "Ent"
12275
+ ent: "Ent",
12276
+ bun: "Bun",
12277
+ sqlx: "sqlx"
10764
12278
  }[goOrm] || goOrm}\n`;
10765
- if (goApi && goApi !== "none") output += `${pc.cyan("•")} API: ${{ "grpc-go": "gRPC-Go" }[goApi] || goApi}\n`;
12279
+ if (goApi && goApi !== "none") output += `${pc.cyan("•")} API: ${{
12280
+ "grpc-go": "gRPC-Go",
12281
+ "grpc-gateway": "grpc-gateway",
12282
+ "connect-go": "Connect-Go",
12283
+ "oapi-codegen": "oapi-codegen"
12284
+ }[goApi] || goApi}\n`;
10766
12285
  if (goCli && goCli !== "none") output += `${pc.cyan("•")} CLI: ${{
10767
12286
  cobra: "Cobra",
10768
12287
  bubbletea: "Bubble Tea",
@@ -10775,8 +12294,25 @@ function displayGoInstructions(config) {
10775
12294
  }[goLogging] || goLogging}\n`;
10776
12295
  if (goAuth && goAuth !== "none") output += `${pc.cyan("•")} Auth: ${{
10777
12296
  casbin: "Casbin",
10778
- jwt: "golang-jwt"
12297
+ jwt: "golang-jwt",
12298
+ goth: "Goth",
12299
+ oauth2: "x/oauth2"
10779
12300
  }[goAuth] || goAuth}\n`;
12301
+ const extras = [
12302
+ ["Testing", goTesting],
12303
+ ["Messaging", goMessageQueue],
12304
+ ["Observability", goObservability],
12305
+ ["Validation", goValidation],
12306
+ ["Code Quality", goQuality],
12307
+ ["Migrations", goMigrations],
12308
+ ["Templating", goTemplating],
12309
+ ["Protobuf Tooling", goProtoTooling],
12310
+ ["Dependency Injection", goDI]
12311
+ ];
12312
+ for (const [label, value] of extras) {
12313
+ const rendered = Array.isArray(value) ? value.filter((item) => item !== "none").join(", ") : value;
12314
+ if (rendered && rendered !== "none") output += `${pc.cyan("•")} ${label}: ${rendered}\n`;
12315
+ }
10780
12316
  output += `\n${pc.bold("Common Go commands:")}\n`;
10781
12317
  output += `${pc.cyan("•")} Build: go build ./...\n`;
10782
12318
  output += `${pc.cyan("•")} Run: go run cmd/server/main.go\n`;
@@ -10914,7 +12450,27 @@ function displayJavaInstructions(config) {
10914
12450
  "springdoc-openapi": "Springdoc OpenAPI",
10915
12451
  lombok: "Lombok",
10916
12452
  mapstruct: "MapStruct",
10917
- caffeine: "Caffeine"
12453
+ caffeine: "Caffeine",
12454
+ "spring-data-redis": "Spring Data Redis",
12455
+ "spring-data-mongodb": "Spring Data MongoDB",
12456
+ "spring-data-elasticsearch": "Spring Data Elasticsearch",
12457
+ "spring-data-neo4j": "Spring Data Neo4j",
12458
+ "spring-data-cassandra": "Spring Data Cassandra",
12459
+ "spring-data-couchbase": "Spring Data Couchbase",
12460
+ "spring-data-jdbc": "Spring Data JDBC",
12461
+ "spring-data-rest": "Spring Data REST",
12462
+ "spring-quartz": "Quartz Scheduler",
12463
+ "spring-pulsar": "Spring for Apache Pulsar",
12464
+ "spring-integration": "Spring Integration",
12465
+ "spring-websocket": "Spring WebSocket",
12466
+ "spring-rsocket": "Spring RSocket",
12467
+ "spring-hateoas": "Spring HATEOAS",
12468
+ "spring-session-redis": "Spring Session Redis",
12469
+ "spring-session-jdbc": "Spring Session JDBC",
12470
+ "spring-ldap": "Spring LDAP",
12471
+ "spring-oauth2-client": "Spring OAuth2 Client",
12472
+ "spring-saml2": "Spring SAML2",
12473
+ "spring-restclient": "Spring REST Client"
10918
12474
  };
10919
12475
  const libraryList = effectiveJavaLibraries.map((library) => libraryNames[library] || library).join(", ");
10920
12476
  output += `${pc.cyan("•")} Libraries: ${libraryList}\n`;
@@ -10953,27 +12509,37 @@ function displayJavaInstructions(config) {
10953
12509
  consola$1.box(output);
10954
12510
  }
10955
12511
  function displayPythonInstructions(config) {
10956
- const { relativePath, depsInstalled, pythonWebFramework, pythonOrm, pythonValidation, pythonAi, pythonApi, pythonTaskQueue, pythonQuality } = config;
12512
+ const { relativePath, depsInstalled, pythonWebFramework, pythonOrm, pythonValidation, pythonAi, pythonApi, pythonTaskQueue, pythonQuality, pythonPackageManager } = config;
10957
12513
  const cdCmd = `cd ${relativePath}`;
10958
- let runCommand = "uv run uvicorn app.main:app --reload";
10959
- if (pythonWebFramework === "django") runCommand = "uv run python manage.py runserver";
10960
- else if (pythonWebFramework === "flask") runCommand = "uv run flask --app app.main run --reload";
10961
- else if (pythonWebFramework === "litestar") runCommand = "litestar --app src.app.main:app run --reload --port 3001";
12514
+ const venvBin = process.platform === "win32" ? ".venv\\Scripts\\" : ".venv/bin/";
12515
+ const runPrefix = pythonPackageManager === "poetry" ? "poetry run " : pythonPackageManager === "uv" ? "uv run " : venvBin;
12516
+ const installCommand = pythonPackageManager === "poetry" ? "poetry install --extras dev" : pythonPackageManager === "uv" ? "uv sync --extra dev" : `${process.platform === "win32" ? "python" : "python3"} -m venv .venv && ${venvBin}pip install -e ".[dev]"`;
12517
+ let runCommand = `${runPrefix}uvicorn app.main:app --reload`;
12518
+ if (pythonWebFramework === "django") runCommand = `${runPrefix}python -m app.main`;
12519
+ else if (pythonWebFramework === "flask") runCommand = `${runPrefix}flask --app app.main run --reload --port 8000`;
12520
+ else if (pythonWebFramework === "litestar") runCommand = `${runPrefix}litestar --app src.app.main:app run --reload --port 8000`;
12521
+ else if (pythonWebFramework === "streamlit") runCommand = `${runPrefix}streamlit run src/app/main.py --server.port 8000`;
12522
+ else if (pythonWebFramework !== "fastapi") runCommand = `${runPrefix}python -m app.main`;
10962
12523
  let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
10963
12524
  let stepCounter = 2;
10964
- if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} uv sync\n`;
12525
+ if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${installCommand}\n`;
10965
12526
  output += `${pc.cyan(`${stepCounter++}.`)} ${runCommand}\n`;
10966
12527
  output += `\n${pc.bold("Your Python project includes:")}\n`;
10967
12528
  if (pythonWebFramework && pythonWebFramework !== "none") output += `${pc.cyan("•")} Web Framework: ${{
10968
12529
  fastapi: "FastAPI",
10969
12530
  django: "Django",
10970
12531
  flask: "Flask",
10971
- litestar: "Litestar"
12532
+ litestar: "Litestar",
12533
+ starlette: "Starlette",
12534
+ aiohttp: "aiohttp",
12535
+ streamlit: "Streamlit"
10972
12536
  }[pythonWebFramework] || pythonWebFramework}\n`;
10973
12537
  if (pythonOrm && pythonOrm !== "none") output += `${pc.cyan("•")} ORM: ${{
10974
12538
  sqlalchemy: "SQLAlchemy",
10975
12539
  sqlmodel: "SQLModel",
10976
- "tortoise-orm": "Tortoise ORM"
12540
+ "tortoise-orm": "Tortoise ORM",
12541
+ peewee: "Peewee",
12542
+ pymongo: "PyMongo"
10977
12543
  }[pythonOrm] || pythonOrm}\n`;
10978
12544
  if (pythonValidation && pythonValidation !== "none") output += `${pc.cyan("•")} Validation: ${{ pydantic: "Pydantic" }[pythonValidation] || pythonValidation}\n`;
10979
12545
  if (pythonAi && pythonAi.length > 0 && !pythonAi.includes("none")) {
@@ -10983,7 +12549,12 @@ function displayPythonInstructions(config) {
10983
12549
  llamaindex: "LlamaIndex",
10984
12550
  "openai-sdk": "OpenAI SDK",
10985
12551
  "anthropic-sdk": "Anthropic SDK",
10986
- crewai: "CrewAI"
12552
+ crewai: "CrewAI",
12553
+ pytorch: "PyTorch",
12554
+ transformers: "Transformers",
12555
+ "scikit-learn": "scikit-learn",
12556
+ tensorflow: "TensorFlow",
12557
+ mcp: "MCP Python SDK"
10987
12558
  };
10988
12559
  const aiList = pythonAi.filter((ai) => ai !== "none").map((ai) => aiNames[ai] || ai).join(", ");
10989
12560
  output += `${pc.cyan("•")} AI: ${aiList}\n`;
@@ -10999,14 +12570,14 @@ function displayPythonInstructions(config) {
10999
12570
  pyright: "Pyright"
11000
12571
  }[pythonQuality] || pythonQuality}\n`;
11001
12572
  output += `\n${pc.bold("Common Python commands:")}\n`;
11002
- output += `${pc.cyan("•")} Install: uv sync\n`;
12573
+ output += `${pc.cyan("•")} Install: ${installCommand}\n`;
11003
12574
  output += `${pc.cyan("•")} Run: ${runCommand}\n`;
11004
- output += `${pc.cyan("•")} Test: uv run pytest\n`;
12575
+ output += `${pc.cyan("•")} Test: ${runPrefix}pytest\n`;
11005
12576
  if (pythonQuality === "ruff") {
11006
- output += `${pc.cyan("•")} Format: uv run ruff format .\n`;
11007
- output += `${pc.cyan("•")} Lint: uv run ruff check .\n`;
11008
- } else if (pythonQuality === "mypy") output += `${pc.cyan("•")} Type check: uv run mypy src/app tests\n`;
11009
- else if (pythonQuality === "pyright") output += `${pc.cyan("•")} Type check: uv run pyright\n`;
12577
+ output += `${pc.cyan("•")} Format: ${runPrefix}ruff format .\n`;
12578
+ output += `${pc.cyan("•")} Lint: ${runPrefix}ruff check .\n`;
12579
+ } else if (pythonQuality === "mypy") output += `${pc.cyan("•")} Type check: ${runPrefix}mypy src/app tests\n`;
12580
+ else if (pythonQuality === "pyright") output += `${pc.cyan("•")} Type check: ${runPrefix}pyright\n`;
11010
12581
  output += `\n${pc.bold("Your project will be available at:")}\n`;
11011
12582
  output += `${pc.cyan("•")} API: http://localhost:8000\n`;
11012
12583
  output += `\n${pc.bold("Enjoying Better Fullstack?")} Help us grow — star the repo!\n`;
@@ -11071,7 +12642,7 @@ async function createProject(options, cliInput = {}) {
11071
12642
  await applyDependencyVersionChannel(projectDir, options.versionChannel);
11072
12643
  await writeBtsConfig(options);
11073
12644
  await formatProject(projectDir);
11074
- await recordScaffoldManifest(projectDir);
12645
+ await recordScaffoldManifest(projectDir, { baselines: collectStructuredBaselines(result.tree) });
11075
12646
  if (!isSilent()) log.success("Project template successfully scaffolded!");
11076
12647
  if (options.install && (options.ecosystem === "typescript" || options.ecosystem === "react-native")) {
11077
12648
  const result$1 = await installDependencies({
@@ -11085,7 +12656,10 @@ async function createProject(options, cliInput = {}) {
11085
12656
  if (!result$1.success) setupFailures.push(result$1);
11086
12657
  }
11087
12658
  if (options.install && options.ecosystem === "python") {
11088
- const result$1 = await runUvSync({ projectDir });
12659
+ const result$1 = await runPythonInstall({
12660
+ projectDir,
12661
+ packageManager: options.pythonPackageManager
12662
+ });
11089
12663
  if (!result$1.success) setupFailures.push(result$1);
11090
12664
  }
11091
12665
  if (options.install && options.ecosystem === "go") {
@@ -11234,6 +12808,8 @@ function getYesBaseConfig(flagConfig) {
11234
12808
  frontend: ["native-bare"],
11235
12809
  addons: [],
11236
12810
  examples: [],
12811
+ database: "none",
12812
+ orm: "none",
11237
12813
  auth: "none",
11238
12814
  payments: "none",
11239
12815
  email: "none",
@@ -11268,9 +12844,15 @@ function getYesBaseConfig(flagConfig) {
11268
12844
  mobileTesting: "none",
11269
12845
  mobilePush: "none",
11270
12846
  mobileOTA: "none",
11271
- mobileDeepLinking: "none"
12847
+ mobileDeepLinking: "none",
12848
+ mobileLibraries: []
11272
12849
  };
11273
12850
  }
12851
+ function reportCompatibilityAdjustments(adjustments) {
12852
+ if (isSilent() || adjustments.length === 0) return;
12853
+ log.warn(pc.yellow("Adjusted incompatible options (use --yolo to bypass):"));
12854
+ for (const adjustment of adjustments) log.message(pc.yellow(` ${adjustment}`));
12855
+ }
11274
12856
  function shouldPromptForVersionChannel(input, hasConfigBase) {
11275
12857
  if (input.yes || input.part?.length || hasConfigBase || input.versionChannel !== void 0 || isSilent()) return false;
11276
12858
  return canPromptInteractively();
@@ -11411,6 +12993,7 @@ async function createProjectHandler(input, options = {}) {
11411
12993
  mobilePush: "none",
11412
12994
  mobileOTA: "none",
11413
12995
  mobileDeepLinking: "none",
12996
+ mobileLibraries: [],
11414
12997
  pythonWebFramework: "none",
11415
12998
  pythonOrm: "none",
11416
12999
  pythonValidation: "none",
@@ -11425,6 +13008,13 @@ async function createProjectHandler(input, options = {}) {
11425
13008
  pythonRealtime: "none",
11426
13009
  pythonObservability: "none",
11427
13010
  pythonCli: [],
13011
+ pythonCloudSdk: "none",
13012
+ pythonHttpClient: "none",
13013
+ pythonData: [],
13014
+ pythonMedia: "none",
13015
+ pythonServer: "none",
13016
+ pythonPackageManager: "uv",
13017
+ pythonMessageQueue: "none",
11428
13018
  goWebFramework: "none",
11429
13019
  goOrm: "none",
11430
13020
  goApi: "none",
@@ -11437,6 +13027,12 @@ async function createProjectHandler(input, options = {}) {
11437
13027
  goCaching: "none",
11438
13028
  goConfig: "none",
11439
13029
  goObservability: "none",
13030
+ goValidation: "none",
13031
+ goQuality: "none",
13032
+ goMigrations: "none",
13033
+ goTemplating: "none",
13034
+ goProtoTooling: "none",
13035
+ goDI: "none",
11440
13036
  javaWebFramework: "none",
11441
13037
  javaBuildTool: "none",
11442
13038
  javaOrm: "none",
@@ -11456,6 +13052,7 @@ async function createProjectHandler(input, options = {}) {
11456
13052
  dotnetValidation: "none",
11457
13053
  dotnetCaching: "none",
11458
13054
  dotnetDeploy: "none",
13055
+ dotnetLibraries: [],
11459
13056
  elixirWebFramework: "none",
11460
13057
  elixirOrm: "none",
11461
13058
  elixirAuth: "none",
@@ -11470,6 +13067,11 @@ async function createProjectHandler(input, options = {}) {
11470
13067
  elixirObservability: "none",
11471
13068
  elixirTesting: "none",
11472
13069
  elixirQuality: "none",
13070
+ elixirI18n: "none",
13071
+ elixirHttpServer: "none",
13072
+ elixirApplicationFramework: "none",
13073
+ elixirDocumentation: "none",
13074
+ elixirClustering: "none",
11473
13075
  elixirDeploy: "none",
11474
13076
  elixirLibraries: [],
11475
13077
  aiDocs: []
@@ -11529,6 +13131,20 @@ async function createProjectHandler(input, options = {}) {
11529
13131
  relativePath: currentPathInput,
11530
13132
  versionChannel
11531
13133
  };
13134
+ if (!cliInput.yolo && !isSilent()) {
13135
+ const { changes, adjustments } = resolveCompatibilityAdjustments(config);
13136
+ if (adjustments.length > 0) {
13137
+ config = {
13138
+ ...config,
13139
+ ...changes
13140
+ };
13141
+ cliInput = {
13142
+ ...cliInput,
13143
+ ...changes
13144
+ };
13145
+ reportCompatibilityAdjustments(adjustments);
13146
+ }
13147
+ }
11532
13148
  validateConfigCompatibility(config, providedFlags, cliInput);
11533
13149
  const yesPreflight = validatePreflightConfig(config);
11534
13150
  if (yesPreflight.hasWarnings && !isSilent()) displayPreflightWarnings(yesPreflight);
@@ -11548,6 +13164,20 @@ async function createProjectHandler(input, options = {}) {
11548
13164
  ...await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, currentPathInput),
11549
13165
  versionChannel
11550
13166
  };
13167
+ if (!cliInput.yolo && !isSilent()) {
13168
+ const { changes, adjustments } = resolveCompatibilityAdjustments(config);
13169
+ if (adjustments.length > 0) {
13170
+ config = {
13171
+ ...config,
13172
+ ...changes
13173
+ };
13174
+ cliInput = {
13175
+ ...cliInput,
13176
+ ...changes
13177
+ };
13178
+ reportCompatibilityAdjustments(adjustments);
13179
+ }
13180
+ }
11551
13181
  validateConfigCompatibility(config, providedFlags, cliInput);
11552
13182
  }
11553
13183
  normalizeKotlinJavaSelection(config);
@@ -11811,7 +13441,7 @@ const router = os.router({
11811
13441
  }
11812
13442
  }),
11813
13443
  add: os.meta({ description: "Add addons, deploy targets, or stack capabilities to an existing Better Fullstack project using its bts.jsonc config" }).input(AddCommandInputSchema).handler(async ({ input }) => {
11814
- const { addHandler } = await import("./add-handler-ztNjzoMN.mjs");
13444
+ const { addHandler } = await import("./add-handler-z4NCxoq6.mjs");
11815
13445
  await addHandler(input);
11816
13446
  }),
11817
13447
  history: os.meta({ description: "Show history of scaffolded projects with reproducible commands" }).input(z.object({
@@ -11839,7 +13469,7 @@ const router = os.router({
11839
13469
  ecosystem: z.string().optional().describe("Filter by ecosystem (effect, tanstack, prisma, etc.)"),
11840
13470
  "list-ecosystems": z.boolean().default(false).describe("List available ecosystems")
11841
13471
  })).handler(async ({ input }) => {
11842
- const { updateDepsHandler, showEcosystems } = await import("./update-deps-aD-iQw4U.mjs");
13472
+ const { updateDepsHandler, showEcosystems } = await import("./update-deps-G3FgqBlW.mjs");
11843
13473
  if (input["list-ecosystems"]) {
11844
13474
  showEcosystems();
11845
13475
  return;
@@ -11860,7 +13490,7 @@ const router = os.router({
11860
13490
  })
11861
13491
  ])).handler(async ({ input }) => {
11862
13492
  const [kind, name, options] = input;
11863
- const { genCommand } = await import("./gen-CCClL7Ve.mjs");
13493
+ const { genCommand } = await import("./gen-CQfQU0uZ.mjs");
11864
13494
  await genCommand({
11865
13495
  kind,
11866
13496
  name,
@@ -11878,7 +13508,7 @@ const router = os.router({
11878
13508
  })
11879
13509
  ])).handler(async ({ input }) => {
11880
13510
  const [action, source, options] = input;
11881
- const { registryHandler } = await import("./registry-DSf2CEaU.mjs");
13511
+ const { registryHandler } = await import("./registry-D0JfLCoH.mjs");
11882
13512
  await registryHandler({
11883
13513
  action,
11884
13514
  source,
@@ -11895,7 +13525,7 @@ const router = os.router({
11895
13525
  recordBaseline: z.boolean().optional().default(false).describe("Adopt the current on-disk state as the scaffold baseline (for projects created before the update engine)")
11896
13526
  })])).handler(async ({ input }) => {
11897
13527
  const [projectDir, options] = input;
11898
- const { updateCommand } = await import("./update-DJ8CI5KW.mjs");
13528
+ const { updateCommand } = await import("./update-CnrBdWrh.mjs");
11899
13529
  await updateCommand({
11900
13530
  projectDir,
11901
13531
  ...options
@@ -11907,7 +13537,7 @@ const router = os.router({
11907
13537
  }),
11908
13538
  doctor: os.meta({ description: "Diagnose a scaffolded Better Fullstack project: verify its bts.jsonc, installed dependencies, required env vars, and run ecosystem build/type checks" }).input(ProjectCheckInputSchema).handler(async ({ input }) => {
11909
13539
  const [projectDir, options] = input;
11910
- const { doctorCommand } = await import("./doctor-a4ca3SMd.mjs");
13540
+ const { doctorCommand } = await import("./doctor-LmNs-hDr.mjs");
11911
13541
  await doctorCommand({
11912
13542
  projectDir,
11913
13543
  ...options
@@ -11915,7 +13545,7 @@ const router = os.router({
11915
13545
  }),
11916
13546
  check: os.meta({ description: "Check a scaffolded Better Fullstack project for config, dependency, env, and generated build/type drift" }).input(ProjectCheckInputSchema).handler(async ({ input }) => {
11917
13547
  const [projectDir, options] = input;
11918
- const { doctorCommand } = await import("./doctor-a4ca3SMd.mjs");
13548
+ const { doctorCommand } = await import("./doctor-LmNs-hDr.mjs");
11919
13549
  await doctorCommand({
11920
13550
  projectDir,
11921
13551
  ...options
@@ -11926,7 +13556,7 @@ const router = os.router({
11926
13556
  ecosystem: z.string().optional().describe("Force an ecosystem (typescript, react-native, rust, go, python, java, ...)"),
11927
13557
  json: z.boolean().default(false).describe("Output the recommendation as JSON")
11928
13558
  })).handler(async ({ input }) => {
11929
- const { recommendStackFromBrief } = await import("./mcp-492OkjcS.mjs");
13559
+ const { recommendStackFromBrief } = await import("./mcp-BBammItk.mjs");
11930
13560
  const result = recommendStackFromBrief(input.brief, input.ecosystem);
11931
13561
  if (input.json) {
11932
13562
  log.message(JSON.stringify(result, null, 2));
@@ -12002,7 +13632,7 @@ async function builder() {
12002
13632
  return caller.builder();
12003
13633
  }
12004
13634
  async function add(input, options) {
12005
- const { addHandler } = await import("./add-handler-ztNjzoMN.mjs");
13635
+ const { addHandler } = await import("./add-handler-z4NCxoq6.mjs");
12006
13636
  return addHandler(input, {
12007
13637
  silent: true,
12008
13638
  telemetrySource: options?.telemetrySource ?? "programmatic"