create-better-fullstack 1.5.4 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{addons-setup-Bll5VFJd.mjs → addons-setup-Cgup_RHm.mjs} +138 -101
- package/dist/addons-setup-Cx9DU_sr.mjs +5 -0
- package/dist/{bts-config-BYD8mHt-.mjs → bts-config-B_rZ4_sj.mjs} +30 -68
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +180 -45
- package/dist/index.mjs +2697 -1089
- package/dist/{mcp-CRjipp-w.mjs → mcp-CuEEG8e5.mjs} +1 -1
- package/dist/mcp-entry.mjs +112 -21
- package/dist/virtual.d.mts +1 -1
- package/package.json +24 -9
- package/dist/addons-setup-CWGwxN68.mjs +0 -5
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as __reExport } from "./chunk-CCII7kTE.mjs";
|
|
3
|
-
import { a as DEFAULT_CONFIG, c as getDefaultConfig, i as getLatestCLIVersion, l as getUserPkgManager, n as updateBtsConfig, o as DEFAULT_UI_LIBRARY_BY_FRONTEND, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-
|
|
4
|
-
import { _ as
|
|
3
|
+
import { a as DEFAULT_CONFIG, c as getDefaultConfig, i as getLatestCLIVersion, l as getUserPkgManager, n as updateBtsConfig, o as DEFAULT_UI_LIBRARY_BY_FRONTEND, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-B_rZ4_sj.mjs";
|
|
4
|
+
import { _ as setIsFirstPrompt$1, a as canPromptInteractively, c as CLIError, d as exitWithError, f as handleError, g as runWithContextAsync, h as isSilent, l as UserCancelledError, m as isFirstPrompt, o as getPackageExecutionArgs, p as didLastPromptShowUI, s as addPackageDependency, t as setupAddons, u as exitCancelled, v as setLastPromptShownUI } from "./addons-setup-Cgup_RHm.mjs";
|
|
5
5
|
import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
|
|
6
6
|
import { createRouterClient, os } from "@orpc/server";
|
|
7
7
|
import pc from "picocolors";
|
|
@@ -10,11 +10,11 @@ import z from "zod";
|
|
|
10
10
|
import envPaths from "env-paths";
|
|
11
11
|
import fs from "fs-extra";
|
|
12
12
|
import path from "node:path";
|
|
13
|
+
import { allowedApisForFrontends, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getLocalWebDevPort, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
|
|
13
14
|
import { ECOSYSTEM_GROUPS, EMBEDDED_TEMPLATES, EMBEDDED_TEMPLATES as EMBEDDED_TEMPLATES$1, TEMPLATE_COUNT, VirtualFileSystem, VirtualFileSystem as VirtualFileSystem$1, checkAllVersions, generateCliReport, generateVirtualProject, generateVirtualProject as generateVirtualProject$1, listEcosystems, processAddonTemplates, processAddonsDeps, validatePreflightConfig } from "@better-fullstack/template-generator";
|
|
14
15
|
import gradient from "gradient-string";
|
|
15
16
|
import path$1 from "path";
|
|
16
17
|
import { writeTreeToFilesystem } from "@better-fullstack/template-generator/fs-writer";
|
|
17
|
-
import { allowedApisForFrontends, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getLocalWebDevPort, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
|
|
18
18
|
import consola, { consola as consola$1 } from "consola";
|
|
19
19
|
import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
|
|
20
20
|
import { $, execa } from "execa";
|
|
@@ -354,6 +354,100 @@ var types_exports = {};
|
|
|
354
354
|
import * as import__better_fullstack_types from "@better-fullstack/types";
|
|
355
355
|
__reExport(types_exports, import__better_fullstack_types);
|
|
356
356
|
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/create-command-input.ts
|
|
359
|
+
const CreateCommandOptionsSchema = z.object({
|
|
360
|
+
template: types_exports.TemplateSchema.optional().describe("Use a predefined template"),
|
|
361
|
+
yes: z.boolean().optional().default(false).describe("Use default configuration"),
|
|
362
|
+
yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
|
|
363
|
+
verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
|
|
364
|
+
dryRun: z.boolean().optional().default(false).describe("Preview generated file tree without writing to disk"),
|
|
365
|
+
ecosystem: types_exports.EcosystemSchema.optional().describe("Language ecosystem (typescript, rust, python, go, or java)"),
|
|
366
|
+
database: types_exports.DatabaseSchema.optional(),
|
|
367
|
+
orm: types_exports.ORMSchema.optional(),
|
|
368
|
+
auth: types_exports.AuthSchema.optional(),
|
|
369
|
+
payments: types_exports.PaymentsSchema.optional(),
|
|
370
|
+
email: types_exports.EmailSchema.optional(),
|
|
371
|
+
fileUpload: types_exports.FileUploadSchema.optional(),
|
|
372
|
+
effect: types_exports.EffectSchema.optional(),
|
|
373
|
+
stateManagement: types_exports.StateManagementSchema.optional(),
|
|
374
|
+
validation: types_exports.ValidationSchema.optional(),
|
|
375
|
+
forms: types_exports.FormsSchema.optional(),
|
|
376
|
+
testing: types_exports.TestingSchema.optional(),
|
|
377
|
+
ai: types_exports.AISchema.optional(),
|
|
378
|
+
realtime: types_exports.RealtimeSchema.optional(),
|
|
379
|
+
jobQueue: types_exports.JobQueueSchema.optional(),
|
|
380
|
+
animation: types_exports.AnimationSchema.optional(),
|
|
381
|
+
logging: types_exports.LoggingSchema.optional(),
|
|
382
|
+
observability: types_exports.ObservabilitySchema.optional(),
|
|
383
|
+
featureFlags: types_exports.FeatureFlagsSchema.optional().describe("Feature flags provider"),
|
|
384
|
+
analytics: types_exports.AnalyticsSchema.optional().describe("Privacy-focused analytics"),
|
|
385
|
+
cms: types_exports.CMSSchema.optional().describe("Headless CMS solution"),
|
|
386
|
+
caching: types_exports.CachingSchema.optional().describe("Caching solution"),
|
|
387
|
+
i18n: types_exports.I18nSchema.optional().describe("Internationalization (i18n) library"),
|
|
388
|
+
search: types_exports.SearchSchema.optional().describe("Search engine solution"),
|
|
389
|
+
fileStorage: types_exports.FileStorageSchema.optional().describe("File storage solution (S3, R2)"),
|
|
390
|
+
frontend: z.array(types_exports.FrontendSchema).optional(),
|
|
391
|
+
astroIntegration: types_exports.AstroIntegrationSchema.optional().describe("Astro UI framework integration (react, vue, svelte, solid)"),
|
|
392
|
+
addons: z.array(types_exports.AddonsSchema).optional(),
|
|
393
|
+
examples: z.array(types_exports.ExamplesSchema).optional(),
|
|
394
|
+
git: z.boolean().optional(),
|
|
395
|
+
packageManager: types_exports.PackageManagerSchema.optional(),
|
|
396
|
+
install: z.boolean().optional(),
|
|
397
|
+
versionChannel: types_exports.VersionChannelSchema.optional().describe("Dependency version channel (stable, latest, beta)"),
|
|
398
|
+
dbSetup: types_exports.DatabaseSetupSchema.optional(),
|
|
399
|
+
backend: types_exports.BackendSchema.optional(),
|
|
400
|
+
runtime: types_exports.RuntimeSchema.optional(),
|
|
401
|
+
api: types_exports.APISchema.optional(),
|
|
402
|
+
cssFramework: types_exports.CSSFrameworkSchema.optional(),
|
|
403
|
+
uiLibrary: types_exports.UILibrarySchema.optional(),
|
|
404
|
+
shadcnBase: types_exports.ShadcnBaseSchema.optional().describe("shadcn/ui headless library (radix, base)"),
|
|
405
|
+
shadcnStyle: types_exports.ShadcnStyleSchema.optional().describe("shadcn/ui visual style (vega, nova, maia, lyra, mira)"),
|
|
406
|
+
shadcnIconLibrary: types_exports.ShadcnIconLibrarySchema.optional().describe("shadcn/ui icon library (lucide, tabler, hugeicons, phosphor, remixicon)"),
|
|
407
|
+
shadcnColorTheme: types_exports.ShadcnColorThemeSchema.optional().describe("shadcn/ui color theme (neutral, blue, violet, etc.)"),
|
|
408
|
+
shadcnBaseColor: types_exports.ShadcnBaseColorSchema.optional().describe("shadcn/ui base neutral color (neutral, stone, zinc, gray)"),
|
|
409
|
+
shadcnFont: types_exports.ShadcnFontSchema.optional().describe("shadcn/ui font (inter, geist, figtree, etc.)"),
|
|
410
|
+
shadcnRadius: types_exports.ShadcnRadiusSchema.optional().describe("shadcn/ui border radius (default, none, small, medium, large)"),
|
|
411
|
+
webDeploy: types_exports.WebDeploySchema.optional(),
|
|
412
|
+
serverDeploy: types_exports.ServerDeploySchema.optional(),
|
|
413
|
+
directoryConflict: types_exports.DirectoryConflictSchema.optional(),
|
|
414
|
+
renderTitle: z.boolean().optional(),
|
|
415
|
+
disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
|
|
416
|
+
manualDb: z.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup"),
|
|
417
|
+
rustWebFramework: types_exports.RustWebFrameworkSchema.optional().describe("Rust web framework (axum, actix-web)"),
|
|
418
|
+
rustFrontend: types_exports.RustFrontendSchema.optional().describe("Rust WASM frontend (leptos, dioxus)"),
|
|
419
|
+
rustOrm: types_exports.RustOrmSchema.optional().describe("Rust ORM/database (sea-orm, sqlx)"),
|
|
420
|
+
rustApi: types_exports.RustApiSchema.optional().describe("Rust API layer (tonic, async-graphql)"),
|
|
421
|
+
rustCli: types_exports.RustCliSchema.optional().describe("Rust CLI tools (clap, ratatui)"),
|
|
422
|
+
rustLibraries: z.array(types_exports.RustLibrariesSchema).optional().describe("Rust core libraries"),
|
|
423
|
+
rustLogging: types_exports.RustLoggingSchema.optional().describe("Rust logging (tracing, env-logger)"),
|
|
424
|
+
rustErrorHandling: types_exports.RustErrorHandlingSchema.optional().describe("Rust error handling (anyhow-thiserror, eyre)"),
|
|
425
|
+
rustCaching: types_exports.RustCachingSchema.optional().describe("Rust caching (moka, redis)"),
|
|
426
|
+
rustAuth: types_exports.RustAuthSchema.optional().describe("Rust auth (oauth2)"),
|
|
427
|
+
pythonWebFramework: types_exports.PythonWebFrameworkSchema.optional().describe("Python web framework (fastapi, django)"),
|
|
428
|
+
pythonOrm: types_exports.PythonOrmSchema.optional().describe("Python ORM/database (sqlalchemy, sqlmodel)"),
|
|
429
|
+
pythonValidation: types_exports.PythonValidationSchema.optional().describe("Python validation (pydantic)"),
|
|
430
|
+
pythonAi: z.array(types_exports.PythonAiSchema).optional().describe("Python AI/ML frameworks"),
|
|
431
|
+
pythonAuth: types_exports.PythonAuthSchema.optional().describe("Python auth library (authlib, jwt)"),
|
|
432
|
+
pythonTaskQueue: types_exports.PythonTaskQueueSchema.optional().describe("Python task queue (celery)"),
|
|
433
|
+
pythonGraphql: types_exports.PythonGraphqlSchema.optional().describe("Python GraphQL framework (strawberry)"),
|
|
434
|
+
pythonQuality: types_exports.PythonQualitySchema.optional().describe("Python code quality (ruff)"),
|
|
435
|
+
goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework (gin, echo, fiber)"),
|
|
436
|
+
goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database (gorm, sqlc)"),
|
|
437
|
+
goApi: types_exports.GoApiSchema.optional().describe("Go API layer (grpc-go)"),
|
|
438
|
+
goCli: types_exports.GoCliSchema.optional().describe("Go CLI tools (cobra, bubbletea)"),
|
|
439
|
+
goLogging: types_exports.GoLoggingSchema.optional().describe("Go logging (zap, zerolog, slog)"),
|
|
440
|
+
goAuth: types_exports.GoAuthSchema.optional().describe("Go auth (casbin, jwt)"),
|
|
441
|
+
javaWebFramework: types_exports.JavaWebFrameworkSchema.optional().describe("Java web framework (spring-boot, none)"),
|
|
442
|
+
javaBuildTool: types_exports.JavaBuildToolSchema.optional().describe("Java build tool (maven, gradle, none)"),
|
|
443
|
+
javaOrm: types_exports.JavaOrmSchema.optional().describe("Java ORM/database (spring-data-jpa)"),
|
|
444
|
+
javaAuth: types_exports.JavaAuthSchema.optional().describe("Java auth (spring-security)"),
|
|
445
|
+
javaLibraries: z.array(types_exports.JavaLibrariesSchema).optional().describe("Java application libraries"),
|
|
446
|
+
javaTestingLibraries: z.array(types_exports.JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
|
|
447
|
+
aiDocs: z.array(types_exports.AiDocsSchema).optional().describe("AI documentation files (claude-md, agents-md, cursorrules)")
|
|
448
|
+
});
|
|
449
|
+
const CreateCommandInputSchema = z.tuple([types_exports.ProjectNameSchema.optional(), CreateCommandOptionsSchema]);
|
|
450
|
+
|
|
357
451
|
//#endregion
|
|
358
452
|
//#region src/utils/error-formatter.ts
|
|
359
453
|
function getCategoryTitle(category) {
|
|
@@ -1341,12 +1435,23 @@ async function applyDependencyVersionChannel(projectDir, channel) {
|
|
|
1341
1435
|
|
|
1342
1436
|
//#endregion
|
|
1343
1437
|
//#region src/helpers/core/install-dependencies.ts
|
|
1438
|
+
function getInstallEnvironment(packageManager) {
|
|
1439
|
+
if (packageManager !== "yarn") return;
|
|
1440
|
+
return {
|
|
1441
|
+
YARN_ENABLE_HARDENED_MODE: "0",
|
|
1442
|
+
YARN_ENABLE_IMMUTABLE_INSTALLS: "false"
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1344
1445
|
async function installDependencies({ projectDir, packageManager }) {
|
|
1345
1446
|
const s = spinner();
|
|
1346
1447
|
try {
|
|
1347
1448
|
s.start(`Running ${packageManager} install...`);
|
|
1348
1449
|
await $({
|
|
1349
1450
|
cwd: projectDir,
|
|
1451
|
+
env: {
|
|
1452
|
+
...process.env,
|
|
1453
|
+
...getInstallEnvironment(packageManager)
|
|
1454
|
+
},
|
|
1350
1455
|
stderr: "inherit"
|
|
1351
1456
|
})`${packageManager} install`;
|
|
1352
1457
|
s.stop("Dependencies installed successfully");
|
|
@@ -1397,6 +1502,36 @@ async function runGoModTidy({ projectDir }) {
|
|
|
1397
1502
|
if (error instanceof Error) consola.error(pc.red(`go mod tidy error: ${error.message}`));
|
|
1398
1503
|
}
|
|
1399
1504
|
}
|
|
1505
|
+
async function runMavenTests({ projectDir }) {
|
|
1506
|
+
const s = spinner();
|
|
1507
|
+
const mvnw = process.platform === "win32" ? "mvnw.cmd" : "./mvnw";
|
|
1508
|
+
try {
|
|
1509
|
+
s.start("Running Maven tests...");
|
|
1510
|
+
await $({
|
|
1511
|
+
cwd: projectDir,
|
|
1512
|
+
stderr: "inherit"
|
|
1513
|
+
})`${mvnw} test`;
|
|
1514
|
+
s.stop("Maven tests completed");
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
s.stop(pc.red("Maven tests failed"));
|
|
1517
|
+
if (error instanceof Error) consola.error(pc.red(`Maven test error: ${error.message}`));
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
async function runGradleTests({ projectDir }) {
|
|
1521
|
+
const s = spinner();
|
|
1522
|
+
const gradlew = process.platform === "win32" ? "gradlew.bat" : "./gradlew";
|
|
1523
|
+
try {
|
|
1524
|
+
s.start("Running Gradle tests...");
|
|
1525
|
+
await $({
|
|
1526
|
+
cwd: projectDir,
|
|
1527
|
+
stderr: "inherit"
|
|
1528
|
+
})`${gradlew} test`;
|
|
1529
|
+
s.stop("Gradle tests completed");
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
s.stop(pc.red("Gradle tests failed"));
|
|
1532
|
+
if (error instanceof Error) consola.error(pc.red(`Gradle test error: ${error.message}`));
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1400
1535
|
|
|
1401
1536
|
//#endregion
|
|
1402
1537
|
//#region src/helpers/core/add-handler.ts
|
|
@@ -1535,70 +1670,104 @@ async function collectPackageJsonPaths(projectDir) {
|
|
|
1535
1670
|
return results;
|
|
1536
1671
|
}
|
|
1537
1672
|
|
|
1673
|
+
//#endregion
|
|
1674
|
+
//#region src/prompts/prompt-contract.ts
|
|
1675
|
+
function createStaticSinglePromptResolution(options, initialValue, selectedValue) {
|
|
1676
|
+
return selectedValue !== void 0 ? {
|
|
1677
|
+
shouldPrompt: false,
|
|
1678
|
+
mode: "single",
|
|
1679
|
+
options,
|
|
1680
|
+
autoValue: selectedValue
|
|
1681
|
+
} : {
|
|
1682
|
+
shouldPrompt: true,
|
|
1683
|
+
mode: "single",
|
|
1684
|
+
options,
|
|
1685
|
+
initialValue
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
function createStaticMultiPromptResolution(options, initialValue, selectedValue) {
|
|
1689
|
+
return selectedValue !== void 0 ? {
|
|
1690
|
+
shouldPrompt: false,
|
|
1691
|
+
mode: "multiple",
|
|
1692
|
+
options,
|
|
1693
|
+
autoValue: selectedValue
|
|
1694
|
+
} : {
|
|
1695
|
+
shouldPrompt: true,
|
|
1696
|
+
mode: "multiple",
|
|
1697
|
+
options,
|
|
1698
|
+
initialValue
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1538
1702
|
//#endregion
|
|
1539
1703
|
//#region src/prompts/ai.ts
|
|
1704
|
+
const AI_PROMPT_OPTIONS = [
|
|
1705
|
+
{
|
|
1706
|
+
value: "vercel-ai",
|
|
1707
|
+
label: "Vercel AI SDK",
|
|
1708
|
+
hint: "The AI Toolkit for TypeScript - supports OpenAI, Anthropic, Google, etc."
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
value: "mastra",
|
|
1712
|
+
label: "Mastra",
|
|
1713
|
+
hint: "TypeScript-native AI agent framework with workflows"
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
value: "voltagent",
|
|
1717
|
+
label: "VoltAgent",
|
|
1718
|
+
hint: "AI Agent framework with memory, workflows, and observability"
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
value: "langgraph",
|
|
1722
|
+
label: "LangGraph.js",
|
|
1723
|
+
hint: "Graph-based agent orchestration with stateful workflows"
|
|
1724
|
+
},
|
|
1725
|
+
{
|
|
1726
|
+
value: "openai-agents",
|
|
1727
|
+
label: "OpenAI Agents SDK",
|
|
1728
|
+
hint: "Official multi-agent framework with handoffs and guardrails"
|
|
1729
|
+
},
|
|
1730
|
+
{
|
|
1731
|
+
value: "google-adk",
|
|
1732
|
+
label: "Google ADK",
|
|
1733
|
+
hint: "Code-first agent development kit for building AI agents"
|
|
1734
|
+
},
|
|
1735
|
+
{
|
|
1736
|
+
value: "modelfusion",
|
|
1737
|
+
label: "ModelFusion",
|
|
1738
|
+
hint: "Type-safe AI library for multi-provider text generation"
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
value: "langchain",
|
|
1742
|
+
label: "LangChain",
|
|
1743
|
+
hint: "Build context-aware reasoning applications"
|
|
1744
|
+
},
|
|
1745
|
+
{
|
|
1746
|
+
value: "llamaindex",
|
|
1747
|
+
label: "LlamaIndex",
|
|
1748
|
+
hint: "Data framework for LLM applications"
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
value: "tanstack-ai",
|
|
1752
|
+
label: "TanStack AI",
|
|
1753
|
+
hint: "Unified LLM interface for AI-powered apps (Alpha)"
|
|
1754
|
+
},
|
|
1755
|
+
{
|
|
1756
|
+
value: "none",
|
|
1757
|
+
label: "None",
|
|
1758
|
+
hint: "No AI SDK"
|
|
1759
|
+
}
|
|
1760
|
+
];
|
|
1761
|
+
function resolveAIPrompt(ai) {
|
|
1762
|
+
return createStaticSinglePromptResolution(AI_PROMPT_OPTIONS, "none", ai);
|
|
1763
|
+
}
|
|
1540
1764
|
async function getAIChoice(ai) {
|
|
1541
|
-
|
|
1765
|
+
const resolution = resolveAIPrompt(ai);
|
|
1766
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1542
1767
|
const response = await navigableSelect({
|
|
1543
1768
|
message: "Select AI SDK",
|
|
1544
|
-
options:
|
|
1545
|
-
|
|
1546
|
-
value: "vercel-ai",
|
|
1547
|
-
label: "Vercel AI SDK",
|
|
1548
|
-
hint: "The AI Toolkit for TypeScript - supports OpenAI, Anthropic, Google, etc."
|
|
1549
|
-
},
|
|
1550
|
-
{
|
|
1551
|
-
value: "mastra",
|
|
1552
|
-
label: "Mastra",
|
|
1553
|
-
hint: "TypeScript-native AI agent framework with workflows"
|
|
1554
|
-
},
|
|
1555
|
-
{
|
|
1556
|
-
value: "voltagent",
|
|
1557
|
-
label: "VoltAgent",
|
|
1558
|
-
hint: "AI Agent framework with memory, workflows, and observability"
|
|
1559
|
-
},
|
|
1560
|
-
{
|
|
1561
|
-
value: "langgraph",
|
|
1562
|
-
label: "LangGraph.js",
|
|
1563
|
-
hint: "Graph-based agent orchestration with stateful workflows"
|
|
1564
|
-
},
|
|
1565
|
-
{
|
|
1566
|
-
value: "openai-agents",
|
|
1567
|
-
label: "OpenAI Agents SDK",
|
|
1568
|
-
hint: "Official multi-agent framework with handoffs and guardrails"
|
|
1569
|
-
},
|
|
1570
|
-
{
|
|
1571
|
-
value: "google-adk",
|
|
1572
|
-
label: "Google ADK",
|
|
1573
|
-
hint: "Code-first agent development kit for building AI agents"
|
|
1574
|
-
},
|
|
1575
|
-
{
|
|
1576
|
-
value: "modelfusion",
|
|
1577
|
-
label: "ModelFusion",
|
|
1578
|
-
hint: "Type-safe AI library for multi-provider text generation"
|
|
1579
|
-
},
|
|
1580
|
-
{
|
|
1581
|
-
value: "langchain",
|
|
1582
|
-
label: "LangChain",
|
|
1583
|
-
hint: "Build context-aware reasoning applications"
|
|
1584
|
-
},
|
|
1585
|
-
{
|
|
1586
|
-
value: "llamaindex",
|
|
1587
|
-
label: "LlamaIndex",
|
|
1588
|
-
hint: "Data framework for LLM applications"
|
|
1589
|
-
},
|
|
1590
|
-
{
|
|
1591
|
-
value: "tanstack-ai",
|
|
1592
|
-
label: "TanStack AI",
|
|
1593
|
-
hint: "Unified LLM interface for AI-powered apps (Alpha)"
|
|
1594
|
-
},
|
|
1595
|
-
{
|
|
1596
|
-
value: "none",
|
|
1597
|
-
label: "None",
|
|
1598
|
-
hint: "No AI SDK"
|
|
1599
|
-
}
|
|
1600
|
-
],
|
|
1601
|
-
initialValue: "none"
|
|
1769
|
+
options: resolution.options,
|
|
1770
|
+
initialValue: resolution.initialValue
|
|
1602
1771
|
});
|
|
1603
1772
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1604
1773
|
return response;
|
|
@@ -1642,10 +1811,20 @@ async function getAiDocsChoice(aiDocs) {
|
|
|
1642
1811
|
|
|
1643
1812
|
//#endregion
|
|
1644
1813
|
//#region src/prompts/animation.ts
|
|
1645
|
-
|
|
1646
|
-
if (animation !== void 0) return
|
|
1647
|
-
|
|
1648
|
-
|
|
1814
|
+
function resolveAnimationPrompt(context = {}) {
|
|
1815
|
+
if (context.animation !== void 0) return {
|
|
1816
|
+
shouldPrompt: false,
|
|
1817
|
+
mode: "single",
|
|
1818
|
+
options: [],
|
|
1819
|
+
autoValue: context.animation
|
|
1820
|
+
};
|
|
1821
|
+
const { web } = splitFrontends$1(context.frontends);
|
|
1822
|
+
if (web.length === 0) return {
|
|
1823
|
+
shouldPrompt: false,
|
|
1824
|
+
mode: "single",
|
|
1825
|
+
options: [],
|
|
1826
|
+
autoValue: "none"
|
|
1827
|
+
};
|
|
1649
1828
|
const isReact = web.some((f) => [
|
|
1650
1829
|
"tanstack-router",
|
|
1651
1830
|
"react-router",
|
|
@@ -1684,10 +1863,23 @@ async function getAnimationChoice(animation, frontends) {
|
|
|
1684
1863
|
label: "None",
|
|
1685
1864
|
hint: "Skip animation library setup"
|
|
1686
1865
|
});
|
|
1687
|
-
|
|
1688
|
-
|
|
1866
|
+
return {
|
|
1867
|
+
shouldPrompt: true,
|
|
1868
|
+
mode: "single",
|
|
1689
1869
|
options,
|
|
1690
1870
|
initialValue: "none"
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
async function getAnimationChoice(animation, frontends) {
|
|
1874
|
+
const resolution = resolveAnimationPrompt({
|
|
1875
|
+
animation,
|
|
1876
|
+
frontends
|
|
1877
|
+
});
|
|
1878
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1879
|
+
const response = await navigableSelect({
|
|
1880
|
+
message: "Select animation library",
|
|
1881
|
+
options: resolution.options,
|
|
1882
|
+
initialValue: resolution.initialValue
|
|
1691
1883
|
});
|
|
1692
1884
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1693
1885
|
return response;
|
|
@@ -1695,42 +1887,72 @@ async function getAnimationChoice(animation, frontends) {
|
|
|
1695
1887
|
|
|
1696
1888
|
//#endregion
|
|
1697
1889
|
//#region src/prompts/api.ts
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1890
|
+
const API_PROMPT_OPTION_MAP = {
|
|
1891
|
+
trpc: {
|
|
1892
|
+
value: "trpc",
|
|
1893
|
+
label: "tRPC",
|
|
1894
|
+
hint: "End-to-end typesafe APIs made easy"
|
|
1895
|
+
},
|
|
1896
|
+
orpc: {
|
|
1897
|
+
value: "orpc",
|
|
1898
|
+
label: "oRPC",
|
|
1899
|
+
hint: "End-to-end type-safe APIs that adhere to OpenAPI standards"
|
|
1900
|
+
},
|
|
1901
|
+
"ts-rest": {
|
|
1902
|
+
value: "ts-rest",
|
|
1903
|
+
label: "ts-rest",
|
|
1904
|
+
hint: "RPC-like client, contract, and server implementation for REST APIs"
|
|
1905
|
+
},
|
|
1906
|
+
garph: {
|
|
1907
|
+
value: "garph",
|
|
1908
|
+
label: "Garph",
|
|
1909
|
+
hint: "Fullstack GraphQL framework with end-to-end type safety"
|
|
1910
|
+
},
|
|
1911
|
+
"graphql-yoga": {
|
|
1912
|
+
value: "graphql-yoga",
|
|
1913
|
+
label: "GraphQL Yoga",
|
|
1914
|
+
hint: "Batteries-included GraphQL server with Pothos schema builder"
|
|
1915
|
+
},
|
|
1916
|
+
none: {
|
|
1917
|
+
value: "none",
|
|
1918
|
+
label: "None",
|
|
1919
|
+
hint: "No API layer (e.g. for full-stack frameworks like Next.js with Route Handlers)"
|
|
1920
|
+
}
|
|
1921
|
+
};
|
|
1922
|
+
function resolveApiPrompt(context = {}) {
|
|
1923
|
+
if (context.backend === "convex" || context.backend === "none") return {
|
|
1924
|
+
shouldPrompt: false,
|
|
1925
|
+
mode: "single",
|
|
1926
|
+
options: [],
|
|
1927
|
+
autoValue: "none"
|
|
1928
|
+
};
|
|
1929
|
+
const allowedOptions = allowedApisForFrontends$1(context.frontend ?? [], context.astroIntegration);
|
|
1930
|
+
const options = allowedOptions.map((value) => API_PROMPT_OPTION_MAP[value]);
|
|
1931
|
+
if (context.api !== void 0) return {
|
|
1932
|
+
shouldPrompt: false,
|
|
1933
|
+
mode: "single",
|
|
1934
|
+
options,
|
|
1935
|
+
autoValue: allowedOptions.includes(context.api) ? context.api : allowedOptions[0] ?? "none"
|
|
1936
|
+
};
|
|
1937
|
+
return {
|
|
1938
|
+
shouldPrompt: true,
|
|
1939
|
+
mode: "single",
|
|
1940
|
+
options,
|
|
1941
|
+
initialValue: allowedOptions[0] ?? "none"
|
|
1728
1942
|
};
|
|
1729
|
-
|
|
1943
|
+
}
|
|
1944
|
+
async function getApiChoice(api, frontend, backend, astroIntegration) {
|
|
1945
|
+
const resolution = resolveApiPrompt({
|
|
1946
|
+
api,
|
|
1947
|
+
frontend,
|
|
1948
|
+
backend,
|
|
1949
|
+
astroIntegration
|
|
1950
|
+
});
|
|
1951
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1730
1952
|
const apiType = await navigableSelect({
|
|
1731
1953
|
message: "Select API type",
|
|
1732
|
-
options:
|
|
1733
|
-
initialValue:
|
|
1954
|
+
options: resolution.options,
|
|
1955
|
+
initialValue: resolution.initialValue
|
|
1734
1956
|
});
|
|
1735
1957
|
if (isCancel$1(apiType)) return exitCancelled("Operation cancelled");
|
|
1736
1958
|
return apiType;
|
|
@@ -1738,38 +1960,43 @@ async function getApiChoice(Api, frontend, backend, astroIntegration) {
|
|
|
1738
1960
|
|
|
1739
1961
|
//#endregion
|
|
1740
1962
|
//#region src/prompts/astro-integration.ts
|
|
1963
|
+
const ASTRO_INTEGRATION_PROMPT_OPTIONS = [
|
|
1964
|
+
{
|
|
1965
|
+
value: "react",
|
|
1966
|
+
label: "React",
|
|
1967
|
+
hint: "Full React component support (required for tRPC)"
|
|
1968
|
+
},
|
|
1969
|
+
{
|
|
1970
|
+
value: "vue",
|
|
1971
|
+
label: "Vue",
|
|
1972
|
+
hint: "Vue 3 component support"
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
value: "svelte",
|
|
1976
|
+
label: "Svelte",
|
|
1977
|
+
hint: "Svelte component support"
|
|
1978
|
+
},
|
|
1979
|
+
{
|
|
1980
|
+
value: "solid",
|
|
1981
|
+
label: "Solid",
|
|
1982
|
+
hint: "SolidJS component support"
|
|
1983
|
+
},
|
|
1984
|
+
{
|
|
1985
|
+
value: "none",
|
|
1986
|
+
label: "None",
|
|
1987
|
+
hint: "Astro components only (no client-side JS framework)"
|
|
1988
|
+
}
|
|
1989
|
+
];
|
|
1990
|
+
function resolveAstroIntegrationPrompt(astroIntegration) {
|
|
1991
|
+
return createStaticSinglePromptResolution(ASTRO_INTEGRATION_PROMPT_OPTIONS, "react", astroIntegration);
|
|
1992
|
+
}
|
|
1741
1993
|
async function getAstroIntegrationChoice(astroIntegration) {
|
|
1742
|
-
|
|
1994
|
+
const resolution = resolveAstroIntegrationPrompt(astroIntegration);
|
|
1995
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1743
1996
|
const response = await navigableSelect({
|
|
1744
1997
|
message: "Choose Astro UI framework integration",
|
|
1745
|
-
options:
|
|
1746
|
-
|
|
1747
|
-
value: "react",
|
|
1748
|
-
label: "React",
|
|
1749
|
-
hint: "Full React component support (required for tRPC)"
|
|
1750
|
-
},
|
|
1751
|
-
{
|
|
1752
|
-
value: "vue",
|
|
1753
|
-
label: "Vue",
|
|
1754
|
-
hint: "Vue 3 component support"
|
|
1755
|
-
},
|
|
1756
|
-
{
|
|
1757
|
-
value: "svelte",
|
|
1758
|
-
label: "Svelte",
|
|
1759
|
-
hint: "Svelte component support"
|
|
1760
|
-
},
|
|
1761
|
-
{
|
|
1762
|
-
value: "solid",
|
|
1763
|
-
label: "Solid",
|
|
1764
|
-
hint: "SolidJS component support"
|
|
1765
|
-
},
|
|
1766
|
-
{
|
|
1767
|
-
value: "none",
|
|
1768
|
-
label: "None",
|
|
1769
|
-
hint: "Astro components only (no client-side JS framework)"
|
|
1770
|
-
}
|
|
1771
|
-
],
|
|
1772
|
-
initialValue: "react"
|
|
1998
|
+
options: resolution.options,
|
|
1999
|
+
initialValue: resolution.initialValue
|
|
1773
2000
|
});
|
|
1774
2001
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1775
2002
|
return response;
|
|
@@ -1777,8 +2004,7 @@ async function getAstroIntegrationChoice(astroIntegration) {
|
|
|
1777
2004
|
|
|
1778
2005
|
//#endregion
|
|
1779
2006
|
//#region src/prompts/auth.ts
|
|
1780
|
-
|
|
1781
|
-
if (auth !== void 0) return auth;
|
|
2007
|
+
function resolveAuthPrompt(context = {}) {
|
|
1782
2008
|
const authOptionOrder = [
|
|
1783
2009
|
{ value: "better-auth" },
|
|
1784
2010
|
{ value: "go-better-auth" },
|
|
@@ -1790,23 +2016,49 @@ async function getAuthChoice(auth, backend, frontend, ecosystem = "typescript")
|
|
|
1790
2016
|
{ value: "none" }
|
|
1791
2017
|
];
|
|
1792
2018
|
const supportedOptions = (0, types_exports.getSupportedCapabilityOptions)("auth", {
|
|
1793
|
-
ecosystem,
|
|
1794
|
-
backend,
|
|
1795
|
-
frontend
|
|
2019
|
+
ecosystem: context.ecosystem ?? "typescript",
|
|
2020
|
+
backend: context.backend,
|
|
2021
|
+
frontend: context.frontend
|
|
1796
2022
|
});
|
|
1797
2023
|
const options = authOptionOrder.flatMap(({ value }) => {
|
|
1798
2024
|
const option = supportedOptions.find((candidate) => candidate.id === value);
|
|
1799
|
-
return option ? [
|
|
1800
|
-
});
|
|
1801
|
-
if (options.length === 1 && options[0]?.id === "none") return "none";
|
|
1802
|
-
const response = await navigableSelect({
|
|
1803
|
-
message: "Select authentication provider",
|
|
1804
|
-
options: options.map((option) => ({
|
|
2025
|
+
return option ? [{
|
|
1805
2026
|
value: option.id,
|
|
1806
2027
|
label: option.label,
|
|
1807
2028
|
hint: option.promptHint
|
|
1808
|
-
}
|
|
1809
|
-
|
|
2029
|
+
}] : [];
|
|
2030
|
+
});
|
|
2031
|
+
if (context.auth !== void 0) return {
|
|
2032
|
+
shouldPrompt: false,
|
|
2033
|
+
mode: "single",
|
|
2034
|
+
options,
|
|
2035
|
+
autoValue: context.auth
|
|
2036
|
+
};
|
|
2037
|
+
if (options.length === 1 && options[0]?.value === "none") return {
|
|
2038
|
+
shouldPrompt: false,
|
|
2039
|
+
mode: "single",
|
|
2040
|
+
options,
|
|
2041
|
+
autoValue: "none"
|
|
2042
|
+
};
|
|
2043
|
+
return {
|
|
2044
|
+
shouldPrompt: true,
|
|
2045
|
+
mode: "single",
|
|
2046
|
+
options,
|
|
2047
|
+
initialValue: options.some((option) => option.value === DEFAULT_CONFIG.auth) ? DEFAULT_CONFIG.auth : options.find((option) => option.value !== "none")?.value ?? "none"
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
async function getAuthChoice(auth, backend, frontend, ecosystem = "typescript") {
|
|
2051
|
+
const resolution = resolveAuthPrompt({
|
|
2052
|
+
auth,
|
|
2053
|
+
backend,
|
|
2054
|
+
frontend,
|
|
2055
|
+
ecosystem
|
|
2056
|
+
});
|
|
2057
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2058
|
+
const response = await navigableSelect({
|
|
2059
|
+
message: "Select authentication provider",
|
|
2060
|
+
options: resolution.options,
|
|
2061
|
+
initialValue: resolution.initialValue
|
|
1810
2062
|
});
|
|
1811
2063
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1812
2064
|
return response;
|
|
@@ -1822,67 +2074,108 @@ const FULLSTACK_FRONTENDS = [
|
|
|
1822
2074
|
"svelte",
|
|
1823
2075
|
"solid-start"
|
|
1824
2076
|
];
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid" || f === "solid-start");
|
|
1828
|
-
const hasFullstackFrontend = frontends?.some((f) => FULLSTACK_FRONTENDS.includes(f));
|
|
1829
|
-
const backendOptions = [];
|
|
1830
|
-
if (hasFullstackFrontend) backendOptions.push({
|
|
2077
|
+
const BACKEND_PROMPT_OPTIONS = [
|
|
2078
|
+
{
|
|
1831
2079
|
value: "self",
|
|
1832
2080
|
label: "Self (Fullstack)",
|
|
1833
2081
|
hint: "Use frontend's built-in api routes"
|
|
1834
|
-
}
|
|
1835
|
-
|
|
2082
|
+
},
|
|
2083
|
+
{
|
|
1836
2084
|
value: "hono",
|
|
1837
2085
|
label: "Hono",
|
|
1838
2086
|
hint: "Lightweight, ultrafast web framework"
|
|
1839
|
-
},
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
1840
2089
|
value: "express",
|
|
1841
2090
|
label: "Express",
|
|
1842
2091
|
hint: "Fast, unopinionated, minimalist web framework for Node.js"
|
|
1843
|
-
},
|
|
2092
|
+
},
|
|
2093
|
+
{
|
|
1844
2094
|
value: "fastify",
|
|
1845
2095
|
label: "Fastify",
|
|
1846
2096
|
hint: "Fast, low-overhead web framework for Node.js"
|
|
1847
|
-
},
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
1848
2099
|
value: "elysia",
|
|
1849
2100
|
label: "Elysia",
|
|
1850
2101
|
hint: "Ergonomic web framework for building backend servers"
|
|
1851
|
-
},
|
|
2102
|
+
},
|
|
2103
|
+
{
|
|
1852
2104
|
value: "fets",
|
|
1853
2105
|
label: "feTS",
|
|
1854
2106
|
hint: "TypeScript HTTP Framework with e2e type-safety"
|
|
1855
|
-
},
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
1856
2109
|
value: "nestjs",
|
|
1857
2110
|
label: "NestJS",
|
|
1858
2111
|
hint: "Progressive Node.js framework for scalable applications"
|
|
1859
|
-
},
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
1860
2114
|
value: "adonisjs",
|
|
1861
2115
|
label: "AdonisJS",
|
|
1862
2116
|
hint: "Full-featured MVC framework for Node.js"
|
|
1863
|
-
},
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
1864
2119
|
value: "nitro",
|
|
1865
2120
|
label: "Nitro",
|
|
1866
2121
|
hint: "Universal server framework from UnJS"
|
|
1867
|
-
},
|
|
2122
|
+
},
|
|
2123
|
+
{
|
|
1868
2124
|
value: "encore",
|
|
1869
2125
|
label: "Encore",
|
|
1870
2126
|
hint: "Backend development platform with built-in infrastructure"
|
|
1871
|
-
}
|
|
1872
|
-
|
|
2127
|
+
},
|
|
2128
|
+
{
|
|
1873
2129
|
value: "convex",
|
|
1874
2130
|
label: "Convex",
|
|
1875
2131
|
hint: "Reactive backend-as-a-service platform"
|
|
1876
|
-
}
|
|
1877
|
-
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
1878
2134
|
value: "none",
|
|
1879
2135
|
label: "None",
|
|
1880
2136
|
hint: "No backend server"
|
|
2137
|
+
}
|
|
2138
|
+
];
|
|
2139
|
+
function resolveBackendPrompt(context = {}) {
|
|
2140
|
+
const hasIncompatibleFrontend = context.frontends?.some((frontend) => frontend === "solid" || frontend === "solid-start");
|
|
2141
|
+
const hasFullstackFrontend = context.frontends?.some((frontend) => FULLSTACK_FRONTENDS.includes(frontend));
|
|
2142
|
+
const availableValues = new Set([
|
|
2143
|
+
...hasFullstackFrontend ? ["self"] : [],
|
|
2144
|
+
"hono",
|
|
2145
|
+
"express",
|
|
2146
|
+
"fastify",
|
|
2147
|
+
"elysia",
|
|
2148
|
+
"fets",
|
|
2149
|
+
"nestjs",
|
|
2150
|
+
"adonisjs",
|
|
2151
|
+
"nitro",
|
|
2152
|
+
"encore",
|
|
2153
|
+
...!hasIncompatibleFrontend ? ["convex"] : [],
|
|
2154
|
+
"none"
|
|
2155
|
+
]);
|
|
2156
|
+
const options = BACKEND_PROMPT_OPTIONS.filter((option) => availableValues.has(option.value));
|
|
2157
|
+
return context.backendFramework !== void 0 ? {
|
|
2158
|
+
shouldPrompt: false,
|
|
2159
|
+
mode: "single",
|
|
2160
|
+
options,
|
|
2161
|
+
autoValue: context.backendFramework
|
|
2162
|
+
} : {
|
|
2163
|
+
shouldPrompt: true,
|
|
2164
|
+
mode: "single",
|
|
2165
|
+
options,
|
|
2166
|
+
initialValue: hasFullstackFrontend ? "self" : DEFAULT_CONFIG.backend
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
2170
|
+
const resolution = resolveBackendPrompt({
|
|
2171
|
+
backendFramework,
|
|
2172
|
+
frontends
|
|
1881
2173
|
});
|
|
2174
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1882
2175
|
const response = await navigableSelect({
|
|
1883
2176
|
message: "Select backend",
|
|
1884
|
-
options:
|
|
1885
|
-
initialValue:
|
|
2177
|
+
options: resolution.options,
|
|
2178
|
+
initialValue: resolution.initialValue
|
|
1886
2179
|
});
|
|
1887
2180
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1888
2181
|
return response;
|
|
@@ -1890,21 +2183,44 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
|
1890
2183
|
|
|
1891
2184
|
//#endregion
|
|
1892
2185
|
//#region src/prompts/caching.ts
|
|
2186
|
+
const CACHING_PROMPT_OPTIONS = [{
|
|
2187
|
+
value: "upstash-redis",
|
|
2188
|
+
label: "Upstash Redis",
|
|
2189
|
+
hint: "Serverless Redis with REST API for edge and serverless"
|
|
2190
|
+
}, {
|
|
2191
|
+
value: "none",
|
|
2192
|
+
label: "None",
|
|
2193
|
+
hint: "Skip caching layer setup"
|
|
2194
|
+
}];
|
|
2195
|
+
function resolveCachingPrompt(context = {}) {
|
|
2196
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
2197
|
+
shouldPrompt: false,
|
|
2198
|
+
mode: "single",
|
|
2199
|
+
options: [],
|
|
2200
|
+
autoValue: "none"
|
|
2201
|
+
};
|
|
2202
|
+
return context.caching !== void 0 ? {
|
|
2203
|
+
shouldPrompt: false,
|
|
2204
|
+
mode: "single",
|
|
2205
|
+
options: CACHING_PROMPT_OPTIONS,
|
|
2206
|
+
autoValue: context.caching
|
|
2207
|
+
} : {
|
|
2208
|
+
shouldPrompt: true,
|
|
2209
|
+
mode: "single",
|
|
2210
|
+
options: CACHING_PROMPT_OPTIONS,
|
|
2211
|
+
initialValue: "none"
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
1893
2214
|
async function getCachingChoice(caching, backend) {
|
|
1894
|
-
|
|
1895
|
-
|
|
2215
|
+
const resolution = resolveCachingPrompt({
|
|
2216
|
+
caching,
|
|
2217
|
+
backend
|
|
2218
|
+
});
|
|
2219
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1896
2220
|
const response = await navigableSelect({
|
|
1897
2221
|
message: "Select caching solution",
|
|
1898
|
-
options:
|
|
1899
|
-
|
|
1900
|
-
label: "Upstash Redis",
|
|
1901
|
-
hint: "Serverless Redis with REST API for edge and serverless"
|
|
1902
|
-
}, {
|
|
1903
|
-
value: "none",
|
|
1904
|
-
label: "None",
|
|
1905
|
-
hint: "Skip caching layer setup"
|
|
1906
|
-
}],
|
|
1907
|
-
initialValue: "none"
|
|
2222
|
+
options: resolution.options,
|
|
2223
|
+
initialValue: resolution.initialValue
|
|
1908
2224
|
});
|
|
1909
2225
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1910
2226
|
return response;
|
|
@@ -1912,39 +2228,62 @@ async function getCachingChoice(caching, backend) {
|
|
|
1912
2228
|
|
|
1913
2229
|
//#endregion
|
|
1914
2230
|
//#region src/prompts/cms.ts
|
|
2231
|
+
const CMS_PROMPT_OPTIONS = [
|
|
2232
|
+
{
|
|
2233
|
+
value: "payload",
|
|
2234
|
+
label: "Payload",
|
|
2235
|
+
hint: "TypeScript-first headless CMS with Next.js integration"
|
|
2236
|
+
},
|
|
2237
|
+
{
|
|
2238
|
+
value: "sanity",
|
|
2239
|
+
label: "Sanity",
|
|
2240
|
+
hint: "Real-time collaborative CMS with schema-as-code"
|
|
2241
|
+
},
|
|
2242
|
+
{
|
|
2243
|
+
value: "strapi",
|
|
2244
|
+
label: "Strapi",
|
|
2245
|
+
hint: "Open-source headless CMS with admin panel"
|
|
2246
|
+
},
|
|
2247
|
+
{
|
|
2248
|
+
value: "tinacms",
|
|
2249
|
+
label: "TinaCMS",
|
|
2250
|
+
hint: "Git-backed headless CMS with visual editing"
|
|
2251
|
+
},
|
|
2252
|
+
{
|
|
2253
|
+
value: "none",
|
|
2254
|
+
label: "None",
|
|
2255
|
+
hint: "Skip headless CMS setup"
|
|
2256
|
+
}
|
|
2257
|
+
];
|
|
2258
|
+
function resolveCMSPrompt(context = {}) {
|
|
2259
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
2260
|
+
shouldPrompt: false,
|
|
2261
|
+
mode: "single",
|
|
2262
|
+
options: [],
|
|
2263
|
+
autoValue: "none"
|
|
2264
|
+
};
|
|
2265
|
+
return context.cms !== void 0 ? {
|
|
2266
|
+
shouldPrompt: false,
|
|
2267
|
+
mode: "single",
|
|
2268
|
+
options: CMS_PROMPT_OPTIONS,
|
|
2269
|
+
autoValue: context.cms
|
|
2270
|
+
} : {
|
|
2271
|
+
shouldPrompt: true,
|
|
2272
|
+
mode: "single",
|
|
2273
|
+
options: CMS_PROMPT_OPTIONS,
|
|
2274
|
+
initialValue: "none"
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
1915
2277
|
async function getCMSChoice(cms, backend) {
|
|
1916
|
-
|
|
1917
|
-
|
|
2278
|
+
const resolution = resolveCMSPrompt({
|
|
2279
|
+
cms,
|
|
2280
|
+
backend
|
|
2281
|
+
});
|
|
2282
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
1918
2283
|
const response = await navigableSelect({
|
|
1919
2284
|
message: "Select headless CMS",
|
|
1920
|
-
options:
|
|
1921
|
-
|
|
1922
|
-
value: "payload",
|
|
1923
|
-
label: "Payload",
|
|
1924
|
-
hint: "TypeScript-first headless CMS with Next.js integration"
|
|
1925
|
-
},
|
|
1926
|
-
{
|
|
1927
|
-
value: "sanity",
|
|
1928
|
-
label: "Sanity",
|
|
1929
|
-
hint: "Real-time collaborative CMS with schema-as-code"
|
|
1930
|
-
},
|
|
1931
|
-
{
|
|
1932
|
-
value: "strapi",
|
|
1933
|
-
label: "Strapi",
|
|
1934
|
-
hint: "Open-source headless CMS with admin panel"
|
|
1935
|
-
},
|
|
1936
|
-
{
|
|
1937
|
-
value: "tinacms",
|
|
1938
|
-
label: "TinaCMS",
|
|
1939
|
-
hint: "Git-backed headless CMS with visual editing"
|
|
1940
|
-
},
|
|
1941
|
-
{
|
|
1942
|
-
value: "none",
|
|
1943
|
-
label: "None",
|
|
1944
|
-
hint: "Skip headless CMS setup"
|
|
1945
|
-
}
|
|
1946
|
-
],
|
|
1947
|
-
initialValue: "none"
|
|
2285
|
+
options: resolution.options,
|
|
2286
|
+
initialValue: resolution.initialValue
|
|
1948
2287
|
});
|
|
1949
2288
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1950
2289
|
return response;
|
|
@@ -1974,17 +2313,39 @@ const CSS_FRAMEWORK_OPTIONS = {
|
|
|
1974
2313
|
hint: "Plain CSS without preprocessors"
|
|
1975
2314
|
}
|
|
1976
2315
|
};
|
|
1977
|
-
|
|
1978
|
-
const compatibleFrameworks = getCompatibleCSSFrameworks$1(uiLibrary);
|
|
1979
|
-
if (cssFramework !== void 0) return
|
|
1980
|
-
|
|
1981
|
-
|
|
2316
|
+
function resolveCSSFrameworkPrompt(context = {}) {
|
|
2317
|
+
const compatibleFrameworks = getCompatibleCSSFrameworks$1(context.uiLibrary);
|
|
2318
|
+
if (context.cssFramework !== void 0) return {
|
|
2319
|
+
shouldPrompt: false,
|
|
2320
|
+
mode: "single",
|
|
2321
|
+
options: compatibleFrameworks.map((fw) => ({
|
|
2322
|
+
value: fw,
|
|
2323
|
+
label: CSS_FRAMEWORK_OPTIONS[fw].label,
|
|
2324
|
+
hint: CSS_FRAMEWORK_OPTIONS[fw].hint
|
|
2325
|
+
})),
|
|
2326
|
+
autoValue: compatibleFrameworks.includes(context.cssFramework) ? context.cssFramework : compatibleFrameworks[0]
|
|
2327
|
+
};
|
|
2328
|
+
return {
|
|
2329
|
+
shouldPrompt: true,
|
|
2330
|
+
mode: "single",
|
|
1982
2331
|
options: compatibleFrameworks.map((fw) => ({
|
|
1983
2332
|
value: fw,
|
|
1984
2333
|
label: CSS_FRAMEWORK_OPTIONS[fw].label,
|
|
1985
2334
|
hint: CSS_FRAMEWORK_OPTIONS[fw].hint
|
|
1986
2335
|
})),
|
|
1987
2336
|
initialValue: compatibleFrameworks.includes("tailwind") ? "tailwind" : compatibleFrameworks[0]
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
async function getCSSFrameworkChoice(cssFramework, uiLibrary) {
|
|
2340
|
+
const resolution = resolveCSSFrameworkPrompt({
|
|
2341
|
+
cssFramework,
|
|
2342
|
+
uiLibrary
|
|
2343
|
+
});
|
|
2344
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2345
|
+
const selected = await navigableSelect({
|
|
2346
|
+
message: "Select CSS framework",
|
|
2347
|
+
options: resolution.options,
|
|
2348
|
+
initialValue: resolution.initialValue
|
|
1988
2349
|
});
|
|
1989
2350
|
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
1990
2351
|
return selected;
|
|
@@ -1992,9 +2353,19 @@ async function getCSSFrameworkChoice(cssFramework, uiLibrary) {
|
|
|
1992
2353
|
|
|
1993
2354
|
//#endregion
|
|
1994
2355
|
//#region src/prompts/database.ts
|
|
1995
|
-
|
|
1996
|
-
if (backend === "convex" || backend === "none") return
|
|
1997
|
-
|
|
2356
|
+
function resolveDatabasePrompt(context = {}) {
|
|
2357
|
+
if (context.backend === "convex" || context.backend === "none") return {
|
|
2358
|
+
shouldPrompt: false,
|
|
2359
|
+
mode: "single",
|
|
2360
|
+
options: [],
|
|
2361
|
+
autoValue: "none"
|
|
2362
|
+
};
|
|
2363
|
+
if (context.database !== void 0) return {
|
|
2364
|
+
shouldPrompt: false,
|
|
2365
|
+
mode: "single",
|
|
2366
|
+
options: [],
|
|
2367
|
+
autoValue: context.database
|
|
2368
|
+
};
|
|
1998
2369
|
const databaseOptions = [
|
|
1999
2370
|
{
|
|
2000
2371
|
value: "none",
|
|
@@ -2017,7 +2388,7 @@ async function getDatabaseChoice(database, backend, runtime) {
|
|
|
2017
2388
|
hint: "popular open-source relational database system"
|
|
2018
2389
|
}
|
|
2019
2390
|
];
|
|
2020
|
-
if (runtime !== "workers") {
|
|
2391
|
+
if (context.runtime !== "workers") {
|
|
2021
2392
|
databaseOptions.push({
|
|
2022
2393
|
value: "mongodb",
|
|
2023
2394
|
label: "MongoDB",
|
|
@@ -2034,10 +2405,24 @@ async function getDatabaseChoice(database, backend, runtime) {
|
|
|
2034
2405
|
hint: "in-memory data store for caching, sessions, and real-time features"
|
|
2035
2406
|
});
|
|
2036
2407
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2408
|
+
return {
|
|
2409
|
+
shouldPrompt: true,
|
|
2410
|
+
mode: "single",
|
|
2039
2411
|
options: databaseOptions,
|
|
2040
2412
|
initialValue: DEFAULT_CONFIG.database
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
async function getDatabaseChoice(database, backend, runtime) {
|
|
2416
|
+
const resolution = resolveDatabasePrompt({
|
|
2417
|
+
database,
|
|
2418
|
+
backend,
|
|
2419
|
+
runtime
|
|
2420
|
+
});
|
|
2421
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2422
|
+
const response = await navigableSelect({
|
|
2423
|
+
message: "Select database",
|
|
2424
|
+
options: resolution.options,
|
|
2425
|
+
initialValue: resolution.initialValue
|
|
2041
2426
|
});
|
|
2042
2427
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2043
2428
|
return response;
|
|
@@ -2045,18 +2430,33 @@ async function getDatabaseChoice(database, backend, runtime) {
|
|
|
2045
2430
|
|
|
2046
2431
|
//#endregion
|
|
2047
2432
|
//#region src/prompts/database-setup.ts
|
|
2048
|
-
|
|
2049
|
-
if (backend === "convex") return
|
|
2050
|
-
|
|
2051
|
-
|
|
2433
|
+
function resolveDBSetupPrompt(context) {
|
|
2434
|
+
if (context.backend === "convex") return {
|
|
2435
|
+
shouldPrompt: false,
|
|
2436
|
+
mode: "single",
|
|
2437
|
+
options: [],
|
|
2438
|
+
autoValue: "none"
|
|
2439
|
+
};
|
|
2440
|
+
if (context.dbSetup !== void 0) return {
|
|
2441
|
+
shouldPrompt: false,
|
|
2442
|
+
mode: "single",
|
|
2443
|
+
options: [],
|
|
2444
|
+
autoValue: context.dbSetup
|
|
2445
|
+
};
|
|
2446
|
+
if (context.databaseType === "none") return {
|
|
2447
|
+
shouldPrompt: false,
|
|
2448
|
+
mode: "single",
|
|
2449
|
+
options: [],
|
|
2450
|
+
autoValue: "none"
|
|
2451
|
+
};
|
|
2052
2452
|
let options = [];
|
|
2053
|
-
if (databaseType === "sqlite") options = [
|
|
2453
|
+
if (context.databaseType === "sqlite") options = [
|
|
2054
2454
|
{
|
|
2055
2455
|
value: "turso",
|
|
2056
2456
|
label: "Turso",
|
|
2057
2457
|
hint: "SQLite for Production. Powered by libSQL"
|
|
2058
2458
|
},
|
|
2059
|
-
...runtime === "workers" ? [{
|
|
2459
|
+
...context.runtime === "workers" ? [{
|
|
2060
2460
|
value: "d1",
|
|
2061
2461
|
label: "Cloudflare D1",
|
|
2062
2462
|
hint: "Cloudflare's managed, serverless database with SQLite's SQL semantics"
|
|
@@ -2067,7 +2467,7 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
|
2067
2467
|
hint: "Manual setup"
|
|
2068
2468
|
}
|
|
2069
2469
|
];
|
|
2070
|
-
else if (databaseType === "postgres") options = [
|
|
2470
|
+
else if (context.databaseType === "postgres") options = [
|
|
2071
2471
|
{
|
|
2072
2472
|
value: "neon",
|
|
2073
2473
|
label: "Neon Postgres",
|
|
@@ -2099,7 +2499,7 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
|
2099
2499
|
hint: "Manual setup"
|
|
2100
2500
|
}
|
|
2101
2501
|
];
|
|
2102
|
-
else if (databaseType === "mysql") options = [
|
|
2502
|
+
else if (context.databaseType === "mysql") options = [
|
|
2103
2503
|
{
|
|
2104
2504
|
value: "planetscale",
|
|
2105
2505
|
label: "PlanetScale",
|
|
@@ -2116,7 +2516,7 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
|
2116
2516
|
hint: "Manual setup"
|
|
2117
2517
|
}
|
|
2118
2518
|
];
|
|
2119
|
-
else if (databaseType === "mongodb") options = [
|
|
2519
|
+
else if (context.databaseType === "mongodb") options = [
|
|
2120
2520
|
{
|
|
2121
2521
|
value: "mongodb-atlas",
|
|
2122
2522
|
label: "MongoDB Atlas",
|
|
@@ -2133,7 +2533,7 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
|
2133
2533
|
hint: "Manual setup"
|
|
2134
2534
|
}
|
|
2135
2535
|
];
|
|
2136
|
-
else if (databaseType === "redis") options = [
|
|
2536
|
+
else if (context.databaseType === "redis") options = [
|
|
2137
2537
|
{
|
|
2138
2538
|
value: "upstash",
|
|
2139
2539
|
label: "Upstash",
|
|
@@ -2150,11 +2550,32 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
|
2150
2550
|
hint: "Manual setup"
|
|
2151
2551
|
}
|
|
2152
2552
|
];
|
|
2153
|
-
else return
|
|
2154
|
-
|
|
2155
|
-
|
|
2553
|
+
else return {
|
|
2554
|
+
shouldPrompt: false,
|
|
2555
|
+
mode: "single",
|
|
2556
|
+
options: [],
|
|
2557
|
+
autoValue: "none"
|
|
2558
|
+
};
|
|
2559
|
+
return {
|
|
2560
|
+
shouldPrompt: true,
|
|
2561
|
+
mode: "single",
|
|
2156
2562
|
options,
|
|
2157
2563
|
initialValue: "none"
|
|
2564
|
+
};
|
|
2565
|
+
}
|
|
2566
|
+
async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
|
|
2567
|
+
const resolution = resolveDBSetupPrompt({
|
|
2568
|
+
databaseType,
|
|
2569
|
+
dbSetup,
|
|
2570
|
+
orm: _orm,
|
|
2571
|
+
backend,
|
|
2572
|
+
runtime
|
|
2573
|
+
});
|
|
2574
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2575
|
+
const response = await navigableSelect({
|
|
2576
|
+
message: `Select ${databaseType} setup option`,
|
|
2577
|
+
options: resolution.options,
|
|
2578
|
+
initialValue: resolution.initialValue
|
|
2158
2579
|
});
|
|
2159
2580
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2160
2581
|
return response;
|
|
@@ -2225,60 +2646,82 @@ async function getEffectChoice(effect) {
|
|
|
2225
2646
|
|
|
2226
2647
|
//#endregion
|
|
2227
2648
|
//#region src/prompts/email.ts
|
|
2649
|
+
const EMAIL_PROMPT_OPTIONS = [
|
|
2650
|
+
{
|
|
2651
|
+
value: "resend",
|
|
2652
|
+
label: "Resend",
|
|
2653
|
+
hint: "Email for developers. Includes React Email components."
|
|
2654
|
+
},
|
|
2655
|
+
{
|
|
2656
|
+
value: "react-email",
|
|
2657
|
+
label: "React Email",
|
|
2658
|
+
hint: "Build emails using React components (no sending service)."
|
|
2659
|
+
},
|
|
2660
|
+
{
|
|
2661
|
+
value: "nodemailer",
|
|
2662
|
+
label: "Nodemailer",
|
|
2663
|
+
hint: "Classic Node.js email sending library."
|
|
2664
|
+
},
|
|
2665
|
+
{
|
|
2666
|
+
value: "postmark",
|
|
2667
|
+
label: "Postmark",
|
|
2668
|
+
hint: "Transactional email service with high deliverability."
|
|
2669
|
+
},
|
|
2670
|
+
{
|
|
2671
|
+
value: "sendgrid",
|
|
2672
|
+
label: "SendGrid",
|
|
2673
|
+
hint: "Email delivery and marketing platform by Twilio."
|
|
2674
|
+
},
|
|
2675
|
+
{
|
|
2676
|
+
value: "aws-ses",
|
|
2677
|
+
label: "AWS SES",
|
|
2678
|
+
hint: "Amazon Simple Email Service for scalable email."
|
|
2679
|
+
},
|
|
2680
|
+
{
|
|
2681
|
+
value: "mailgun",
|
|
2682
|
+
label: "Mailgun",
|
|
2683
|
+
hint: "Email API service for sending and tracking emails."
|
|
2684
|
+
},
|
|
2685
|
+
{
|
|
2686
|
+
value: "plunk",
|
|
2687
|
+
label: "Plunk",
|
|
2688
|
+
hint: "Open-source email platform for developers."
|
|
2689
|
+
},
|
|
2690
|
+
{
|
|
2691
|
+
value: "none",
|
|
2692
|
+
label: "None",
|
|
2693
|
+
hint: "No email integration"
|
|
2694
|
+
}
|
|
2695
|
+
];
|
|
2696
|
+
function resolveEmailPrompt(context = {}) {
|
|
2697
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
2698
|
+
shouldPrompt: false,
|
|
2699
|
+
mode: "single",
|
|
2700
|
+
options: [],
|
|
2701
|
+
autoValue: "none"
|
|
2702
|
+
};
|
|
2703
|
+
return context.email !== void 0 ? {
|
|
2704
|
+
shouldPrompt: false,
|
|
2705
|
+
mode: "single",
|
|
2706
|
+
options: EMAIL_PROMPT_OPTIONS,
|
|
2707
|
+
autoValue: context.email
|
|
2708
|
+
} : {
|
|
2709
|
+
shouldPrompt: true,
|
|
2710
|
+
mode: "single",
|
|
2711
|
+
options: EMAIL_PROMPT_OPTIONS,
|
|
2712
|
+
initialValue: DEFAULT_CONFIG.email ?? "none"
|
|
2713
|
+
};
|
|
2714
|
+
}
|
|
2228
2715
|
async function getEmailChoice(email, backend) {
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2716
|
+
const resolution = resolveEmailPrompt({
|
|
2717
|
+
email,
|
|
2718
|
+
backend
|
|
2719
|
+
});
|
|
2720
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2232
2721
|
const response = await navigableSelect({
|
|
2233
2722
|
message: "Select email solution",
|
|
2234
|
-
options:
|
|
2235
|
-
|
|
2236
|
-
value: "resend",
|
|
2237
|
-
label: "Resend",
|
|
2238
|
-
hint: "Email for developers. Includes React Email components."
|
|
2239
|
-
},
|
|
2240
|
-
{
|
|
2241
|
-
value: "react-email",
|
|
2242
|
-
label: "React Email",
|
|
2243
|
-
hint: "Build emails using React components (no sending service)."
|
|
2244
|
-
},
|
|
2245
|
-
{
|
|
2246
|
-
value: "nodemailer",
|
|
2247
|
-
label: "Nodemailer",
|
|
2248
|
-
hint: "Classic Node.js email sending library."
|
|
2249
|
-
},
|
|
2250
|
-
{
|
|
2251
|
-
value: "postmark",
|
|
2252
|
-
label: "Postmark",
|
|
2253
|
-
hint: "Transactional email service with high deliverability."
|
|
2254
|
-
},
|
|
2255
|
-
{
|
|
2256
|
-
value: "sendgrid",
|
|
2257
|
-
label: "SendGrid",
|
|
2258
|
-
hint: "Email delivery and marketing platform by Twilio."
|
|
2259
|
-
},
|
|
2260
|
-
{
|
|
2261
|
-
value: "aws-ses",
|
|
2262
|
-
label: "AWS SES",
|
|
2263
|
-
hint: "Amazon Simple Email Service for scalable email."
|
|
2264
|
-
},
|
|
2265
|
-
{
|
|
2266
|
-
value: "mailgun",
|
|
2267
|
-
label: "Mailgun",
|
|
2268
|
-
hint: "Email API service for sending and tracking emails."
|
|
2269
|
-
},
|
|
2270
|
-
{
|
|
2271
|
-
value: "plunk",
|
|
2272
|
-
label: "Plunk",
|
|
2273
|
-
hint: "Open-source email platform for developers."
|
|
2274
|
-
},
|
|
2275
|
-
{
|
|
2276
|
-
value: "none",
|
|
2277
|
-
label: "None",
|
|
2278
|
-
hint: "No email integration"
|
|
2279
|
-
}
|
|
2280
|
-
],
|
|
2281
|
-
initialValue: DEFAULT_CONFIG.email ?? "none"
|
|
2723
|
+
options: resolution.options,
|
|
2724
|
+
initialValue: resolution.initialValue
|
|
2282
2725
|
});
|
|
2283
2726
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2284
2727
|
return response;
|
|
@@ -2344,34 +2787,57 @@ async function getFileStorageChoice(fileStorage, backend) {
|
|
|
2344
2787
|
|
|
2345
2788
|
//#endregion
|
|
2346
2789
|
//#region src/prompts/file-upload.ts
|
|
2790
|
+
const FILE_UPLOAD_PROMPT_OPTIONS = [
|
|
2791
|
+
{
|
|
2792
|
+
value: "uploadthing",
|
|
2793
|
+
label: "UploadThing",
|
|
2794
|
+
hint: "TypeScript-first file uploads with built-in validation"
|
|
2795
|
+
},
|
|
2796
|
+
{
|
|
2797
|
+
value: "filepond",
|
|
2798
|
+
label: "FilePond",
|
|
2799
|
+
hint: "Flexible file upload with image preview and drag & drop"
|
|
2800
|
+
},
|
|
2801
|
+
{
|
|
2802
|
+
value: "uppy",
|
|
2803
|
+
label: "Uppy",
|
|
2804
|
+
hint: "Modular file uploader with resumable uploads and plugins"
|
|
2805
|
+
},
|
|
2806
|
+
{
|
|
2807
|
+
value: "none",
|
|
2808
|
+
label: "None",
|
|
2809
|
+
hint: "Skip file upload integration"
|
|
2810
|
+
}
|
|
2811
|
+
];
|
|
2812
|
+
function resolveFileUploadPrompt(context = {}) {
|
|
2813
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
2814
|
+
shouldPrompt: false,
|
|
2815
|
+
mode: "single",
|
|
2816
|
+
options: [],
|
|
2817
|
+
autoValue: "none"
|
|
2818
|
+
};
|
|
2819
|
+
return context.fileUpload !== void 0 ? {
|
|
2820
|
+
shouldPrompt: false,
|
|
2821
|
+
mode: "single",
|
|
2822
|
+
options: FILE_UPLOAD_PROMPT_OPTIONS,
|
|
2823
|
+
autoValue: context.fileUpload
|
|
2824
|
+
} : {
|
|
2825
|
+
shouldPrompt: true,
|
|
2826
|
+
mode: "single",
|
|
2827
|
+
options: FILE_UPLOAD_PROMPT_OPTIONS,
|
|
2828
|
+
initialValue: "none"
|
|
2829
|
+
};
|
|
2830
|
+
}
|
|
2347
2831
|
async function getFileUploadChoice(fileUpload, backend) {
|
|
2348
|
-
|
|
2349
|
-
|
|
2832
|
+
const resolution = resolveFileUploadPrompt({
|
|
2833
|
+
fileUpload,
|
|
2834
|
+
backend
|
|
2835
|
+
});
|
|
2836
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2350
2837
|
const response = await navigableSelect({
|
|
2351
2838
|
message: "Select file upload solution",
|
|
2352
|
-
options:
|
|
2353
|
-
|
|
2354
|
-
value: "uploadthing",
|
|
2355
|
-
label: "UploadThing",
|
|
2356
|
-
hint: "TypeScript-first file uploads with built-in validation"
|
|
2357
|
-
},
|
|
2358
|
-
{
|
|
2359
|
-
value: "filepond",
|
|
2360
|
-
label: "FilePond",
|
|
2361
|
-
hint: "Flexible file upload with image preview and drag & drop"
|
|
2362
|
-
},
|
|
2363
|
-
{
|
|
2364
|
-
value: "uppy",
|
|
2365
|
-
label: "Uppy",
|
|
2366
|
-
hint: "Modular file uploader with resumable uploads and plugins"
|
|
2367
|
-
},
|
|
2368
|
-
{
|
|
2369
|
-
value: "none",
|
|
2370
|
-
label: "None",
|
|
2371
|
-
hint: "Skip file upload integration"
|
|
2372
|
-
}
|
|
2373
|
-
],
|
|
2374
|
-
initialValue: "none"
|
|
2839
|
+
options: resolution.options,
|
|
2840
|
+
initialValue: resolution.initialValue
|
|
2375
2841
|
});
|
|
2376
2842
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2377
2843
|
return response;
|
|
@@ -2379,10 +2845,20 @@ async function getFileUploadChoice(fileUpload, backend) {
|
|
|
2379
2845
|
|
|
2380
2846
|
//#endregion
|
|
2381
2847
|
//#region src/prompts/forms.ts
|
|
2382
|
-
|
|
2383
|
-
if (forms !== void 0) return
|
|
2384
|
-
|
|
2385
|
-
|
|
2848
|
+
function resolveFormsPrompt(context = {}) {
|
|
2849
|
+
if (context.forms !== void 0) return {
|
|
2850
|
+
shouldPrompt: false,
|
|
2851
|
+
mode: "single",
|
|
2852
|
+
options: [],
|
|
2853
|
+
autoValue: context.forms
|
|
2854
|
+
};
|
|
2855
|
+
const { web } = splitFrontends$1(context.frontends);
|
|
2856
|
+
if (web.length === 0) return {
|
|
2857
|
+
shouldPrompt: false,
|
|
2858
|
+
mode: "single",
|
|
2859
|
+
options: [],
|
|
2860
|
+
autoValue: "none"
|
|
2861
|
+
};
|
|
2386
2862
|
const isReact = web.some((f) => [
|
|
2387
2863
|
"tanstack-router",
|
|
2388
2864
|
"react-router",
|
|
@@ -2427,10 +2903,23 @@ async function getFormsChoice(forms, frontends) {
|
|
|
2427
2903
|
label: "None",
|
|
2428
2904
|
hint: "Build custom form handling"
|
|
2429
2905
|
});
|
|
2906
|
+
return {
|
|
2907
|
+
shouldPrompt: true,
|
|
2908
|
+
mode: "single",
|
|
2909
|
+
options,
|
|
2910
|
+
initialValue: isReact ? "react-hook-form" : options.find((option) => option.value !== "none")?.value ?? "none"
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
async function getFormsChoice(forms, frontends) {
|
|
2914
|
+
const resolution = resolveFormsPrompt({
|
|
2915
|
+
forms,
|
|
2916
|
+
frontends
|
|
2917
|
+
});
|
|
2918
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2430
2919
|
const response = await navigableSelect({
|
|
2431
2920
|
message: "Select form library",
|
|
2432
|
-
options,
|
|
2433
|
-
initialValue:
|
|
2921
|
+
options: resolution.options,
|
|
2922
|
+
initialValue: resolution.initialValue
|
|
2434
2923
|
});
|
|
2435
2924
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2436
2925
|
return response;
|
|
@@ -2438,8 +2927,119 @@ async function getFormsChoice(forms, frontends) {
|
|
|
2438
2927
|
|
|
2439
2928
|
//#endregion
|
|
2440
2929
|
//#region src/prompts/frontend.ts
|
|
2930
|
+
const WEB_FRONTEND_PROMPT_OPTIONS = [
|
|
2931
|
+
{
|
|
2932
|
+
value: "tanstack-router",
|
|
2933
|
+
label: "TanStack Router",
|
|
2934
|
+
hint: "Modern and scalable routing for React Applications"
|
|
2935
|
+
},
|
|
2936
|
+
{
|
|
2937
|
+
value: "react-router",
|
|
2938
|
+
label: "React Router",
|
|
2939
|
+
hint: "A user-obsessed, standards-focused, multi-strategy router"
|
|
2940
|
+
},
|
|
2941
|
+
{
|
|
2942
|
+
value: "react-vite",
|
|
2943
|
+
label: "React + Vite",
|
|
2944
|
+
hint: "Client-routed React SPA powered by Vite"
|
|
2945
|
+
},
|
|
2946
|
+
{
|
|
2947
|
+
value: "next",
|
|
2948
|
+
label: "Next.js",
|
|
2949
|
+
hint: "The React Framework for the Web"
|
|
2950
|
+
},
|
|
2951
|
+
{
|
|
2952
|
+
value: "nuxt",
|
|
2953
|
+
label: "Nuxt",
|
|
2954
|
+
hint: "The Progressive Web Framework for Vue.js"
|
|
2955
|
+
},
|
|
2956
|
+
{
|
|
2957
|
+
value: "svelte",
|
|
2958
|
+
label: "SvelteKit",
|
|
2959
|
+
hint: "Full-stack Svelte framework with SSR and server routes"
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
value: "solid",
|
|
2963
|
+
label: "Solid",
|
|
2964
|
+
hint: "Simple and performant reactivity for building user interfaces"
|
|
2965
|
+
},
|
|
2966
|
+
{
|
|
2967
|
+
value: "solid-start",
|
|
2968
|
+
label: "SolidStart",
|
|
2969
|
+
hint: "Full-stack Solid framework with SSR and API routes"
|
|
2970
|
+
},
|
|
2971
|
+
{
|
|
2972
|
+
value: "astro",
|
|
2973
|
+
label: "Astro",
|
|
2974
|
+
hint: "Content-focused with Island Architecture"
|
|
2975
|
+
},
|
|
2976
|
+
{
|
|
2977
|
+
value: "tanstack-start",
|
|
2978
|
+
label: "TanStack Start",
|
|
2979
|
+
hint: "SSR, Server Functions, API Routes and more with TanStack Router"
|
|
2980
|
+
},
|
|
2981
|
+
{
|
|
2982
|
+
value: "qwik",
|
|
2983
|
+
label: "Qwik",
|
|
2984
|
+
hint: "Resumable framework with instant load times"
|
|
2985
|
+
},
|
|
2986
|
+
{
|
|
2987
|
+
value: "angular",
|
|
2988
|
+
label: "Angular",
|
|
2989
|
+
hint: "Enterprise-grade TypeScript framework by Google"
|
|
2990
|
+
},
|
|
2991
|
+
{
|
|
2992
|
+
value: "redwood",
|
|
2993
|
+
label: "RedwoodJS",
|
|
2994
|
+
hint: "Opinionated fullstack (React + GraphQL + Prisma)"
|
|
2995
|
+
},
|
|
2996
|
+
{
|
|
2997
|
+
value: "fresh",
|
|
2998
|
+
label: "Fresh",
|
|
2999
|
+
hint: "Deno-native framework with islands architecture"
|
|
3000
|
+
}
|
|
3001
|
+
];
|
|
3002
|
+
const NATIVE_FRONTEND_PROMPT_OPTIONS = [
|
|
3003
|
+
{
|
|
3004
|
+
value: "native-bare",
|
|
3005
|
+
label: "Bare",
|
|
3006
|
+
hint: "Bare Expo without styling library"
|
|
3007
|
+
},
|
|
3008
|
+
{
|
|
3009
|
+
value: "native-uniwind",
|
|
3010
|
+
label: "Uniwind",
|
|
3011
|
+
hint: "Fastest Tailwind bindings for React Native with HeroUI Native"
|
|
3012
|
+
},
|
|
3013
|
+
{
|
|
3014
|
+
value: "native-unistyles",
|
|
3015
|
+
label: "Unistyles",
|
|
3016
|
+
hint: "Consistent styling for React Native"
|
|
3017
|
+
}
|
|
3018
|
+
];
|
|
3019
|
+
function resolveFrontendPrompt(context = {}) {
|
|
3020
|
+
const options = [...WEB_FRONTEND_PROMPT_OPTIONS.filter((option) => isFrontendAllowedWithBackend$1(option.value, context.backend, context.auth)), ...NATIVE_FRONTEND_PROMPT_OPTIONS];
|
|
3021
|
+
return context.frontendOptions !== void 0 ? {
|
|
3022
|
+
shouldPrompt: false,
|
|
3023
|
+
mode: "multiple",
|
|
3024
|
+
options,
|
|
3025
|
+
autoValue: context.frontendOptions
|
|
3026
|
+
} : {
|
|
3027
|
+
shouldPrompt: true,
|
|
3028
|
+
mode: "multiple",
|
|
3029
|
+
options,
|
|
3030
|
+
initialValue: DEFAULT_CONFIG.frontend
|
|
3031
|
+
};
|
|
3032
|
+
}
|
|
2441
3033
|
async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
2442
|
-
|
|
3034
|
+
const resolution = resolveFrontendPrompt({
|
|
3035
|
+
frontendOptions,
|
|
3036
|
+
backend,
|
|
3037
|
+
auth
|
|
3038
|
+
});
|
|
3039
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
|
|
3040
|
+
const allowedValues = new Set(resolution.options.map((option) => option.value));
|
|
3041
|
+
const initialValues = resolution.initialValue ?? DEFAULT_CONFIG.frontend;
|
|
3042
|
+
const initialTypes = [...initialValues.some((value) => WEB_FRONTEND_PROMPT_OPTIONS.some((option) => option.value === value)) ? ["web"] : [], ...initialValues.some((value) => NATIVE_FRONTEND_PROMPT_OPTIONS.some((option) => option.value === value)) ? ["native"] : []];
|
|
2443
3043
|
while (true) {
|
|
2444
3044
|
const wasFirstPrompt = isFirstPrompt();
|
|
2445
3045
|
const frontendTypes = await navigableMultiselect({
|
|
@@ -2454,7 +3054,7 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
|
2454
3054
|
hint: "Create a React Native/Expo app"
|
|
2455
3055
|
}],
|
|
2456
3056
|
required: false,
|
|
2457
|
-
initialValues: ["web"]
|
|
3057
|
+
initialValues: initialTypes.length > 0 ? [...initialTypes] : ["web"]
|
|
2458
3058
|
});
|
|
2459
3059
|
if (isGoBack(frontendTypes)) return GO_BACK_SYMBOL;
|
|
2460
3060
|
if (isCancel$1(frontendTypes)) return exitCancelled("Operation cancelled");
|
|
@@ -2462,81 +3062,12 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
|
2462
3062
|
const result = [];
|
|
2463
3063
|
let shouldRestart = false;
|
|
2464
3064
|
if (frontendTypes.includes("web")) {
|
|
3065
|
+
const webOptions = WEB_FRONTEND_PROMPT_OPTIONS.filter((option) => allowedValues.has(option.value));
|
|
3066
|
+
const initialWebValue = initialValues.find((value) => webOptions.some((option) => option.value === value)) ?? webOptions[0]?.value;
|
|
2465
3067
|
const webFramework = await navigableSelect({
|
|
2466
3068
|
message: "Select web framework",
|
|
2467
|
-
options:
|
|
2468
|
-
|
|
2469
|
-
value: "tanstack-router",
|
|
2470
|
-
label: "TanStack Router",
|
|
2471
|
-
hint: "Modern and scalable routing for React Applications"
|
|
2472
|
-
},
|
|
2473
|
-
{
|
|
2474
|
-
value: "react-router",
|
|
2475
|
-
label: "React Router",
|
|
2476
|
-
hint: "A user‑obsessed, standards‑focused, multi‑strategy router"
|
|
2477
|
-
},
|
|
2478
|
-
{
|
|
2479
|
-
value: "react-vite",
|
|
2480
|
-
label: "React + Vite",
|
|
2481
|
-
hint: "Client-routed React SPA powered by Vite"
|
|
2482
|
-
},
|
|
2483
|
-
{
|
|
2484
|
-
value: "next",
|
|
2485
|
-
label: "Next.js",
|
|
2486
|
-
hint: "The React Framework for the Web"
|
|
2487
|
-
},
|
|
2488
|
-
{
|
|
2489
|
-
value: "nuxt",
|
|
2490
|
-
label: "Nuxt",
|
|
2491
|
-
hint: "The Progressive Web Framework for Vue.js"
|
|
2492
|
-
},
|
|
2493
|
-
{
|
|
2494
|
-
value: "svelte",
|
|
2495
|
-
label: "SvelteKit",
|
|
2496
|
-
hint: "Full-stack Svelte framework with SSR and server routes"
|
|
2497
|
-
},
|
|
2498
|
-
{
|
|
2499
|
-
value: "solid",
|
|
2500
|
-
label: "Solid",
|
|
2501
|
-
hint: "Simple and performant reactivity for building user interfaces"
|
|
2502
|
-
},
|
|
2503
|
-
{
|
|
2504
|
-
value: "solid-start",
|
|
2505
|
-
label: "SolidStart",
|
|
2506
|
-
hint: "Full-stack Solid framework with SSR and API routes"
|
|
2507
|
-
},
|
|
2508
|
-
{
|
|
2509
|
-
value: "astro",
|
|
2510
|
-
label: "Astro",
|
|
2511
|
-
hint: "Content-focused with Island Architecture"
|
|
2512
|
-
},
|
|
2513
|
-
{
|
|
2514
|
-
value: "tanstack-start",
|
|
2515
|
-
label: "TanStack Start",
|
|
2516
|
-
hint: "SSR, Server Functions, API Routes and more with TanStack Router"
|
|
2517
|
-
},
|
|
2518
|
-
{
|
|
2519
|
-
value: "qwik",
|
|
2520
|
-
label: "Qwik",
|
|
2521
|
-
hint: "Resumable framework with instant load times"
|
|
2522
|
-
},
|
|
2523
|
-
{
|
|
2524
|
-
value: "angular",
|
|
2525
|
-
label: "Angular",
|
|
2526
|
-
hint: "Enterprise-grade TypeScript framework by Google"
|
|
2527
|
-
},
|
|
2528
|
-
{
|
|
2529
|
-
value: "redwood",
|
|
2530
|
-
label: "RedwoodJS",
|
|
2531
|
-
hint: "Opinionated fullstack (React + GraphQL + Prisma)"
|
|
2532
|
-
},
|
|
2533
|
-
{
|
|
2534
|
-
value: "fresh",
|
|
2535
|
-
label: "Fresh",
|
|
2536
|
-
hint: "Deno-native framework with islands architecture"
|
|
2537
|
-
}
|
|
2538
|
-
].filter((option) => isFrontendAllowedWithBackend$1(option.value, backend, auth)),
|
|
2539
|
-
initialValue: DEFAULT_CONFIG.frontend[0]
|
|
3069
|
+
options: webOptions,
|
|
3070
|
+
...initialWebValue ? { initialValue: initialWebValue } : {}
|
|
2540
3071
|
});
|
|
2541
3072
|
if (isGoBack(webFramework)) shouldRestart = true;
|
|
2542
3073
|
else if (isCancel$1(webFramework)) return exitCancelled("Operation cancelled");
|
|
@@ -2547,26 +3078,12 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
|
|
|
2547
3078
|
continue;
|
|
2548
3079
|
}
|
|
2549
3080
|
if (frontendTypes.includes("native")) {
|
|
3081
|
+
const nativeOptions = NATIVE_FRONTEND_PROMPT_OPTIONS.filter((option) => allowedValues.has(option.value));
|
|
3082
|
+
const initialNativeValue = initialValues.find((value) => nativeOptions.some((option) => option.value === value)) ?? nativeOptions[0]?.value;
|
|
2550
3083
|
const nativeFramework = await navigableSelect({
|
|
2551
3084
|
message: "Choose native",
|
|
2552
|
-
options:
|
|
2553
|
-
|
|
2554
|
-
value: "native-bare",
|
|
2555
|
-
label: "Bare",
|
|
2556
|
-
hint: "Bare Expo without styling library"
|
|
2557
|
-
},
|
|
2558
|
-
{
|
|
2559
|
-
value: "native-uniwind",
|
|
2560
|
-
label: "Uniwind",
|
|
2561
|
-
hint: "Fastest Tailwind bindings for React Native with HeroUI Native"
|
|
2562
|
-
},
|
|
2563
|
-
{
|
|
2564
|
-
value: "native-unistyles",
|
|
2565
|
-
label: "Unistyles",
|
|
2566
|
-
hint: "Consistent styling for React Native"
|
|
2567
|
-
}
|
|
2568
|
-
],
|
|
2569
|
-
initialValue: "native-bare"
|
|
3085
|
+
options: nativeOptions,
|
|
3086
|
+
...initialNativeValue ? { initialValue: initialNativeValue } : {}
|
|
2570
3087
|
});
|
|
2571
3088
|
if (isGoBack(nativeFramework)) if (frontendTypes.includes("web")) shouldRestart = true;
|
|
2572
3089
|
else {
|
|
@@ -2598,100 +3115,226 @@ async function getGitChoice(git) {
|
|
|
2598
3115
|
|
|
2599
3116
|
//#endregion
|
|
2600
3117
|
//#region src/prompts/go-ecosystem.ts
|
|
3118
|
+
const GO_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
3119
|
+
{
|
|
3120
|
+
value: "gin",
|
|
3121
|
+
label: "Gin",
|
|
3122
|
+
hint: "High-performance HTTP web framework with martini-like API"
|
|
3123
|
+
},
|
|
3124
|
+
{
|
|
3125
|
+
value: "echo",
|
|
3126
|
+
label: "Echo",
|
|
3127
|
+
hint: "High performance, minimalist Go web framework"
|
|
3128
|
+
},
|
|
3129
|
+
{
|
|
3130
|
+
value: "fiber",
|
|
3131
|
+
label: "Fiber",
|
|
3132
|
+
hint: "Express-inspired web framework built on Fasthttp"
|
|
3133
|
+
},
|
|
3134
|
+
{
|
|
3135
|
+
value: "chi",
|
|
3136
|
+
label: "Chi",
|
|
3137
|
+
hint: "Lightweight, zero-dependency router built on net/http"
|
|
3138
|
+
},
|
|
3139
|
+
{
|
|
3140
|
+
value: "none",
|
|
3141
|
+
label: "None",
|
|
3142
|
+
hint: "No web framework"
|
|
3143
|
+
}
|
|
3144
|
+
];
|
|
3145
|
+
const GO_ORM_PROMPT_OPTIONS = [
|
|
3146
|
+
{
|
|
3147
|
+
value: "gorm",
|
|
3148
|
+
label: "GORM",
|
|
3149
|
+
hint: "The fantastic ORM library for Golang"
|
|
3150
|
+
},
|
|
3151
|
+
{
|
|
3152
|
+
value: "sqlc",
|
|
3153
|
+
label: "sqlc",
|
|
3154
|
+
hint: "Generate type-safe Go code from SQL"
|
|
3155
|
+
},
|
|
3156
|
+
{
|
|
3157
|
+
value: "ent",
|
|
3158
|
+
label: "Ent",
|
|
3159
|
+
hint: "Code-first ORM by Meta with graph traversal API, 15k+ stars"
|
|
3160
|
+
},
|
|
3161
|
+
{
|
|
3162
|
+
value: "none",
|
|
3163
|
+
label: "None",
|
|
3164
|
+
hint: "No ORM/database layer"
|
|
3165
|
+
}
|
|
3166
|
+
];
|
|
3167
|
+
const GO_API_PROMPT_OPTIONS = [{
|
|
3168
|
+
value: "grpc-go",
|
|
3169
|
+
label: "gRPC-Go",
|
|
3170
|
+
hint: "The Go implementation of gRPC"
|
|
3171
|
+
}, {
|
|
3172
|
+
value: "none",
|
|
3173
|
+
label: "None",
|
|
3174
|
+
hint: "No API layer"
|
|
3175
|
+
}];
|
|
3176
|
+
const GO_CLI_PROMPT_OPTIONS = [
|
|
3177
|
+
{
|
|
3178
|
+
value: "cobra",
|
|
3179
|
+
label: "Cobra",
|
|
3180
|
+
hint: "Library for creating powerful modern CLI applications"
|
|
3181
|
+
},
|
|
3182
|
+
{
|
|
3183
|
+
value: "bubbletea",
|
|
3184
|
+
label: "Bubble Tea",
|
|
3185
|
+
hint: "Powerful TUI framework based on The Elm Architecture"
|
|
3186
|
+
},
|
|
3187
|
+
{
|
|
3188
|
+
value: "none",
|
|
3189
|
+
label: "None",
|
|
3190
|
+
hint: "No CLI tools"
|
|
3191
|
+
}
|
|
3192
|
+
];
|
|
3193
|
+
const GO_LOGGING_PROMPT_OPTIONS = [
|
|
3194
|
+
{
|
|
3195
|
+
value: "zap",
|
|
3196
|
+
label: "Zap",
|
|
3197
|
+
hint: "Blazing fast, structured, leveled logging in Go"
|
|
3198
|
+
},
|
|
3199
|
+
{
|
|
3200
|
+
value: "zerolog",
|
|
3201
|
+
label: "Zerolog",
|
|
3202
|
+
hint: "Zero-allocation JSON logger, fastest in benchmarks"
|
|
3203
|
+
},
|
|
3204
|
+
{
|
|
3205
|
+
value: "slog",
|
|
3206
|
+
label: "slog",
|
|
3207
|
+
hint: "Go 1.21+ stdlib structured logging (no external dependency)"
|
|
3208
|
+
},
|
|
3209
|
+
{
|
|
3210
|
+
value: "none",
|
|
3211
|
+
label: "None",
|
|
3212
|
+
hint: "No logging library"
|
|
3213
|
+
}
|
|
3214
|
+
];
|
|
3215
|
+
const GO_AUTH_PROMPT_OPTIONS = [
|
|
3216
|
+
{
|
|
3217
|
+
value: "casbin",
|
|
3218
|
+
label: "Casbin",
|
|
3219
|
+
hint: "Model-based authorization (ACL, RBAC, ABAC) via config files"
|
|
3220
|
+
},
|
|
3221
|
+
{
|
|
3222
|
+
value: "jwt",
|
|
3223
|
+
label: "golang-jwt",
|
|
3224
|
+
hint: "JWT token creation and validation with HMAC/RSA/ECDSA signing"
|
|
3225
|
+
},
|
|
3226
|
+
{
|
|
3227
|
+
value: "none",
|
|
3228
|
+
label: "None",
|
|
3229
|
+
hint: "No authentication library"
|
|
3230
|
+
}
|
|
3231
|
+
];
|
|
3232
|
+
function resolveGoWebFrameworkPrompt(goWebFramework) {
|
|
3233
|
+
return createStaticSinglePromptResolution(GO_WEB_FRAMEWORK_PROMPT_OPTIONS, "gin", goWebFramework);
|
|
3234
|
+
}
|
|
2601
3235
|
async function getGoWebFrameworkChoice(goWebFramework) {
|
|
2602
|
-
|
|
3236
|
+
const resolution = resolveGoWebFrameworkPrompt(goWebFramework);
|
|
3237
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2603
3238
|
const response = await navigableSelect({
|
|
2604
3239
|
message: "Select Go web framework",
|
|
2605
|
-
options:
|
|
2606
|
-
|
|
2607
|
-
value: "gin",
|
|
2608
|
-
label: "Gin",
|
|
2609
|
-
hint: "High-performance HTTP web framework with martini-like API"
|
|
2610
|
-
},
|
|
2611
|
-
{
|
|
2612
|
-
value: "echo",
|
|
2613
|
-
label: "Echo",
|
|
2614
|
-
hint: "High performance, minimalist Go web framework"
|
|
2615
|
-
},
|
|
2616
|
-
{
|
|
2617
|
-
value: "fiber",
|
|
2618
|
-
label: "Fiber",
|
|
2619
|
-
hint: "Express-inspired web framework built on Fasthttp"
|
|
2620
|
-
},
|
|
2621
|
-
{
|
|
2622
|
-
value: "none",
|
|
2623
|
-
label: "None",
|
|
2624
|
-
hint: "No web framework"
|
|
2625
|
-
}
|
|
2626
|
-
],
|
|
2627
|
-
initialValue: "gin"
|
|
3240
|
+
options: resolution.options,
|
|
3241
|
+
initialValue: resolution.initialValue
|
|
2628
3242
|
});
|
|
2629
3243
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2630
3244
|
return response;
|
|
2631
3245
|
}
|
|
3246
|
+
function resolveGoOrmPrompt(goOrm) {
|
|
3247
|
+
return createStaticSinglePromptResolution(GO_ORM_PROMPT_OPTIONS, "gorm", goOrm);
|
|
3248
|
+
}
|
|
2632
3249
|
async function getGoOrmChoice(goOrm) {
|
|
2633
|
-
|
|
3250
|
+
const resolution = resolveGoOrmPrompt(goOrm);
|
|
3251
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2634
3252
|
const response = await navigableSelect({
|
|
2635
3253
|
message: "Select Go ORM/database layer",
|
|
2636
|
-
options:
|
|
2637
|
-
|
|
2638
|
-
value: "gorm",
|
|
2639
|
-
label: "GORM",
|
|
2640
|
-
hint: "The fantastic ORM library for Golang"
|
|
2641
|
-
},
|
|
2642
|
-
{
|
|
2643
|
-
value: "sqlc",
|
|
2644
|
-
label: "sqlc",
|
|
2645
|
-
hint: "Generate type-safe Go code from SQL"
|
|
2646
|
-
},
|
|
2647
|
-
{
|
|
2648
|
-
value: "none",
|
|
2649
|
-
label: "None",
|
|
2650
|
-
hint: "No ORM/database layer"
|
|
2651
|
-
}
|
|
2652
|
-
],
|
|
2653
|
-
initialValue: "gorm"
|
|
3254
|
+
options: resolution.options,
|
|
3255
|
+
initialValue: resolution.initialValue
|
|
2654
3256
|
});
|
|
2655
3257
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2656
3258
|
return response;
|
|
2657
3259
|
}
|
|
3260
|
+
function resolveGoApiPrompt(goApi) {
|
|
3261
|
+
return createStaticSinglePromptResolution(GO_API_PROMPT_OPTIONS, "none", goApi);
|
|
3262
|
+
}
|
|
2658
3263
|
async function getGoApiChoice(goApi) {
|
|
2659
|
-
|
|
3264
|
+
const resolution = resolveGoApiPrompt(goApi);
|
|
3265
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2660
3266
|
const response = await navigableSelect({
|
|
2661
3267
|
message: "Select Go API layer",
|
|
2662
|
-
options:
|
|
2663
|
-
|
|
2664
|
-
label: "gRPC-Go",
|
|
2665
|
-
hint: "The Go implementation of gRPC"
|
|
2666
|
-
}, {
|
|
2667
|
-
value: "none",
|
|
2668
|
-
label: "None",
|
|
2669
|
-
hint: "No API layer"
|
|
2670
|
-
}],
|
|
2671
|
-
initialValue: "none"
|
|
3268
|
+
options: resolution.options,
|
|
3269
|
+
initialValue: resolution.initialValue
|
|
2672
3270
|
});
|
|
2673
3271
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2674
3272
|
return response;
|
|
2675
3273
|
}
|
|
3274
|
+
function resolveGoCliPrompt(goCli) {
|
|
3275
|
+
return createStaticSinglePromptResolution(GO_CLI_PROMPT_OPTIONS, "none", goCli);
|
|
3276
|
+
}
|
|
2676
3277
|
async function getGoCliChoice(goCli) {
|
|
2677
|
-
|
|
3278
|
+
const resolution = resolveGoCliPrompt(goCli);
|
|
3279
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2678
3280
|
const response = await navigableSelect({
|
|
2679
3281
|
message: "Select Go CLI tools",
|
|
3282
|
+
options: resolution.options,
|
|
3283
|
+
initialValue: resolution.initialValue
|
|
3284
|
+
});
|
|
3285
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3286
|
+
return response;
|
|
3287
|
+
}
|
|
3288
|
+
function resolveGoLoggingPrompt(goLogging) {
|
|
3289
|
+
return createStaticSinglePromptResolution(GO_LOGGING_PROMPT_OPTIONS, "zap", goLogging);
|
|
3290
|
+
}
|
|
3291
|
+
async function getGoLoggingChoice(goLogging) {
|
|
3292
|
+
const resolution = resolveGoLoggingPrompt(goLogging);
|
|
3293
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3294
|
+
const response = await navigableSelect({
|
|
3295
|
+
message: "Select Go logging library",
|
|
3296
|
+
options: resolution.options,
|
|
3297
|
+
initialValue: resolution.initialValue
|
|
3298
|
+
});
|
|
3299
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3300
|
+
return response;
|
|
3301
|
+
}
|
|
3302
|
+
function resolveGoAuthPrompt(goAuth) {
|
|
3303
|
+
return createStaticSinglePromptResolution(GO_AUTH_PROMPT_OPTIONS, "none", goAuth);
|
|
3304
|
+
}
|
|
3305
|
+
async function getGoAuthChoice(goAuth) {
|
|
3306
|
+
const resolution = resolveGoAuthPrompt(goAuth);
|
|
3307
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3308
|
+
const response = await navigableSelect({
|
|
3309
|
+
message: "Select Go authentication library",
|
|
3310
|
+
options: resolution.options,
|
|
3311
|
+
initialValue: resolution.initialValue
|
|
3312
|
+
});
|
|
3313
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3314
|
+
return response;
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3317
|
+
//#endregion
|
|
3318
|
+
//#region src/prompts/i18n.ts
|
|
3319
|
+
async function getI18nChoice(i18n, frontend) {
|
|
3320
|
+
if (i18n !== void 0) return i18n;
|
|
3321
|
+
const response = await navigableSelect({
|
|
3322
|
+
message: "Select internationalization (i18n) library",
|
|
2680
3323
|
options: [
|
|
2681
3324
|
{
|
|
2682
|
-
value: "
|
|
2683
|
-
label: "
|
|
2684
|
-
hint: "
|
|
2685
|
-
},
|
|
2686
|
-
{
|
|
2687
|
-
value: "bubbletea",
|
|
2688
|
-
label: "Bubble Tea",
|
|
2689
|
-
hint: "Powerful TUI framework based on The Elm Architecture"
|
|
3325
|
+
value: "i18next",
|
|
3326
|
+
label: "i18next",
|
|
3327
|
+
hint: "Full-featured i18n framework, works with all frontends"
|
|
2690
3328
|
},
|
|
3329
|
+
...frontend?.includes("next") ?? false ? [{
|
|
3330
|
+
value: "next-intl",
|
|
3331
|
+
label: "next-intl",
|
|
3332
|
+
hint: "Lightweight i18n for Next.js with App Router support"
|
|
3333
|
+
}] : [],
|
|
2691
3334
|
{
|
|
2692
3335
|
value: "none",
|
|
2693
3336
|
label: "None",
|
|
2694
|
-
hint: "No
|
|
3337
|
+
hint: "No internationalization setup"
|
|
2695
3338
|
}
|
|
2696
3339
|
],
|
|
2697
3340
|
initialValue: "none"
|
|
@@ -2699,24 +3342,6 @@ async function getGoCliChoice(goCli) {
|
|
|
2699
3342
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2700
3343
|
return response;
|
|
2701
3344
|
}
|
|
2702
|
-
async function getGoLoggingChoice(goLogging) {
|
|
2703
|
-
if (goLogging !== void 0) return goLogging;
|
|
2704
|
-
const response = await navigableSelect({
|
|
2705
|
-
message: "Select Go logging library",
|
|
2706
|
-
options: [{
|
|
2707
|
-
value: "zap",
|
|
2708
|
-
label: "Zap",
|
|
2709
|
-
hint: "Blazing fast, structured, leveled logging in Go"
|
|
2710
|
-
}, {
|
|
2711
|
-
value: "none",
|
|
2712
|
-
label: "None",
|
|
2713
|
-
hint: "No logging library"
|
|
2714
|
-
}],
|
|
2715
|
-
initialValue: "zap"
|
|
2716
|
-
});
|
|
2717
|
-
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2718
|
-
return response;
|
|
2719
|
-
}
|
|
2720
3345
|
|
|
2721
3346
|
//#endregion
|
|
2722
3347
|
//#region src/utils/command-exists.ts
|
|
@@ -2731,7 +3356,7 @@ async function commandExists(command) {
|
|
|
2731
3356
|
|
|
2732
3357
|
//#endregion
|
|
2733
3358
|
//#region src/prompts/install.ts
|
|
2734
|
-
async function getinstallChoice(install, ecosystem) {
|
|
3359
|
+
async function getinstallChoice(install, ecosystem, javaBuildTool) {
|
|
2735
3360
|
if (install !== void 0) return install;
|
|
2736
3361
|
if (ecosystem === "rust") {
|
|
2737
3362
|
if (!await commandExists("cargo")) {
|
|
@@ -2769,6 +3394,22 @@ async function getinstallChoice(install, ecosystem) {
|
|
|
2769
3394
|
if (isCancel$1(response$1)) return exitCancelled("Operation cancelled");
|
|
2770
3395
|
return response$1;
|
|
2771
3396
|
}
|
|
3397
|
+
if (ecosystem === "java") {
|
|
3398
|
+
if (!await commandExists("java")) {
|
|
3399
|
+
log.warn("Java is not installed. Please install a JDK from https://adoptium.net/ or your preferred vendor.");
|
|
3400
|
+
return false;
|
|
3401
|
+
}
|
|
3402
|
+
if (javaBuildTool === "none") {
|
|
3403
|
+
log.warn("No Java build tool selected. Skipping Java install verification.");
|
|
3404
|
+
return false;
|
|
3405
|
+
}
|
|
3406
|
+
const response$1 = await navigableConfirm({
|
|
3407
|
+
message: `Run ${javaBuildTool === "gradle" ? "./gradlew test" : "./mvnw test"}?`,
|
|
3408
|
+
initialValue: DEFAULT_CONFIG.install
|
|
3409
|
+
});
|
|
3410
|
+
if (isCancel$1(response$1)) return exitCancelled("Operation cancelled");
|
|
3411
|
+
return response$1;
|
|
3412
|
+
}
|
|
2772
3413
|
const response = await navigableConfirm({
|
|
2773
3414
|
message: "Install dependencies?",
|
|
2774
3415
|
initialValue: DEFAULT_CONFIG.install
|
|
@@ -2777,41 +3418,243 @@ async function getinstallChoice(install, ecosystem) {
|
|
|
2777
3418
|
return response;
|
|
2778
3419
|
}
|
|
2779
3420
|
|
|
3421
|
+
//#endregion
|
|
3422
|
+
//#region src/prompts/java-ecosystem.ts
|
|
3423
|
+
const JAVA_WEB_FRAMEWORK_PROMPT_OPTIONS = [{
|
|
3424
|
+
value: "spring-boot",
|
|
3425
|
+
label: "Spring Boot",
|
|
3426
|
+
hint: "Production-grade Java framework with embedded server and auto-configuration"
|
|
3427
|
+
}, {
|
|
3428
|
+
value: "none",
|
|
3429
|
+
label: "None",
|
|
3430
|
+
hint: "No Java web framework"
|
|
3431
|
+
}];
|
|
3432
|
+
const JAVA_BUILD_TOOL_PROMPT_OPTIONS = [
|
|
3433
|
+
{
|
|
3434
|
+
value: "maven",
|
|
3435
|
+
label: "Maven",
|
|
3436
|
+
hint: "Convention-based build tool with Maven Wrapper support"
|
|
3437
|
+
},
|
|
3438
|
+
{
|
|
3439
|
+
value: "gradle",
|
|
3440
|
+
label: "Gradle",
|
|
3441
|
+
hint: "Flexible build tool with Gradle Wrapper support"
|
|
3442
|
+
},
|
|
3443
|
+
{
|
|
3444
|
+
value: "none",
|
|
3445
|
+
label: "None",
|
|
3446
|
+
hint: "No Java build tool"
|
|
3447
|
+
}
|
|
3448
|
+
];
|
|
3449
|
+
const JAVA_ORM_PROMPT_OPTIONS = [{
|
|
3450
|
+
value: "spring-data-jpa",
|
|
3451
|
+
label: "Spring Data JPA",
|
|
3452
|
+
hint: "Repository abstraction built on JPA/Hibernate"
|
|
3453
|
+
}, {
|
|
3454
|
+
value: "none",
|
|
3455
|
+
label: "None",
|
|
3456
|
+
hint: "No Java ORM/database layer"
|
|
3457
|
+
}];
|
|
3458
|
+
const JAVA_AUTH_PROMPT_OPTIONS = [{
|
|
3459
|
+
value: "spring-security",
|
|
3460
|
+
label: "Spring Security",
|
|
3461
|
+
hint: "Authentication and authorization for Spring applications"
|
|
3462
|
+
}, {
|
|
3463
|
+
value: "none",
|
|
3464
|
+
label: "None",
|
|
3465
|
+
hint: "No Java authentication library"
|
|
3466
|
+
}];
|
|
3467
|
+
const JAVA_TESTING_LIBRARY_PROMPT_OPTIONS = [
|
|
3468
|
+
{
|
|
3469
|
+
value: "junit5",
|
|
3470
|
+
label: "JUnit 5",
|
|
3471
|
+
hint: "Modern Java unit testing platform"
|
|
3472
|
+
},
|
|
3473
|
+
{
|
|
3474
|
+
value: "mockito",
|
|
3475
|
+
label: "Mockito",
|
|
3476
|
+
hint: "Mocking framework for isolated unit tests"
|
|
3477
|
+
},
|
|
3478
|
+
{
|
|
3479
|
+
value: "testcontainers",
|
|
3480
|
+
label: "Testcontainers",
|
|
3481
|
+
hint: "Disposable Docker-based integration tests"
|
|
3482
|
+
},
|
|
3483
|
+
{
|
|
3484
|
+
value: "none",
|
|
3485
|
+
label: "None",
|
|
3486
|
+
hint: "No extra testing libraries"
|
|
3487
|
+
}
|
|
3488
|
+
];
|
|
3489
|
+
const JAVA_LIBRARY_PROMPT_OPTIONS = [
|
|
3490
|
+
{
|
|
3491
|
+
value: "spring-actuator",
|
|
3492
|
+
label: "Spring Actuator",
|
|
3493
|
+
hint: "Production health, metrics, and diagnostics endpoints"
|
|
3494
|
+
},
|
|
3495
|
+
{
|
|
3496
|
+
value: "spring-validation",
|
|
3497
|
+
label: "Spring Validation",
|
|
3498
|
+
hint: "Bean validation for request and entity constraints"
|
|
3499
|
+
},
|
|
3500
|
+
{
|
|
3501
|
+
value: "flyway",
|
|
3502
|
+
label: "Flyway",
|
|
3503
|
+
hint: "Versioned SQL database migrations for JPA-backed apps"
|
|
3504
|
+
},
|
|
3505
|
+
{
|
|
3506
|
+
value: "none",
|
|
3507
|
+
label: "None",
|
|
3508
|
+
hint: "No extra Java libraries"
|
|
3509
|
+
}
|
|
3510
|
+
];
|
|
3511
|
+
function resolveJavaWebFrameworkPrompt(javaWebFramework) {
|
|
3512
|
+
return createStaticSinglePromptResolution(JAVA_WEB_FRAMEWORK_PROMPT_OPTIONS, "spring-boot", javaWebFramework);
|
|
3513
|
+
}
|
|
3514
|
+
async function getJavaWebFrameworkChoice(javaWebFramework) {
|
|
3515
|
+
const resolution = resolveJavaWebFrameworkPrompt(javaWebFramework);
|
|
3516
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3517
|
+
const response = await navigableSelect({
|
|
3518
|
+
message: "Select Java web framework",
|
|
3519
|
+
options: resolution.options,
|
|
3520
|
+
initialValue: resolution.initialValue
|
|
3521
|
+
});
|
|
3522
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3523
|
+
return response;
|
|
3524
|
+
}
|
|
3525
|
+
function resolveJavaBuildToolPrompt(javaBuildTool) {
|
|
3526
|
+
return createStaticSinglePromptResolution(JAVA_BUILD_TOOL_PROMPT_OPTIONS, "maven", javaBuildTool);
|
|
3527
|
+
}
|
|
3528
|
+
async function getJavaBuildToolChoice(javaBuildTool) {
|
|
3529
|
+
const resolution = resolveJavaBuildToolPrompt(javaBuildTool);
|
|
3530
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3531
|
+
const response = await navigableSelect({
|
|
3532
|
+
message: "Select Java build tool",
|
|
3533
|
+
options: resolution.options,
|
|
3534
|
+
initialValue: resolution.initialValue
|
|
3535
|
+
});
|
|
3536
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3537
|
+
return response;
|
|
3538
|
+
}
|
|
3539
|
+
function resolveJavaOrmPrompt(javaOrm) {
|
|
3540
|
+
return createStaticSinglePromptResolution(JAVA_ORM_PROMPT_OPTIONS, "none", javaOrm);
|
|
3541
|
+
}
|
|
3542
|
+
async function getJavaOrmChoice(javaOrm) {
|
|
3543
|
+
const resolution = resolveJavaOrmPrompt(javaOrm);
|
|
3544
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3545
|
+
const response = await navigableSelect({
|
|
3546
|
+
message: "Select Java ORM/database layer",
|
|
3547
|
+
options: resolution.options,
|
|
3548
|
+
initialValue: resolution.initialValue
|
|
3549
|
+
});
|
|
3550
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3551
|
+
return response;
|
|
3552
|
+
}
|
|
3553
|
+
function resolveJavaAuthPrompt(javaAuth) {
|
|
3554
|
+
return createStaticSinglePromptResolution(JAVA_AUTH_PROMPT_OPTIONS, "none", javaAuth);
|
|
3555
|
+
}
|
|
3556
|
+
async function getJavaAuthChoice(javaAuth) {
|
|
3557
|
+
const resolution = resolveJavaAuthPrompt(javaAuth);
|
|
3558
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3559
|
+
const response = await navigableSelect({
|
|
3560
|
+
message: "Select Java authentication library",
|
|
3561
|
+
options: resolution.options,
|
|
3562
|
+
initialValue: resolution.initialValue
|
|
3563
|
+
});
|
|
3564
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3565
|
+
return response;
|
|
3566
|
+
}
|
|
3567
|
+
function resolveJavaLibrariesPrompt(javaLibraries) {
|
|
3568
|
+
return createStaticMultiPromptResolution(JAVA_LIBRARY_PROMPT_OPTIONS, [], javaLibraries);
|
|
3569
|
+
}
|
|
3570
|
+
async function getJavaLibrariesChoice(javaLibraries) {
|
|
3571
|
+
const resolution = resolveJavaLibrariesPrompt(javaLibraries);
|
|
3572
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
|
|
3573
|
+
const response = await navigableMultiselect({
|
|
3574
|
+
message: "Select Java application libraries",
|
|
3575
|
+
options: resolution.options,
|
|
3576
|
+
required: false,
|
|
3577
|
+
initialValues: resolution.initialValue
|
|
3578
|
+
});
|
|
3579
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3580
|
+
if (response.includes("none")) return [];
|
|
3581
|
+
return response;
|
|
3582
|
+
}
|
|
3583
|
+
function resolveJavaTestingLibrariesPrompt(javaTestingLibraries) {
|
|
3584
|
+
return createStaticMultiPromptResolution(JAVA_TESTING_LIBRARY_PROMPT_OPTIONS, ["junit5"], javaTestingLibraries);
|
|
3585
|
+
}
|
|
3586
|
+
async function getJavaTestingLibrariesChoice(javaTestingLibraries) {
|
|
3587
|
+
const resolution = resolveJavaTestingLibrariesPrompt(javaTestingLibraries);
|
|
3588
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
|
|
3589
|
+
const response = await navigableMultiselect({
|
|
3590
|
+
message: "Select Java testing libraries",
|
|
3591
|
+
options: resolution.options,
|
|
3592
|
+
required: false,
|
|
3593
|
+
initialValues: resolution.initialValue
|
|
3594
|
+
});
|
|
3595
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3596
|
+
if (response.includes("none")) return [];
|
|
3597
|
+
return response;
|
|
3598
|
+
}
|
|
3599
|
+
|
|
2780
3600
|
//#endregion
|
|
2781
3601
|
//#region src/prompts/job-queue.ts
|
|
3602
|
+
const JOB_QUEUE_PROMPT_OPTIONS = [
|
|
3603
|
+
{
|
|
3604
|
+
value: "bullmq",
|
|
3605
|
+
label: "BullMQ",
|
|
3606
|
+
hint: "Redis-backed job queue for background tasks and scheduling"
|
|
3607
|
+
},
|
|
3608
|
+
{
|
|
3609
|
+
value: "trigger-dev",
|
|
3610
|
+
label: "Trigger.dev",
|
|
3611
|
+
hint: "Background jobs as code with serverless execution"
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
value: "inngest",
|
|
3615
|
+
label: "Inngest",
|
|
3616
|
+
hint: "Event-driven functions with built-in queuing and scheduling"
|
|
3617
|
+
},
|
|
3618
|
+
{
|
|
3619
|
+
value: "temporal",
|
|
3620
|
+
label: "Temporal",
|
|
3621
|
+
hint: "Durable workflow orchestration for reliable distributed systems"
|
|
3622
|
+
},
|
|
3623
|
+
{
|
|
3624
|
+
value: "none",
|
|
3625
|
+
label: "None",
|
|
3626
|
+
hint: "Skip job queue/background worker setup"
|
|
3627
|
+
}
|
|
3628
|
+
];
|
|
3629
|
+
function resolveJobQueuePrompt(context = {}) {
|
|
3630
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
3631
|
+
shouldPrompt: false,
|
|
3632
|
+
mode: "single",
|
|
3633
|
+
options: [],
|
|
3634
|
+
autoValue: "none"
|
|
3635
|
+
};
|
|
3636
|
+
return context.jobQueue !== void 0 ? {
|
|
3637
|
+
shouldPrompt: false,
|
|
3638
|
+
mode: "single",
|
|
3639
|
+
options: JOB_QUEUE_PROMPT_OPTIONS,
|
|
3640
|
+
autoValue: context.jobQueue
|
|
3641
|
+
} : {
|
|
3642
|
+
shouldPrompt: true,
|
|
3643
|
+
mode: "single",
|
|
3644
|
+
options: JOB_QUEUE_PROMPT_OPTIONS,
|
|
3645
|
+
initialValue: "none"
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
2782
3648
|
async function getJobQueueChoice(jobQueue, backend) {
|
|
2783
|
-
|
|
2784
|
-
|
|
3649
|
+
const resolution = resolveJobQueuePrompt({
|
|
3650
|
+
jobQueue,
|
|
3651
|
+
backend
|
|
3652
|
+
});
|
|
3653
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2785
3654
|
const response = await navigableSelect({
|
|
2786
3655
|
message: "Select job queue solution",
|
|
2787
|
-
options:
|
|
2788
|
-
|
|
2789
|
-
value: "bullmq",
|
|
2790
|
-
label: "BullMQ",
|
|
2791
|
-
hint: "Redis-backed job queue for background tasks and scheduling"
|
|
2792
|
-
},
|
|
2793
|
-
{
|
|
2794
|
-
value: "trigger-dev",
|
|
2795
|
-
label: "Trigger.dev",
|
|
2796
|
-
hint: "Background jobs as code with serverless execution"
|
|
2797
|
-
},
|
|
2798
|
-
{
|
|
2799
|
-
value: "inngest",
|
|
2800
|
-
label: "Inngest",
|
|
2801
|
-
hint: "Event-driven functions with built-in queuing and scheduling"
|
|
2802
|
-
},
|
|
2803
|
-
{
|
|
2804
|
-
value: "temporal",
|
|
2805
|
-
label: "Temporal",
|
|
2806
|
-
hint: "Durable workflow orchestration for reliable distributed systems"
|
|
2807
|
-
},
|
|
2808
|
-
{
|
|
2809
|
-
value: "none",
|
|
2810
|
-
label: "None",
|
|
2811
|
-
hint: "Skip job queue/background worker setup"
|
|
2812
|
-
}
|
|
2813
|
-
],
|
|
2814
|
-
initialValue: "none"
|
|
3656
|
+
options: resolution.options,
|
|
3657
|
+
initialValue: resolution.initialValue
|
|
2815
3658
|
});
|
|
2816
3659
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2817
3660
|
return response;
|
|
@@ -2819,29 +3662,52 @@ async function getJobQueueChoice(jobQueue, backend) {
|
|
|
2819
3662
|
|
|
2820
3663
|
//#endregion
|
|
2821
3664
|
//#region src/prompts/logging.ts
|
|
3665
|
+
const LOGGING_PROMPT_OPTIONS = [
|
|
3666
|
+
{
|
|
3667
|
+
value: "pino",
|
|
3668
|
+
label: "Pino",
|
|
3669
|
+
hint: "Fast JSON logger with minimal overhead"
|
|
3670
|
+
},
|
|
3671
|
+
{
|
|
3672
|
+
value: "winston",
|
|
3673
|
+
label: "Winston",
|
|
3674
|
+
hint: "Flexible logging library with multiple transports"
|
|
3675
|
+
},
|
|
3676
|
+
{
|
|
3677
|
+
value: "none",
|
|
3678
|
+
label: "None",
|
|
3679
|
+
hint: "Skip logging framework setup"
|
|
3680
|
+
}
|
|
3681
|
+
];
|
|
3682
|
+
function resolveLoggingPrompt(context = {}) {
|
|
3683
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
3684
|
+
shouldPrompt: false,
|
|
3685
|
+
mode: "single",
|
|
3686
|
+
options: [],
|
|
3687
|
+
autoValue: "none"
|
|
3688
|
+
};
|
|
3689
|
+
return context.logging !== void 0 ? {
|
|
3690
|
+
shouldPrompt: false,
|
|
3691
|
+
mode: "single",
|
|
3692
|
+
options: LOGGING_PROMPT_OPTIONS,
|
|
3693
|
+
autoValue: context.logging
|
|
3694
|
+
} : {
|
|
3695
|
+
shouldPrompt: true,
|
|
3696
|
+
mode: "single",
|
|
3697
|
+
options: LOGGING_PROMPT_OPTIONS,
|
|
3698
|
+
initialValue: "none"
|
|
3699
|
+
};
|
|
3700
|
+
}
|
|
2822
3701
|
async function getLoggingChoice(logging, backend) {
|
|
2823
|
-
|
|
2824
|
-
|
|
3702
|
+
const resolution = resolveLoggingPrompt({
|
|
3703
|
+
logging,
|
|
3704
|
+
backend
|
|
3705
|
+
});
|
|
3706
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2825
3707
|
const response = await navigableSelect({
|
|
2826
3708
|
message: "Select logging framework",
|
|
2827
|
-
options:
|
|
2828
|
-
|
|
2829
|
-
value: "pino",
|
|
2830
|
-
label: "Pino",
|
|
2831
|
-
hint: "Fast JSON logger with minimal overhead"
|
|
2832
|
-
},
|
|
2833
|
-
{
|
|
2834
|
-
value: "winston",
|
|
2835
|
-
label: "Winston",
|
|
2836
|
-
hint: "Flexible logging library with multiple transports"
|
|
2837
|
-
},
|
|
2838
|
-
{
|
|
2839
|
-
value: "none",
|
|
2840
|
-
label: "None",
|
|
2841
|
-
hint: "Skip logging framework setup"
|
|
2842
|
-
}
|
|
2843
|
-
],
|
|
2844
|
-
initialValue: "none"
|
|
3709
|
+
options: resolution.options,
|
|
3710
|
+
initialValue: resolution.initialValue
|
|
2845
3711
|
});
|
|
2846
3712
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2847
3713
|
return response;
|
|
@@ -2906,34 +3772,57 @@ async function navigableGroup(prompts, opts) {
|
|
|
2906
3772
|
|
|
2907
3773
|
//#endregion
|
|
2908
3774
|
//#region src/prompts/observability.ts
|
|
3775
|
+
const OBSERVABILITY_PROMPT_OPTIONS = [
|
|
3776
|
+
{
|
|
3777
|
+
value: "opentelemetry",
|
|
3778
|
+
label: "OpenTelemetry",
|
|
3779
|
+
hint: "Observability framework for traces, metrics, and logs"
|
|
3780
|
+
},
|
|
3781
|
+
{
|
|
3782
|
+
value: "sentry",
|
|
3783
|
+
label: "Sentry",
|
|
3784
|
+
hint: "Error tracking and performance monitoring"
|
|
3785
|
+
},
|
|
3786
|
+
{
|
|
3787
|
+
value: "grafana",
|
|
3788
|
+
label: "Grafana",
|
|
3789
|
+
hint: "Prometheus metrics for Grafana dashboards and alerting"
|
|
3790
|
+
},
|
|
3791
|
+
{
|
|
3792
|
+
value: "none",
|
|
3793
|
+
label: "None",
|
|
3794
|
+
hint: "Skip observability/tracing setup"
|
|
3795
|
+
}
|
|
3796
|
+
];
|
|
3797
|
+
function resolveObservabilityPrompt(context = {}) {
|
|
3798
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
3799
|
+
shouldPrompt: false,
|
|
3800
|
+
mode: "single",
|
|
3801
|
+
options: [],
|
|
3802
|
+
autoValue: "none"
|
|
3803
|
+
};
|
|
3804
|
+
return context.observability !== void 0 ? {
|
|
3805
|
+
shouldPrompt: false,
|
|
3806
|
+
mode: "single",
|
|
3807
|
+
options: OBSERVABILITY_PROMPT_OPTIONS,
|
|
3808
|
+
autoValue: context.observability
|
|
3809
|
+
} : {
|
|
3810
|
+
shouldPrompt: true,
|
|
3811
|
+
mode: "single",
|
|
3812
|
+
options: OBSERVABILITY_PROMPT_OPTIONS,
|
|
3813
|
+
initialValue: "none"
|
|
3814
|
+
};
|
|
3815
|
+
}
|
|
2909
3816
|
async function getObservabilityChoice(observability, backend) {
|
|
2910
|
-
|
|
2911
|
-
|
|
3817
|
+
const resolution = resolveObservabilityPrompt({
|
|
3818
|
+
observability,
|
|
3819
|
+
backend
|
|
3820
|
+
});
|
|
3821
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2912
3822
|
const response = await navigableSelect({
|
|
2913
3823
|
message: "Select observability solution",
|
|
2914
|
-
options:
|
|
2915
|
-
|
|
2916
|
-
value: "opentelemetry",
|
|
2917
|
-
label: "OpenTelemetry",
|
|
2918
|
-
hint: "Observability framework for traces, metrics, and logs"
|
|
2919
|
-
},
|
|
2920
|
-
{
|
|
2921
|
-
value: "sentry",
|
|
2922
|
-
label: "Sentry",
|
|
2923
|
-
hint: "Error tracking and performance monitoring"
|
|
2924
|
-
},
|
|
2925
|
-
{
|
|
2926
|
-
value: "grafana",
|
|
2927
|
-
label: "Grafana",
|
|
2928
|
-
hint: "Prometheus metrics for Grafana dashboards and alerting"
|
|
2929
|
-
},
|
|
2930
|
-
{
|
|
2931
|
-
value: "none",
|
|
2932
|
-
label: "None",
|
|
2933
|
-
hint: "Skip observability/tracing setup"
|
|
2934
|
-
}
|
|
2935
|
-
],
|
|
2936
|
-
initialValue: "none"
|
|
3824
|
+
options: resolution.options,
|
|
3825
|
+
initialValue: resolution.initialValue
|
|
2937
3826
|
});
|
|
2938
3827
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
2939
3828
|
return response;
|
|
@@ -2978,15 +3867,29 @@ const ormOptions = {
|
|
|
2978
3867
|
hint: "Mature ORM with wide adoption"
|
|
2979
3868
|
}
|
|
2980
3869
|
};
|
|
2981
|
-
|
|
2982
|
-
if (backend === "convex") return
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3870
|
+
function resolveORMPrompt(context) {
|
|
3871
|
+
if (context.backend === "convex" || !context.hasDatabase) return {
|
|
3872
|
+
shouldPrompt: false,
|
|
3873
|
+
mode: "single",
|
|
3874
|
+
options: [],
|
|
3875
|
+
autoValue: "none"
|
|
3876
|
+
};
|
|
3877
|
+
if (context.database === "edgedb" || context.database === "redis") return {
|
|
3878
|
+
shouldPrompt: false,
|
|
3879
|
+
mode: "single",
|
|
3880
|
+
options: [],
|
|
3881
|
+
autoValue: "none"
|
|
3882
|
+
};
|
|
3883
|
+
if (context.orm !== void 0) return {
|
|
3884
|
+
shouldPrompt: false,
|
|
3885
|
+
mode: "single",
|
|
3886
|
+
options: [],
|
|
3887
|
+
autoValue: context.orm
|
|
3888
|
+
};
|
|
3889
|
+
return {
|
|
3890
|
+
shouldPrompt: true,
|
|
3891
|
+
mode: "single",
|
|
3892
|
+
options: context.database === "mongodb" ? [ormOptions.prisma, ormOptions.mongoose] : [
|
|
2990
3893
|
ormOptions.drizzle,
|
|
2991
3894
|
ormOptions.prisma,
|
|
2992
3895
|
ormOptions.typeorm,
|
|
@@ -2994,7 +3897,22 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
|
|
|
2994
3897
|
ormOptions.mikroorm,
|
|
2995
3898
|
ormOptions.sequelize
|
|
2996
3899
|
],
|
|
2997
|
-
initialValue: database === "mongodb" ? "prisma" : runtime === "workers" ? "drizzle" : DEFAULT_CONFIG.orm
|
|
3900
|
+
initialValue: context.database === "mongodb" ? "prisma" : context.runtime === "workers" ? "drizzle" : DEFAULT_CONFIG.orm
|
|
3901
|
+
};
|
|
3902
|
+
}
|
|
3903
|
+
async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
|
|
3904
|
+
const resolution = resolveORMPrompt({
|
|
3905
|
+
orm,
|
|
3906
|
+
hasDatabase,
|
|
3907
|
+
database,
|
|
3908
|
+
backend,
|
|
3909
|
+
runtime
|
|
3910
|
+
});
|
|
3911
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3912
|
+
const response = await navigableSelect({
|
|
3913
|
+
message: "Select ORM",
|
|
3914
|
+
options: resolution.options,
|
|
3915
|
+
initialValue: resolution.initialValue
|
|
2998
3916
|
});
|
|
2999
3917
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3000
3918
|
return response;
|
|
@@ -3036,10 +3954,20 @@ async function getPackageManagerChoice(packageManager) {
|
|
|
3036
3954
|
|
|
3037
3955
|
//#endregion
|
|
3038
3956
|
//#region src/prompts/payments.ts
|
|
3039
|
-
|
|
3040
|
-
if (payments !== void 0) return
|
|
3041
|
-
|
|
3042
|
-
|
|
3957
|
+
function resolvePaymentsPrompt(context = {}) {
|
|
3958
|
+
if (context.payments !== void 0) return {
|
|
3959
|
+
shouldPrompt: false,
|
|
3960
|
+
mode: "single",
|
|
3961
|
+
options: [],
|
|
3962
|
+
autoValue: context.payments
|
|
3963
|
+
};
|
|
3964
|
+
if (context.backend === "none") return {
|
|
3965
|
+
shouldPrompt: false,
|
|
3966
|
+
mode: "single",
|
|
3967
|
+
options: [],
|
|
3968
|
+
autoValue: "none"
|
|
3969
|
+
};
|
|
3970
|
+
const isPolarCompatible = context.auth === "better-auth" && (context.frontends?.length === 0 || splitFrontends$1(context.frontends).web.length > 0);
|
|
3043
3971
|
const options = [];
|
|
3044
3972
|
if (isPolarCompatible) options.push({
|
|
3045
3973
|
value: "polar",
|
|
@@ -3067,172 +3995,281 @@ async function getPaymentsChoice(payments, auth, backend, frontends) {
|
|
|
3067
3995
|
label: "None",
|
|
3068
3996
|
hint: "No payments integration"
|
|
3069
3997
|
});
|
|
3070
|
-
|
|
3071
|
-
|
|
3998
|
+
return {
|
|
3999
|
+
shouldPrompt: true,
|
|
4000
|
+
mode: "single",
|
|
3072
4001
|
options,
|
|
3073
4002
|
initialValue: DEFAULT_CONFIG.payments
|
|
3074
|
-
}
|
|
3075
|
-
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3076
|
-
return response;
|
|
4003
|
+
};
|
|
3077
4004
|
}
|
|
3078
|
-
|
|
4005
|
+
async function getPaymentsChoice(payments, auth, backend, frontends) {
|
|
4006
|
+
const resolution = resolvePaymentsPrompt({
|
|
4007
|
+
payments,
|
|
4008
|
+
auth,
|
|
4009
|
+
backend,
|
|
4010
|
+
frontends
|
|
4011
|
+
});
|
|
4012
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4013
|
+
const response = await navigableSelect({
|
|
4014
|
+
message: "Select payments provider",
|
|
4015
|
+
options: resolution.options,
|
|
4016
|
+
initialValue: resolution.initialValue
|
|
4017
|
+
});
|
|
4018
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4019
|
+
return response;
|
|
4020
|
+
}
|
|
4021
|
+
|
|
3079
4022
|
//#endregion
|
|
3080
4023
|
//#region src/prompts/python-ecosystem.ts
|
|
4024
|
+
const PYTHON_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
4025
|
+
{
|
|
4026
|
+
value: "fastapi",
|
|
4027
|
+
label: "FastAPI",
|
|
4028
|
+
hint: "Modern, fast (high-performance) web framework for building APIs"
|
|
4029
|
+
},
|
|
4030
|
+
{
|
|
4031
|
+
value: "django",
|
|
4032
|
+
label: "Django",
|
|
4033
|
+
hint: "High-level Python web framework with batteries included"
|
|
4034
|
+
},
|
|
4035
|
+
{
|
|
4036
|
+
value: "flask",
|
|
4037
|
+
label: "Flask",
|
|
4038
|
+
hint: "Lightweight WSGI web framework with minimal boilerplate"
|
|
4039
|
+
},
|
|
4040
|
+
{
|
|
4041
|
+
value: "litestar",
|
|
4042
|
+
label: "Litestar",
|
|
4043
|
+
hint: "High-performance ASGI framework with class-based controllers"
|
|
4044
|
+
},
|
|
4045
|
+
{
|
|
4046
|
+
value: "none",
|
|
4047
|
+
label: "None",
|
|
4048
|
+
hint: "No web framework"
|
|
4049
|
+
}
|
|
4050
|
+
];
|
|
4051
|
+
const PYTHON_ORM_PROMPT_OPTIONS = [
|
|
4052
|
+
{
|
|
4053
|
+
value: "sqlalchemy",
|
|
4054
|
+
label: "SQLAlchemy",
|
|
4055
|
+
hint: "The SQL toolkit and ORM for Python"
|
|
4056
|
+
},
|
|
4057
|
+
{
|
|
4058
|
+
value: "sqlmodel",
|
|
4059
|
+
label: "SQLModel",
|
|
4060
|
+
hint: "SQL databases in Python with Pydantic and SQLAlchemy"
|
|
4061
|
+
},
|
|
4062
|
+
{
|
|
4063
|
+
value: "tortoise-orm",
|
|
4064
|
+
label: "Tortoise ORM",
|
|
4065
|
+
hint: "Async-first ORM with Django-like API"
|
|
4066
|
+
},
|
|
4067
|
+
{
|
|
4068
|
+
value: "none",
|
|
4069
|
+
label: "None",
|
|
4070
|
+
hint: "No ORM/database layer"
|
|
4071
|
+
}
|
|
4072
|
+
];
|
|
4073
|
+
const PYTHON_VALIDATION_PROMPT_OPTIONS = [{
|
|
4074
|
+
value: "pydantic",
|
|
4075
|
+
label: "Pydantic",
|
|
4076
|
+
hint: "Data validation using Python type hints"
|
|
4077
|
+
}, {
|
|
4078
|
+
value: "none",
|
|
4079
|
+
label: "None",
|
|
4080
|
+
hint: "No validation library"
|
|
4081
|
+
}];
|
|
4082
|
+
const PYTHON_AI_PROMPT_OPTIONS = [
|
|
4083
|
+
{
|
|
4084
|
+
value: "none",
|
|
4085
|
+
label: "None",
|
|
4086
|
+
hint: "No AI/ML framework"
|
|
4087
|
+
},
|
|
4088
|
+
{
|
|
4089
|
+
value: "langchain",
|
|
4090
|
+
label: "LangChain",
|
|
4091
|
+
hint: "Building applications with LLMs through composability"
|
|
4092
|
+
},
|
|
4093
|
+
{
|
|
4094
|
+
value: "llamaindex",
|
|
4095
|
+
label: "LlamaIndex",
|
|
4096
|
+
hint: "Data framework for LLM applications"
|
|
4097
|
+
},
|
|
4098
|
+
{
|
|
4099
|
+
value: "openai-sdk",
|
|
4100
|
+
label: "OpenAI SDK",
|
|
4101
|
+
hint: "Official OpenAI Python client"
|
|
4102
|
+
},
|
|
4103
|
+
{
|
|
4104
|
+
value: "anthropic-sdk",
|
|
4105
|
+
label: "Anthropic SDK",
|
|
4106
|
+
hint: "Official Anthropic Claude API client"
|
|
4107
|
+
},
|
|
4108
|
+
{
|
|
4109
|
+
value: "langgraph",
|
|
4110
|
+
label: "LangGraph",
|
|
4111
|
+
hint: "Graph-based agent orchestration"
|
|
4112
|
+
},
|
|
4113
|
+
{
|
|
4114
|
+
value: "crewai",
|
|
4115
|
+
label: "CrewAI",
|
|
4116
|
+
hint: "Multi-agent orchestration framework"
|
|
4117
|
+
}
|
|
4118
|
+
];
|
|
4119
|
+
const PYTHON_AUTH_PROMPT_OPTIONS = [
|
|
4120
|
+
{
|
|
4121
|
+
value: "authlib",
|
|
4122
|
+
label: "Authlib",
|
|
4123
|
+
hint: "Comprehensive auth library — OAuth1/2, OIDC, JWS, JWK, JWT"
|
|
4124
|
+
},
|
|
4125
|
+
{
|
|
4126
|
+
value: "jwt",
|
|
4127
|
+
label: "JWT (python-jose)",
|
|
4128
|
+
hint: "Simple JWT token creation and verification"
|
|
4129
|
+
},
|
|
4130
|
+
{
|
|
4131
|
+
value: "none",
|
|
4132
|
+
label: "None",
|
|
4133
|
+
hint: "No authentication library"
|
|
4134
|
+
}
|
|
4135
|
+
];
|
|
4136
|
+
const PYTHON_TASK_QUEUE_PROMPT_OPTIONS = [{
|
|
4137
|
+
value: "celery",
|
|
4138
|
+
label: "Celery",
|
|
4139
|
+
hint: "Distributed task queue for Python"
|
|
4140
|
+
}, {
|
|
4141
|
+
value: "none",
|
|
4142
|
+
label: "None",
|
|
4143
|
+
hint: "No task queue"
|
|
4144
|
+
}];
|
|
4145
|
+
const PYTHON_GRAPHQL_PROMPT_OPTIONS = [{
|
|
4146
|
+
value: "strawberry",
|
|
4147
|
+
label: "Strawberry",
|
|
4148
|
+
hint: "Python GraphQL library using dataclasses and type hints"
|
|
4149
|
+
}, {
|
|
4150
|
+
value: "none",
|
|
4151
|
+
label: "None",
|
|
4152
|
+
hint: "No GraphQL framework"
|
|
4153
|
+
}];
|
|
4154
|
+
const PYTHON_QUALITY_PROMPT_OPTIONS = [{
|
|
4155
|
+
value: "ruff",
|
|
4156
|
+
label: "Ruff",
|
|
4157
|
+
hint: "An extremely fast Python linter and formatter"
|
|
4158
|
+
}, {
|
|
4159
|
+
value: "none",
|
|
4160
|
+
label: "None",
|
|
4161
|
+
hint: "No code quality tools"
|
|
4162
|
+
}];
|
|
4163
|
+
function resolvePythonWebFrameworkPrompt(pythonWebFramework) {
|
|
4164
|
+
return createStaticSinglePromptResolution(PYTHON_WEB_FRAMEWORK_PROMPT_OPTIONS, "fastapi", pythonWebFramework);
|
|
4165
|
+
}
|
|
3081
4166
|
async function getPythonWebFrameworkChoice(pythonWebFramework) {
|
|
3082
|
-
|
|
4167
|
+
const resolution = resolvePythonWebFrameworkPrompt(pythonWebFramework);
|
|
4168
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3083
4169
|
const response = await navigableSelect({
|
|
3084
4170
|
message: "Select Python web framework",
|
|
3085
|
-
options:
|
|
3086
|
-
|
|
3087
|
-
value: "fastapi",
|
|
3088
|
-
label: "FastAPI",
|
|
3089
|
-
hint: "Modern, fast (high-performance) web framework for building APIs"
|
|
3090
|
-
},
|
|
3091
|
-
{
|
|
3092
|
-
value: "django",
|
|
3093
|
-
label: "Django",
|
|
3094
|
-
hint: "High-level Python web framework with batteries included"
|
|
3095
|
-
},
|
|
3096
|
-
{
|
|
3097
|
-
value: "flask",
|
|
3098
|
-
label: "Flask",
|
|
3099
|
-
hint: "Lightweight WSGI web framework with minimal boilerplate"
|
|
3100
|
-
},
|
|
3101
|
-
{
|
|
3102
|
-
value: "none",
|
|
3103
|
-
label: "None",
|
|
3104
|
-
hint: "No web framework"
|
|
3105
|
-
}
|
|
3106
|
-
],
|
|
3107
|
-
initialValue: "fastapi"
|
|
4171
|
+
options: resolution.options,
|
|
4172
|
+
initialValue: resolution.initialValue
|
|
3108
4173
|
});
|
|
3109
4174
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3110
4175
|
return response;
|
|
3111
4176
|
}
|
|
4177
|
+
function resolvePythonOrmPrompt(pythonOrm) {
|
|
4178
|
+
return createStaticSinglePromptResolution(PYTHON_ORM_PROMPT_OPTIONS, "sqlalchemy", pythonOrm);
|
|
4179
|
+
}
|
|
3112
4180
|
async function getPythonOrmChoice(pythonOrm) {
|
|
3113
|
-
|
|
4181
|
+
const resolution = resolvePythonOrmPrompt(pythonOrm);
|
|
4182
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3114
4183
|
const response = await navigableSelect({
|
|
3115
4184
|
message: "Select Python ORM/database layer",
|
|
3116
|
-
options:
|
|
3117
|
-
|
|
3118
|
-
value: "sqlalchemy",
|
|
3119
|
-
label: "SQLAlchemy",
|
|
3120
|
-
hint: "The SQL toolkit and ORM for Python"
|
|
3121
|
-
},
|
|
3122
|
-
{
|
|
3123
|
-
value: "sqlmodel",
|
|
3124
|
-
label: "SQLModel",
|
|
3125
|
-
hint: "SQL databases in Python with Pydantic and SQLAlchemy"
|
|
3126
|
-
},
|
|
3127
|
-
{
|
|
3128
|
-
value: "none",
|
|
3129
|
-
label: "None",
|
|
3130
|
-
hint: "No ORM/database layer"
|
|
3131
|
-
}
|
|
3132
|
-
],
|
|
3133
|
-
initialValue: "sqlalchemy"
|
|
4185
|
+
options: resolution.options,
|
|
4186
|
+
initialValue: resolution.initialValue
|
|
3134
4187
|
});
|
|
3135
4188
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3136
4189
|
return response;
|
|
3137
4190
|
}
|
|
4191
|
+
function resolvePythonValidationPrompt(pythonValidation) {
|
|
4192
|
+
return createStaticSinglePromptResolution(PYTHON_VALIDATION_PROMPT_OPTIONS, "pydantic", pythonValidation);
|
|
4193
|
+
}
|
|
3138
4194
|
async function getPythonValidationChoice(pythonValidation) {
|
|
3139
|
-
|
|
4195
|
+
const resolution = resolvePythonValidationPrompt(pythonValidation);
|
|
4196
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3140
4197
|
const response = await navigableSelect({
|
|
3141
4198
|
message: "Select Python validation library",
|
|
3142
|
-
options:
|
|
3143
|
-
|
|
3144
|
-
label: "Pydantic",
|
|
3145
|
-
hint: "Data validation using Python type hints"
|
|
3146
|
-
}, {
|
|
3147
|
-
value: "none",
|
|
3148
|
-
label: "None",
|
|
3149
|
-
hint: "No validation library"
|
|
3150
|
-
}],
|
|
3151
|
-
initialValue: "pydantic"
|
|
4199
|
+
options: resolution.options,
|
|
4200
|
+
initialValue: resolution.initialValue
|
|
3152
4201
|
});
|
|
3153
4202
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3154
4203
|
return response;
|
|
3155
4204
|
}
|
|
4205
|
+
function resolvePythonAiPrompt(pythonAi) {
|
|
4206
|
+
return createStaticMultiPromptResolution(PYTHON_AI_PROMPT_OPTIONS, [], pythonAi);
|
|
4207
|
+
}
|
|
3156
4208
|
async function getPythonAiChoice(pythonAi) {
|
|
3157
|
-
|
|
4209
|
+
const resolution = resolvePythonAiPrompt(pythonAi);
|
|
4210
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
|
|
3158
4211
|
const response = await navigableMultiselect({
|
|
3159
4212
|
message: "Select Python AI/ML frameworks",
|
|
3160
|
-
options:
|
|
3161
|
-
{
|
|
3162
|
-
value: "none",
|
|
3163
|
-
label: "None",
|
|
3164
|
-
hint: "No AI/ML framework"
|
|
3165
|
-
},
|
|
3166
|
-
{
|
|
3167
|
-
value: "langchain",
|
|
3168
|
-
label: "LangChain",
|
|
3169
|
-
hint: "Building applications with LLMs through composability"
|
|
3170
|
-
},
|
|
3171
|
-
{
|
|
3172
|
-
value: "llamaindex",
|
|
3173
|
-
label: "LlamaIndex",
|
|
3174
|
-
hint: "Data framework for LLM applications"
|
|
3175
|
-
},
|
|
3176
|
-
{
|
|
3177
|
-
value: "openai-sdk",
|
|
3178
|
-
label: "OpenAI SDK",
|
|
3179
|
-
hint: "Official OpenAI Python client"
|
|
3180
|
-
},
|
|
3181
|
-
{
|
|
3182
|
-
value: "anthropic-sdk",
|
|
3183
|
-
label: "Anthropic SDK",
|
|
3184
|
-
hint: "Official Anthropic Claude API client"
|
|
3185
|
-
},
|
|
3186
|
-
{
|
|
3187
|
-
value: "langgraph",
|
|
3188
|
-
label: "LangGraph",
|
|
3189
|
-
hint: "Graph-based agent orchestration"
|
|
3190
|
-
},
|
|
3191
|
-
{
|
|
3192
|
-
value: "crewai",
|
|
3193
|
-
label: "CrewAI",
|
|
3194
|
-
hint: "Multi-agent orchestration framework"
|
|
3195
|
-
}
|
|
3196
|
-
],
|
|
4213
|
+
options: resolution.options,
|
|
3197
4214
|
required: false,
|
|
3198
|
-
initialValues:
|
|
4215
|
+
initialValues: resolution.initialValue
|
|
3199
4216
|
});
|
|
3200
4217
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3201
4218
|
if (response.includes("none")) return [];
|
|
3202
4219
|
return response;
|
|
3203
4220
|
}
|
|
4221
|
+
function resolvePythonAuthPrompt(pythonAuth) {
|
|
4222
|
+
return createStaticSinglePromptResolution(PYTHON_AUTH_PROMPT_OPTIONS, "none", pythonAuth);
|
|
4223
|
+
}
|
|
4224
|
+
async function getPythonAuthChoice(pythonAuth) {
|
|
4225
|
+
const resolution = resolvePythonAuthPrompt(pythonAuth);
|
|
4226
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4227
|
+
const response = await navigableSelect({
|
|
4228
|
+
message: "Select Python authentication library",
|
|
4229
|
+
options: resolution.options,
|
|
4230
|
+
initialValue: resolution.initialValue
|
|
4231
|
+
});
|
|
4232
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4233
|
+
return response;
|
|
4234
|
+
}
|
|
4235
|
+
function resolvePythonTaskQueuePrompt(pythonTaskQueue) {
|
|
4236
|
+
return createStaticSinglePromptResolution(PYTHON_TASK_QUEUE_PROMPT_OPTIONS, "none", pythonTaskQueue);
|
|
4237
|
+
}
|
|
3204
4238
|
async function getPythonTaskQueueChoice(pythonTaskQueue) {
|
|
3205
|
-
|
|
4239
|
+
const resolution = resolvePythonTaskQueuePrompt(pythonTaskQueue);
|
|
4240
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3206
4241
|
const response = await navigableSelect({
|
|
3207
4242
|
message: "Select Python task queue",
|
|
3208
|
-
options:
|
|
3209
|
-
|
|
3210
|
-
label: "Celery",
|
|
3211
|
-
hint: "Distributed task queue for Python"
|
|
3212
|
-
}, {
|
|
3213
|
-
value: "none",
|
|
3214
|
-
label: "None",
|
|
3215
|
-
hint: "No task queue"
|
|
3216
|
-
}],
|
|
3217
|
-
initialValue: "none"
|
|
4243
|
+
options: resolution.options,
|
|
4244
|
+
initialValue: resolution.initialValue
|
|
3218
4245
|
});
|
|
3219
4246
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3220
4247
|
return response;
|
|
3221
4248
|
}
|
|
4249
|
+
function resolvePythonGraphqlPrompt(pythonGraphql) {
|
|
4250
|
+
return createStaticSinglePromptResolution(PYTHON_GRAPHQL_PROMPT_OPTIONS, "none", pythonGraphql);
|
|
4251
|
+
}
|
|
4252
|
+
async function getPythonGraphqlChoice(pythonGraphql) {
|
|
4253
|
+
const resolution = resolvePythonGraphqlPrompt(pythonGraphql);
|
|
4254
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4255
|
+
const response = await navigableSelect({
|
|
4256
|
+
message: "Select Python GraphQL framework",
|
|
4257
|
+
options: resolution.options,
|
|
4258
|
+
initialValue: resolution.initialValue
|
|
4259
|
+
});
|
|
4260
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4261
|
+
return response;
|
|
4262
|
+
}
|
|
4263
|
+
function resolvePythonQualityPrompt(pythonQuality) {
|
|
4264
|
+
return createStaticSinglePromptResolution(PYTHON_QUALITY_PROMPT_OPTIONS, "ruff", pythonQuality);
|
|
4265
|
+
}
|
|
3222
4266
|
async function getPythonQualityChoice(pythonQuality) {
|
|
3223
|
-
|
|
4267
|
+
const resolution = resolvePythonQualityPrompt(pythonQuality);
|
|
4268
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3224
4269
|
const response = await navigableSelect({
|
|
3225
4270
|
message: "Select Python code quality tool",
|
|
3226
|
-
options:
|
|
3227
|
-
|
|
3228
|
-
label: "Ruff",
|
|
3229
|
-
hint: "An extremely fast Python linter and formatter"
|
|
3230
|
-
}, {
|
|
3231
|
-
value: "none",
|
|
3232
|
-
label: "None",
|
|
3233
|
-
hint: "No code quality tools"
|
|
3234
|
-
}],
|
|
3235
|
-
initialValue: "ruff"
|
|
4271
|
+
options: resolution.options,
|
|
4272
|
+
initialValue: resolution.initialValue
|
|
3236
4273
|
});
|
|
3237
4274
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3238
4275
|
return response;
|
|
@@ -3240,49 +4277,72 @@ async function getPythonQualityChoice(pythonQuality) {
|
|
|
3240
4277
|
|
|
3241
4278
|
//#endregion
|
|
3242
4279
|
//#region src/prompts/realtime.ts
|
|
4280
|
+
const REALTIME_PROMPT_OPTIONS = [
|
|
4281
|
+
{
|
|
4282
|
+
value: "socket-io",
|
|
4283
|
+
label: "Socket.IO",
|
|
4284
|
+
hint: "Real-time bidirectional communication with fallbacks"
|
|
4285
|
+
},
|
|
4286
|
+
{
|
|
4287
|
+
value: "partykit",
|
|
4288
|
+
label: "PartyKit",
|
|
4289
|
+
hint: "Edge-native multiplayer infrastructure on Cloudflare"
|
|
4290
|
+
},
|
|
4291
|
+
{
|
|
4292
|
+
value: "ably",
|
|
4293
|
+
label: "Ably",
|
|
4294
|
+
hint: "Real-time messaging platform with pub/sub and presence"
|
|
4295
|
+
},
|
|
4296
|
+
{
|
|
4297
|
+
value: "pusher",
|
|
4298
|
+
label: "Pusher",
|
|
4299
|
+
hint: "Real-time communication APIs with channels and events"
|
|
4300
|
+
},
|
|
4301
|
+
{
|
|
4302
|
+
value: "liveblocks",
|
|
4303
|
+
label: "Liveblocks",
|
|
4304
|
+
hint: "Collaboration infrastructure for multiplayer experiences"
|
|
4305
|
+
},
|
|
4306
|
+
{
|
|
4307
|
+
value: "yjs",
|
|
4308
|
+
label: "Y.js",
|
|
4309
|
+
hint: "CRDT library for real-time collaboration with conflict-free sync"
|
|
4310
|
+
},
|
|
4311
|
+
{
|
|
4312
|
+
value: "none",
|
|
4313
|
+
label: "None",
|
|
4314
|
+
hint: "Skip real-time/WebSocket integration"
|
|
4315
|
+
}
|
|
4316
|
+
];
|
|
4317
|
+
function resolveRealtimePrompt(context = {}) {
|
|
4318
|
+
if (context.backend === "none" || context.backend === "convex") return {
|
|
4319
|
+
shouldPrompt: false,
|
|
4320
|
+
mode: "single",
|
|
4321
|
+
options: [],
|
|
4322
|
+
autoValue: "none"
|
|
4323
|
+
};
|
|
4324
|
+
return context.realtime !== void 0 ? {
|
|
4325
|
+
shouldPrompt: false,
|
|
4326
|
+
mode: "single",
|
|
4327
|
+
options: REALTIME_PROMPT_OPTIONS,
|
|
4328
|
+
autoValue: context.realtime
|
|
4329
|
+
} : {
|
|
4330
|
+
shouldPrompt: true,
|
|
4331
|
+
mode: "single",
|
|
4332
|
+
options: REALTIME_PROMPT_OPTIONS,
|
|
4333
|
+
initialValue: "none"
|
|
4334
|
+
};
|
|
4335
|
+
}
|
|
3243
4336
|
async function getRealtimeChoice(realtime, backend) {
|
|
3244
|
-
|
|
3245
|
-
|
|
4337
|
+
const resolution = resolveRealtimePrompt({
|
|
4338
|
+
realtime,
|
|
4339
|
+
backend
|
|
4340
|
+
});
|
|
4341
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3246
4342
|
const response = await navigableSelect({
|
|
3247
4343
|
message: "Select real-time solution",
|
|
3248
|
-
options:
|
|
3249
|
-
|
|
3250
|
-
value: "socket-io",
|
|
3251
|
-
label: "Socket.IO",
|
|
3252
|
-
hint: "Real-time bidirectional communication with fallbacks"
|
|
3253
|
-
},
|
|
3254
|
-
{
|
|
3255
|
-
value: "partykit",
|
|
3256
|
-
label: "PartyKit",
|
|
3257
|
-
hint: "Edge-native multiplayer infrastructure on Cloudflare"
|
|
3258
|
-
},
|
|
3259
|
-
{
|
|
3260
|
-
value: "ably",
|
|
3261
|
-
label: "Ably",
|
|
3262
|
-
hint: "Real-time messaging platform with pub/sub and presence"
|
|
3263
|
-
},
|
|
3264
|
-
{
|
|
3265
|
-
value: "pusher",
|
|
3266
|
-
label: "Pusher",
|
|
3267
|
-
hint: "Real-time communication APIs with channels and events"
|
|
3268
|
-
},
|
|
3269
|
-
{
|
|
3270
|
-
value: "liveblocks",
|
|
3271
|
-
label: "Liveblocks",
|
|
3272
|
-
hint: "Collaboration infrastructure for multiplayer experiences"
|
|
3273
|
-
},
|
|
3274
|
-
{
|
|
3275
|
-
value: "yjs",
|
|
3276
|
-
label: "Y.js",
|
|
3277
|
-
hint: "CRDT library for real-time collaboration with conflict-free sync"
|
|
3278
|
-
},
|
|
3279
|
-
{
|
|
3280
|
-
value: "none",
|
|
3281
|
-
label: "None",
|
|
3282
|
-
hint: "Skip real-time/WebSocket integration"
|
|
3283
|
-
}
|
|
3284
|
-
],
|
|
3285
|
-
initialValue: "none"
|
|
4344
|
+
options: resolution.options,
|
|
4345
|
+
initialValue: resolution.initialValue
|
|
3286
4346
|
});
|
|
3287
4347
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3288
4348
|
return response;
|
|
@@ -3290,27 +4350,53 @@ async function getRealtimeChoice(realtime, backend) {
|
|
|
3290
4350
|
|
|
3291
4351
|
//#endregion
|
|
3292
4352
|
//#region src/prompts/runtime.ts
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
if (runtime !== void 0) return runtime;
|
|
3296
|
-
const runtimeOptions = [{
|
|
4353
|
+
const RUNTIME_PROMPT_OPTIONS = [
|
|
4354
|
+
{
|
|
3297
4355
|
value: "bun",
|
|
3298
4356
|
label: "Bun",
|
|
3299
4357
|
hint: "Fast all-in-one JavaScript runtime"
|
|
3300
|
-
},
|
|
4358
|
+
},
|
|
4359
|
+
{
|
|
3301
4360
|
value: "node",
|
|
3302
4361
|
label: "Node.js",
|
|
3303
4362
|
hint: "Traditional Node.js runtime"
|
|
3304
|
-
}
|
|
3305
|
-
|
|
4363
|
+
},
|
|
4364
|
+
{
|
|
3306
4365
|
value: "workers",
|
|
3307
4366
|
label: "Cloudflare Workers",
|
|
3308
4367
|
hint: "Edge runtime on Cloudflare's global network"
|
|
4368
|
+
}
|
|
4369
|
+
];
|
|
4370
|
+
function resolveRuntimePrompt(context = {}) {
|
|
4371
|
+
if (context.backend === "convex" || context.backend === "none" || context.backend === "self") return {
|
|
4372
|
+
shouldPrompt: false,
|
|
4373
|
+
mode: "single",
|
|
4374
|
+
options: [],
|
|
4375
|
+
autoValue: "none"
|
|
4376
|
+
};
|
|
4377
|
+
const options = RUNTIME_PROMPT_OPTIONS.filter((option) => option.value !== "workers" || context.backend === "hono");
|
|
4378
|
+
return context.runtime !== void 0 ? {
|
|
4379
|
+
shouldPrompt: false,
|
|
4380
|
+
mode: "single",
|
|
4381
|
+
options,
|
|
4382
|
+
autoValue: context.runtime
|
|
4383
|
+
} : {
|
|
4384
|
+
shouldPrompt: true,
|
|
4385
|
+
mode: "single",
|
|
4386
|
+
options,
|
|
4387
|
+
initialValue: DEFAULT_CONFIG.runtime
|
|
4388
|
+
};
|
|
4389
|
+
}
|
|
4390
|
+
async function getRuntimeChoice(runtime, backend) {
|
|
4391
|
+
const resolution = resolveRuntimePrompt({
|
|
4392
|
+
runtime,
|
|
4393
|
+
backend
|
|
3309
4394
|
});
|
|
4395
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3310
4396
|
const response = await navigableSelect({
|
|
3311
4397
|
message: "Select runtime",
|
|
3312
|
-
options:
|
|
3313
|
-
initialValue:
|
|
4398
|
+
options: resolution.options,
|
|
4399
|
+
initialValue: resolution.initialValue
|
|
3314
4400
|
});
|
|
3315
4401
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3316
4402
|
return response;
|
|
@@ -3318,200 +4404,325 @@ async function getRuntimeChoice(runtime, backend) {
|
|
|
3318
4404
|
|
|
3319
4405
|
//#endregion
|
|
3320
4406
|
//#region src/prompts/rust-ecosystem.ts
|
|
4407
|
+
const RUST_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
4408
|
+
{
|
|
4409
|
+
value: "axum",
|
|
4410
|
+
label: "Axum",
|
|
4411
|
+
hint: "Ergonomic and modular web framework from Tokio"
|
|
4412
|
+
},
|
|
4413
|
+
{
|
|
4414
|
+
value: "actix-web",
|
|
4415
|
+
label: "Actix Web",
|
|
4416
|
+
hint: "Powerful, pragmatic, and extremely fast web framework"
|
|
4417
|
+
},
|
|
4418
|
+
{
|
|
4419
|
+
value: "rocket",
|
|
4420
|
+
label: "Rocket",
|
|
4421
|
+
hint: "Convention-over-configuration web framework, 25k+ stars"
|
|
4422
|
+
},
|
|
4423
|
+
{
|
|
4424
|
+
value: "none",
|
|
4425
|
+
label: "None",
|
|
4426
|
+
hint: "No web framework"
|
|
4427
|
+
}
|
|
4428
|
+
];
|
|
4429
|
+
const RUST_FRONTEND_PROMPT_OPTIONS = [
|
|
4430
|
+
{
|
|
4431
|
+
value: "leptos",
|
|
4432
|
+
label: "Leptos",
|
|
4433
|
+
hint: "Build fast web applications with Rust"
|
|
4434
|
+
},
|
|
4435
|
+
{
|
|
4436
|
+
value: "dioxus",
|
|
4437
|
+
label: "Dioxus",
|
|
4438
|
+
hint: "Fullstack, cross-platform UI library for Rust"
|
|
4439
|
+
},
|
|
4440
|
+
{
|
|
4441
|
+
value: "none",
|
|
4442
|
+
label: "None",
|
|
4443
|
+
hint: "No Rust frontend (API only)"
|
|
4444
|
+
}
|
|
4445
|
+
];
|
|
4446
|
+
const RUST_ORM_PROMPT_OPTIONS = [
|
|
4447
|
+
{
|
|
4448
|
+
value: "sea-orm",
|
|
4449
|
+
label: "SeaORM",
|
|
4450
|
+
hint: "Async & dynamic ORM for Rust"
|
|
4451
|
+
},
|
|
4452
|
+
{
|
|
4453
|
+
value: "sqlx",
|
|
4454
|
+
label: "SQLx",
|
|
4455
|
+
hint: "Async SQL toolkit with compile-time checked queries"
|
|
4456
|
+
},
|
|
4457
|
+
{
|
|
4458
|
+
value: "diesel",
|
|
4459
|
+
label: "Diesel",
|
|
4460
|
+
hint: "Safe, extensible ORM with compile-time query validation"
|
|
4461
|
+
},
|
|
4462
|
+
{
|
|
4463
|
+
value: "none",
|
|
4464
|
+
label: "None",
|
|
4465
|
+
hint: "No database layer"
|
|
4466
|
+
}
|
|
4467
|
+
];
|
|
4468
|
+
const RUST_API_PROMPT_OPTIONS = [
|
|
4469
|
+
{
|
|
4470
|
+
value: "tonic",
|
|
4471
|
+
label: "Tonic",
|
|
4472
|
+
hint: "gRPC implementation for Rust"
|
|
4473
|
+
},
|
|
4474
|
+
{
|
|
4475
|
+
value: "async-graphql",
|
|
4476
|
+
label: "async-graphql",
|
|
4477
|
+
hint: "High-performance GraphQL server library"
|
|
4478
|
+
},
|
|
4479
|
+
{
|
|
4480
|
+
value: "none",
|
|
4481
|
+
label: "None",
|
|
4482
|
+
hint: "REST API only"
|
|
4483
|
+
}
|
|
4484
|
+
];
|
|
4485
|
+
const RUST_CLI_PROMPT_OPTIONS = [
|
|
4486
|
+
{
|
|
4487
|
+
value: "clap",
|
|
4488
|
+
label: "Clap",
|
|
4489
|
+
hint: "Command Line Argument Parser for Rust"
|
|
4490
|
+
},
|
|
4491
|
+
{
|
|
4492
|
+
value: "ratatui",
|
|
4493
|
+
label: "Ratatui",
|
|
4494
|
+
hint: "Build rich terminal user interfaces"
|
|
4495
|
+
},
|
|
4496
|
+
{
|
|
4497
|
+
value: "none",
|
|
4498
|
+
label: "None",
|
|
4499
|
+
hint: "No CLI tools"
|
|
4500
|
+
}
|
|
4501
|
+
];
|
|
4502
|
+
const RUST_LIBRARIES_PROMPT_OPTIONS = [
|
|
4503
|
+
{
|
|
4504
|
+
value: "serde",
|
|
4505
|
+
label: "Serde",
|
|
4506
|
+
hint: "Serialization framework for Rust"
|
|
4507
|
+
},
|
|
4508
|
+
{
|
|
4509
|
+
value: "validator",
|
|
4510
|
+
label: "Validator",
|
|
4511
|
+
hint: "Struct validation derive macros"
|
|
4512
|
+
},
|
|
4513
|
+
{
|
|
4514
|
+
value: "jsonwebtoken",
|
|
4515
|
+
label: "jsonwebtoken",
|
|
4516
|
+
hint: "JWT encoding/decoding library"
|
|
4517
|
+
},
|
|
4518
|
+
{
|
|
4519
|
+
value: "argon2",
|
|
4520
|
+
label: "Argon2",
|
|
4521
|
+
hint: "Password hashing library"
|
|
4522
|
+
},
|
|
4523
|
+
{
|
|
4524
|
+
value: "tokio-test",
|
|
4525
|
+
label: "Tokio Test",
|
|
4526
|
+
hint: "Testing utilities for Tokio"
|
|
4527
|
+
},
|
|
4528
|
+
{
|
|
4529
|
+
value: "mockall",
|
|
4530
|
+
label: "Mockall",
|
|
4531
|
+
hint: "Powerful mocking library for Rust"
|
|
4532
|
+
}
|
|
4533
|
+
];
|
|
4534
|
+
const RUST_LOGGING_PROMPT_OPTIONS = [
|
|
4535
|
+
{
|
|
4536
|
+
value: "tracing",
|
|
4537
|
+
label: "Tracing",
|
|
4538
|
+
hint: "Structured, composable instrumentation framework from Tokio"
|
|
4539
|
+
},
|
|
4540
|
+
{
|
|
4541
|
+
value: "env-logger",
|
|
4542
|
+
label: "env_logger",
|
|
4543
|
+
hint: "Simple logger configured via environment variables"
|
|
4544
|
+
},
|
|
4545
|
+
{
|
|
4546
|
+
value: "none",
|
|
4547
|
+
label: "None",
|
|
4548
|
+
hint: "No logging library"
|
|
4549
|
+
}
|
|
4550
|
+
];
|
|
4551
|
+
const RUST_ERROR_HANDLING_PROMPT_OPTIONS = [
|
|
4552
|
+
{
|
|
4553
|
+
value: "anyhow-thiserror",
|
|
4554
|
+
label: "anyhow + thiserror",
|
|
4555
|
+
hint: "anyhow for application errors, thiserror for custom error types"
|
|
4556
|
+
},
|
|
4557
|
+
{
|
|
4558
|
+
value: "eyre",
|
|
4559
|
+
label: "eyre + color-eyre",
|
|
4560
|
+
hint: "Customizable error reports with pretty backtraces via color-eyre"
|
|
4561
|
+
},
|
|
4562
|
+
{
|
|
4563
|
+
value: "none",
|
|
4564
|
+
label: "None",
|
|
4565
|
+
hint: "No error handling library (uses standard library only)"
|
|
4566
|
+
}
|
|
4567
|
+
];
|
|
4568
|
+
const RUST_CACHING_PROMPT_OPTIONS = [
|
|
4569
|
+
{
|
|
4570
|
+
value: "moka",
|
|
4571
|
+
label: "Moka",
|
|
4572
|
+
hint: "High-performance concurrent in-memory cache (Caffeine-inspired)"
|
|
4573
|
+
},
|
|
4574
|
+
{
|
|
4575
|
+
value: "redis",
|
|
4576
|
+
label: "Redis",
|
|
4577
|
+
hint: "Redis client with async support and connection pooling"
|
|
4578
|
+
},
|
|
4579
|
+
{
|
|
4580
|
+
value: "none",
|
|
4581
|
+
label: "None",
|
|
4582
|
+
hint: "No caching library"
|
|
4583
|
+
}
|
|
4584
|
+
];
|
|
4585
|
+
function resolveRustWebFrameworkPrompt(rustWebFramework) {
|
|
4586
|
+
return createStaticSinglePromptResolution(RUST_WEB_FRAMEWORK_PROMPT_OPTIONS, "axum", rustWebFramework);
|
|
4587
|
+
}
|
|
3321
4588
|
async function getRustWebFrameworkChoice(rustWebFramework) {
|
|
3322
|
-
|
|
4589
|
+
const resolution = resolveRustWebFrameworkPrompt(rustWebFramework);
|
|
4590
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3323
4591
|
const response = await navigableSelect({
|
|
3324
4592
|
message: "Select Rust web framework",
|
|
3325
|
-
options:
|
|
3326
|
-
|
|
3327
|
-
value: "axum",
|
|
3328
|
-
label: "Axum",
|
|
3329
|
-
hint: "Ergonomic and modular web framework from Tokio"
|
|
3330
|
-
},
|
|
3331
|
-
{
|
|
3332
|
-
value: "actix-web",
|
|
3333
|
-
label: "Actix Web",
|
|
3334
|
-
hint: "Powerful, pragmatic, and extremely fast web framework"
|
|
3335
|
-
},
|
|
3336
|
-
{
|
|
3337
|
-
value: "none",
|
|
3338
|
-
label: "None",
|
|
3339
|
-
hint: "No web framework"
|
|
3340
|
-
}
|
|
3341
|
-
],
|
|
3342
|
-
initialValue: "axum"
|
|
4593
|
+
options: resolution.options,
|
|
4594
|
+
initialValue: resolution.initialValue
|
|
3343
4595
|
});
|
|
3344
4596
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3345
4597
|
return response;
|
|
3346
4598
|
}
|
|
4599
|
+
function resolveRustFrontendPrompt(rustFrontend) {
|
|
4600
|
+
return createStaticSinglePromptResolution(RUST_FRONTEND_PROMPT_OPTIONS, "none", rustFrontend);
|
|
4601
|
+
}
|
|
3347
4602
|
async function getRustFrontendChoice(rustFrontend) {
|
|
3348
|
-
|
|
4603
|
+
const resolution = resolveRustFrontendPrompt(rustFrontend);
|
|
4604
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3349
4605
|
const response = await navigableSelect({
|
|
3350
4606
|
message: "Select Rust frontend framework",
|
|
3351
|
-
options:
|
|
3352
|
-
|
|
3353
|
-
value: "leptos",
|
|
3354
|
-
label: "Leptos",
|
|
3355
|
-
hint: "Build fast web applications with Rust"
|
|
3356
|
-
},
|
|
3357
|
-
{
|
|
3358
|
-
value: "dioxus",
|
|
3359
|
-
label: "Dioxus",
|
|
3360
|
-
hint: "Fullstack, cross-platform UI library for Rust"
|
|
3361
|
-
},
|
|
3362
|
-
{
|
|
3363
|
-
value: "none",
|
|
3364
|
-
label: "None",
|
|
3365
|
-
hint: "No Rust frontend (API only)"
|
|
3366
|
-
}
|
|
3367
|
-
],
|
|
3368
|
-
initialValue: "none"
|
|
4607
|
+
options: resolution.options,
|
|
4608
|
+
initialValue: resolution.initialValue
|
|
3369
4609
|
});
|
|
3370
4610
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3371
4611
|
return response;
|
|
3372
4612
|
}
|
|
4613
|
+
function resolveRustOrmPrompt(rustOrm) {
|
|
4614
|
+
return createStaticSinglePromptResolution(RUST_ORM_PROMPT_OPTIONS, "none", rustOrm);
|
|
4615
|
+
}
|
|
3373
4616
|
async function getRustOrmChoice(rustOrm) {
|
|
3374
|
-
|
|
4617
|
+
const resolution = resolveRustOrmPrompt(rustOrm);
|
|
4618
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3375
4619
|
const response = await navigableSelect({
|
|
3376
4620
|
message: "Select Rust ORM/database layer",
|
|
3377
|
-
options:
|
|
3378
|
-
|
|
3379
|
-
value: "sea-orm",
|
|
3380
|
-
label: "SeaORM",
|
|
3381
|
-
hint: "Async & dynamic ORM for Rust"
|
|
3382
|
-
},
|
|
3383
|
-
{
|
|
3384
|
-
value: "sqlx",
|
|
3385
|
-
label: "SQLx",
|
|
3386
|
-
hint: "Async SQL toolkit with compile-time checked queries"
|
|
3387
|
-
},
|
|
3388
|
-
{
|
|
3389
|
-
value: "none",
|
|
3390
|
-
label: "None",
|
|
3391
|
-
hint: "No database layer"
|
|
3392
|
-
}
|
|
3393
|
-
],
|
|
3394
|
-
initialValue: "none"
|
|
3395
|
-
});
|
|
3396
|
-
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3397
|
-
return response;
|
|
3398
|
-
}
|
|
3399
|
-
async function getRustApiChoice(rustApi) {
|
|
3400
|
-
if (rustApi !== void 0) return rustApi;
|
|
3401
|
-
const response = await navigableSelect({
|
|
3402
|
-
message: "Select Rust API layer",
|
|
3403
|
-
options: [
|
|
3404
|
-
{
|
|
3405
|
-
value: "tonic",
|
|
3406
|
-
label: "Tonic",
|
|
3407
|
-
hint: "gRPC implementation for Rust"
|
|
3408
|
-
},
|
|
3409
|
-
{
|
|
3410
|
-
value: "async-graphql",
|
|
3411
|
-
label: "async-graphql",
|
|
3412
|
-
hint: "High-performance GraphQL server library"
|
|
3413
|
-
},
|
|
3414
|
-
{
|
|
3415
|
-
value: "none",
|
|
3416
|
-
label: "None",
|
|
3417
|
-
hint: "REST API only"
|
|
3418
|
-
}
|
|
3419
|
-
],
|
|
3420
|
-
initialValue: "none"
|
|
4621
|
+
options: resolution.options,
|
|
4622
|
+
initialValue: resolution.initialValue
|
|
3421
4623
|
});
|
|
3422
4624
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3423
4625
|
return response;
|
|
3424
4626
|
}
|
|
4627
|
+
function resolveRustApiPrompt(rustApi) {
|
|
4628
|
+
return createStaticSinglePromptResolution(RUST_API_PROMPT_OPTIONS, "none", rustApi);
|
|
4629
|
+
}
|
|
4630
|
+
async function getRustApiChoice(rustApi) {
|
|
4631
|
+
const resolution = resolveRustApiPrompt(rustApi);
|
|
4632
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4633
|
+
const response = await navigableSelect({
|
|
4634
|
+
message: "Select Rust API layer",
|
|
4635
|
+
options: resolution.options,
|
|
4636
|
+
initialValue: resolution.initialValue
|
|
4637
|
+
});
|
|
4638
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4639
|
+
return response;
|
|
4640
|
+
}
|
|
4641
|
+
function resolveRustCliPrompt(rustCli) {
|
|
4642
|
+
return createStaticSinglePromptResolution(RUST_CLI_PROMPT_OPTIONS, "none", rustCli);
|
|
4643
|
+
}
|
|
3425
4644
|
async function getRustCliChoice(rustCli) {
|
|
3426
|
-
|
|
4645
|
+
const resolution = resolveRustCliPrompt(rustCli);
|
|
4646
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3427
4647
|
const response = await navigableSelect({
|
|
3428
4648
|
message: "Select Rust CLI tools",
|
|
3429
|
-
options:
|
|
3430
|
-
|
|
3431
|
-
value: "clap",
|
|
3432
|
-
label: "Clap",
|
|
3433
|
-
hint: "Command Line Argument Parser for Rust"
|
|
3434
|
-
},
|
|
3435
|
-
{
|
|
3436
|
-
value: "ratatui",
|
|
3437
|
-
label: "Ratatui",
|
|
3438
|
-
hint: "Build rich terminal user interfaces"
|
|
3439
|
-
},
|
|
3440
|
-
{
|
|
3441
|
-
value: "none",
|
|
3442
|
-
label: "None",
|
|
3443
|
-
hint: "No CLI tools"
|
|
3444
|
-
}
|
|
3445
|
-
],
|
|
3446
|
-
initialValue: "none"
|
|
4649
|
+
options: resolution.options,
|
|
4650
|
+
initialValue: resolution.initialValue
|
|
3447
4651
|
});
|
|
3448
4652
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3449
4653
|
return response;
|
|
3450
4654
|
}
|
|
4655
|
+
function resolveRustLibrariesPrompt(rustLibraries) {
|
|
4656
|
+
return createStaticMultiPromptResolution(RUST_LIBRARIES_PROMPT_OPTIONS, [], rustLibraries);
|
|
4657
|
+
}
|
|
3451
4658
|
async function getRustLibrariesChoice(rustLibraries) {
|
|
3452
|
-
|
|
4659
|
+
const resolution = resolveRustLibrariesPrompt(rustLibraries);
|
|
4660
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? [];
|
|
3453
4661
|
const response = await navigableMultiselect({
|
|
3454
4662
|
message: "Select Rust libraries",
|
|
3455
|
-
options:
|
|
3456
|
-
{
|
|
3457
|
-
value: "serde",
|
|
3458
|
-
label: "Serde",
|
|
3459
|
-
hint: "Serialization framework for Rust"
|
|
3460
|
-
},
|
|
3461
|
-
{
|
|
3462
|
-
value: "validator",
|
|
3463
|
-
label: "Validator",
|
|
3464
|
-
hint: "Struct validation derive macros"
|
|
3465
|
-
},
|
|
3466
|
-
{
|
|
3467
|
-
value: "jsonwebtoken",
|
|
3468
|
-
label: "jsonwebtoken",
|
|
3469
|
-
hint: "JWT encoding/decoding library"
|
|
3470
|
-
},
|
|
3471
|
-
{
|
|
3472
|
-
value: "argon2",
|
|
3473
|
-
label: "Argon2",
|
|
3474
|
-
hint: "Password hashing library"
|
|
3475
|
-
},
|
|
3476
|
-
{
|
|
3477
|
-
value: "tokio-test",
|
|
3478
|
-
label: "Tokio Test",
|
|
3479
|
-
hint: "Testing utilities for Tokio"
|
|
3480
|
-
},
|
|
3481
|
-
{
|
|
3482
|
-
value: "mockall",
|
|
3483
|
-
label: "Mockall",
|
|
3484
|
-
hint: "Powerful mocking library for Rust"
|
|
3485
|
-
}
|
|
3486
|
-
],
|
|
4663
|
+
options: resolution.options,
|
|
3487
4664
|
required: false,
|
|
3488
|
-
initialValues:
|
|
4665
|
+
initialValues: resolution.initialValue
|
|
3489
4666
|
});
|
|
3490
4667
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3491
4668
|
return response;
|
|
3492
4669
|
}
|
|
4670
|
+
function resolveRustLoggingPrompt(rustLogging) {
|
|
4671
|
+
return createStaticSinglePromptResolution(RUST_LOGGING_PROMPT_OPTIONS, "tracing", rustLogging);
|
|
4672
|
+
}
|
|
3493
4673
|
async function getRustLoggingChoice(rustLogging) {
|
|
3494
|
-
|
|
4674
|
+
const resolution = resolveRustLoggingPrompt(rustLogging);
|
|
4675
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3495
4676
|
const response = await navigableSelect({
|
|
3496
4677
|
message: "Select Rust logging library",
|
|
3497
|
-
options:
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
4678
|
+
options: resolution.options,
|
|
4679
|
+
initialValue: resolution.initialValue
|
|
4680
|
+
});
|
|
4681
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4682
|
+
return response;
|
|
4683
|
+
}
|
|
4684
|
+
function resolveRustErrorHandlingPrompt(rustErrorHandling) {
|
|
4685
|
+
return createStaticSinglePromptResolution(RUST_ERROR_HANDLING_PROMPT_OPTIONS, "anyhow-thiserror", rustErrorHandling);
|
|
4686
|
+
}
|
|
4687
|
+
async function getRustErrorHandlingChoice(rustErrorHandling) {
|
|
4688
|
+
const resolution = resolveRustErrorHandlingPrompt(rustErrorHandling);
|
|
4689
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4690
|
+
const response = await navigableSelect({
|
|
4691
|
+
message: "Select Rust error handling library",
|
|
4692
|
+
options: resolution.options,
|
|
4693
|
+
initialValue: resolution.initialValue
|
|
4694
|
+
});
|
|
4695
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4696
|
+
return response;
|
|
4697
|
+
}
|
|
4698
|
+
function resolveRustCachingPrompt(rustCaching) {
|
|
4699
|
+
return createStaticSinglePromptResolution(RUST_CACHING_PROMPT_OPTIONS, "none", rustCaching);
|
|
4700
|
+
}
|
|
4701
|
+
async function getRustCachingChoice(rustCaching) {
|
|
4702
|
+
const resolution = resolveRustCachingPrompt(rustCaching);
|
|
4703
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4704
|
+
const response = await navigableSelect({
|
|
4705
|
+
message: "Select Rust caching library",
|
|
4706
|
+
options: resolution.options,
|
|
4707
|
+
initialValue: resolution.initialValue
|
|
4708
|
+
});
|
|
4709
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4710
|
+
return response;
|
|
4711
|
+
}
|
|
4712
|
+
async function getRustAuthChoice(rustAuth) {
|
|
4713
|
+
if (rustAuth !== void 0) return rustAuth;
|
|
4714
|
+
const response = await navigableSelect({
|
|
4715
|
+
message: "Select Rust authentication library",
|
|
4716
|
+
options: [{
|
|
4717
|
+
value: "oauth2",
|
|
4718
|
+
label: "OAuth2",
|
|
4719
|
+
hint: "OAuth2 client with authorization code, PKCE, and token exchange flows"
|
|
4720
|
+
}, {
|
|
4721
|
+
value: "none",
|
|
4722
|
+
label: "None",
|
|
4723
|
+
hint: "No authentication library"
|
|
4724
|
+
}],
|
|
4725
|
+
initialValue: "none"
|
|
3515
4726
|
});
|
|
3516
4727
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3517
4728
|
return response;
|
|
@@ -3955,10 +5166,20 @@ async function promptShadcnRadius() {
|
|
|
3955
5166
|
|
|
3956
5167
|
//#endregion
|
|
3957
5168
|
//#region src/prompts/state-management.ts
|
|
3958
|
-
|
|
3959
|
-
if (stateManagement !== void 0) return
|
|
3960
|
-
|
|
3961
|
-
|
|
5169
|
+
function resolveStateManagementPrompt(context = {}) {
|
|
5170
|
+
if (context.stateManagement !== void 0) return {
|
|
5171
|
+
shouldPrompt: false,
|
|
5172
|
+
mode: "single",
|
|
5173
|
+
options: [],
|
|
5174
|
+
autoValue: context.stateManagement
|
|
5175
|
+
};
|
|
5176
|
+
const { web } = splitFrontends$1(context.frontends);
|
|
5177
|
+
if (web.length === 0) return {
|
|
5178
|
+
shouldPrompt: false,
|
|
5179
|
+
mode: "single",
|
|
5180
|
+
options: [],
|
|
5181
|
+
autoValue: "none"
|
|
5182
|
+
};
|
|
3962
5183
|
const isReact = web.some((f) => [
|
|
3963
5184
|
"tanstack-router",
|
|
3964
5185
|
"react-router",
|
|
@@ -4012,10 +5233,23 @@ async function getStateManagementChoice(stateManagement, frontends) {
|
|
|
4012
5233
|
label: "None",
|
|
4013
5234
|
hint: "Skip state management setup"
|
|
4014
5235
|
});
|
|
4015
|
-
|
|
4016
|
-
|
|
5236
|
+
return {
|
|
5237
|
+
shouldPrompt: true,
|
|
5238
|
+
mode: "single",
|
|
4017
5239
|
options,
|
|
4018
5240
|
initialValue: "none"
|
|
5241
|
+
};
|
|
5242
|
+
}
|
|
5243
|
+
async function getStateManagementChoice(stateManagement, frontends) {
|
|
5244
|
+
const resolution = resolveStateManagementPrompt({
|
|
5245
|
+
stateManagement,
|
|
5246
|
+
frontends
|
|
5247
|
+
});
|
|
5248
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
5249
|
+
const response = await navigableSelect({
|
|
5250
|
+
message: "Select state management",
|
|
5251
|
+
options: resolution.options,
|
|
5252
|
+
initialValue: resolution.initialValue
|
|
4019
5253
|
});
|
|
4020
5254
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4021
5255
|
return response;
|
|
@@ -4023,43 +5257,48 @@ async function getStateManagementChoice(stateManagement, frontends) {
|
|
|
4023
5257
|
|
|
4024
5258
|
//#endregion
|
|
4025
5259
|
//#region src/prompts/testing.ts
|
|
5260
|
+
const TESTING_PROMPT_OPTIONS = [
|
|
5261
|
+
{
|
|
5262
|
+
value: "vitest",
|
|
5263
|
+
label: "Vitest",
|
|
5264
|
+
hint: "Blazing fast Vite-native unit test framework"
|
|
5265
|
+
},
|
|
5266
|
+
{
|
|
5267
|
+
value: "vitest-playwright",
|
|
5268
|
+
label: "Vitest + Playwright",
|
|
5269
|
+
hint: "Both unit and E2E testing for complete coverage"
|
|
5270
|
+
},
|
|
5271
|
+
{
|
|
5272
|
+
value: "playwright",
|
|
5273
|
+
label: "Playwright",
|
|
5274
|
+
hint: "End-to-end testing framework by Microsoft"
|
|
5275
|
+
},
|
|
5276
|
+
{
|
|
5277
|
+
value: "jest",
|
|
5278
|
+
label: "Jest",
|
|
5279
|
+
hint: "Classic testing framework with wide ecosystem"
|
|
5280
|
+
},
|
|
5281
|
+
{
|
|
5282
|
+
value: "cypress",
|
|
5283
|
+
label: "Cypress",
|
|
5284
|
+
hint: "E2E testing with time travel debugging"
|
|
5285
|
+
},
|
|
5286
|
+
{
|
|
5287
|
+
value: "none",
|
|
5288
|
+
label: "None",
|
|
5289
|
+
hint: "Skip testing framework setup"
|
|
5290
|
+
}
|
|
5291
|
+
];
|
|
5292
|
+
function resolveTestingPrompt(testing) {
|
|
5293
|
+
return createStaticSinglePromptResolution(TESTING_PROMPT_OPTIONS, "vitest", testing);
|
|
5294
|
+
}
|
|
4026
5295
|
async function getTestingChoice(testing) {
|
|
4027
|
-
|
|
5296
|
+
const resolution = resolveTestingPrompt(testing);
|
|
5297
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4028
5298
|
const response = await navigableSelect({
|
|
4029
5299
|
message: "Select testing framework",
|
|
4030
|
-
options:
|
|
4031
|
-
|
|
4032
|
-
value: "vitest",
|
|
4033
|
-
label: "Vitest",
|
|
4034
|
-
hint: "Blazing fast Vite-native unit test framework"
|
|
4035
|
-
},
|
|
4036
|
-
{
|
|
4037
|
-
value: "vitest-playwright",
|
|
4038
|
-
label: "Vitest + Playwright",
|
|
4039
|
-
hint: "Both unit and E2E testing for complete coverage"
|
|
4040
|
-
},
|
|
4041
|
-
{
|
|
4042
|
-
value: "playwright",
|
|
4043
|
-
label: "Playwright",
|
|
4044
|
-
hint: "End-to-end testing framework by Microsoft"
|
|
4045
|
-
},
|
|
4046
|
-
{
|
|
4047
|
-
value: "jest",
|
|
4048
|
-
label: "Jest",
|
|
4049
|
-
hint: "Classic testing framework with wide ecosystem"
|
|
4050
|
-
},
|
|
4051
|
-
{
|
|
4052
|
-
value: "cypress",
|
|
4053
|
-
label: "Cypress",
|
|
4054
|
-
hint: "E2E testing with time travel debugging"
|
|
4055
|
-
},
|
|
4056
|
-
{
|
|
4057
|
-
value: "none",
|
|
4058
|
-
label: "None",
|
|
4059
|
-
hint: "Skip testing framework setup"
|
|
4060
|
-
}
|
|
4061
|
-
],
|
|
4062
|
-
initialValue: "vitest"
|
|
5300
|
+
options: resolution.options,
|
|
5301
|
+
initialValue: resolution.initialValue
|
|
4063
5302
|
});
|
|
4064
5303
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4065
5304
|
return response;
|
|
@@ -4117,21 +5356,48 @@ const UI_LIBRARY_OPTIONS = {
|
|
|
4117
5356
|
hint: "No UI component library"
|
|
4118
5357
|
}
|
|
4119
5358
|
};
|
|
4120
|
-
|
|
4121
|
-
const { web } = splitFrontends$1(frontends);
|
|
4122
|
-
if (web.length === 0) return
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
5359
|
+
function resolveUILibraryPrompt(context = {}) {
|
|
5360
|
+
const { web } = splitFrontends$1(context.frontends);
|
|
5361
|
+
if (web.length === 0) return {
|
|
5362
|
+
shouldPrompt: false,
|
|
5363
|
+
mode: "single",
|
|
5364
|
+
options: [],
|
|
5365
|
+
autoValue: "none"
|
|
5366
|
+
};
|
|
5367
|
+
const compatibleLibraries = getCompatibleUILibraries$1(context.frontends, context.astroIntegration);
|
|
5368
|
+
if (context.uiLibrary !== void 0) return {
|
|
5369
|
+
shouldPrompt: false,
|
|
5370
|
+
mode: "single",
|
|
5371
|
+
options: compatibleLibraries.map((lib) => ({
|
|
5372
|
+
value: lib,
|
|
5373
|
+
label: UI_LIBRARY_OPTIONS[lib].label,
|
|
5374
|
+
hint: UI_LIBRARY_OPTIONS[lib].hint
|
|
5375
|
+
})),
|
|
5376
|
+
autoValue: compatibleLibraries.includes(context.uiLibrary) ? context.uiLibrary : compatibleLibraries[0]
|
|
5377
|
+
};
|
|
4130
5378
|
const defaultLib = DEFAULT_UI_LIBRARY_BY_FRONTEND[web[0]];
|
|
5379
|
+
return {
|
|
5380
|
+
shouldPrompt: true,
|
|
5381
|
+
mode: "single",
|
|
5382
|
+
options: compatibleLibraries.map((lib) => ({
|
|
5383
|
+
value: lib,
|
|
5384
|
+
label: UI_LIBRARY_OPTIONS[lib].label,
|
|
5385
|
+
hint: UI_LIBRARY_OPTIONS[lib].hint
|
|
5386
|
+
})),
|
|
5387
|
+
initialValue: compatibleLibraries.includes(defaultLib) ? defaultLib : compatibleLibraries[0]
|
|
5388
|
+
};
|
|
5389
|
+
}
|
|
5390
|
+
async function getUILibraryChoice(uiLibrary, frontends, astroIntegration) {
|
|
5391
|
+
const resolution = resolveUILibraryPrompt({
|
|
5392
|
+
uiLibrary,
|
|
5393
|
+
frontends,
|
|
5394
|
+
astroIntegration
|
|
5395
|
+
});
|
|
5396
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4131
5397
|
const selected = await navigableSelect({
|
|
4132
5398
|
message: "Select UI component library",
|
|
4133
|
-
options,
|
|
4134
|
-
initialValue:
|
|
5399
|
+
options: resolution.options,
|
|
5400
|
+
initialValue: resolution.initialValue
|
|
4135
5401
|
});
|
|
4136
5402
|
if (isCancel$1(selected)) return exitCancelled("Operation cancelled");
|
|
4137
5403
|
return selected;
|
|
@@ -4139,53 +5405,58 @@ async function getUILibraryChoice(uiLibrary, frontends, astroIntegration) {
|
|
|
4139
5405
|
|
|
4140
5406
|
//#endregion
|
|
4141
5407
|
//#region src/prompts/validation.ts
|
|
5408
|
+
const VALIDATION_PROMPT_OPTIONS = [
|
|
5409
|
+
{
|
|
5410
|
+
value: "zod",
|
|
5411
|
+
label: "Zod",
|
|
5412
|
+
hint: "TypeScript-first schema validation (recommended)"
|
|
5413
|
+
},
|
|
5414
|
+
{
|
|
5415
|
+
value: "valibot",
|
|
5416
|
+
label: "Valibot",
|
|
5417
|
+
hint: "Smaller bundle alternative to Zod (~1KB)"
|
|
5418
|
+
},
|
|
5419
|
+
{
|
|
5420
|
+
value: "arktype",
|
|
5421
|
+
label: "ArkType",
|
|
5422
|
+
hint: "TypeScript-first validation, 2-4x faster than Zod"
|
|
5423
|
+
},
|
|
5424
|
+
{
|
|
5425
|
+
value: "typebox",
|
|
5426
|
+
label: "TypeBox",
|
|
5427
|
+
hint: "JSON Schema type builder for TypeScript"
|
|
5428
|
+
},
|
|
5429
|
+
{
|
|
5430
|
+
value: "typia",
|
|
5431
|
+
label: "Typia",
|
|
5432
|
+
hint: "Super-fast validation via compile-time transform"
|
|
5433
|
+
},
|
|
5434
|
+
{
|
|
5435
|
+
value: "runtypes",
|
|
5436
|
+
label: "Runtypes",
|
|
5437
|
+
hint: "Runtime type validation with composable validators"
|
|
5438
|
+
},
|
|
5439
|
+
{
|
|
5440
|
+
value: "effect-schema",
|
|
5441
|
+
label: "@effect/schema",
|
|
5442
|
+
hint: "Effect ecosystem schema validation with powerful transformations"
|
|
5443
|
+
},
|
|
5444
|
+
{
|
|
5445
|
+
value: "none",
|
|
5446
|
+
label: "None",
|
|
5447
|
+
hint: "Use Zod internally only (no additional library)"
|
|
5448
|
+
}
|
|
5449
|
+
];
|
|
5450
|
+
function resolveValidationPrompt(validation) {
|
|
5451
|
+
return createStaticSinglePromptResolution(VALIDATION_PROMPT_OPTIONS, "zod", validation);
|
|
5452
|
+
}
|
|
4142
5453
|
async function getValidationChoice(validation) {
|
|
4143
|
-
|
|
5454
|
+
const resolution = resolveValidationPrompt(validation);
|
|
5455
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4144
5456
|
const response = await navigableSelect({
|
|
4145
5457
|
message: "Select validation library",
|
|
4146
|
-
options:
|
|
4147
|
-
|
|
4148
|
-
value: "zod",
|
|
4149
|
-
label: "Zod",
|
|
4150
|
-
hint: "TypeScript-first schema validation (recommended)"
|
|
4151
|
-
},
|
|
4152
|
-
{
|
|
4153
|
-
value: "valibot",
|
|
4154
|
-
label: "Valibot",
|
|
4155
|
-
hint: "Smaller bundle alternative to Zod (~1KB)"
|
|
4156
|
-
},
|
|
4157
|
-
{
|
|
4158
|
-
value: "arktype",
|
|
4159
|
-
label: "ArkType",
|
|
4160
|
-
hint: "TypeScript-first validation, 2-4x faster than Zod"
|
|
4161
|
-
},
|
|
4162
|
-
{
|
|
4163
|
-
value: "typebox",
|
|
4164
|
-
label: "TypeBox",
|
|
4165
|
-
hint: "JSON Schema type builder for TypeScript"
|
|
4166
|
-
},
|
|
4167
|
-
{
|
|
4168
|
-
value: "typia",
|
|
4169
|
-
label: "Typia",
|
|
4170
|
-
hint: "Super-fast validation via compile-time transform"
|
|
4171
|
-
},
|
|
4172
|
-
{
|
|
4173
|
-
value: "runtypes",
|
|
4174
|
-
label: "Runtypes",
|
|
4175
|
-
hint: "Runtime type validation with composable validators"
|
|
4176
|
-
},
|
|
4177
|
-
{
|
|
4178
|
-
value: "effect-schema",
|
|
4179
|
-
label: "@effect/schema",
|
|
4180
|
-
hint: "Effect ecosystem schema validation with powerful transformations"
|
|
4181
|
-
},
|
|
4182
|
-
{
|
|
4183
|
-
value: "none",
|
|
4184
|
-
label: "None",
|
|
4185
|
-
hint: "Use Zod internally only (no additional library)"
|
|
4186
|
-
}
|
|
4187
|
-
],
|
|
4188
|
-
initialValue: "zod"
|
|
5458
|
+
options: resolution.options,
|
|
5459
|
+
initialValue: resolution.initialValue
|
|
4189
5460
|
});
|
|
4190
5461
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4191
5462
|
return response;
|
|
@@ -4220,6 +5491,10 @@ function getDeploymentDisplay(deployment) {
|
|
|
4220
5491
|
label: "Cloudflare",
|
|
4221
5492
|
hint: "Deploy to Cloudflare Workers using Alchemy"
|
|
4222
5493
|
};
|
|
5494
|
+
if (deployment === "vercel") return {
|
|
5495
|
+
label: "Vercel",
|
|
5496
|
+
hint: "Deploy to Vercel's edge network"
|
|
5497
|
+
};
|
|
4223
5498
|
return {
|
|
4224
5499
|
label: deployment,
|
|
4225
5500
|
hint: `Add ${deployment} deployment`
|
|
@@ -4230,7 +5505,11 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
|
|
|
4230
5505
|
if (!hasWebFrontend(frontend)) return "none";
|
|
4231
5506
|
const response = await navigableSelect({
|
|
4232
5507
|
message: "Select web deployment",
|
|
4233
|
-
options: [
|
|
5508
|
+
options: [
|
|
5509
|
+
"cloudflare",
|
|
5510
|
+
"vercel",
|
|
5511
|
+
"none"
|
|
5512
|
+
].map((deploy) => {
|
|
4234
5513
|
const { label, hint } = getDeploymentDisplay(deploy);
|
|
4235
5514
|
return {
|
|
4236
5515
|
value: deploy,
|
|
@@ -4398,6 +5677,10 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
4398
5677
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
4399
5678
|
return getCachingChoice(flags.caching, results.backend);
|
|
4400
5679
|
},
|
|
5680
|
+
i18n: ({ results }) => {
|
|
5681
|
+
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
5682
|
+
return getI18nChoice(flags.i18n, results.frontend);
|
|
5683
|
+
},
|
|
4401
5684
|
search: ({ results }) => {
|
|
4402
5685
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
4403
5686
|
return getSearchChoice(flags.search, results.backend);
|
|
@@ -4434,6 +5717,18 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
4434
5717
|
if (results.ecosystem !== "rust") return Promise.resolve("none");
|
|
4435
5718
|
return getRustLoggingChoice(flags.rustLogging);
|
|
4436
5719
|
},
|
|
5720
|
+
rustErrorHandling: ({ results }) => {
|
|
5721
|
+
if (results.ecosystem !== "rust") return Promise.resolve("none");
|
|
5722
|
+
return getRustErrorHandlingChoice(flags.rustErrorHandling);
|
|
5723
|
+
},
|
|
5724
|
+
rustCaching: ({ results }) => {
|
|
5725
|
+
if (results.ecosystem !== "rust") return Promise.resolve("none");
|
|
5726
|
+
return getRustCachingChoice(flags.rustCaching);
|
|
5727
|
+
},
|
|
5728
|
+
rustAuth: ({ results }) => {
|
|
5729
|
+
if (results.ecosystem !== "rust") return Promise.resolve("none");
|
|
5730
|
+
return getRustAuthChoice(flags.rustAuth);
|
|
5731
|
+
},
|
|
4437
5732
|
pythonWebFramework: ({ results }) => {
|
|
4438
5733
|
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
4439
5734
|
return getPythonWebFrameworkChoice(flags.pythonWebFramework);
|
|
@@ -4450,10 +5745,18 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
4450
5745
|
if (results.ecosystem !== "python") return Promise.resolve([]);
|
|
4451
5746
|
return getPythonAiChoice(flags.pythonAi);
|
|
4452
5747
|
},
|
|
5748
|
+
pythonAuth: ({ results }) => {
|
|
5749
|
+
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
5750
|
+
return getPythonAuthChoice(flags.pythonAuth);
|
|
5751
|
+
},
|
|
4453
5752
|
pythonTaskQueue: ({ results }) => {
|
|
4454
5753
|
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
4455
5754
|
return getPythonTaskQueueChoice(flags.pythonTaskQueue);
|
|
4456
5755
|
},
|
|
5756
|
+
pythonGraphql: ({ results }) => {
|
|
5757
|
+
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
5758
|
+
return getPythonGraphqlChoice(flags.pythonGraphql);
|
|
5759
|
+
},
|
|
4457
5760
|
pythonQuality: ({ results }) => {
|
|
4458
5761
|
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
4459
5762
|
return getPythonQualityChoice(flags.pythonQuality);
|
|
@@ -4478,13 +5781,45 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
4478
5781
|
if (results.ecosystem !== "go") return Promise.resolve("none");
|
|
4479
5782
|
return getGoLoggingChoice(flags.goLogging);
|
|
4480
5783
|
},
|
|
5784
|
+
goAuth: ({ results }) => {
|
|
5785
|
+
if (results.ecosystem !== "go") return Promise.resolve("none");
|
|
5786
|
+
return getGoAuthChoice(flags.goAuth);
|
|
5787
|
+
},
|
|
5788
|
+
javaWebFramework: ({ results }) => {
|
|
5789
|
+
if (results.ecosystem !== "java") return Promise.resolve("none");
|
|
5790
|
+
return getJavaWebFrameworkChoice(flags.javaWebFramework);
|
|
5791
|
+
},
|
|
5792
|
+
javaBuildTool: ({ results }) => {
|
|
5793
|
+
if (results.ecosystem !== "java") return Promise.resolve("none");
|
|
5794
|
+
return getJavaBuildToolChoice(flags.javaBuildTool);
|
|
5795
|
+
},
|
|
5796
|
+
javaOrm: ({ results }) => {
|
|
5797
|
+
if (results.ecosystem !== "java") return Promise.resolve("none");
|
|
5798
|
+
if (results.javaWebFramework !== "spring-boot" || results.javaBuildTool === "none") return Promise.resolve("none");
|
|
5799
|
+
return getJavaOrmChoice(flags.javaOrm);
|
|
5800
|
+
},
|
|
5801
|
+
javaAuth: ({ results }) => {
|
|
5802
|
+
if (results.ecosystem !== "java") return Promise.resolve("none");
|
|
5803
|
+
if (results.javaWebFramework !== "spring-boot" || results.javaBuildTool === "none") return Promise.resolve("none");
|
|
5804
|
+
return getJavaAuthChoice(flags.javaAuth);
|
|
5805
|
+
},
|
|
5806
|
+
javaLibraries: ({ results }) => {
|
|
5807
|
+
if (results.ecosystem !== "java") return Promise.resolve([]);
|
|
5808
|
+
if (results.javaWebFramework !== "spring-boot" || results.javaBuildTool === "none") return Promise.resolve([]);
|
|
5809
|
+
return getJavaLibrariesChoice(flags.javaLibraries);
|
|
5810
|
+
},
|
|
5811
|
+
javaTestingLibraries: ({ results }) => {
|
|
5812
|
+
if (results.ecosystem !== "java") return Promise.resolve([]);
|
|
5813
|
+
if (results.javaBuildTool === "none") return Promise.resolve([]);
|
|
5814
|
+
return getJavaTestingLibrariesChoice(flags.javaTestingLibraries);
|
|
5815
|
+
},
|
|
4481
5816
|
aiDocs: () => getAiDocsChoice(flags.aiDocs),
|
|
4482
5817
|
git: () => getGitChoice(flags.git),
|
|
4483
5818
|
packageManager: ({ results }) => {
|
|
4484
|
-
if (results.ecosystem === "rust" || results.ecosystem === "python" || results.ecosystem === "go") return Promise.resolve(flags.packageManager ?? getUserPkgManager());
|
|
5819
|
+
if (results.ecosystem === "rust" || results.ecosystem === "python" || results.ecosystem === "go" || results.ecosystem === "java") return Promise.resolve(flags.packageManager ?? getUserPkgManager());
|
|
4485
5820
|
return getPackageManagerChoice(flags.packageManager);
|
|
4486
5821
|
},
|
|
4487
|
-
install: ({ results }) => getinstallChoice(flags.install, results.ecosystem)
|
|
5822
|
+
install: ({ results }) => getinstallChoice(flags.install, results.ecosystem, results.javaBuildTool)
|
|
4488
5823
|
}, { onCancel: () => exitCancelled("Operation cancelled") });
|
|
4489
5824
|
return {
|
|
4490
5825
|
projectName,
|
|
@@ -4527,6 +5862,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
4527
5862
|
analytics: result.analytics,
|
|
4528
5863
|
cms: result.cms,
|
|
4529
5864
|
caching: result.caching,
|
|
5865
|
+
i18n: result.i18n,
|
|
4530
5866
|
search: result.search,
|
|
4531
5867
|
fileStorage: result.fileStorage,
|
|
4532
5868
|
ecosystem: result.ecosystem,
|
|
@@ -4537,17 +5873,29 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
4537
5873
|
rustCli: result.rustCli,
|
|
4538
5874
|
rustLibraries: result.rustLibraries,
|
|
4539
5875
|
rustLogging: result.rustLogging,
|
|
5876
|
+
rustErrorHandling: result.rustErrorHandling,
|
|
5877
|
+
rustCaching: result.rustCaching,
|
|
5878
|
+
rustAuth: result.rustAuth,
|
|
4540
5879
|
pythonWebFramework: result.pythonWebFramework,
|
|
4541
5880
|
pythonOrm: result.pythonOrm,
|
|
4542
5881
|
pythonValidation: result.pythonValidation,
|
|
4543
5882
|
pythonAi: result.pythonAi,
|
|
5883
|
+
pythonAuth: result.pythonAuth,
|
|
4544
5884
|
pythonTaskQueue: result.pythonTaskQueue,
|
|
5885
|
+
pythonGraphql: result.pythonGraphql,
|
|
4545
5886
|
pythonQuality: result.pythonQuality,
|
|
4546
5887
|
goWebFramework: result.goWebFramework,
|
|
4547
5888
|
goOrm: result.goOrm,
|
|
4548
5889
|
goApi: result.goApi,
|
|
4549
5890
|
goCli: result.goCli,
|
|
4550
5891
|
goLogging: result.goLogging,
|
|
5892
|
+
goAuth: result.goAuth,
|
|
5893
|
+
javaWebFramework: result.javaWebFramework,
|
|
5894
|
+
javaBuildTool: result.javaBuildTool,
|
|
5895
|
+
javaOrm: result.javaOrm,
|
|
5896
|
+
javaAuth: result.javaAuth,
|
|
5897
|
+
javaLibraries: result.javaLibraries,
|
|
5898
|
+
javaTestingLibraries: result.javaTestingLibraries,
|
|
4551
5899
|
aiDocs: result.aiDocs
|
|
4552
5900
|
};
|
|
4553
5901
|
}
|
|
@@ -4802,6 +6150,7 @@ function getTypeScriptFlags(config) {
|
|
|
4802
6150
|
flags.push(`--logging ${config.logging}`);
|
|
4803
6151
|
flags.push(`--observability ${config.observability}`);
|
|
4804
6152
|
flags.push(`--caching ${config.caching}`);
|
|
6153
|
+
flags.push(`--i18n ${config.i18n}`);
|
|
4805
6154
|
flags.push(`--cms ${config.cms}`);
|
|
4806
6155
|
flags.push(`--search ${config.search}`);
|
|
4807
6156
|
flags.push(`--file-storage ${config.fileStorage}`);
|
|
@@ -4824,6 +6173,9 @@ function getRustFlags(config) {
|
|
|
4824
6173
|
flags.push(`--rust-cli ${config.rustCli}`);
|
|
4825
6174
|
flags.push(formatArrayFlag("rust-libraries", config.rustLibraries));
|
|
4826
6175
|
flags.push(`--rust-logging ${config.rustLogging}`);
|
|
6176
|
+
flags.push(`--rust-error-handling ${config.rustErrorHandling}`);
|
|
6177
|
+
flags.push(`--rust-caching ${config.rustCaching}`);
|
|
6178
|
+
flags.push(`--rust-auth ${config.rustAuth}`);
|
|
4827
6179
|
appendSharedNonTypeScriptFlags(flags, config);
|
|
4828
6180
|
appendCommonFlags(flags, config);
|
|
4829
6181
|
return flags;
|
|
@@ -4834,7 +6186,9 @@ function getPythonFlags(config) {
|
|
|
4834
6186
|
flags.push(`--python-orm ${config.pythonOrm}`);
|
|
4835
6187
|
flags.push(`--python-validation ${config.pythonValidation}`);
|
|
4836
6188
|
flags.push(formatArrayFlag("python-ai", config.pythonAi));
|
|
6189
|
+
flags.push(`--python-auth ${config.pythonAuth}`);
|
|
4837
6190
|
flags.push(`--python-task-queue ${config.pythonTaskQueue}`);
|
|
6191
|
+
flags.push(`--python-graphql ${config.pythonGraphql}`);
|
|
4838
6192
|
flags.push(`--python-quality ${config.pythonQuality}`);
|
|
4839
6193
|
appendSharedNonTypeScriptFlags(flags, config);
|
|
4840
6194
|
appendCommonFlags(flags, config);
|
|
@@ -4847,11 +6201,24 @@ function getGoFlags(config) {
|
|
|
4847
6201
|
flags.push(`--go-api ${config.goApi}`);
|
|
4848
6202
|
flags.push(`--go-cli ${config.goCli}`);
|
|
4849
6203
|
flags.push(`--go-logging ${config.goLogging}`);
|
|
6204
|
+
flags.push(`--go-auth ${config.goAuth}`);
|
|
4850
6205
|
flags.push(`--auth ${config.auth}`);
|
|
4851
6206
|
appendSharedNonTypeScriptFlags(flags, config);
|
|
4852
6207
|
appendCommonFlags(flags, config);
|
|
4853
6208
|
return flags;
|
|
4854
6209
|
}
|
|
6210
|
+
function getJavaFlags(config) {
|
|
6211
|
+
const flags = ["--ecosystem java"];
|
|
6212
|
+
flags.push(`--java-web-framework ${config.javaWebFramework}`);
|
|
6213
|
+
flags.push(`--java-build-tool ${config.javaBuildTool}`);
|
|
6214
|
+
flags.push(`--java-orm ${config.javaOrm}`);
|
|
6215
|
+
flags.push(`--java-auth ${config.javaAuth}`);
|
|
6216
|
+
flags.push(formatArrayFlag("java-libraries", config.javaLibraries));
|
|
6217
|
+
flags.push(formatArrayFlag("java-testing-libraries", config.javaTestingLibraries));
|
|
6218
|
+
appendSharedNonTypeScriptFlags(flags, config);
|
|
6219
|
+
appendCommonFlags(flags, config);
|
|
6220
|
+
return flags;
|
|
6221
|
+
}
|
|
4855
6222
|
function generateReproducibleCommand(config) {
|
|
4856
6223
|
let flags;
|
|
4857
6224
|
switch (config.ecosystem) {
|
|
@@ -4864,6 +6231,9 @@ function generateReproducibleCommand(config) {
|
|
|
4864
6231
|
case "go":
|
|
4865
6232
|
flags = getGoFlags(config);
|
|
4866
6233
|
break;
|
|
6234
|
+
case "java":
|
|
6235
|
+
flags = getJavaFlags(config);
|
|
6236
|
+
break;
|
|
4867
6237
|
case "typescript":
|
|
4868
6238
|
default:
|
|
4869
6239
|
flags = getTypeScriptFlags(config);
|
|
@@ -5071,6 +6441,7 @@ function processFlags(options, projectName) {
|
|
|
5071
6441
|
if (options.observability !== void 0) config.observability = options.observability;
|
|
5072
6442
|
if (options.cms !== void 0) config.cms = options.cms;
|
|
5073
6443
|
if (options.caching !== void 0) config.caching = options.caching;
|
|
6444
|
+
if (options.i18n !== void 0) config.i18n = options.i18n;
|
|
5074
6445
|
if (options.search !== void 0) config.search = options.search;
|
|
5075
6446
|
if (options.fileStorage !== void 0) config.fileStorage = options.fileStorage;
|
|
5076
6447
|
if (options.analytics !== void 0) config.analytics = options.analytics;
|
|
@@ -5107,17 +6478,29 @@ function processFlags(options, projectName) {
|
|
|
5107
6478
|
if (options.rustCli !== void 0) config.rustCli = options.rustCli;
|
|
5108
6479
|
if (options.rustLibraries !== void 0) config.rustLibraries = processArrayOption(options.rustLibraries);
|
|
5109
6480
|
if (options.rustLogging !== void 0) config.rustLogging = options.rustLogging;
|
|
6481
|
+
if (options.rustErrorHandling !== void 0) config.rustErrorHandling = options.rustErrorHandling;
|
|
6482
|
+
if (options.rustCaching !== void 0) config.rustCaching = options.rustCaching;
|
|
6483
|
+
if (options.rustAuth !== void 0) config.rustAuth = options.rustAuth;
|
|
5110
6484
|
if (options.pythonWebFramework !== void 0) config.pythonWebFramework = options.pythonWebFramework;
|
|
5111
6485
|
if (options.pythonOrm !== void 0) config.pythonOrm = options.pythonOrm;
|
|
5112
6486
|
if (options.pythonValidation !== void 0) config.pythonValidation = options.pythonValidation;
|
|
5113
6487
|
if (options.pythonAi !== void 0) config.pythonAi = processArrayOption(options.pythonAi);
|
|
6488
|
+
if (options.pythonAuth !== void 0) config.pythonAuth = options.pythonAuth;
|
|
5114
6489
|
if (options.pythonTaskQueue !== void 0) config.pythonTaskQueue = options.pythonTaskQueue;
|
|
6490
|
+
if (options.pythonGraphql !== void 0) config.pythonGraphql = options.pythonGraphql;
|
|
5115
6491
|
if (options.pythonQuality !== void 0) config.pythonQuality = options.pythonQuality;
|
|
5116
6492
|
if (options.goWebFramework !== void 0) config.goWebFramework = options.goWebFramework;
|
|
5117
6493
|
if (options.goOrm !== void 0) config.goOrm = options.goOrm;
|
|
5118
6494
|
if (options.goApi !== void 0) config.goApi = options.goApi;
|
|
5119
6495
|
if (options.goCli !== void 0) config.goCli = options.goCli;
|
|
5120
6496
|
if (options.goLogging !== void 0) config.goLogging = options.goLogging;
|
|
6497
|
+
if (options.goAuth !== void 0) config.goAuth = options.goAuth;
|
|
6498
|
+
if (options.javaWebFramework !== void 0) config.javaWebFramework = options.javaWebFramework;
|
|
6499
|
+
if (options.javaBuildTool !== void 0) config.javaBuildTool = options.javaBuildTool;
|
|
6500
|
+
if (options.javaOrm !== void 0) config.javaOrm = options.javaOrm;
|
|
6501
|
+
if (options.javaAuth !== void 0) config.javaAuth = options.javaAuth;
|
|
6502
|
+
if (options.javaLibraries !== void 0) config.javaLibraries = processArrayOption(options.javaLibraries);
|
|
6503
|
+
if (options.javaTestingLibraries !== void 0) config.javaTestingLibraries = processArrayOption(options.javaTestingLibraries);
|
|
5121
6504
|
return config;
|
|
5122
6505
|
}
|
|
5123
6506
|
function getProvidedFlags(options) {
|
|
@@ -5131,6 +6514,11 @@ function validateArrayOptions(options) {
|
|
|
5131
6514
|
validateNoneExclusivity(options.frontend, "frontend options");
|
|
5132
6515
|
validateNoneExclusivity(options.addons, "addons");
|
|
5133
6516
|
validateNoneExclusivity(options.examples, "examples");
|
|
6517
|
+
validateNoneExclusivity(options.aiDocs, "ai docs");
|
|
6518
|
+
validateNoneExclusivity(options.rustLibraries, "rust libraries");
|
|
6519
|
+
validateNoneExclusivity(options.pythonAi, "python ai libraries");
|
|
6520
|
+
validateNoneExclusivity(options.javaLibraries, "java libraries");
|
|
6521
|
+
validateNoneExclusivity(options.javaTestingLibraries, "java testing libraries");
|
|
5134
6522
|
}
|
|
5135
6523
|
|
|
5136
6524
|
//#endregion
|
|
@@ -5566,6 +6954,41 @@ function validateFrontendConstraints(config, providedFlags) {
|
|
|
5566
6954
|
validateWebDeployRequiresWebFrontend(config.webDeploy, hasWebFrontendFlag);
|
|
5567
6955
|
}
|
|
5568
6956
|
function validateApiConstraints(_config, _options) {}
|
|
6957
|
+
function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set()) {
|
|
6958
|
+
if (config.ecosystem !== "java") return;
|
|
6959
|
+
const hasSpringBoot = config.javaWebFramework === "spring-boot";
|
|
6960
|
+
const hasNoBuildTool = config.javaBuildTool === "none";
|
|
6961
|
+
const hasJavaLibraries = (config.javaLibraries ?? []).some((library) => library !== "none");
|
|
6962
|
+
const hasJavaTestingLibraries = (config.javaTestingLibraries ?? []).some((library) => library !== "none");
|
|
6963
|
+
const hasSpringOnlyFeatures = config.javaOrm !== "none" || config.javaAuth !== "none" || hasJavaLibraries;
|
|
6964
|
+
if (hasNoBuildTool && hasSpringBoot) incompatibilityError({
|
|
6965
|
+
message: "Spring Boot requires Maven or Gradle in the Java scaffold.",
|
|
6966
|
+
provided: {
|
|
6967
|
+
"java-web-framework": config.javaWebFramework ?? "none",
|
|
6968
|
+
"java-build-tool": config.javaBuildTool ?? "none"
|
|
6969
|
+
},
|
|
6970
|
+
suggestions: ["Use --java-build-tool maven or --java-build-tool gradle with Spring Boot", "Use --java-web-framework none for a plain Java source-only scaffold"]
|
|
6971
|
+
});
|
|
6972
|
+
if ((config.javaWebFramework === "none" || hasNoBuildTool) && hasSpringOnlyFeatures) incompatibilityError({
|
|
6973
|
+
message: "Spring-only Java features require the Spring Boot scaffold with Maven or Gradle.",
|
|
6974
|
+
provided: {
|
|
6975
|
+
"java-web-framework": config.javaWebFramework ?? "none",
|
|
6976
|
+
"java-build-tool": config.javaBuildTool ?? "none",
|
|
6977
|
+
"java-orm": config.javaOrm ?? "none",
|
|
6978
|
+
"java-auth": config.javaAuth ?? "none",
|
|
6979
|
+
"java-libraries": (config.javaLibraries ?? []).join(" ") || "none"
|
|
6980
|
+
},
|
|
6981
|
+
suggestions: ["Use --java-web-framework spring-boot and a real build tool for Spring features", "Clear --java-orm, --java-auth, and --java-libraries when using plain Java"]
|
|
6982
|
+
});
|
|
6983
|
+
if (hasNoBuildTool && hasJavaTestingLibraries) incompatibilityError({
|
|
6984
|
+
message: "Java testing libraries require Maven or Gradle to manage test dependencies.",
|
|
6985
|
+
provided: {
|
|
6986
|
+
"java-build-tool": config.javaBuildTool ?? "none",
|
|
6987
|
+
"java-testing-libraries": (config.javaTestingLibraries ?? []).join(" ") || "none"
|
|
6988
|
+
},
|
|
6989
|
+
suggestions: ["Use --java-build-tool maven or --java-build-tool gradle to enable JUnit/Mockito/Testcontainers", "Set --java-testing-libraries none for a source-only plain Java scaffold"]
|
|
6990
|
+
});
|
|
6991
|
+
}
|
|
5569
6992
|
function validateShadcnConstraints(config, providedFlags) {
|
|
5570
6993
|
const shadcnFlagMap = {
|
|
5571
6994
|
shadcnBase: "--shadcn-base",
|
|
@@ -5598,11 +7021,24 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
5598
7021
|
validateBackendConstraints(config, providedFlags, options);
|
|
5599
7022
|
validateFrontendConstraints(config, providedFlags);
|
|
5600
7023
|
/* @__PURE__ */ validateApiConstraints(config, options);
|
|
7024
|
+
validateJavaConstraints(config, providedFlags);
|
|
5601
7025
|
validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
|
|
5602
7026
|
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
5603
7027
|
validateWorkersCompatibility(providedFlags, options, config);
|
|
5604
7028
|
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose 'alchemy' for --server-deploy.");
|
|
5605
7029
|
if (providedFlags.has("serverDeploy") && config.serverDeploy === "cloudflare" && config.runtime !== "workers") exitWithError(`Server deployment '${config.serverDeploy}' requires '--runtime workers'. Please use '--runtime workers' or choose a different server deployment.`);
|
|
7030
|
+
if (config.serverDeploy === "vercel" && [
|
|
7031
|
+
"nestjs",
|
|
7032
|
+
"adonisjs",
|
|
7033
|
+
"encore"
|
|
7034
|
+
].includes(config.backend)) incompatibilityError({
|
|
7035
|
+
message: "Vercel serverless functions cannot host persistent-process backends",
|
|
7036
|
+
provided: {
|
|
7037
|
+
backend: config.backend,
|
|
7038
|
+
serverDeploy: config.serverDeploy
|
|
7039
|
+
},
|
|
7040
|
+
suggestions: ["Use --server-deploy fly or --server-deploy railway for NestJS/AdonisJS", "Switch to a serverless-compatible backend like Hono or Express"]
|
|
7041
|
+
});
|
|
5606
7042
|
if (config.addons && config.addons.length > 0) {
|
|
5607
7043
|
validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
|
|
5608
7044
|
config.addons = [...new Set(config.addons)];
|
|
@@ -5621,6 +7057,7 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
5621
7057
|
validateDatabaseOrmAuth(config);
|
|
5622
7058
|
if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
|
|
5623
7059
|
validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
|
|
7060
|
+
validateJavaConstraints(config);
|
|
5624
7061
|
validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
|
|
5625
7062
|
if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
|
|
5626
7063
|
validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
|
|
@@ -5927,6 +7364,12 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
5927
7364
|
displayManualSetupInstructions$4();
|
|
5928
7365
|
return;
|
|
5929
7366
|
}
|
|
7367
|
+
if (!canPromptInteractively()) {
|
|
7368
|
+
log.info("MongoDB Atlas manual setup selected (non-interactive mode)");
|
|
7369
|
+
await writeEnvFile$4(projectDir, backend);
|
|
7370
|
+
displayManualSetupInstructions$4();
|
|
7371
|
+
return;
|
|
7372
|
+
}
|
|
5930
7373
|
const mode = await select({
|
|
5931
7374
|
message: "MongoDB Atlas setup: choose mode",
|
|
5932
7375
|
options: [{
|
|
@@ -6079,6 +7522,11 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
6079
7522
|
displayManualSetupInstructions$3(backend === "self" ? "apps/web" : "apps/server");
|
|
6080
7523
|
return;
|
|
6081
7524
|
}
|
|
7525
|
+
if (!canPromptInteractively()) {
|
|
7526
|
+
await writeEnvFile$3(projectDir, backend);
|
|
7527
|
+
displayManualSetupInstructions$3(backend === "self" ? "apps/web" : "apps/server");
|
|
7528
|
+
return;
|
|
7529
|
+
}
|
|
6082
7530
|
const mode = await select({
|
|
6083
7531
|
message: "Neon setup: choose mode",
|
|
6084
7532
|
options: [{
|
|
@@ -6123,7 +7571,7 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
6123
7571
|
const regionId = await select({
|
|
6124
7572
|
message: "Select a region for your Neon project:",
|
|
6125
7573
|
options: NEON_REGIONS,
|
|
6126
|
-
initialValue: NEON_REGIONS[0]
|
|
7574
|
+
initialValue: NEON_REGIONS[0]?.value ?? "aws-us-east-1"
|
|
6127
7575
|
});
|
|
6128
7576
|
if (isCancel(projectName) || isCancel(regionId)) return exitCancelled("Operation cancelled");
|
|
6129
7577
|
const neonConfig = await createNeonProject(projectName, regionId, packageManager);
|
|
@@ -6232,11 +7680,11 @@ const AVAILABLE_REGIONS = [
|
|
|
6232
7680
|
async function setupWithCreateDb(serverDir, packageManager) {
|
|
6233
7681
|
try {
|
|
6234
7682
|
log.info("Starting Prisma Postgres setup with create-db.");
|
|
6235
|
-
const selectedRegion = await select({
|
|
7683
|
+
const selectedRegion = canPromptInteractively() ? await select({
|
|
6236
7684
|
message: "Select your preferred region:",
|
|
6237
7685
|
options: AVAILABLE_REGIONS,
|
|
6238
7686
|
initialValue: "ap-southeast-1"
|
|
6239
|
-
});
|
|
7687
|
+
}) : "ap-southeast-1";
|
|
6240
7688
|
if (isCancel(selectedRegion)) return null;
|
|
6241
7689
|
const createDbArgs = getPackageExecutionArgs(packageManager, `create-db@latest --json --region ${selectedRegion}`);
|
|
6242
7690
|
const s = spinner();
|
|
@@ -6299,6 +7747,11 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
6299
7747
|
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
6300
7748
|
return;
|
|
6301
7749
|
}
|
|
7750
|
+
if (!canPromptInteractively()) {
|
|
7751
|
+
await writeEnvFile$2(projectDir, backend);
|
|
7752
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
7753
|
+
return;
|
|
7754
|
+
}
|
|
6302
7755
|
const setupMode = await select({
|
|
6303
7756
|
message: "Prisma Postgres setup: choose mode",
|
|
6304
7757
|
options: [{
|
|
@@ -6434,6 +7887,11 @@ async function setupSupabase(config, cliInput) {
|
|
|
6434
7887
|
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
6435
7888
|
return;
|
|
6436
7889
|
}
|
|
7890
|
+
if (!canPromptInteractively()) {
|
|
7891
|
+
displayManualSupabaseInstructions();
|
|
7892
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
7893
|
+
return;
|
|
7894
|
+
}
|
|
6437
7895
|
const mode = await select({
|
|
6438
7896
|
message: "Supabase setup: choose mode",
|
|
6439
7897
|
options: [{
|
|
@@ -6623,6 +8081,11 @@ async function setupTurso(config, cliInput) {
|
|
|
6623
8081
|
displayManualSetupInstructions$1();
|
|
6624
8082
|
return;
|
|
6625
8083
|
}
|
|
8084
|
+
if (!canPromptInteractively()) {
|
|
8085
|
+
await writeEnvFile$1(projectDir, backend);
|
|
8086
|
+
displayManualSetupInstructions$1();
|
|
8087
|
+
return;
|
|
8088
|
+
}
|
|
6626
8089
|
const mode = await select({
|
|
6627
8090
|
message: "Turso setup: choose mode",
|
|
6628
8091
|
options: [{
|
|
@@ -6745,6 +8208,12 @@ async function setupUpstash(config, cliInput) {
|
|
|
6745
8208
|
displayManualSetupInstructions();
|
|
6746
8209
|
return;
|
|
6747
8210
|
}
|
|
8211
|
+
if (!canPromptInteractively()) {
|
|
8212
|
+
log.info("Upstash Redis manual setup selected (non-interactive mode)");
|
|
8213
|
+
await writeEnvFile(projectDir, backend);
|
|
8214
|
+
displayManualSetupInstructions();
|
|
8215
|
+
return;
|
|
8216
|
+
}
|
|
6748
8217
|
const mode = await select({
|
|
6749
8218
|
message: "Upstash Redis setup: choose mode",
|
|
6750
8219
|
options: [{
|
|
@@ -6953,6 +8422,10 @@ async function displayPostInstallInstructions(config) {
|
|
|
6953
8422
|
displayGoInstructions(config);
|
|
6954
8423
|
return;
|
|
6955
8424
|
}
|
|
8425
|
+
if (ecosystem === "java") {
|
|
8426
|
+
displayJavaInstructions(config);
|
|
8427
|
+
return;
|
|
8428
|
+
}
|
|
6956
8429
|
if (ecosystem === "python") {
|
|
6957
8430
|
displayPythonInstructions(config);
|
|
6958
8431
|
return;
|
|
@@ -6977,6 +8450,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6977
8450
|
const polarInstructions = config.payments === "polar" ? getPolarInstructions(backend, packageManager) : "";
|
|
6978
8451
|
const paymentSetupInstructions = getPaymentSetupInstructions(config.payments, backend);
|
|
6979
8452
|
const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
|
|
8453
|
+
const vercelDeployInstructions = getVercelDeployInstructions(webDeploy, serverDeploy, backend);
|
|
6980
8454
|
const hasWeb = frontend?.some((f) => WEB_FRAMEWORKS.includes(f));
|
|
6981
8455
|
const hasNative = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles");
|
|
6982
8456
|
const bunWebNativeWarning = packageManager === "bun" && hasNative && hasWeb ? getBunWebNativeWarning() : "";
|
|
@@ -7022,6 +8496,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
7022
8496
|
if (lintingInstructions) output += `\n${lintingInstructions.trim()}\n`;
|
|
7023
8497
|
if (pwaInstructions) output += `\n${pwaInstructions.trim()}\n`;
|
|
7024
8498
|
if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
|
|
8499
|
+
if (vercelDeployInstructions) output += `\n${vercelDeployInstructions.trim()}\n`;
|
|
7025
8500
|
if (starlightInstructions) output += `\n${starlightInstructions.trim()}\n`;
|
|
7026
8501
|
if (clerkInstructions) output += `\n${clerkInstructions.trim()}\n`;
|
|
7027
8502
|
if (authSetupInstructions) output += `\n${authSetupInstructions.trim()}\n`;
|
|
@@ -7162,6 +8637,18 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend)
|
|
|
7162
8637
|
else if (webDeploy === "cloudflare" && (serverDeploy === "cloudflare" || isBackendSelf)) instructions.push(`${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
|
|
7163
8638
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
7164
8639
|
}
|
|
8640
|
+
function getVercelDeployInstructions(webDeploy, serverDeploy, backend) {
|
|
8641
|
+
const instructions = [];
|
|
8642
|
+
const isBackendSelf = backend === "self";
|
|
8643
|
+
if (webDeploy === "vercel" || serverDeploy === "vercel") {
|
|
8644
|
+
instructions.push(pc.bold("Deploy with Vercel:"));
|
|
8645
|
+
instructions.push(`${pc.cyan("•")} Install Vercel CLI: ${pc.white("npm i -g vercel")}`);
|
|
8646
|
+
if (webDeploy === "vercel") instructions.push(`${pc.cyan("•")} Deploy web: ${pc.white(`cd apps/web && vercel`)}`);
|
|
8647
|
+
if (serverDeploy === "vercel" && !isBackendSelf) instructions.push(`${pc.cyan("•")} Deploy server: ${pc.white(`cd apps/server && vercel`)}`);
|
|
8648
|
+
instructions.push(`${pc.cyan("•")} Docs: ${pc.underline("https://vercel.com/docs")}`);
|
|
8649
|
+
}
|
|
8650
|
+
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
8651
|
+
}
|
|
7165
8652
|
function displayRustInstructions(config) {
|
|
7166
8653
|
const { relativePath, rustWebFramework, rustFrontend, rustOrm, rustApi, rustCli } = config;
|
|
7167
8654
|
const cdCmd = `cd ${relativePath}`;
|
|
@@ -7198,6 +8685,18 @@ function displayRustInstructions(config) {
|
|
|
7198
8685
|
tracing: "Tracing",
|
|
7199
8686
|
"env-logger": "env_logger"
|
|
7200
8687
|
}[rustLogging] || rustLogging}\n`;
|
|
8688
|
+
const { rustErrorHandling } = config;
|
|
8689
|
+
if (rustErrorHandling && rustErrorHandling !== "none") output += `${pc.cyan("•")} Error Handling: ${{
|
|
8690
|
+
"anyhow-thiserror": "anyhow + thiserror",
|
|
8691
|
+
eyre: "eyre + color-eyre"
|
|
8692
|
+
}[rustErrorHandling] || rustErrorHandling}\n`;
|
|
8693
|
+
const { rustCaching } = config;
|
|
8694
|
+
if (rustCaching && rustCaching !== "none") output += `${pc.cyan("•")} Caching: ${{
|
|
8695
|
+
moka: "Moka",
|
|
8696
|
+
redis: "Redis"
|
|
8697
|
+
}[rustCaching] || rustCaching}\n`;
|
|
8698
|
+
const { rustAuth } = config;
|
|
8699
|
+
if (rustAuth && rustAuth !== "none") output += `${pc.cyan("•")} Auth: ${{ oauth2: "OAuth2" }[rustAuth] || rustAuth}\n`;
|
|
7201
8700
|
output += `\n${pc.bold("Common Cargo commands:")}\n`;
|
|
7202
8701
|
output += `${pc.cyan("•")} Build: cargo build\n`;
|
|
7203
8702
|
output += `${pc.cyan("•")} Run: cargo run\n`;
|
|
@@ -7211,7 +8710,7 @@ function displayRustInstructions(config) {
|
|
|
7211
8710
|
consola$1.box(output);
|
|
7212
8711
|
}
|
|
7213
8712
|
function displayGoInstructions(config) {
|
|
7214
|
-
const { relativePath, depsInstalled, goWebFramework, goOrm, goApi, goCli, goLogging } = config;
|
|
8713
|
+
const { relativePath, depsInstalled, goWebFramework, goOrm, goApi, goCli, goLogging, goAuth } = config;
|
|
7215
8714
|
const cdCmd = `cd ${relativePath}`;
|
|
7216
8715
|
let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
|
|
7217
8716
|
let stepCounter = 2;
|
|
@@ -7221,18 +8720,28 @@ function displayGoInstructions(config) {
|
|
|
7221
8720
|
if (goWebFramework && goWebFramework !== "none") output += `${pc.cyan("•")} Web Framework: ${{
|
|
7222
8721
|
gin: "Gin",
|
|
7223
8722
|
echo: "Echo",
|
|
7224
|
-
fiber: "Fiber"
|
|
8723
|
+
fiber: "Fiber",
|
|
8724
|
+
chi: "Chi"
|
|
7225
8725
|
}[goWebFramework] || goWebFramework}\n`;
|
|
7226
8726
|
if (goOrm && goOrm !== "none") output += `${pc.cyan("•")} Database: ${{
|
|
7227
8727
|
gorm: "GORM",
|
|
7228
|
-
sqlc: "sqlc"
|
|
8728
|
+
sqlc: "sqlc",
|
|
8729
|
+
ent: "Ent"
|
|
7229
8730
|
}[goOrm] || goOrm}\n`;
|
|
7230
8731
|
if (goApi && goApi !== "none") output += `${pc.cyan("•")} API: ${{ "grpc-go": "gRPC-Go" }[goApi] || goApi}\n`;
|
|
7231
8732
|
if (goCli && goCli !== "none") output += `${pc.cyan("•")} CLI: ${{
|
|
7232
8733
|
cobra: "Cobra",
|
|
7233
8734
|
bubbletea: "Bubble Tea"
|
|
7234
8735
|
}[goCli] || goCli}\n`;
|
|
7235
|
-
if (goLogging && goLogging !== "none") output += `${pc.cyan("•")} Logging: ${{
|
|
8736
|
+
if (goLogging && goLogging !== "none") output += `${pc.cyan("•")} Logging: ${{
|
|
8737
|
+
zap: "Zap",
|
|
8738
|
+
zerolog: "Zerolog",
|
|
8739
|
+
slog: "slog"
|
|
8740
|
+
}[goLogging] || goLogging}\n`;
|
|
8741
|
+
if (goAuth && goAuth !== "none") output += `${pc.cyan("•")} Auth: ${{
|
|
8742
|
+
casbin: "Casbin",
|
|
8743
|
+
jwt: "golang-jwt"
|
|
8744
|
+
}[goAuth] || goAuth}\n`;
|
|
7236
8745
|
output += `\n${pc.bold("Common Go commands:")}\n`;
|
|
7237
8746
|
output += `${pc.cyan("•")} Build: go build ./...\n`;
|
|
7238
8747
|
output += `${pc.cyan("•")} Run: go run cmd/server/main.go\n`;
|
|
@@ -7248,12 +8757,150 @@ function displayGoInstructions(config) {
|
|
|
7248
8757
|
output += pc.dim("Your star helps other developers discover the project.");
|
|
7249
8758
|
consola$1.box(output);
|
|
7250
8759
|
}
|
|
8760
|
+
const JAVA_GROUP_ID = "com.example";
|
|
8761
|
+
const JAVA_RESERVED_WORDS = new Set([
|
|
8762
|
+
"abstract",
|
|
8763
|
+
"assert",
|
|
8764
|
+
"boolean",
|
|
8765
|
+
"break",
|
|
8766
|
+
"byte",
|
|
8767
|
+
"case",
|
|
8768
|
+
"catch",
|
|
8769
|
+
"char",
|
|
8770
|
+
"class",
|
|
8771
|
+
"const",
|
|
8772
|
+
"continue",
|
|
8773
|
+
"default",
|
|
8774
|
+
"do",
|
|
8775
|
+
"double",
|
|
8776
|
+
"else",
|
|
8777
|
+
"enum",
|
|
8778
|
+
"extends",
|
|
8779
|
+
"final",
|
|
8780
|
+
"finally",
|
|
8781
|
+
"float",
|
|
8782
|
+
"for",
|
|
8783
|
+
"goto",
|
|
8784
|
+
"if",
|
|
8785
|
+
"implements",
|
|
8786
|
+
"import",
|
|
8787
|
+
"instanceof",
|
|
8788
|
+
"int",
|
|
8789
|
+
"interface",
|
|
8790
|
+
"long",
|
|
8791
|
+
"native",
|
|
8792
|
+
"new",
|
|
8793
|
+
"non-sealed",
|
|
8794
|
+
"package",
|
|
8795
|
+
"private",
|
|
8796
|
+
"protected",
|
|
8797
|
+
"public",
|
|
8798
|
+
"return",
|
|
8799
|
+
"sealed",
|
|
8800
|
+
"short",
|
|
8801
|
+
"static",
|
|
8802
|
+
"strictfp",
|
|
8803
|
+
"super",
|
|
8804
|
+
"switch",
|
|
8805
|
+
"synchronized",
|
|
8806
|
+
"this",
|
|
8807
|
+
"throw",
|
|
8808
|
+
"throws",
|
|
8809
|
+
"transient",
|
|
8810
|
+
"try",
|
|
8811
|
+
"void",
|
|
8812
|
+
"volatile",
|
|
8813
|
+
"while",
|
|
8814
|
+
"yield",
|
|
8815
|
+
"record",
|
|
8816
|
+
"permits",
|
|
8817
|
+
"true",
|
|
8818
|
+
"false",
|
|
8819
|
+
"null"
|
|
8820
|
+
]);
|
|
8821
|
+
function sanitizeJavaPackageSuffix(projectName) {
|
|
8822
|
+
const alphanumericOnly = projectName.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
8823
|
+
const withLetterPrefix = /^[a-z]/.test(alphanumericOnly) ? alphanumericOnly : `app${alphanumericOnly}`;
|
|
8824
|
+
return (JAVA_RESERVED_WORDS.has(withLetterPrefix) ? `app${withLetterPrefix}` : withLetterPrefix) || "app";
|
|
8825
|
+
}
|
|
8826
|
+
function getJavaMainClass(projectName) {
|
|
8827
|
+
return `${JAVA_GROUP_ID}.${sanitizeJavaPackageSuffix(projectName)}.Application`;
|
|
8828
|
+
}
|
|
8829
|
+
function getJavaMainSourcePath(projectName) {
|
|
8830
|
+
return `src/main/java/${getJavaMainClass(projectName).replace(/\./g, "/")}.java`;
|
|
8831
|
+
}
|
|
8832
|
+
function displayJavaInstructions(config) {
|
|
8833
|
+
const { projectName, relativePath, depsInstalled, javaWebFramework, javaBuildTool, javaOrm, javaAuth, javaLibraries, javaTestingLibraries } = config;
|
|
8834
|
+
const cdCmd = `cd ${relativePath}`;
|
|
8835
|
+
const isSpringBoot = javaWebFramework === "spring-boot" && javaBuildTool !== "none";
|
|
8836
|
+
const effectiveJavaLibraries = isSpringBoot ? javaLibraries.filter((library) => library !== "none") : [];
|
|
8837
|
+
const effectiveJavaTestingLibraries = javaBuildTool === "none" ? [] : javaTestingLibraries.filter((library) => library !== "none");
|
|
8838
|
+
const buildToolCommand = javaBuildTool === "none" ? null : javaBuildTool === "gradle" ? process.platform === "win32" ? "gradlew.bat" : "./gradlew" : process.platform === "win32" ? "mvnw.cmd" : "./mvnw";
|
|
8839
|
+
const runCommand = buildToolCommand ? isSpringBoot ? javaBuildTool === "gradle" ? `${buildToolCommand} bootRun` : `${buildToolCommand} spring-boot:run` : javaBuildTool === "gradle" ? `${buildToolCommand} run` : `${buildToolCommand} exec:java` : null;
|
|
8840
|
+
const packageCommand = buildToolCommand ? javaBuildTool === "gradle" ? `${buildToolCommand} build` : `${buildToolCommand} package` : null;
|
|
8841
|
+
const sourceCompileCommand = buildToolCommand ? null : `javac -d out ${getJavaMainSourcePath(projectName)}`;
|
|
8842
|
+
const sourceRunCommand = buildToolCommand ? null : `java -cp out ${getJavaMainClass(projectName)}`;
|
|
8843
|
+
let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
|
|
8844
|
+
let stepCounter = 2;
|
|
8845
|
+
if (!depsInstalled && buildToolCommand && effectiveJavaTestingLibraries.length > 0) output += `${pc.cyan(`${stepCounter++}.`)} ${buildToolCommand} test\n`;
|
|
8846
|
+
if (runCommand) output += `${pc.cyan(`${stepCounter++}.`)} ${runCommand}\n`;
|
|
8847
|
+
else if (sourceCompileCommand && sourceRunCommand) {
|
|
8848
|
+
output += `${pc.cyan(`${stepCounter++}.`)} ${sourceCompileCommand}\n`;
|
|
8849
|
+
output += `${pc.cyan(`${stepCounter++}.`)} ${sourceRunCommand}\n`;
|
|
8850
|
+
} else output += `${pc.cyan(`${stepCounter++}.`)} Add Maven or Gradle, then run the app\n`;
|
|
8851
|
+
output += `\n${pc.bold("Your Java project includes:")}\n`;
|
|
8852
|
+
if (isSpringBoot) output += `${pc.cyan("•")} Web Framework: ${{ "spring-boot": "Spring Boot" }[javaWebFramework] || javaWebFramework}\n`;
|
|
8853
|
+
else output += `${pc.cyan("•")} Scaffold: Plain Java\n`;
|
|
8854
|
+
if (javaBuildTool && javaBuildTool !== "none") output += `${pc.cyan("•")} Build Tool: ${{
|
|
8855
|
+
maven: "Maven Wrapper",
|
|
8856
|
+
gradle: "Gradle Wrapper"
|
|
8857
|
+
}[javaBuildTool] || javaBuildTool}\n`;
|
|
8858
|
+
else output += `${pc.cyan("•")} Build Tool: None\n`;
|
|
8859
|
+
if (isSpringBoot && javaOrm && javaOrm !== "none") output += `${pc.cyan("•")} ORM: ${{ "spring-data-jpa": "Spring Data JPA" }[javaOrm] || javaOrm}\n`;
|
|
8860
|
+
if (isSpringBoot && javaAuth && javaAuth !== "none") output += `${pc.cyan("•")} Auth: ${{ "spring-security": "Spring Security" }[javaAuth] || javaAuth}\n`;
|
|
8861
|
+
if (effectiveJavaLibraries.length > 0) {
|
|
8862
|
+
const libraryNames = {
|
|
8863
|
+
"spring-actuator": "Spring Actuator",
|
|
8864
|
+
"spring-validation": "Spring Validation",
|
|
8865
|
+
flyway: "Flyway"
|
|
8866
|
+
};
|
|
8867
|
+
const libraryList = effectiveJavaLibraries.map((library) => libraryNames[library] || library).join(", ");
|
|
8868
|
+
output += `${pc.cyan("•")} Libraries: ${libraryList}\n`;
|
|
8869
|
+
}
|
|
8870
|
+
if (effectiveJavaTestingLibraries.length > 0) {
|
|
8871
|
+
const testingNames = {
|
|
8872
|
+
junit5: "JUnit 5",
|
|
8873
|
+
mockito: "Mockito",
|
|
8874
|
+
testcontainers: "Testcontainers"
|
|
8875
|
+
};
|
|
8876
|
+
const testingList = effectiveJavaTestingLibraries.map((library) => testingNames[library] || library).join(", ");
|
|
8877
|
+
output += `${pc.cyan("•")} Testing: ${testingList}\n`;
|
|
8878
|
+
}
|
|
8879
|
+
output += `\n${pc.bold("Common Java commands:")}\n`;
|
|
8880
|
+
if (buildToolCommand && runCommand && packageCommand) {
|
|
8881
|
+
if (effectiveJavaTestingLibraries.length > 0) output += `${pc.cyan("•")} Test: ${buildToolCommand} test\n`;
|
|
8882
|
+
output += `${pc.cyan("•")} Run: ${runCommand}\n`;
|
|
8883
|
+
output += `${pc.cyan("•")} Package: ${packageCommand}\n`;
|
|
8884
|
+
} else if (sourceCompileCommand && sourceRunCommand) {
|
|
8885
|
+
output += `${pc.cyan("•")} Compile: ${sourceCompileCommand}\n`;
|
|
8886
|
+
output += `${pc.cyan("•")} Run: ${sourceRunCommand}\n`;
|
|
8887
|
+
} else output += `${pc.cyan("•")} Configure Maven or Gradle before running build commands\n`;
|
|
8888
|
+
if (isSpringBoot) {
|
|
8889
|
+
output += `\n${pc.bold("Your project will be available at:")}\n`;
|
|
8890
|
+
output += `${pc.cyan("•")} API: http://localhost:8080\n`;
|
|
8891
|
+
}
|
|
8892
|
+
output += `\n${pc.bold("Enjoying Better Fullstack?")} Help us grow — star the repo!\n`;
|
|
8893
|
+
output += `${pc.cyan("https://github.com/Marve10s/Better-Fullstack")}\n`;
|
|
8894
|
+
output += pc.dim("Your star helps other developers discover the project.");
|
|
8895
|
+
consola$1.box(output);
|
|
8896
|
+
}
|
|
7251
8897
|
function displayPythonInstructions(config) {
|
|
7252
8898
|
const { relativePath, depsInstalled, pythonWebFramework, pythonOrm, pythonValidation, pythonAi, pythonTaskQueue, pythonQuality } = config;
|
|
7253
8899
|
const cdCmd = `cd ${relativePath}`;
|
|
7254
8900
|
let runCommand = "uv run uvicorn app.main:app --reload";
|
|
7255
8901
|
if (pythonWebFramework === "django") runCommand = "uv run python manage.py runserver";
|
|
7256
8902
|
else if (pythonWebFramework === "flask") runCommand = "uv run flask --app app.main run --reload";
|
|
8903
|
+
else if (pythonWebFramework === "litestar") runCommand = "litestar --app src.app.main:app run --reload --port 3001";
|
|
7257
8904
|
let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
|
|
7258
8905
|
let stepCounter = 2;
|
|
7259
8906
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} uv sync\n`;
|
|
@@ -7262,11 +8909,13 @@ function displayPythonInstructions(config) {
|
|
|
7262
8909
|
if (pythonWebFramework && pythonWebFramework !== "none") output += `${pc.cyan("•")} Web Framework: ${{
|
|
7263
8910
|
fastapi: "FastAPI",
|
|
7264
8911
|
django: "Django",
|
|
7265
|
-
flask: "Flask"
|
|
8912
|
+
flask: "Flask",
|
|
8913
|
+
litestar: "Litestar"
|
|
7266
8914
|
}[pythonWebFramework] || pythonWebFramework}\n`;
|
|
7267
8915
|
if (pythonOrm && pythonOrm !== "none") output += `${pc.cyan("•")} ORM: ${{
|
|
7268
8916
|
sqlalchemy: "SQLAlchemy",
|
|
7269
|
-
sqlmodel: "SQLModel"
|
|
8917
|
+
sqlmodel: "SQLModel",
|
|
8918
|
+
"tortoise-orm": "Tortoise ORM"
|
|
7270
8919
|
}[pythonOrm] || pythonOrm}\n`;
|
|
7271
8920
|
if (pythonValidation && pythonValidation !== "none") output += `${pc.cyan("•")} Validation: ${{ pydantic: "Pydantic" }[pythonValidation] || pythonValidation}\n`;
|
|
7272
8921
|
if (pythonAi && pythonAi.length > 0 && !pythonAi.includes("none")) {
|
|
@@ -7311,6 +8960,7 @@ async function createProject(options, cliInput = {}) {
|
|
|
7311
8960
|
if (!result.success || !result.tree) throw new Error(result.error || "Failed to generate project templates");
|
|
7312
8961
|
await writeTreeToFilesystem(result.tree, projectDir);
|
|
7313
8962
|
await setPackageManagerVersion(projectDir, options.packageManager);
|
|
8963
|
+
await ensurePackageManagerProjectFiles(projectDir, options.packageManager);
|
|
7314
8964
|
if (!isConvex && options.database !== "none") await setupDatabase(options, cliInput);
|
|
7315
8965
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
7316
8966
|
await applyDependencyVersionChannel(projectDir, options.versionChannel);
|
|
@@ -7324,6 +8974,8 @@ async function createProject(options, cliInput = {}) {
|
|
|
7324
8974
|
if (options.install && options.ecosystem === "rust") await runCargoBuild({ projectDir });
|
|
7325
8975
|
if (options.install && options.ecosystem === "python") await runUvSync({ projectDir });
|
|
7326
8976
|
if (options.install && options.ecosystem === "go") await runGoModTidy({ projectDir });
|
|
8977
|
+
if (options.install && options.ecosystem === "java" && options.javaBuildTool !== "none") if (options.javaBuildTool === "gradle") await runGradleTests({ projectDir });
|
|
8978
|
+
else await runMavenTests({ projectDir });
|
|
7327
8979
|
await initializeGit(projectDir, options.git);
|
|
7328
8980
|
if (!isSilent()) await displayPostInstallInstructions({
|
|
7329
8981
|
...options,
|
|
@@ -7355,12 +9007,18 @@ async function setPackageManagerVersion(projectDir, packageManager) {
|
|
|
7355
9007
|
await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
7356
9008
|
}
|
|
7357
9009
|
}
|
|
9010
|
+
async function ensurePackageManagerProjectFiles(projectDir, packageManager) {
|
|
9011
|
+
if (packageManager !== "yarn") return;
|
|
9012
|
+
const yarnLockPath = path.join(projectDir, "yarn.lock");
|
|
9013
|
+
if (await fs.pathExists(yarnLockPath)) return;
|
|
9014
|
+
await fs.writeFile(yarnLockPath, "");
|
|
9015
|
+
}
|
|
7358
9016
|
|
|
7359
9017
|
//#endregion
|
|
7360
9018
|
//#region src/helpers/core/command-handlers.ts
|
|
7361
9019
|
function shouldPromptForVersionChannel(input) {
|
|
7362
9020
|
if (input.yes || input.versionChannel !== void 0 || isSilent()) return false;
|
|
7363
|
-
return
|
|
9021
|
+
return canPromptInteractively();
|
|
7364
9022
|
}
|
|
7365
9023
|
async function createProjectHandler(input, options = {}) {
|
|
7366
9024
|
const { silent = false } = options;
|
|
@@ -7450,8 +9108,12 @@ async function createProjectHandler(input, options = {}) {
|
|
|
7450
9108
|
rustCli: "none",
|
|
7451
9109
|
rustLibraries: [],
|
|
7452
9110
|
rustLogging: "none",
|
|
9111
|
+
rustErrorHandling: "none",
|
|
9112
|
+
rustCaching: "none",
|
|
9113
|
+
rustAuth: "none",
|
|
7453
9114
|
cms: "none",
|
|
7454
9115
|
caching: "none",
|
|
9116
|
+
i18n: "none",
|
|
7455
9117
|
search: "none",
|
|
7456
9118
|
featureFlags: "none",
|
|
7457
9119
|
analytics: "none",
|
|
@@ -7460,13 +9122,22 @@ async function createProjectHandler(input, options = {}) {
|
|
|
7460
9122
|
pythonOrm: "none",
|
|
7461
9123
|
pythonValidation: "none",
|
|
7462
9124
|
pythonAi: [],
|
|
9125
|
+
pythonAuth: "none",
|
|
7463
9126
|
pythonTaskQueue: "none",
|
|
9127
|
+
pythonGraphql: "none",
|
|
7464
9128
|
pythonQuality: "none",
|
|
7465
9129
|
goWebFramework: "none",
|
|
7466
9130
|
goOrm: "none",
|
|
7467
9131
|
goApi: "none",
|
|
7468
9132
|
goCli: "none",
|
|
7469
9133
|
goLogging: "none",
|
|
9134
|
+
goAuth: "none",
|
|
9135
|
+
javaWebFramework: "none",
|
|
9136
|
+
javaBuildTool: "none",
|
|
9137
|
+
javaOrm: "none",
|
|
9138
|
+
javaAuth: "none",
|
|
9139
|
+
javaLibraries: [],
|
|
9140
|
+
javaTestingLibraries: [],
|
|
7470
9141
|
aiDocs: []
|
|
7471
9142
|
},
|
|
7472
9143
|
reproducibleCommand: "",
|
|
@@ -7736,83 +9407,7 @@ const router = os.router({
|
|
|
7736
9407
|
description: "Scaffold a new Better Fullstack project from 270+ compatible stack options",
|
|
7737
9408
|
default: true,
|
|
7738
9409
|
negateBooleans: true
|
|
7739
|
-
}).input(
|
|
7740
|
-
template: types_exports.TemplateSchema.optional().describe("Use a predefined template"),
|
|
7741
|
-
yes: z.boolean().optional().default(false).describe("Use default configuration"),
|
|
7742
|
-
yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
|
|
7743
|
-
verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
|
|
7744
|
-
dryRun: z.boolean().optional().default(false).describe("Preview generated file tree without writing to disk"),
|
|
7745
|
-
ecosystem: types_exports.EcosystemSchema.optional().describe("Language ecosystem (typescript, rust, python, or go)"),
|
|
7746
|
-
database: types_exports.DatabaseSchema.optional(),
|
|
7747
|
-
orm: types_exports.ORMSchema.optional(),
|
|
7748
|
-
auth: types_exports.AuthSchema.optional(),
|
|
7749
|
-
payments: types_exports.PaymentsSchema.optional(),
|
|
7750
|
-
email: types_exports.EmailSchema.optional(),
|
|
7751
|
-
fileUpload: types_exports.FileUploadSchema.optional(),
|
|
7752
|
-
effect: types_exports.EffectSchema.optional(),
|
|
7753
|
-
stateManagement: types_exports.StateManagementSchema.optional(),
|
|
7754
|
-
validation: types_exports.ValidationSchema.optional(),
|
|
7755
|
-
forms: types_exports.FormsSchema.optional(),
|
|
7756
|
-
testing: types_exports.TestingSchema.optional(),
|
|
7757
|
-
ai: types_exports.AISchema.optional(),
|
|
7758
|
-
realtime: types_exports.RealtimeSchema.optional(),
|
|
7759
|
-
jobQueue: types_exports.JobQueueSchema.optional(),
|
|
7760
|
-
animation: types_exports.AnimationSchema.optional(),
|
|
7761
|
-
logging: types_exports.LoggingSchema.optional(),
|
|
7762
|
-
observability: types_exports.ObservabilitySchema.optional(),
|
|
7763
|
-
featureFlags: types_exports.FeatureFlagsSchema.optional().describe("Feature flags provider"),
|
|
7764
|
-
analytics: types_exports.AnalyticsSchema.optional().describe("Privacy-focused analytics"),
|
|
7765
|
-
cms: types_exports.CMSSchema.optional().describe("Headless CMS solution"),
|
|
7766
|
-
caching: types_exports.CachingSchema.optional().describe("Caching solution"),
|
|
7767
|
-
search: types_exports.SearchSchema.optional().describe("Search engine solution"),
|
|
7768
|
-
fileStorage: types_exports.FileStorageSchema.optional().describe("File storage solution (S3, R2)"),
|
|
7769
|
-
frontend: z.array(types_exports.FrontendSchema).optional(),
|
|
7770
|
-
astroIntegration: types_exports.AstroIntegrationSchema.optional().describe("Astro UI framework integration (react, vue, svelte, solid)"),
|
|
7771
|
-
addons: z.array(types_exports.AddonsSchema).optional(),
|
|
7772
|
-
examples: z.array(types_exports.ExamplesSchema).optional(),
|
|
7773
|
-
git: z.boolean().optional(),
|
|
7774
|
-
packageManager: types_exports.PackageManagerSchema.optional(),
|
|
7775
|
-
install: z.boolean().optional(),
|
|
7776
|
-
versionChannel: types_exports.VersionChannelSchema.optional().describe("Dependency version channel (stable, latest, beta)"),
|
|
7777
|
-
dbSetup: types_exports.DatabaseSetupSchema.optional(),
|
|
7778
|
-
backend: types_exports.BackendSchema.optional(),
|
|
7779
|
-
runtime: types_exports.RuntimeSchema.optional(),
|
|
7780
|
-
api: types_exports.APISchema.optional(),
|
|
7781
|
-
cssFramework: types_exports.CSSFrameworkSchema.optional(),
|
|
7782
|
-
uiLibrary: types_exports.UILibrarySchema.optional(),
|
|
7783
|
-
shadcnBase: types_exports.ShadcnBaseSchema.optional().describe("shadcn/ui headless library (radix, base)"),
|
|
7784
|
-
shadcnStyle: types_exports.ShadcnStyleSchema.optional().describe("shadcn/ui visual style (vega, nova, maia, lyra, mira)"),
|
|
7785
|
-
shadcnIconLibrary: types_exports.ShadcnIconLibrarySchema.optional().describe("shadcn/ui icon library (lucide, tabler, hugeicons, phosphor, remixicon)"),
|
|
7786
|
-
shadcnColorTheme: types_exports.ShadcnColorThemeSchema.optional().describe("shadcn/ui color theme (neutral, blue, violet, etc.)"),
|
|
7787
|
-
shadcnBaseColor: types_exports.ShadcnBaseColorSchema.optional().describe("shadcn/ui base neutral color (neutral, stone, zinc, gray)"),
|
|
7788
|
-
shadcnFont: types_exports.ShadcnFontSchema.optional().describe("shadcn/ui font (inter, geist, figtree, etc.)"),
|
|
7789
|
-
shadcnRadius: types_exports.ShadcnRadiusSchema.optional().describe("shadcn/ui border radius (default, none, small, medium, large)"),
|
|
7790
|
-
webDeploy: types_exports.WebDeploySchema.optional(),
|
|
7791
|
-
serverDeploy: types_exports.ServerDeploySchema.optional(),
|
|
7792
|
-
directoryConflict: types_exports.DirectoryConflictSchema.optional(),
|
|
7793
|
-
renderTitle: z.boolean().optional(),
|
|
7794
|
-
disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
|
|
7795
|
-
manualDb: z.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup"),
|
|
7796
|
-
rustWebFramework: types_exports.RustWebFrameworkSchema.optional().describe("Rust web framework (axum, actix-web)"),
|
|
7797
|
-
rustFrontend: types_exports.RustFrontendSchema.optional().describe("Rust WASM frontend (leptos, dioxus)"),
|
|
7798
|
-
rustOrm: types_exports.RustOrmSchema.optional().describe("Rust ORM/database (sea-orm, sqlx)"),
|
|
7799
|
-
rustApi: types_exports.RustApiSchema.optional().describe("Rust API layer (tonic, async-graphql)"),
|
|
7800
|
-
rustCli: types_exports.RustCliSchema.optional().describe("Rust CLI tools (clap, ratatui)"),
|
|
7801
|
-
rustLibraries: z.array(types_exports.RustLibrariesSchema).optional().describe("Rust core libraries"),
|
|
7802
|
-
rustLogging: types_exports.RustLoggingSchema.optional().describe("Rust logging (tracing, env-logger)"),
|
|
7803
|
-
pythonWebFramework: types_exports.PythonWebFrameworkSchema.optional().describe("Python web framework (fastapi, django)"),
|
|
7804
|
-
pythonOrm: types_exports.PythonOrmSchema.optional().describe("Python ORM/database (sqlalchemy, sqlmodel)"),
|
|
7805
|
-
pythonValidation: types_exports.PythonValidationSchema.optional().describe("Python validation (pydantic)"),
|
|
7806
|
-
pythonAi: z.array(types_exports.PythonAiSchema).optional().describe("Python AI/ML frameworks"),
|
|
7807
|
-
pythonTaskQueue: types_exports.PythonTaskQueueSchema.optional().describe("Python task queue (celery)"),
|
|
7808
|
-
pythonQuality: types_exports.PythonQualitySchema.optional().describe("Python code quality (ruff)"),
|
|
7809
|
-
goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework (gin, echo, fiber)"),
|
|
7810
|
-
goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database (gorm, sqlc)"),
|
|
7811
|
-
goApi: types_exports.GoApiSchema.optional().describe("Go API layer (grpc-go)"),
|
|
7812
|
-
goCli: types_exports.GoCliSchema.optional().describe("Go CLI tools (cobra, bubbletea)"),
|
|
7813
|
-
goLogging: types_exports.GoLoggingSchema.optional().describe("Go logging (zap)"),
|
|
7814
|
-
aiDocs: z.array(types_exports.AiDocsSchema).optional().describe("AI documentation files (claude-md, agents-md, cursorrules)")
|
|
7815
|
-
})])).handler(async ({ input }) => {
|
|
9410
|
+
}).input(CreateCommandInputSchema).handler(async ({ input }) => {
|
|
7816
9411
|
const [projectName, options] = input;
|
|
7817
9412
|
const result = await createProjectHandler({
|
|
7818
9413
|
projectName,
|
|
@@ -8032,6 +9627,7 @@ async function createVirtual(options) {
|
|
|
8032
9627
|
analytics: options.analytics || "none",
|
|
8033
9628
|
cms: options.cms || "none",
|
|
8034
9629
|
caching: options.caching || "none",
|
|
9630
|
+
i18n: options.i18n || "none",
|
|
8035
9631
|
search: options.search || "none",
|
|
8036
9632
|
fileStorage: options.fileStorage || "none",
|
|
8037
9633
|
rustWebFramework: options.rustWebFramework || "none",
|
|
@@ -8041,17 +9637,29 @@ async function createVirtual(options) {
|
|
|
8041
9637
|
rustCli: options.rustCli || "none",
|
|
8042
9638
|
rustLibraries: options.rustLibraries || [],
|
|
8043
9639
|
rustLogging: options.rustLogging || (options.ecosystem === "rust" ? "tracing" : "none"),
|
|
9640
|
+
rustErrorHandling: options.rustErrorHandling || (options.ecosystem === "rust" ? "anyhow-thiserror" : "none"),
|
|
9641
|
+
rustCaching: options.rustCaching || "none",
|
|
9642
|
+
rustAuth: options.rustAuth || "none",
|
|
8044
9643
|
pythonWebFramework: options.pythonWebFramework || "none",
|
|
8045
9644
|
pythonOrm: options.pythonOrm || "none",
|
|
8046
9645
|
pythonValidation: options.pythonValidation || "none",
|
|
8047
9646
|
pythonAi: options.pythonAi || [],
|
|
9647
|
+
pythonAuth: options.pythonAuth || "none",
|
|
8048
9648
|
pythonTaskQueue: options.pythonTaskQueue || "none",
|
|
9649
|
+
pythonGraphql: options.pythonGraphql || "none",
|
|
8049
9650
|
pythonQuality: options.pythonQuality || "none",
|
|
8050
9651
|
goWebFramework: options.goWebFramework || "none",
|
|
8051
9652
|
goOrm: options.goOrm || "none",
|
|
8052
9653
|
goApi: options.goApi || "none",
|
|
8053
9654
|
goCli: options.goCli || "none",
|
|
8054
9655
|
goLogging: options.goLogging || "none",
|
|
9656
|
+
goAuth: options.goAuth || "none",
|
|
9657
|
+
javaWebFramework: options.javaWebFramework || (options.ecosystem === "java" ? "spring-boot" : "none"),
|
|
9658
|
+
javaBuildTool: options.javaBuildTool || (options.ecosystem === "java" ? "maven" : "none"),
|
|
9659
|
+
javaOrm: options.javaOrm || "none",
|
|
9660
|
+
javaAuth: options.javaAuth || "none",
|
|
9661
|
+
javaLibraries: options.javaLibraries || [],
|
|
9662
|
+
javaTestingLibraries: options.javaTestingLibraries || (options.ecosystem === "java" ? ["junit5"] : []),
|
|
8055
9663
|
aiDocs: options.aiDocs || ["claude-md"]
|
|
8056
9664
|
},
|
|
8057
9665
|
templates: EMBEDDED_TEMPLATES$1
|