Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/cli/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const DEFAULT_CONFIG_BASE = {
caching: "none",
search: "none",
fileStorage: "none",
i18n: "none",
animation: "none",
logging: "none",
observability: "none",
Expand Down Expand Up @@ -73,12 +74,14 @@ export const DEFAULT_CONFIG_BASE = {
rustLibraries: [],
rustLogging: "tracing",
rustErrorHandling: "anyhow-thiserror",
rustCaching: "none",
// Python ecosystem defaults
pythonWebFramework: "fastapi",
pythonOrm: "sqlalchemy",
pythonValidation: "pydantic",
pythonAi: [],
pythonAuth: "none",
pythonGraphql: "none",
pythonTaskQueue: "none",
pythonQuality: "ruff",
// Go ecosystem defaults
Expand Down
3 changes: 3 additions & 0 deletions apps/cli/src/helpers/core/command-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,20 @@ export async function createProjectHandler(
rustLibraries: [],
rustLogging: "none",
rustErrorHandling: "none",
rustCaching: "none",
cms: "none",
caching: "none",
search: "none",
featureFlags: "none",
analytics: "none",
fileStorage: "none",
i18n: "none",
pythonWebFramework: "none",
pythonOrm: "none",
pythonValidation: "none",
pythonAi: [],
pythonAuth: "none",
pythonGraphql: "none",
pythonTaskQueue: "none",
pythonQuality: "none",
goWebFramework: "none",
Expand Down
9 changes: 9 additions & 0 deletions apps/cli/src/helpers/core/post-installation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,15 @@ function displayRustInstructions(config: ProjectConfig & { depsInstalled: boolea
output += `${pc.cyan("•")} Error Handling: ${errorHandlingNames[rustErrorHandling] || rustErrorHandling}\n`;
}

const { rustCaching } = config;
if (rustCaching && rustCaching !== "none") {
const cachingNames: Record<string, string> = {
moka: "Moka",
redis: "Redis",
};
output += `${pc.cyan("•")} Caching: ${cachingNames[rustCaching] || rustCaching}\n`;
}

output += `\n${pc.bold("Common Cargo commands:")}\n`;
output += `${pc.cyan("•")} Build: cargo build\n`;
output += `${pc.cyan("•")} Run: cargo run\n`;
Expand Down
12 changes: 12 additions & 0 deletions apps/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ import {
CachingSchema,
type Caching,
SearchSchema,
I18nSchema,
FileStorageSchema,
type I18n,
RustWebFrameworkSchema,
type RustWebFramework,
RustFrontendSchema,
Expand All @@ -96,7 +98,9 @@ import {
RustLoggingSchema,
type RustLogging,
RustErrorHandlingSchema,
RustCachingSchema,
type RustErrorHandling,
type RustCaching,
PythonWebFrameworkSchema,
type PythonWebFramework,
PythonOrmSchema,
Expand All @@ -107,6 +111,8 @@ import {
type PythonAi,
PythonAuthSchema,
type PythonAuth,
PythonGraphqlSchema,
type PythonGraphql,
PythonTaskQueueSchema,
type PythonTaskQueue,
PythonQualitySchema,
Expand Down Expand Up @@ -191,6 +197,7 @@ export const router = os.router({
caching: CachingSchema.optional().describe("Caching solution"),
search: SearchSchema.optional().describe("Search engine solution"),
fileStorage: FileStorageSchema.optional().describe("File storage solution (S3, R2)"),
i18n: I18nSchema.optional().describe("Internationalization (i18n) library"),
frontend: z.array(FrontendSchema).optional(),
astroIntegration: AstroIntegrationSchema.optional().describe(
"Astro UI framework integration (react, vue, svelte, solid)",
Expand Down Expand Up @@ -253,6 +260,7 @@ export const router = os.router({
rustLibraries: z.array(RustLibrariesSchema).optional().describe("Rust core libraries"),
rustLogging: RustLoggingSchema.optional().describe("Rust logging (tracing, env-logger)"),
rustErrorHandling: RustErrorHandlingSchema.optional().describe("Rust error handling (anyhow-thiserror, eyre)"),
rustCaching: RustCachingSchema.optional().describe("Rust caching (moka, redis)"),
// Python ecosystem options
pythonWebFramework: PythonWebFrameworkSchema.optional().describe(
"Python web framework (fastapi, django)",
Expand All @@ -265,6 +273,7 @@ export const router = os.router({
),
pythonAi: z.array(PythonAiSchema).optional().describe("Python AI/ML frameworks"),
pythonAuth: PythonAuthSchema.optional().describe("Python auth library (authlib, jwt)"),
pythonGraphql: PythonGraphqlSchema.optional().describe("Python GraphQL library (strawberry)"),
pythonTaskQueue: PythonTaskQueueSchema.optional().describe("Python task queue (celery)"),
pythonQuality: PythonQualitySchema.optional().describe("Python code quality (ruff)"),
// Go ecosystem options
Expand Down Expand Up @@ -573,6 +582,7 @@ export async function createVirtual(
caching: options.caching || "none",
search: options.search || "none",
fileStorage: options.fileStorage || "none",
i18n: options.i18n || "none",
// Rust ecosystem options
rustWebFramework: options.rustWebFramework || "none",
rustFrontend: options.rustFrontend || "none",
Expand All @@ -582,12 +592,14 @@ export async function createVirtual(
rustLibraries: options.rustLibraries || [],
rustLogging: options.rustLogging || (options.ecosystem === "rust" ? "tracing" : "none"),
rustErrorHandling: options.rustErrorHandling || (options.ecosystem === "rust" ? "anyhow-thiserror" : "none"),
rustCaching: options.rustCaching || "none",
// Python ecosystem options
pythonWebFramework: options.pythonWebFramework || "none",
pythonOrm: options.pythonOrm || "none",
pythonValidation: options.pythonValidation || "none",
pythonAi: options.pythonAi || [],
pythonAuth: options.pythonAuth || "none",
pythonGraphql: options.pythonGraphql || "none",
pythonTaskQueue: options.pythonTaskQueue || "none",
pythonQuality: options.pythonQuality || "none",
// Go ecosystem options
Expand Down
21 changes: 18 additions & 3 deletions apps/cli/src/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
ExamplesSchema,
FeatureFlagsSchema,
FileStorageSchema,
I18nSchema,
FileUploadSchema,
FormsSchema,
FrontendSchema,
Expand All @@ -39,6 +40,7 @@ import {
type ProjectConfig,
PythonAiSchema,
PythonAuthSchema,
PythonGraphqlSchema,
PythonOrmSchema,
PythonQualitySchema,
PythonTaskQueueSchema,
Expand All @@ -52,6 +54,7 @@ import {
RustLibrariesSchema,
RustLoggingSchema,
RustErrorHandlingSchema,
RustCachingSchema,
RustOrmSchema,
RustWebFrameworkSchema,
SearchSchema,
Expand Down Expand Up @@ -173,6 +176,7 @@ const SCHEMA_MAP: Record<string, z.ZodType> = {
caching: CachingSchema,
search: SearchSchema,
fileStorage: FileStorageSchema,
i18n: I18nSchema,
addons: AddonsSchema,
examples: ExamplesSchema,
packageManager: PackageManagerSchema,
Expand All @@ -188,11 +192,13 @@ const SCHEMA_MAP: Record<string, z.ZodType> = {
rustLibraries: RustLibrariesSchema,
rustLogging: RustLoggingSchema,
rustErrorHandling: RustErrorHandlingSchema,
rustCaching: RustCachingSchema,
pythonWebFramework: PythonWebFrameworkSchema,
pythonOrm: PythonOrmSchema,
pythonValidation: PythonValidationSchema,
pythonAi: PythonAiSchema,
pythonAuth: PythonAuthSchema,
pythonGraphql: PythonGraphqlSchema,
pythonTaskQueue: PythonTaskQueueSchema,
pythonQuality: PythonQualitySchema,
goWebFramework: GoWebFrameworkSchema,
Expand All @@ -208,10 +214,10 @@ const ECOSYSTEM_CATEGORIES: Record<string, string[]> = {
"email", "fileUpload", "effect", "ai", "stateManagement", "forms", "validation",
"testing", "cssFramework", "uiLibrary", "realtime", "jobQueue", "animation",
"logging", "observability", "featureFlags", "analytics", "cms", "caching",
"search", "fileStorage", "astroIntegration",
"search", "fileStorage", "i18n", "astroIntegration",
],
rust: ["rustWebFramework", "rustFrontend", "rustOrm", "rustApi", "rustCli", "rustLibraries", "rustLogging", "rustErrorHandling"],
python: ["pythonWebFramework", "pythonOrm", "pythonValidation", "pythonAi", "pythonAuth", "pythonTaskQueue", "pythonQuality"],
rust: ["rustWebFramework", "rustFrontend", "rustOrm", "rustApi", "rustCli", "rustLibraries", "rustLogging", "rustErrorHandling", "rustCaching"],
python: ["pythonWebFramework", "pythonOrm", "pythonValidation", "pythonAi", "pythonAuth", "pythonGraphql", "pythonTaskQueue", "pythonQuality"],
go: ["goWebFramework", "goOrm", "goApi", "goCli", "goLogging"],
shared: ["ecosystem", "packageManager", "addons", "examples", "webDeploy", "serverDeploy", "dbSetup"],
};
Expand Down Expand Up @@ -311,6 +317,7 @@ function buildProjectConfig(
caching: (input.caching as ProjectConfig["caching"]) ?? "none",
search: (input.search as ProjectConfig["search"]) ?? "none",
fileStorage: (input.fileStorage as ProjectConfig["fileStorage"]) ?? "none",
i18n: (input.i18n as ProjectConfig["i18n"]) ?? "none",
addons: (input.addons as ProjectConfig["addons"]) ?? [],
examples: (input.examples as ProjectConfig["examples"]) ?? [],
packageManager: (input.packageManager as ProjectConfig["packageManager"]) ?? "bun",
Expand All @@ -330,11 +337,13 @@ function buildProjectConfig(
rustLibraries: (input.rustLibraries as ProjectConfig["rustLibraries"]) ?? [],
rustLogging: (input.rustLogging as ProjectConfig["rustLogging"]) ?? "none",
rustErrorHandling: (input.rustErrorHandling as ProjectConfig["rustErrorHandling"]) ?? "none",
rustCaching: (input.rustCaching as ProjectConfig["rustCaching"]) ?? "none",
pythonWebFramework: (input.pythonWebFramework as ProjectConfig["pythonWebFramework"]) ?? "none",
pythonOrm: (input.pythonOrm as ProjectConfig["pythonOrm"]) ?? "none",
pythonValidation: (input.pythonValidation as ProjectConfig["pythonValidation"]) ?? "none",
pythonAi: (input.pythonAi as ProjectConfig["pythonAi"]) ?? [],
pythonAuth: (input.pythonAuth as ProjectConfig["pythonAuth"]) ?? "none",
pythonGraphql: (input.pythonGraphql as ProjectConfig["pythonGraphql"]) ?? "none",
pythonTaskQueue: (input.pythonTaskQueue as ProjectConfig["pythonTaskQueue"]) ?? "none",
pythonQuality: (input.pythonQuality as ProjectConfig["pythonQuality"]) ?? "none",
goWebFramework: (input.goWebFramework as ProjectConfig["goWebFramework"]) ?? "none",
Expand Down Expand Up @@ -403,6 +412,7 @@ function buildCompatibilityInput(input: Record<string, unknown>): CompatibilityI
cms: (input.cms as string) ?? "none",
search: (input.search as string) ?? "none",
fileStorage: (input.fileStorage as string) ?? "none",
i18n: (input.i18n as string) ?? "none",
codeQuality,
documentation,
appPlatforms,
Expand All @@ -425,11 +435,13 @@ function buildCompatibilityInput(input: Record<string, unknown>): CompatibilityI
rustLibraries: ((input.rustLibraries as string[]) ?? []).join(",") || "none",
rustLogging: (input.rustLogging as string) ?? "none",
rustErrorHandling: (input.rustErrorHandling as string) ?? "none",
rustCaching: (input.rustCaching as string) ?? "none",
pythonWebFramework: (input.pythonWebFramework as string) ?? "none",
pythonOrm: (input.pythonOrm as string) ?? "none",
pythonValidation: (input.pythonValidation as string) ?? "none",
pythonAi: ((input.pythonAi as string[]) ?? []).join(",") || "none",
pythonAuth: (input.pythonAuth as string) ?? "none",
pythonGraphql: (input.pythonGraphql as string) ?? "none",
pythonTaskQueue: (input.pythonTaskQueue as string) ?? "none",
pythonQuality: (input.pythonQuality as string) ?? "none",
goWebFramework: (input.goWebFramework as string) ?? "none",
Expand Down Expand Up @@ -633,6 +645,7 @@ export async function startMcpServer() {
caching: CachingSchema.optional().describe("Caching solution"),
cms: CMSSchema.optional().describe("CMS"),
fileStorage: FileStorageSchema.optional().describe("File storage"),
i18n: I18nSchema.optional().describe("Internationalization (i18n) library"),
fileUpload: FileUploadSchema.optional().describe("File upload"),
webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
Expand All @@ -645,11 +658,13 @@ export async function startMcpServer() {
rustLibraries: z.array(RustLibrariesSchema).optional().describe("Rust libraries"),
rustLogging: RustLoggingSchema.optional().describe("Rust logging library"),
rustErrorHandling: RustErrorHandlingSchema.optional().describe("Rust error handling library"),
rustCaching: RustCachingSchema.optional().describe("Rust caching library"),
pythonWebFramework: PythonWebFrameworkSchema.optional().describe("Python web framework"),
pythonOrm: PythonOrmSchema.optional().describe("Python ORM"),
pythonValidation: PythonValidationSchema.optional().describe("Python validation"),
pythonAi: z.array(PythonAiSchema).optional().describe("Python AI libraries"),
pythonAuth: PythonAuthSchema.optional().describe("Python auth library"),
pythonGraphql: PythonGraphqlSchema.optional().describe("Python GraphQL library"),
pythonTaskQueue: PythonTaskQueueSchema.optional().describe("Python task queue"),
pythonQuality: PythonQualitySchema.optional().describe("Python code quality"),
goWebFramework: GoWebFrameworkSchema.optional().describe("Go web framework"),
Expand Down
24 changes: 24 additions & 0 deletions apps/cli/src/prompts/config-prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
Examples,
FeatureFlags,
FileUpload,
I18n,
Forms,
Frontend,
GoApi,
Expand All @@ -35,6 +36,7 @@ import type {
ProjectConfig,
PythonAi,
PythonAuth,
PythonGraphql,
PythonOrm,
PythonQuality,
PythonTaskQueue,
Expand All @@ -44,6 +46,7 @@ import type {
RustApi,
RustCli,
RustErrorHandling,
RustCaching,
RustFrontend,
RustLibraries,
RustLogging,
Expand Down Expand Up @@ -103,6 +106,7 @@ import { getPaymentsChoice } from "./payments";
import {
getPythonAiChoice,
getPythonAuthChoice,
getPythonGraphqlChoice,
getPythonOrmChoice,
getPythonQualityChoice,
getPythonTaskQueueChoice,
Expand All @@ -118,9 +122,11 @@ import {
getRustLibrariesChoice,
getRustLoggingChoice,
getRustErrorHandlingChoice,
getRustCachingChoice,
getRustOrmChoice,
getRustWebFrameworkChoice,
} from "./rust-ecosystem";
import { getI18nChoice } from "./i18n";
import { getSearchChoice } from "./search";
import { getServerDeploymentChoice } from "./server-deploy";
import { getShadcnOptions, type ShadcnOptions } from "./shadcn-options";
Expand Down Expand Up @@ -170,6 +176,7 @@ type PromptGroupResults = {
caching: Caching;
search: Search;
fileStorage: FileStorage;
i18n: I18n;
// Rust ecosystem
rustWebFramework: RustWebFramework;
rustFrontend: RustFrontend;
Expand All @@ -179,12 +186,14 @@ type PromptGroupResults = {
rustLibraries: RustLibraries[];
rustLogging: RustLogging;
rustErrorHandling: RustErrorHandling;
rustCaching: RustCaching;
// Python ecosystem
pythonWebFramework: PythonWebFramework;
pythonOrm: PythonOrm;
pythonValidation: PythonValidation;
pythonAi: PythonAi[];
pythonAuth: PythonAuth;
pythonGraphql: PythonGraphql;
pythonTaskQueue: PythonTaskQueue;
pythonQuality: PythonQuality;
// Go ecosystem
Expand Down Expand Up @@ -417,6 +426,10 @@ export async function gatherConfig(
if (results.ecosystem !== "typescript") return Promise.resolve("none" as FileStorage);
return getFileStorageChoice(flags.fileStorage, results.backend);
},
i18n: ({ results }) => {
if (results.ecosystem !== "typescript") return Promise.resolve("none" as I18n);
return getI18nChoice(flags.i18n, results.frontend);
},
// Rust ecosystem prompts (skip if TypeScript or Python)
rustWebFramework: ({ results }) => {
if (results.ecosystem !== "rust") return Promise.resolve("none" as RustWebFramework);
Expand Down Expand Up @@ -450,6 +463,10 @@ export async function gatherConfig(
if (results.ecosystem !== "rust") return Promise.resolve("none" as RustErrorHandling);
return getRustErrorHandlingChoice(flags.rustErrorHandling);
},
rustCaching: ({ results }) => {
if (results.ecosystem !== "rust") return Promise.resolve("none" as RustCaching);
return getRustCachingChoice(flags.rustCaching);
},
// Python ecosystem prompts (skip if TypeScript or Rust)
pythonWebFramework: ({ results }) => {
if (results.ecosystem !== "python") return Promise.resolve("none" as PythonWebFramework);
Expand All @@ -471,6 +488,10 @@ export async function gatherConfig(
if (results.ecosystem !== "python") return Promise.resolve("none" as PythonAuth);
return getPythonAuthChoice(flags.pythonAuth);
},
pythonGraphql: ({ results }) => {
if (results.ecosystem !== "python") return Promise.resolve("none" as PythonGraphql);
return getPythonGraphqlChoice(flags.pythonGraphql);
},
pythonTaskQueue: ({ results }) => {
if (results.ecosystem !== "python") return Promise.resolve("none" as PythonTaskQueue);
return getPythonTaskQueueChoice(flags.pythonTaskQueue);
Expand Down Expand Up @@ -564,6 +585,7 @@ export async function gatherConfig(
caching: result.caching,
search: result.search,
fileStorage: result.fileStorage,
i18n: result.i18n,
// Ecosystem
ecosystem: result.ecosystem,
// Rust ecosystem options
Expand All @@ -575,12 +597,14 @@ export async function gatherConfig(
rustLibraries: result.rustLibraries,
rustLogging: result.rustLogging,
rustErrorHandling: result.rustErrorHandling,
rustCaching: result.rustCaching,
// Python ecosystem options
pythonWebFramework: result.pythonWebFramework,
pythonOrm: result.pythonOrm,
pythonValidation: result.pythonValidation,
pythonAi: result.pythonAi,
pythonAuth: result.pythonAuth,
pythonGraphql: result.pythonGraphql,
pythonTaskQueue: result.pythonTaskQueue,
pythonQuality: result.pythonQuality,
// Go ecosystem options
Expand Down
Loading
Loading