create-better-fullstack 2.1.5 → 2.1.7
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/{add-handler-BNSL6HdM.mjs → add-handler-ztNjzoMN.mjs} +52 -6
- package/dist/addons-setup-DnLjAzTw.mjs +7 -0
- package/dist/{addons-setup-CyrP1IV-.mjs → addons-setup-LaAj43NP.mjs} +10 -24
- package/dist/analytics-DVltG11u.mjs +170 -0
- package/dist/{errors-Cyol8zbN.mjs → bts-config-DQVWvPDs.mjs} +72 -149
- package/dist/cli.mjs +2 -2
- package/dist/{templates-CnTOtKjm.mjs → config-processing-D9-F2Us9.mjs} +57 -2
- package/dist/{doctor-DBoq7bZ9.mjs → doctor-a4ca3SMd.mjs} +3 -2
- package/dist/errors-ns_o2OKg.mjs +86 -0
- package/dist/{file-formatter-B3dsev2l.mjs → file-formatter-gvmrpd-g.mjs} +78 -6
- package/dist/gen-CCClL7Ve.mjs +274 -0
- package/dist/{generated-checks-C8hn9w2i.mjs → generated-checks-BV9jol5h.mjs} +1 -1
- package/dist/index.d.mts +162 -64
- package/dist/index.mjs +17 -8
- package/dist/{install-dependencies-CgNh-aOy.mjs → install-dependencies-RoUyaE8o.mjs} +80 -21
- package/dist/mcp-492OkjcS.mjs +11 -0
- package/dist/mcp-entry.mjs +205 -30
- package/dist/prompt-environment-BR0Kkw2W.mjs +26 -0
- package/dist/registry-DSf2CEaU.mjs +408 -0
- package/dist/{run-BYse4yJy.mjs → run-D9I7NdES.mjs} +2081 -464
- package/dist/run-buK4aZS8.mjs +15 -0
- package/dist/scaffold-manifest-DGRyepdb.mjs +4 -0
- package/dist/scaffold-manifest-Dyi0voqE.mjs +135 -0
- package/dist/update-DJ8CI5KW.mjs +401 -0
- package/package.json +3 -3
- package/dist/addons-setup-DyMm42a5.mjs +0 -5
- package/dist/mcp-CsW3i66c.mjs +0 -6
- package/dist/run-_cf_sFwM.mjs +0 -10
- /package/dist/{update-deps-D5OG0KmJ.mjs → update-deps-aD-iQw4U.mjs} +0 -0
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { _ as DEFAULT_UI_LIBRARY_BY_FRONTEND, b as types_exports, c as getGraphBackendDeployInstructions, d as getGraphSummary, g as DEFAULT_CONFIG, h as BUILDER_URL, i as readBtsConfigFromFile, l as getGraphBackendUrl, m as getLatestCLIVersion, o as writeBtsConfig, p as hasGraphPart, t as buildBtsConfigForPersistence, u as getGraphPart, v as getDefaultConfig, y as getUserPkgManager } from "./bts-config-DQVWvPDs.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
|
-
import { i as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { n as
|
|
8
|
-
import { n as
|
|
9
|
-
import {
|
|
4
|
+
import { a as handleError, c as isSilent, d as setLastPromptShownUI, i as exitWithError, l as runWithContextAsync, n as UserCancelledError, o as didLastPromptShowUI, r as exitCancelled, s as isFirstPrompt, t as CLIError, u as setIsFirstPrompt } from "./errors-ns_o2OKg.mjs";
|
|
5
|
+
import { t as canPromptInteractively } from "./prompt-environment-BR0Kkw2W.mjs";
|
|
6
|
+
import { a as trackProjectCreation, i as trackEvent, n as isTelemetryEnabled, o as getPersistedTelemetryPreference, r as maybeShowTelemetryNotice, s as setTelemetryPreference, t as hasTelemetryEnvOverride } from "./analytics-DVltG11u.mjs";
|
|
7
|
+
import { _ as CreateCommandInputSchema, a as allowedApisForFrontends$1, c as getCompatibleUILibraries$1, d as isExampleChatSdkAllowed$1, f as isFrontendAllowedWithBackend$1, h as splitFrontends$1, i as validateFullConfig, l as hasWebStyling$1, m as requiresChatSdkVercelAI, n as formatProject, p as isWebFrontend$1, r as validateConfigForProgrammaticUse, s as getCompatibleCSSFrameworks$1, u as isExampleAIAllowed$1, v as CreateCommandOptionsSchema } from "./file-formatter-gvmrpd-g.mjs";
|
|
8
|
+
import { _ as isGoBack, a as runMavenTests, c as applyDependencyVersionChannel, d as isCancel$1, f as navigableConfirm, g as GO_BACK_SYMBOL, h as setIsFirstPrompt$1, i as runGradleTests, l as getAddonsChoice, m as navigableSelect, n as runCargoBuild, o as runMixCompile, p as navigableMultiselect, r as runGoModTidy, s as runUvSync, t as installDependencies } from "./install-dependencies-RoUyaE8o.mjs";
|
|
9
|
+
import { n as commandExists, t as runGeneratedChecks } from "./generated-checks-BV9jol5h.mjs";
|
|
10
|
+
import { a as getTemplateConfig, i as validateArrayOptions, n as getProvidedFlags, o as getTemplateDescription, r as processFlags, s as generateReproducibleCommand, t as applyEffectBackendDefaults } from "./config-processing-D9-F2Us9.mjs";
|
|
11
|
+
import { a as recordScaffoldManifest } from "./scaffold-manifest-Dyi0voqE.mjs";
|
|
12
|
+
import { n as getPackageExecutionArgs, r as addPackageDependency, t as setupAddons } from "./addons-setup-LaAj43NP.mjs";
|
|
13
|
+
import { cancel, confirm, intro, isCancel, log, note, outro, select, spinner, text } from "@clack/prompts";
|
|
10
14
|
import { createRouterClient, os } from "@orpc/server";
|
|
11
15
|
import pc from "picocolors";
|
|
12
16
|
import { createCli } from "trpc-cli";
|
|
@@ -17,14 +21,13 @@ import path from "node:path";
|
|
|
17
21
|
import { formatStackPartSpec, getLocalWebDevPort } from "@better-fullstack/types";
|
|
18
22
|
import consola, { consola as consola$1 } from "consola";
|
|
19
23
|
import { $, execa } from "execa";
|
|
20
|
-
import { cliInputToProjectConfigPartial } from "@better-fullstack/types/stack-translation";
|
|
21
24
|
import os$1 from "node:os";
|
|
22
25
|
|
|
23
26
|
//#region src/utils/project-history.ts
|
|
24
|
-
const paths
|
|
27
|
+
const paths = envPaths("better-fullstack", { suffix: "" });
|
|
25
28
|
const HISTORY_FILE = "history.json";
|
|
26
29
|
function getHistoryPath() {
|
|
27
|
-
return path.join(paths
|
|
30
|
+
return path.join(paths.data, HISTORY_FILE);
|
|
28
31
|
}
|
|
29
32
|
function generateId() {
|
|
30
33
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
@@ -47,7 +50,7 @@ async function readHistory() {
|
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
async function writeHistory(history$1) {
|
|
50
|
-
await fs.ensureDir(paths
|
|
53
|
+
await fs.ensureDir(paths.data);
|
|
51
54
|
await fs.writeJson(getHistoryPath(), history$1, { spaces: 2 });
|
|
52
55
|
}
|
|
53
56
|
async function addToHistory(config, reproducibleCommand) {
|
|
@@ -154,141 +157,13 @@ async function historyHandler(input) {
|
|
|
154
157
|
}
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
//#endregion
|
|
158
|
-
//#region src/utils/telemetry-settings.ts
|
|
159
|
-
const paths = envPaths("better-fullstack", { suffix: "" });
|
|
160
|
-
const SETTINGS_FILE = "telemetry.json";
|
|
161
|
-
function getSettingsPath() {
|
|
162
|
-
return path.join(paths.data, SETTINGS_FILE);
|
|
163
|
-
}
|
|
164
|
-
function emptySettings() {
|
|
165
|
-
return {
|
|
166
|
-
version: 1,
|
|
167
|
-
noticeShown: false
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
async function readTelemetrySettings() {
|
|
171
|
-
const settingsPath = getSettingsPath();
|
|
172
|
-
if (!await fs.pathExists(settingsPath)) return emptySettings();
|
|
173
|
-
try {
|
|
174
|
-
const data = await fs.readJson(settingsPath);
|
|
175
|
-
if (!data || typeof data !== "object") return emptySettings();
|
|
176
|
-
return {
|
|
177
|
-
version: typeof data.version === "number" ? data.version : 1,
|
|
178
|
-
enabled: typeof data.enabled === "boolean" ? data.enabled : void 0,
|
|
179
|
-
noticeShown: data.noticeShown === true
|
|
180
|
-
};
|
|
181
|
-
} catch {
|
|
182
|
-
return emptySettings();
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
async function writeTelemetrySettings(settings) {
|
|
186
|
-
await fs.ensureDir(paths.data);
|
|
187
|
-
await fs.writeJson(getSettingsPath(), settings, { spaces: 2 });
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* The user's explicit persisted preference, or `undefined` when they never chose.
|
|
191
|
-
*/
|
|
192
|
-
async function getPersistedTelemetryPreference() {
|
|
193
|
-
return (await readTelemetrySettings()).enabled;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Persist an explicit opt-in/opt-out. Choosing a preference also marks the
|
|
197
|
-
* first-run notice as shown so it never appears afterwards.
|
|
198
|
-
*/
|
|
199
|
-
async function setTelemetryPreference(enabled) {
|
|
200
|
-
const settings = await readTelemetrySettings();
|
|
201
|
-
settings.enabled = enabled;
|
|
202
|
-
settings.noticeShown = true;
|
|
203
|
-
await writeTelemetrySettings(settings);
|
|
204
|
-
}
|
|
205
|
-
async function hasTelemetryNoticeBeenShown() {
|
|
206
|
-
return (await readTelemetrySettings()).noticeShown;
|
|
207
|
-
}
|
|
208
|
-
async function markTelemetryNoticeShown() {
|
|
209
|
-
const settings = await readTelemetrySettings();
|
|
210
|
-
settings.noticeShown = true;
|
|
211
|
-
await writeTelemetrySettings(settings);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
//#endregion
|
|
215
|
-
//#region src/utils/analytics.ts
|
|
216
|
-
const CONVEX_INGEST_URL = "https://curious-elephant-653.convex.site/api/analytics/ingest";
|
|
217
|
-
/**
|
|
218
|
-
* Whether telemetry is explicitly overridden at runtime.
|
|
219
|
-
*
|
|
220
|
-
* Only `BTS_TELEMETRY_DISABLED` is a runtime override: `BTS_TELEMETRY` is inlined
|
|
221
|
-
* by the bundler at build time (see tsdown.config.ts) and therefore acts as a
|
|
222
|
-
* build-time default, not a runtime switch.
|
|
223
|
-
*/
|
|
224
|
-
function hasTelemetryEnvOverride() {
|
|
225
|
-
return process.env.BTS_TELEMETRY_DISABLED !== void 0;
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Resolve whether telemetry is enabled.
|
|
229
|
-
*
|
|
230
|
-
* Precedence: runtime env override (`BTS_TELEMETRY_DISABLED`) > persisted
|
|
231
|
-
* preference > default. The default honors the build-time `BTS_TELEMETRY` flag
|
|
232
|
-
* (inlined by the bundler, "0" by default) and falls back to enabled when the
|
|
233
|
-
* flag is unset (e.g. running from source).
|
|
234
|
-
*
|
|
235
|
-
* `BTS_TELEMETRY` is intentionally evaluated last: the bundler replaces it with
|
|
236
|
-
* a literal, so an early `!== undefined` check would always short-circuit and
|
|
237
|
-
* make the persisted preference unreachable in the shipped CLI.
|
|
238
|
-
*/
|
|
239
|
-
async function isTelemetryEnabled() {
|
|
240
|
-
const disabled = process.env.BTS_TELEMETRY_DISABLED;
|
|
241
|
-
if (disabled !== void 0) return disabled !== "1";
|
|
242
|
-
const persisted = await getPersistedTelemetryPreference();
|
|
243
|
-
if (persisted !== void 0) return persisted;
|
|
244
|
-
const buildDefault = "1";
|
|
245
|
-
return buildDefault === void 0 ? true : buildDefault === "1";
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Print a one-time notice describing the anonymous telemetry the CLI collects
|
|
249
|
-
* and how to opt out, then remember that it was shown so it never repeats.
|
|
250
|
-
*
|
|
251
|
-
* No-ops when telemetry is explicitly configured via env var, when a persisted
|
|
252
|
-
* preference already exists, when the notice was already shown, when telemetry
|
|
253
|
-
* is disabled by the build default, or when the CLI is not running interactively
|
|
254
|
-
* (CI / silent / non-TTY).
|
|
255
|
-
*/
|
|
256
|
-
async function maybeShowTelemetryNotice() {
|
|
257
|
-
if (hasTelemetryEnvOverride()) return;
|
|
258
|
-
if (!canPromptInteractively()) return;
|
|
259
|
-
if (await getPersistedTelemetryPreference() !== void 0) return;
|
|
260
|
-
if (await hasTelemetryNoticeBeenShown()) return;
|
|
261
|
-
if (!await isTelemetryEnabled()) return;
|
|
262
|
-
log.info(`${pc.bold("Anonymous usage telemetry is enabled.")}\n${pc.dim("We collect your selected stack options (e.g. frontend, backend, database),")}\n${pc.dim("plus CLI version, Node.js version, and OS platform — never project names,")}\n${pc.dim("file paths, or any personal data.")}\nOpt out anytime with ${pc.cyan("create-better-fullstack telemetry disable")} or ${pc.cyan("BTS_TELEMETRY_DISABLED=1")}.`);
|
|
263
|
-
try {
|
|
264
|
-
await markTelemetryNoticeShown();
|
|
265
|
-
} catch {}
|
|
266
|
-
}
|
|
267
|
-
async function sendConvexEvent(payload) {
|
|
268
|
-
try {
|
|
269
|
-
await fetch(CONVEX_INGEST_URL, {
|
|
270
|
-
method: "POST",
|
|
271
|
-
headers: { "Content-Type": "application/json" },
|
|
272
|
-
body: JSON.stringify(payload)
|
|
273
|
-
});
|
|
274
|
-
} catch {}
|
|
275
|
-
}
|
|
276
|
-
async function trackProjectCreation(config, disableAnalytics = false) {
|
|
277
|
-
if (disableAnalytics || !await isTelemetryEnabled()) return;
|
|
278
|
-
const { projectName: _projectName, projectDir: _projectDir, relativePath: _relativePath, ...safeConfig } = config;
|
|
279
|
-
try {
|
|
280
|
-
await sendConvexEvent({
|
|
281
|
-
...safeConfig,
|
|
282
|
-
cli_version: getLatestCLIVersion(),
|
|
283
|
-
node_version: typeof process !== "undefined" ? process.version : "",
|
|
284
|
-
platform: typeof process !== "undefined" ? process.platform : ""
|
|
285
|
-
});
|
|
286
|
-
} catch {}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
160
|
//#endregion
|
|
290
161
|
//#region src/commands/telemetry.ts
|
|
291
|
-
const COLLECTED = [
|
|
162
|
+
const COLLECTED = [
|
|
163
|
+
"Selected stack options (frontend, backend, database, ORM, auth, API, etc.)",
|
|
164
|
+
"CLI version, Node.js version, and OS platform",
|
|
165
|
+
"A random anonymous install ID used to count unique and returning installs"
|
|
166
|
+
];
|
|
292
167
|
const NOT_COLLECTED = ["Project names, directory paths, or file contents", "Personal or otherwise identifying information"];
|
|
293
168
|
function resolveSource(persisted) {
|
|
294
169
|
if (hasTelemetryEnvOverride()) return "env";
|
|
@@ -792,6 +667,11 @@ const BACKEND_PROMPT_OPTIONS = [
|
|
|
792
667
|
label: "feTS",
|
|
793
668
|
hint: "TypeScript HTTP Framework with e2e type-safety"
|
|
794
669
|
},
|
|
670
|
+
{
|
|
671
|
+
value: "effect",
|
|
672
|
+
label: "Effect",
|
|
673
|
+
hint: "Effect-first service backend with layers and schema"
|
|
674
|
+
},
|
|
795
675
|
{
|
|
796
676
|
value: "nestjs",
|
|
797
677
|
label: "NestJS",
|
|
@@ -833,6 +713,7 @@ function resolveBackendPrompt(context = {}) {
|
|
|
833
713
|
"fastify",
|
|
834
714
|
"elysia",
|
|
835
715
|
"fets",
|
|
716
|
+
"effect",
|
|
836
717
|
"nestjs",
|
|
837
718
|
"adonisjs",
|
|
838
719
|
"nitro",
|
|
@@ -870,15 +751,24 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
|
870
751
|
|
|
871
752
|
//#endregion
|
|
872
753
|
//#region src/prompts/caching.ts
|
|
873
|
-
const CACHING_PROMPT_OPTIONS = [
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
754
|
+
const CACHING_PROMPT_OPTIONS = [
|
|
755
|
+
{
|
|
756
|
+
value: "upstash-redis",
|
|
757
|
+
label: "Upstash Redis",
|
|
758
|
+
hint: "Serverless Redis with REST API for edge and serverless"
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
value: "redis",
|
|
762
|
+
label: "Redis",
|
|
763
|
+
hint: "Self-hosted Redis via ioredis (TCP) — full command surface"
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
value: "none",
|
|
767
|
+
label: "None",
|
|
768
|
+
hint: "Skip caching layer setup"
|
|
769
|
+
}
|
|
770
|
+
];
|
|
771
|
+
const NON_TS_CACHING_PROMPT_OPTIONS = CACHING_PROMPT_OPTIONS.filter((option) => option.value !== "redis");
|
|
882
772
|
function resolveCachingPrompt(context = {}) {
|
|
883
773
|
if (context.ecosystem === "react-native" || context.ecosystem === "elixir") return {
|
|
884
774
|
shouldPrompt: false,
|
|
@@ -889,12 +779,12 @@ function resolveCachingPrompt(context = {}) {
|
|
|
889
779
|
if (context.ecosystem && context.ecosystem !== "typescript") return context.caching !== void 0 ? {
|
|
890
780
|
shouldPrompt: false,
|
|
891
781
|
mode: "single",
|
|
892
|
-
options:
|
|
782
|
+
options: NON_TS_CACHING_PROMPT_OPTIONS,
|
|
893
783
|
autoValue: context.caching
|
|
894
784
|
} : {
|
|
895
785
|
shouldPrompt: true,
|
|
896
786
|
mode: "single",
|
|
897
|
-
options:
|
|
787
|
+
options: NON_TS_CACHING_PROMPT_OPTIONS,
|
|
898
788
|
initialValue: "none"
|
|
899
789
|
};
|
|
900
790
|
if (context.backend === "none" || context.backend === "convex") return {
|
|
@@ -1004,6 +894,475 @@ async function getCMSChoice(cms, backend) {
|
|
|
1004
894
|
return response;
|
|
1005
895
|
}
|
|
1006
896
|
|
|
897
|
+
//#endregion
|
|
898
|
+
//#region src/prompts/config-scope.ts
|
|
899
|
+
const CONFIG_SCOPE_ALWAYS_KEYS = [
|
|
900
|
+
"aiDocs",
|
|
901
|
+
"git",
|
|
902
|
+
"workspaceShape",
|
|
903
|
+
"packageManager",
|
|
904
|
+
"install"
|
|
905
|
+
];
|
|
906
|
+
const sharedServiceSection = {
|
|
907
|
+
id: "shared-services",
|
|
908
|
+
label: "Shared Services",
|
|
909
|
+
promptKeys: [
|
|
910
|
+
"email",
|
|
911
|
+
"caching",
|
|
912
|
+
"search",
|
|
913
|
+
"observability"
|
|
914
|
+
]
|
|
915
|
+
};
|
|
916
|
+
const typescriptSections = [
|
|
917
|
+
{
|
|
918
|
+
id: "ui-styling",
|
|
919
|
+
label: "UI & Styling",
|
|
920
|
+
promptKeys: [
|
|
921
|
+
"uiLibrary",
|
|
922
|
+
"shadcnOptions",
|
|
923
|
+
"cssFramework"
|
|
924
|
+
]
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
id: "state-forms",
|
|
928
|
+
label: "State, Forms & Animation",
|
|
929
|
+
promptKeys: [
|
|
930
|
+
"stateManagement",
|
|
931
|
+
"forms",
|
|
932
|
+
"animation"
|
|
933
|
+
]
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
id: "type-safety",
|
|
937
|
+
label: "Validation & Effect",
|
|
938
|
+
promptKeys: ["validation", "effect"]
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
id: "payments-email",
|
|
942
|
+
label: "Payments & Email",
|
|
943
|
+
promptKeys: ["payments", "email"]
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
id: "ai",
|
|
947
|
+
label: "AI & Vector DB",
|
|
948
|
+
promptKeys: ["ai", "vectorDb"]
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
id: "data-storage",
|
|
952
|
+
label: "Data & Storage",
|
|
953
|
+
promptKeys: [
|
|
954
|
+
"caching",
|
|
955
|
+
"search",
|
|
956
|
+
"fileStorage",
|
|
957
|
+
"fileUpload"
|
|
958
|
+
]
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
id: "backend-extras",
|
|
962
|
+
label: "Jobs, Realtime & Rate Limiting",
|
|
963
|
+
promptKeys: [
|
|
964
|
+
"jobQueue",
|
|
965
|
+
"realtime",
|
|
966
|
+
"rateLimit"
|
|
967
|
+
]
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
id: "quality",
|
|
971
|
+
label: "Testing & Observability",
|
|
972
|
+
promptKeys: [
|
|
973
|
+
"testing",
|
|
974
|
+
"logging",
|
|
975
|
+
"observability"
|
|
976
|
+
]
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
id: "content",
|
|
980
|
+
label: "Content, Analytics & i18n",
|
|
981
|
+
promptKeys: [
|
|
982
|
+
"cms",
|
|
983
|
+
"analytics",
|
|
984
|
+
"i18n",
|
|
985
|
+
"featureFlags"
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
id: "deploy",
|
|
990
|
+
label: "Deployment",
|
|
991
|
+
promptKeys: ["webDeploy", "serverDeploy"]
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
id: "addons-examples",
|
|
995
|
+
label: "Addons & Examples",
|
|
996
|
+
promptKeys: ["addons", "examples"]
|
|
997
|
+
}
|
|
998
|
+
];
|
|
999
|
+
const CONFIG_SCOPE_REGISTRY = {
|
|
1000
|
+
typescript: {
|
|
1001
|
+
core: [
|
|
1002
|
+
"frontend",
|
|
1003
|
+
"astroIntegration",
|
|
1004
|
+
"backend",
|
|
1005
|
+
"runtime",
|
|
1006
|
+
"database",
|
|
1007
|
+
"orm",
|
|
1008
|
+
"api",
|
|
1009
|
+
"auth",
|
|
1010
|
+
"dbSetup"
|
|
1011
|
+
],
|
|
1012
|
+
sections: typescriptSections
|
|
1013
|
+
},
|
|
1014
|
+
"react-native": {
|
|
1015
|
+
core: [
|
|
1016
|
+
"frontend",
|
|
1017
|
+
"mobileNavigation",
|
|
1018
|
+
"backend",
|
|
1019
|
+
"runtime",
|
|
1020
|
+
"database",
|
|
1021
|
+
"orm",
|
|
1022
|
+
"api",
|
|
1023
|
+
"auth",
|
|
1024
|
+
"dbSetup"
|
|
1025
|
+
],
|
|
1026
|
+
sections: [
|
|
1027
|
+
{
|
|
1028
|
+
id: "mobile-experience",
|
|
1029
|
+
label: "Mobile Experience",
|
|
1030
|
+
promptKeys: [
|
|
1031
|
+
"mobileUI",
|
|
1032
|
+
"mobileStorage",
|
|
1033
|
+
"mobileDeepLinking"
|
|
1034
|
+
]
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
id: "mobile-delivery",
|
|
1038
|
+
label: "Mobile Delivery",
|
|
1039
|
+
promptKeys: [
|
|
1040
|
+
"mobilePush",
|
|
1041
|
+
"mobileOTA",
|
|
1042
|
+
"mobileTesting"
|
|
1043
|
+
]
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
id: "commerce",
|
|
1047
|
+
label: "Payments",
|
|
1048
|
+
promptKeys: ["payments"]
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
id: "extras",
|
|
1052
|
+
label: "Data & Discovery",
|
|
1053
|
+
promptKeys: [
|
|
1054
|
+
"caching",
|
|
1055
|
+
"search",
|
|
1056
|
+
"observability"
|
|
1057
|
+
]
|
|
1058
|
+
}
|
|
1059
|
+
]
|
|
1060
|
+
},
|
|
1061
|
+
rust: {
|
|
1062
|
+
core: [
|
|
1063
|
+
"rustWebFramework",
|
|
1064
|
+
"rustFrontend",
|
|
1065
|
+
"database",
|
|
1066
|
+
"dbSetup",
|
|
1067
|
+
"rustOrm",
|
|
1068
|
+
"rustApi",
|
|
1069
|
+
"rustAuth"
|
|
1070
|
+
],
|
|
1071
|
+
sections: [
|
|
1072
|
+
sharedServiceSection,
|
|
1073
|
+
{
|
|
1074
|
+
id: "cli-libraries",
|
|
1075
|
+
label: "CLI & Libraries",
|
|
1076
|
+
promptKeys: [
|
|
1077
|
+
"rustCli",
|
|
1078
|
+
"rustLibraries",
|
|
1079
|
+
"rustTemplating"
|
|
1080
|
+
]
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
id: "quality",
|
|
1084
|
+
label: "Logging & Error Handling",
|
|
1085
|
+
promptKeys: ["rustLogging", "rustErrorHandling"]
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
id: "backend-extras",
|
|
1089
|
+
label: "Caching, Realtime & Queues",
|
|
1090
|
+
promptKeys: [
|
|
1091
|
+
"rustCaching",
|
|
1092
|
+
"rustRealtime",
|
|
1093
|
+
"rustMessageQueue"
|
|
1094
|
+
]
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
id: "observability",
|
|
1098
|
+
label: "Observability",
|
|
1099
|
+
promptKeys: ["rustObservability"]
|
|
1100
|
+
}
|
|
1101
|
+
]
|
|
1102
|
+
},
|
|
1103
|
+
python: {
|
|
1104
|
+
core: [
|
|
1105
|
+
"pythonWebFramework",
|
|
1106
|
+
"database",
|
|
1107
|
+
"dbSetup",
|
|
1108
|
+
"pythonOrm",
|
|
1109
|
+
"pythonAuth",
|
|
1110
|
+
"pythonApi"
|
|
1111
|
+
],
|
|
1112
|
+
sections: [
|
|
1113
|
+
sharedServiceSection,
|
|
1114
|
+
{
|
|
1115
|
+
id: "type-safety-ai",
|
|
1116
|
+
label: "Validation & AI",
|
|
1117
|
+
promptKeys: ["pythonValidation", "pythonAi"]
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
id: "api-jobs",
|
|
1121
|
+
label: "GraphQL, Tasks & CLI",
|
|
1122
|
+
promptKeys: [
|
|
1123
|
+
"pythonGraphql",
|
|
1124
|
+
"pythonTaskQueue",
|
|
1125
|
+
"pythonCli"
|
|
1126
|
+
]
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
id: "data-realtime",
|
|
1130
|
+
label: "Caching & Realtime",
|
|
1131
|
+
promptKeys: ["pythonCaching", "pythonRealtime"]
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
id: "quality",
|
|
1135
|
+
label: "Quality, Testing & Observability",
|
|
1136
|
+
promptKeys: [
|
|
1137
|
+
"pythonQuality",
|
|
1138
|
+
"pythonTesting",
|
|
1139
|
+
"pythonObservability"
|
|
1140
|
+
]
|
|
1141
|
+
}
|
|
1142
|
+
]
|
|
1143
|
+
},
|
|
1144
|
+
go: {
|
|
1145
|
+
core: [
|
|
1146
|
+
"goWebFramework",
|
|
1147
|
+
"database",
|
|
1148
|
+
"dbSetup",
|
|
1149
|
+
"goOrm",
|
|
1150
|
+
"goApi",
|
|
1151
|
+
"goAuth"
|
|
1152
|
+
],
|
|
1153
|
+
sections: [
|
|
1154
|
+
sharedServiceSection,
|
|
1155
|
+
{
|
|
1156
|
+
id: "cli-config",
|
|
1157
|
+
label: "CLI, Config & Logging",
|
|
1158
|
+
promptKeys: [
|
|
1159
|
+
"goCli",
|
|
1160
|
+
"goConfig",
|
|
1161
|
+
"goLogging"
|
|
1162
|
+
]
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
id: "backend-extras",
|
|
1166
|
+
label: "Realtime, Queues & Caching",
|
|
1167
|
+
promptKeys: [
|
|
1168
|
+
"goRealtime",
|
|
1169
|
+
"goMessageQueue",
|
|
1170
|
+
"goCaching"
|
|
1171
|
+
]
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
id: "quality",
|
|
1175
|
+
label: "Testing & Observability",
|
|
1176
|
+
promptKeys: ["goTesting", "goObservability"]
|
|
1177
|
+
}
|
|
1178
|
+
]
|
|
1179
|
+
},
|
|
1180
|
+
java: {
|
|
1181
|
+
core: [
|
|
1182
|
+
"javaWebFramework",
|
|
1183
|
+
"javaLanguage",
|
|
1184
|
+
"javaBuildTool",
|
|
1185
|
+
"database",
|
|
1186
|
+
"dbSetup",
|
|
1187
|
+
"javaOrm",
|
|
1188
|
+
"javaAuth",
|
|
1189
|
+
"javaApi"
|
|
1190
|
+
],
|
|
1191
|
+
sections: [
|
|
1192
|
+
sharedServiceSection,
|
|
1193
|
+
{
|
|
1194
|
+
id: "libraries",
|
|
1195
|
+
label: "Libraries",
|
|
1196
|
+
promptKeys: ["javaLibraries"]
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
id: "quality",
|
|
1200
|
+
label: "Logging & Testing",
|
|
1201
|
+
promptKeys: ["javaLogging", "javaTestingLibraries"]
|
|
1202
|
+
}
|
|
1203
|
+
]
|
|
1204
|
+
},
|
|
1205
|
+
dotnet: {
|
|
1206
|
+
core: [
|
|
1207
|
+
"dotnetWebFramework",
|
|
1208
|
+
"database",
|
|
1209
|
+
"dbSetup",
|
|
1210
|
+
"dotnetOrm",
|
|
1211
|
+
"dotnetAuth",
|
|
1212
|
+
"dotnetApi"
|
|
1213
|
+
],
|
|
1214
|
+
sections: [
|
|
1215
|
+
sharedServiceSection,
|
|
1216
|
+
{
|
|
1217
|
+
id: "quality",
|
|
1218
|
+
label: "Testing & Observability",
|
|
1219
|
+
promptKeys: ["dotnetTesting", "dotnetObservability"]
|
|
1220
|
+
},
|
|
1221
|
+
{
|
|
1222
|
+
id: "backend-extras",
|
|
1223
|
+
label: "Jobs, Realtime & Caching",
|
|
1224
|
+
promptKeys: [
|
|
1225
|
+
"dotnetJobQueue",
|
|
1226
|
+
"dotnetRealtime",
|
|
1227
|
+
"dotnetCaching"
|
|
1228
|
+
]
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
id: "validation-deploy",
|
|
1232
|
+
label: "Validation & Deployment",
|
|
1233
|
+
promptKeys: ["dotnetValidation", "dotnetDeploy"]
|
|
1234
|
+
}
|
|
1235
|
+
]
|
|
1236
|
+
},
|
|
1237
|
+
elixir: {
|
|
1238
|
+
core: [
|
|
1239
|
+
"elixirWebFramework",
|
|
1240
|
+
"database",
|
|
1241
|
+
"dbSetup",
|
|
1242
|
+
"elixirOrm",
|
|
1243
|
+
"elixirAuth",
|
|
1244
|
+
"elixirApi"
|
|
1245
|
+
],
|
|
1246
|
+
sections: [
|
|
1247
|
+
{
|
|
1248
|
+
id: "backend-extras",
|
|
1249
|
+
label: "Realtime & Jobs",
|
|
1250
|
+
promptKeys: ["elixirRealtime", "elixirJobs"]
|
|
1251
|
+
},
|
|
1252
|
+
{
|
|
1253
|
+
id: "type-safety-http",
|
|
1254
|
+
label: "Validation, HTTP & JSON",
|
|
1255
|
+
promptKeys: [
|
|
1256
|
+
"elixirValidation",
|
|
1257
|
+
"elixirHttp",
|
|
1258
|
+
"elixirJson"
|
|
1259
|
+
]
|
|
1260
|
+
},
|
|
1261
|
+
{
|
|
1262
|
+
id: "data-email",
|
|
1263
|
+
label: "Email & Caching",
|
|
1264
|
+
promptKeys: ["elixirEmail", "elixirCaching"]
|
|
1265
|
+
},
|
|
1266
|
+
{
|
|
1267
|
+
id: "quality",
|
|
1268
|
+
label: "Testing, Quality & Observability",
|
|
1269
|
+
promptKeys: [
|
|
1270
|
+
"elixirTesting",
|
|
1271
|
+
"elixirQuality",
|
|
1272
|
+
"elixirObservability"
|
|
1273
|
+
]
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
id: "deploy-libraries",
|
|
1277
|
+
label: "Deployment & Libraries",
|
|
1278
|
+
promptKeys: ["elixirDeploy", "elixirLibraries"]
|
|
1279
|
+
}
|
|
1280
|
+
]
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
const SCOPED_CONFIG_PROMPT_KEYS = [...new Set(Object.values(CONFIG_SCOPE_REGISTRY).flatMap((registry) => [
|
|
1284
|
+
...registry.core,
|
|
1285
|
+
...registry.sections.flatMap((section) => section.promptKeys),
|
|
1286
|
+
...CONFIG_SCOPE_ALWAYS_KEYS
|
|
1287
|
+
]))].sort();
|
|
1288
|
+
function getConfigScopePromptKeys(ecosystem, scope, selectedSectionIds = []) {
|
|
1289
|
+
const registry = CONFIG_SCOPE_REGISTRY[ecosystem];
|
|
1290
|
+
const keys = new Set([...registry.core, ...CONFIG_SCOPE_ALWAYS_KEYS]);
|
|
1291
|
+
if (scope === "full") for (const section of registry.sections) for (const key of section.promptKeys) keys.add(key);
|
|
1292
|
+
if (scope === "custom") {
|
|
1293
|
+
const selected = new Set(selectedSectionIds);
|
|
1294
|
+
for (const section of registry.sections) {
|
|
1295
|
+
if (!selected.has(section.id)) continue;
|
|
1296
|
+
for (const key of section.promptKeys) keys.add(key);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
return keys;
|
|
1300
|
+
}
|
|
1301
|
+
function shouldAskConfigPromptKey(ecosystem, key, scope, selectedSectionIds) {
|
|
1302
|
+
if (!ecosystem || !scope || scope === "full") return true;
|
|
1303
|
+
const registry = CONFIG_SCOPE_REGISTRY[ecosystem];
|
|
1304
|
+
if (!new Set([
|
|
1305
|
+
...registry.core,
|
|
1306
|
+
...registry.sections.flatMap((section) => section.promptKeys),
|
|
1307
|
+
...CONFIG_SCOPE_ALWAYS_KEYS
|
|
1308
|
+
]).has(key)) return true;
|
|
1309
|
+
return getConfigScopePromptKeys(ecosystem, scope, selectedSectionIds).has(key);
|
|
1310
|
+
}
|
|
1311
|
+
function getDefaultPromptValue(key) {
|
|
1312
|
+
if (key === "astroIntegration") return void 0;
|
|
1313
|
+
const defaults = getDefaultConfig();
|
|
1314
|
+
if (key === "shadcnOptions") return {
|
|
1315
|
+
shadcnBase: defaults.shadcnBase,
|
|
1316
|
+
shadcnStyle: defaults.shadcnStyle,
|
|
1317
|
+
shadcnIconLibrary: defaults.shadcnIconLibrary,
|
|
1318
|
+
shadcnColorTheme: defaults.shadcnColorTheme,
|
|
1319
|
+
shadcnBaseColor: defaults.shadcnBaseColor,
|
|
1320
|
+
shadcnFont: defaults.shadcnFont,
|
|
1321
|
+
shadcnRadius: defaults.shadcnRadius
|
|
1322
|
+
};
|
|
1323
|
+
return defaults[key];
|
|
1324
|
+
}
|
|
1325
|
+
async function getConfigScopeChoice() {
|
|
1326
|
+
const response = await navigableSelect({
|
|
1327
|
+
message: "How much do you want to configure?",
|
|
1328
|
+
options: [
|
|
1329
|
+
{
|
|
1330
|
+
value: "core",
|
|
1331
|
+
label: "Core",
|
|
1332
|
+
hint: "essentials only — framework, database, auth, API; sensible defaults for everything else"
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
value: "full",
|
|
1336
|
+
label: "Full",
|
|
1337
|
+
hint: "walk through every option"
|
|
1338
|
+
},
|
|
1339
|
+
{
|
|
1340
|
+
value: "custom",
|
|
1341
|
+
label: "Custom",
|
|
1342
|
+
hint: "pick which sections to configure"
|
|
1343
|
+
}
|
|
1344
|
+
],
|
|
1345
|
+
initialValue: "core"
|
|
1346
|
+
});
|
|
1347
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1348
|
+
return response;
|
|
1349
|
+
}
|
|
1350
|
+
async function getConfigSectionsChoice(ecosystem, initialValues = [], availableSectionIds) {
|
|
1351
|
+
const sections = CONFIG_SCOPE_REGISTRY[ecosystem].sections.filter((section) => !availableSectionIds || availableSectionIds.includes(section.id));
|
|
1352
|
+
const response = await navigableMultiselect({
|
|
1353
|
+
message: `Which sections do you want to configure? ${pc.dim("(essentials are always included)")}`,
|
|
1354
|
+
options: sections.map((section) => ({
|
|
1355
|
+
value: section.id,
|
|
1356
|
+
label: section.label
|
|
1357
|
+
})),
|
|
1358
|
+
initialValues,
|
|
1359
|
+
required: false
|
|
1360
|
+
});
|
|
1361
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
1362
|
+
if (isGoBack(response)) return response;
|
|
1363
|
+
return response;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1007
1366
|
//#endregion
|
|
1008
1367
|
//#region src/prompts/css-framework.ts
|
|
1009
1368
|
const CSS_FRAMEWORK_OPTIONS = {
|
|
@@ -1549,6 +1908,16 @@ const DEPLOY_OPTIONS$1 = [
|
|
|
1549
1908
|
hint: "No .NET deploy target"
|
|
1550
1909
|
}
|
|
1551
1910
|
];
|
|
1911
|
+
const resolveDotnetWebFrameworkPrompt = (value) => createStaticSinglePromptResolution(WEB_FRAMEWORK_OPTIONS$1, "aspnet-minimal", value);
|
|
1912
|
+
const resolveDotnetOrmPrompt = (value) => createStaticSinglePromptResolution(ORM_OPTIONS$1, "ef-core", value);
|
|
1913
|
+
const resolveDotnetAuthPrompt = (value) => createStaticSinglePromptResolution(AUTH_OPTIONS$1, "aspnet-identity", value);
|
|
1914
|
+
const resolveDotnetApiPrompt = (value) => createStaticSinglePromptResolution(API_OPTIONS$1, "minimal-api", value);
|
|
1915
|
+
const resolveDotnetTestingPrompt = (value) => createStaticMultiPromptResolution(TESTING_OPTIONS$1, ["xunit"], value);
|
|
1916
|
+
const resolveDotnetJobQueuePrompt = (value) => createStaticSinglePromptResolution(JOB_QUEUE_OPTIONS, "none", value);
|
|
1917
|
+
const resolveDotnetRealtimePrompt = (value) => createStaticSinglePromptResolution(REALTIME_OPTIONS$1, "signalr", value);
|
|
1918
|
+
const resolveDotnetObservabilityPrompt = (value) => createStaticMultiPromptResolution(OBSERVABILITY_OPTIONS$1, ["serilog"], value);
|
|
1919
|
+
const resolveDotnetCachingPrompt = (value) => createStaticSinglePromptResolution(CACHING_OPTIONS$1, "none", value);
|
|
1920
|
+
const resolveDotnetDeployPrompt = (value) => createStaticSinglePromptResolution(DEPLOY_OPTIONS$1, "docker", value);
|
|
1552
1921
|
const getDotnetWebFrameworkChoice = (value) => makeChoice$1("Select .NET web framework", WEB_FRAMEWORK_OPTIONS$1, "aspnet-minimal", value);
|
|
1553
1922
|
const getDotnetOrmChoice = (value) => makeChoice$1("Select .NET data access", ORM_OPTIONS$1, "ef-core", value);
|
|
1554
1923
|
const getDotnetAuthChoice = (value) => makeChoice$1("Select .NET auth", AUTH_OPTIONS$1, "aspnet-identity", value);
|
|
@@ -1891,6 +2260,21 @@ const DEPLOY_OPTIONS = [
|
|
|
1891
2260
|
hint: "No deploy files"
|
|
1892
2261
|
}
|
|
1893
2262
|
];
|
|
2263
|
+
const resolveElixirWebFrameworkPrompt = (value) => createStaticSinglePromptResolution(WEB_FRAMEWORK_OPTIONS, "phoenix", value);
|
|
2264
|
+
const resolveElixirOrmPrompt = (value) => createStaticSinglePromptResolution(ORM_OPTIONS, "ecto-sql", value);
|
|
2265
|
+
const resolveElixirAuthPrompt = (value) => createStaticSinglePromptResolution(AUTH_OPTIONS, "none", value);
|
|
2266
|
+
const resolveElixirApiPrompt = (value) => createStaticSinglePromptResolution(API_OPTIONS, "rest", value);
|
|
2267
|
+
const resolveElixirRealtimePrompt = (value) => createStaticSinglePromptResolution(REALTIME_OPTIONS, "channels", value);
|
|
2268
|
+
const resolveElixirJobsPrompt = (value) => createStaticSinglePromptResolution(JOB_OPTIONS, "none", value);
|
|
2269
|
+
const resolveElixirValidationPrompt = (value) => createStaticSinglePromptResolution(VALIDATION_OPTIONS, "ecto-changesets", value);
|
|
2270
|
+
const resolveElixirHttpPrompt = (value) => createStaticSinglePromptResolution(HTTP_OPTIONS, "req", value);
|
|
2271
|
+
const resolveElixirJsonPrompt = (value) => createStaticSinglePromptResolution(JSON_OPTIONS, "jason", value);
|
|
2272
|
+
const resolveElixirEmailPrompt = (value) => createStaticSinglePromptResolution(EMAIL_OPTIONS, "none", value);
|
|
2273
|
+
const resolveElixirCachingPrompt = (value) => createStaticSinglePromptResolution(CACHING_OPTIONS, "none", value);
|
|
2274
|
+
const resolveElixirObservabilityPrompt = (value) => createStaticSinglePromptResolution(OBSERVABILITY_OPTIONS, "telemetry", value);
|
|
2275
|
+
const resolveElixirTestingPrompt = (value) => createStaticSinglePromptResolution(TESTING_OPTIONS, "ex_unit", value);
|
|
2276
|
+
const resolveElixirQualityPrompt = (value) => createStaticSinglePromptResolution(QUALITY_OPTIONS, "credo", value);
|
|
2277
|
+
const resolveElixirDeployPrompt = (value) => createStaticSinglePromptResolution(DEPLOY_OPTIONS, "none", value);
|
|
1894
2278
|
const getElixirWebFrameworkChoice = (value) => makeChoice("Select Elixir web framework", WEB_FRAMEWORK_OPTIONS, "phoenix", value);
|
|
1895
2279
|
const getElixirOrmChoice = (value) => makeChoice("Select Elixir database layer", ORM_OPTIONS, "ecto-sql", value);
|
|
1896
2280
|
const getElixirAuthChoice = (value) => makeChoice("Select Elixir auth", AUTH_OPTIONS, "none", value);
|
|
@@ -1968,22 +2352,22 @@ async function getEcosystemChoice(ecosystem) {
|
|
|
1968
2352
|
async function getEffectChoice(effect) {
|
|
1969
2353
|
if (effect !== void 0) return effect;
|
|
1970
2354
|
const response = await navigableSelect({
|
|
1971
|
-
message: "Select Effect
|
|
2355
|
+
message: "Select Effect services",
|
|
1972
2356
|
options: [
|
|
1973
2357
|
{
|
|
1974
2358
|
value: "effect",
|
|
1975
|
-
label: "Effect
|
|
1976
|
-
hint: "
|
|
2359
|
+
label: "Effect Core",
|
|
2360
|
+
hint: "Add Effect services and layers to the selected stack"
|
|
1977
2361
|
},
|
|
1978
2362
|
{
|
|
1979
2363
|
value: "effect-full",
|
|
1980
|
-
label: "Effect
|
|
1981
|
-
hint: "
|
|
2364
|
+
label: "Effect Platform + SQL",
|
|
2365
|
+
hint: "Core plus Platform, browser/server adapters, SQL, and Vitest integration"
|
|
1982
2366
|
},
|
|
1983
2367
|
{
|
|
1984
2368
|
value: "none",
|
|
1985
2369
|
label: "None",
|
|
1986
|
-
hint: "No Effect
|
|
2370
|
+
hint: "No additional Effect services"
|
|
1987
2371
|
}
|
|
1988
2372
|
],
|
|
1989
2373
|
initialValue: "none"
|
|
@@ -2135,6 +2519,11 @@ async function getFileStorageChoice(fileStorage, backend) {
|
|
|
2135
2519
|
label: "Cloudinary",
|
|
2136
2520
|
hint: "Image and media storage with transformations"
|
|
2137
2521
|
},
|
|
2522
|
+
{
|
|
2523
|
+
value: "supabase-storage",
|
|
2524
|
+
label: "Supabase Storage",
|
|
2525
|
+
hint: "S3-compatible object storage with signed URLs and RLS"
|
|
2526
|
+
},
|
|
2138
2527
|
{
|
|
2139
2528
|
value: "none",
|
|
2140
2529
|
label: "None",
|
|
@@ -2515,6 +2904,11 @@ const GO_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
|
2515
2904
|
label: "Chi",
|
|
2516
2905
|
hint: "Lightweight, zero-dependency router built on net/http"
|
|
2517
2906
|
},
|
|
2907
|
+
{
|
|
2908
|
+
value: "stdlib",
|
|
2909
|
+
label: "net/http",
|
|
2910
|
+
hint: "Go 1.22+ standard-library routing (ServeMux), zero dependencies"
|
|
2911
|
+
},
|
|
2518
2912
|
{
|
|
2519
2913
|
value: "none",
|
|
2520
2914
|
label: "None",
|
|
@@ -2537,6 +2931,11 @@ const GO_ORM_PROMPT_OPTIONS = [
|
|
|
2537
2931
|
label: "Ent",
|
|
2538
2932
|
hint: "Code-first ORM by Meta with graph traversal API, 15k+ stars"
|
|
2539
2933
|
},
|
|
2934
|
+
{
|
|
2935
|
+
value: "bun",
|
|
2936
|
+
label: "Bun",
|
|
2937
|
+
hint: "SQL-first Go ORM by uptrace with a lightweight query builder"
|
|
2938
|
+
},
|
|
2540
2939
|
{
|
|
2541
2940
|
value: "none",
|
|
2542
2941
|
label: "None",
|
|
@@ -2913,10 +3312,19 @@ const PARAGLIDE_FRONTENDS = new Set([
|
|
|
2913
3312
|
async function getI18nChoice(i18n, frontend) {
|
|
2914
3313
|
if (i18n !== void 0) return i18n;
|
|
2915
3314
|
const hasNext = frontend?.includes("next") ?? false;
|
|
3315
|
+
const hasParaglideFrontend = frontend?.some((f) => PARAGLIDE_FRONTENDS.has(f)) ?? false;
|
|
3316
|
+
const hasIntlayerFrontend = frontend?.some((f) => [
|
|
3317
|
+
"next",
|
|
3318
|
+
"vinext",
|
|
3319
|
+
"tanstack-router",
|
|
3320
|
+
"tanstack-start",
|
|
3321
|
+
"react-router",
|
|
3322
|
+
"react-vite"
|
|
3323
|
+
].includes(f)) ?? false;
|
|
2916
3324
|
const response = await navigableSelect({
|
|
2917
3325
|
message: "Select internationalization (i18n) library",
|
|
2918
3326
|
options: [
|
|
2919
|
-
...
|
|
3327
|
+
...hasParaglideFrontend ? [{
|
|
2920
3328
|
value: "paraglide",
|
|
2921
3329
|
label: "Paraglide",
|
|
2922
3330
|
hint: "Type-safe, compiler-based i18n for modern web frontends"
|
|
@@ -2931,6 +3339,11 @@ async function getI18nChoice(i18n, frontend) {
|
|
|
2931
3339
|
label: "next-intl",
|
|
2932
3340
|
hint: "Lightweight i18n for Next.js with App Router support"
|
|
2933
3341
|
}] : [],
|
|
3342
|
+
...hasIntlayerFrontend ? [{
|
|
3343
|
+
value: "intlayer",
|
|
3344
|
+
label: "Intlayer",
|
|
3345
|
+
hint: "Component-level, type-safe i18n for React, Next.js, and Vite"
|
|
3346
|
+
}] : [],
|
|
2934
3347
|
{
|
|
2935
3348
|
value: "none",
|
|
2936
3349
|
label: "None",
|
|
@@ -3032,12 +3445,26 @@ const JAVA_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
|
3032
3445
|
label: "Quarkus",
|
|
3033
3446
|
hint: "Cloud-native Java framework optimized for fast startup and lower memory use"
|
|
3034
3447
|
},
|
|
3448
|
+
{
|
|
3449
|
+
value: "micronaut",
|
|
3450
|
+
label: "Micronaut",
|
|
3451
|
+
hint: "Modern JVM framework with compile-time DI/AOP and fast startup, low memory"
|
|
3452
|
+
},
|
|
3035
3453
|
{
|
|
3036
3454
|
value: "none",
|
|
3037
3455
|
label: "None",
|
|
3038
3456
|
hint: "No Java web framework"
|
|
3039
3457
|
}
|
|
3040
3458
|
];
|
|
3459
|
+
const JAVA_LANGUAGE_PROMPT_OPTIONS = [{
|
|
3460
|
+
value: "java",
|
|
3461
|
+
label: "Java",
|
|
3462
|
+
hint: "Classic Java sources (default)"
|
|
3463
|
+
}, {
|
|
3464
|
+
value: "kotlin",
|
|
3465
|
+
label: "Kotlin",
|
|
3466
|
+
hint: "Idiomatic Kotlin sources (Spring Boot only)"
|
|
3467
|
+
}];
|
|
3041
3468
|
const JAVA_BUILD_TOOL_PROMPT_OPTIONS = [
|
|
3042
3469
|
{
|
|
3043
3470
|
value: "maven",
|
|
@@ -3257,6 +3684,20 @@ async function getJavaWebFrameworkChoice(javaWebFramework) {
|
|
|
3257
3684
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3258
3685
|
return response;
|
|
3259
3686
|
}
|
|
3687
|
+
function resolveJavaLanguagePrompt(javaLanguage) {
|
|
3688
|
+
return createStaticSinglePromptResolution(JAVA_LANGUAGE_PROMPT_OPTIONS, "java", javaLanguage);
|
|
3689
|
+
}
|
|
3690
|
+
async function getJavaLanguageChoice(javaLanguage) {
|
|
3691
|
+
const resolution = resolveJavaLanguagePrompt(javaLanguage);
|
|
3692
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "java";
|
|
3693
|
+
const response = await navigableSelect({
|
|
3694
|
+
message: "Select JVM language",
|
|
3695
|
+
options: resolution.options,
|
|
3696
|
+
initialValue: resolution.initialValue
|
|
3697
|
+
});
|
|
3698
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3699
|
+
return response;
|
|
3700
|
+
}
|
|
3260
3701
|
function resolveJavaBuildToolPrompt(javaBuildTool) {
|
|
3261
3702
|
return createStaticSinglePromptResolution(JAVA_BUILD_TOOL_PROMPT_OPTIONS, "maven", javaBuildTool);
|
|
3262
3703
|
}
|
|
@@ -3331,24 +3772,45 @@ async function getJavaTestingLibrariesChoice(javaTestingLibraries) {
|
|
|
3331
3772
|
if (response.includes("none")) return [];
|
|
3332
3773
|
return response;
|
|
3333
3774
|
}
|
|
3334
|
-
const JAVA_API_PROMPT_OPTIONS = [
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3775
|
+
const JAVA_API_PROMPT_OPTIONS = [
|
|
3776
|
+
{
|
|
3777
|
+
value: "spring-graphql",
|
|
3778
|
+
label: "Spring for GraphQL",
|
|
3779
|
+
hint: "GraphQL schema + annotated controllers on Spring Boot"
|
|
3780
|
+
},
|
|
3781
|
+
{
|
|
3782
|
+
value: "openapi-generator",
|
|
3783
|
+
label: "OpenAPI Generator",
|
|
3784
|
+
hint: "Generate Spring API interfaces + models from an OpenAPI spec at build time"
|
|
3785
|
+
},
|
|
3786
|
+
{
|
|
3787
|
+
value: "grpc",
|
|
3788
|
+
label: "gRPC",
|
|
3789
|
+
hint: "grpc-java service (protoc codegen) started alongside Spring Boot"
|
|
3790
|
+
},
|
|
3791
|
+
{
|
|
3792
|
+
value: "none",
|
|
3793
|
+
label: "None",
|
|
3794
|
+
hint: "REST controllers only"
|
|
3795
|
+
}
|
|
3796
|
+
];
|
|
3797
|
+
const JAVA_LOGGING_PROMPT_OPTIONS = [
|
|
3798
|
+
{
|
|
3799
|
+
value: "logback",
|
|
3800
|
+
label: "Logback",
|
|
3801
|
+
hint: "Spring Boot default logger with explicit logback-spring.xml"
|
|
3802
|
+
},
|
|
3803
|
+
{
|
|
3804
|
+
value: "log4j2",
|
|
3805
|
+
label: "Log4j2",
|
|
3806
|
+
hint: "High-performance Apache logging with async loggers (Spring Boot, Micronaut, plain Java)"
|
|
3807
|
+
},
|
|
3808
|
+
{
|
|
3809
|
+
value: "none",
|
|
3810
|
+
label: "None",
|
|
3811
|
+
hint: "Spring Boot logging defaults"
|
|
3812
|
+
}
|
|
3813
|
+
];
|
|
3352
3814
|
function resolveJavaApiPrompt(javaApi) {
|
|
3353
3815
|
return createStaticSinglePromptResolution(JAVA_API_PROMPT_OPTIONS, "none", javaApi);
|
|
3354
3816
|
}
|
|
@@ -3615,6 +4077,27 @@ async function promptMobileOption(options, defaultValue, selected, message) {
|
|
|
3615
4077
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
3616
4078
|
return response;
|
|
3617
4079
|
}
|
|
4080
|
+
function resolveMobileNavigationPrompt(mobileNavigation) {
|
|
4081
|
+
return createStaticSinglePromptResolution(MOBILE_NAVIGATION_OPTIONS, "expo-router", mobileNavigation);
|
|
4082
|
+
}
|
|
4083
|
+
function resolveMobileUIPrompt(mobileUI) {
|
|
4084
|
+
return createStaticSinglePromptResolution(MOBILE_UI_OPTIONS, "none", mobileUI);
|
|
4085
|
+
}
|
|
4086
|
+
function resolveMobileStoragePrompt(mobileStorage) {
|
|
4087
|
+
return createStaticSinglePromptResolution(MOBILE_STORAGE_OPTIONS, "none", mobileStorage);
|
|
4088
|
+
}
|
|
4089
|
+
function resolveMobileTestingPrompt(mobileTesting) {
|
|
4090
|
+
return createStaticSinglePromptResolution(MOBILE_TESTING_OPTIONS, "none", mobileTesting);
|
|
4091
|
+
}
|
|
4092
|
+
function resolveMobilePushPrompt(mobilePush) {
|
|
4093
|
+
return createStaticSinglePromptResolution(MOBILE_PUSH_OPTIONS, "none", mobilePush);
|
|
4094
|
+
}
|
|
4095
|
+
function resolveMobileOTAPrompt(mobileOTA) {
|
|
4096
|
+
return createStaticSinglePromptResolution(MOBILE_OTA_OPTIONS, "none", mobileOTA);
|
|
4097
|
+
}
|
|
4098
|
+
function resolveMobileDeepLinkingPrompt(mobileDeepLinking) {
|
|
4099
|
+
return createStaticSinglePromptResolution(MOBILE_DEEP_LINKING_OPTIONS, "expo-linking", mobileDeepLinking);
|
|
4100
|
+
}
|
|
3618
4101
|
function getMobileNavigationChoice(mobileNavigation) {
|
|
3619
4102
|
return promptMobileOption(MOBILE_NAVIGATION_OPTIONS, "expo-router", mobileNavigation, "Select mobile navigation");
|
|
3620
4103
|
}
|
|
@@ -4211,6 +4694,16 @@ const RUST_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
|
4211
4694
|
label: "Rocket",
|
|
4212
4695
|
hint: "Convention-over-configuration web framework, 25k+ stars"
|
|
4213
4696
|
},
|
|
4697
|
+
{
|
|
4698
|
+
value: "poem",
|
|
4699
|
+
label: "Poem",
|
|
4700
|
+
hint: "Full-featured, fast web framework built on Tokio and hyper"
|
|
4701
|
+
},
|
|
4702
|
+
{
|
|
4703
|
+
value: "loco",
|
|
4704
|
+
label: "Loco",
|
|
4705
|
+
hint: "The Rails of Rust: opinionated full-stack framework (runs DB-free too)"
|
|
4706
|
+
},
|
|
4214
4707
|
{
|
|
4215
4708
|
value: "none",
|
|
4216
4709
|
label: "None",
|
|
@@ -5341,6 +5834,13 @@ function promptValue(value) {
|
|
|
5341
5834
|
if (isCancel$1(value) || isGoBack(value)) return exitCancelled("Operation cancelled");
|
|
5342
5835
|
return value;
|
|
5343
5836
|
}
|
|
5837
|
+
function hasMultiStackPromptFlags(flags) {
|
|
5838
|
+
return Object.keys(flags).some((key) => key !== "projectName" && key !== "projectDir" && key !== "relativePath");
|
|
5839
|
+
}
|
|
5840
|
+
async function scopedPromptValue(ecosystem, key, scope, selectedSectionIds, prompt) {
|
|
5841
|
+
if (!shouldAskConfigPromptKey(ecosystem, key, scope, selectedSectionIds)) return getDefaultPromptValue(key);
|
|
5842
|
+
return promptValue(await prompt());
|
|
5843
|
+
}
|
|
5344
5844
|
async function selectDatabaseConfig(flags) {
|
|
5345
5845
|
const database = promptValue(await getDatabaseChoice(flags.database, "hono", "bun"));
|
|
5346
5846
|
return {
|
|
@@ -5350,6 +5850,12 @@ async function selectDatabaseConfig(flags) {
|
|
|
5350
5850
|
}
|
|
5351
5851
|
async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relativePath) {
|
|
5352
5852
|
const baseConfig = getDefaultConfig();
|
|
5853
|
+
const configScope = !hasMultiStackPromptFlags(flags) ? promptValue(await getConfigScopeChoice()) : "full";
|
|
5854
|
+
const typeScriptSections = configScope === "custom" ? promptValue(await getConfigSectionsChoice("typescript", [], [
|
|
5855
|
+
"ui-styling",
|
|
5856
|
+
"deploy",
|
|
5857
|
+
"addons-examples"
|
|
5858
|
+
])) : [];
|
|
5353
5859
|
const frontend = promptValue(await navigableSelect({
|
|
5354
5860
|
message: "Select TypeScript web frontend",
|
|
5355
5861
|
options: WEB_FRONTEND_PROMPT_OPTIONS,
|
|
@@ -5357,8 +5863,8 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5357
5863
|
}));
|
|
5358
5864
|
const frontendList = [frontend];
|
|
5359
5865
|
const astroIntegration = frontend === "astro" ? promptValue(await getAstroIntegrationChoice(flags.astroIntegration)) : void 0;
|
|
5360
|
-
const uiLibrary = hasWebStyling$1(frontendList) ?
|
|
5361
|
-
const shadcnOptions = uiLibrary === "shadcn-ui" ? promptValue(await getShadcnOptions({
|
|
5866
|
+
const uiLibrary = hasWebStyling$1(frontendList) ? await scopedPromptValue("typescript", "uiLibrary", configScope, typeScriptSections, () => getUILibraryChoice(flags.uiLibrary, frontendList, astroIntegration)) : "none";
|
|
5867
|
+
const shadcnOptions = uiLibrary === "shadcn-ui" ? shouldAskConfigPromptKey("typescript", "shadcnOptions", configScope, typeScriptSections) ? promptValue(await getShadcnOptions({
|
|
5362
5868
|
shadcnBase: flags.shadcnBase,
|
|
5363
5869
|
shadcnStyle: flags.shadcnStyle,
|
|
5364
5870
|
shadcnIconLibrary: flags.shadcnIconLibrary,
|
|
@@ -5366,9 +5872,10 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5366
5872
|
shadcnBaseColor: flags.shadcnBaseColor,
|
|
5367
5873
|
shadcnFont: flags.shadcnFont,
|
|
5368
5874
|
shadcnRadius: flags.shadcnRadius
|
|
5369
|
-
})) : void 0;
|
|
5370
|
-
const cssFramework = hasWebStyling$1(frontendList) ?
|
|
5875
|
+
})) : getDefaultPromptValue("shadcnOptions") : void 0;
|
|
5876
|
+
const cssFramework = hasWebStyling$1(frontendList) ? await scopedPromptValue("typescript", "cssFramework", configScope, typeScriptSections, () => getCSSFrameworkChoice(flags.cssFramework, uiLibrary)) : "none";
|
|
5371
5877
|
const backendEcosystem = await selectBackendEcosystem();
|
|
5878
|
+
const backendSections = configScope === "custom" ? promptValue(await getConfigSectionsChoice(backendEcosystem)) : [];
|
|
5372
5879
|
const stackPartSpecs = [`frontend:typescript:${frontend}`];
|
|
5373
5880
|
const backendChoices = {};
|
|
5374
5881
|
let database = "none";
|
|
@@ -5383,14 +5890,14 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5383
5890
|
const goOrm = database === "none" || goWebFramework === "none" ? "none" : promptValue(await getGoOrmChoice(flags.goOrm));
|
|
5384
5891
|
const goApi = goWebFramework === "none" ? "none" : promptValue(await getGoApiChoice(flags.goApi));
|
|
5385
5892
|
const goAuth = goWebFramework === "none" ? "none" : promptValue(await getGoAuthChoice(flags.goAuth));
|
|
5386
|
-
const goCli = goWebFramework === "none" ? "none" :
|
|
5387
|
-
const goLogging = goWebFramework === "none" ? "none" :
|
|
5388
|
-
const goTesting = goWebFramework === "none" ? [] :
|
|
5389
|
-
const goRealtime = goWebFramework === "none" ? "none" :
|
|
5390
|
-
const goMessageQueue = goWebFramework === "none" ? "none" :
|
|
5391
|
-
const goCaching = goWebFramework === "none" ? "none" :
|
|
5392
|
-
const goConfig = goWebFramework === "none" ? "none" :
|
|
5393
|
-
const goObservability = goWebFramework === "none" ? "none" :
|
|
5893
|
+
const goCli = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goCli", configScope, backendSections, () => getGoCliChoice(flags.goCli));
|
|
5894
|
+
const goLogging = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goLogging", configScope, backendSections, () => getGoLoggingChoice(flags.goLogging));
|
|
5895
|
+
const goTesting = goWebFramework === "none" ? [] : await scopedPromptValue("go", "goTesting", configScope, backendSections, () => getGoTestingChoice(flags.goTesting));
|
|
5896
|
+
const goRealtime = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goRealtime", configScope, backendSections, () => getGoRealtimeChoice(flags.goRealtime));
|
|
5897
|
+
const goMessageQueue = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goMessageQueue", configScope, backendSections, () => getGoMessageQueueChoice(flags.goMessageQueue));
|
|
5898
|
+
const goCaching = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goCaching", configScope, backendSections, () => getGoCachingChoice(flags.goCaching));
|
|
5899
|
+
const goConfig = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goConfig", configScope, backendSections, () => getGoConfigChoice(flags.goConfig));
|
|
5900
|
+
const goObservability = goWebFramework === "none" ? "none" : await scopedPromptValue("go", "goObservability", configScope, backendSections, () => getGoObservabilityChoice(flags.goObservability));
|
|
5394
5901
|
Object.assign(backendChoices, {
|
|
5395
5902
|
goWebFramework,
|
|
5396
5903
|
goOrm,
|
|
@@ -5427,15 +5934,15 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5427
5934
|
const rustApi = rustWebFramework === "none" ? "none" : promptValue(await getRustApiChoice(flags.rustApi));
|
|
5428
5935
|
const rustAuth = rustWebFramework === "none" ? "none" : promptValue(await getRustAuthChoice(flags.rustAuth));
|
|
5429
5936
|
const rustFrontend = "none";
|
|
5430
|
-
const rustCli = rustWebFramework === "none" ? "none" :
|
|
5431
|
-
const rustLibraries = rustWebFramework === "none" ? [] :
|
|
5432
|
-
const rustLogging = rustWebFramework === "none" ? "none" :
|
|
5433
|
-
const rustErrorHandling =
|
|
5434
|
-
const rustCaching = rustWebFramework === "none" ? "none" :
|
|
5435
|
-
const rustRealtime = rustWebFramework === "none" ? "none" :
|
|
5436
|
-
const rustMessageQueue = rustWebFramework === "none" ? "none" :
|
|
5437
|
-
const rustObservability = rustWebFramework === "none" ? "none" :
|
|
5438
|
-
const rustTemplating = rustWebFramework === "none" ? "none" :
|
|
5937
|
+
const rustCli = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustCli", configScope, backendSections, () => getRustCliChoice(flags.rustCli));
|
|
5938
|
+
const rustLibraries = rustWebFramework === "none" ? [] : await scopedPromptValue("rust", "rustLibraries", configScope, backendSections, () => getRustLibrariesChoice(flags.rustLibraries));
|
|
5939
|
+
const rustLogging = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustLogging", configScope, backendSections, () => getRustLoggingChoice(flags.rustLogging));
|
|
5940
|
+
const rustErrorHandling = await scopedPromptValue("rust", "rustErrorHandling", configScope, backendSections, () => getRustErrorHandlingChoice(flags.rustErrorHandling));
|
|
5941
|
+
const rustCaching = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustCaching", configScope, backendSections, () => getRustCachingChoice(flags.rustCaching));
|
|
5942
|
+
const rustRealtime = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustRealtime", configScope, backendSections, () => getRustRealtimeChoice(flags.rustRealtime));
|
|
5943
|
+
const rustMessageQueue = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustMessageQueue", configScope, backendSections, () => getRustMessageQueueChoice(flags.rustMessageQueue));
|
|
5944
|
+
const rustObservability = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustObservability", configScope, backendSections, () => getRustObservabilityChoice(flags.rustObservability));
|
|
5945
|
+
const rustTemplating = rustWebFramework === "none" ? "none" : await scopedPromptValue("rust", "rustTemplating", configScope, backendSections, () => getRustTemplatingChoice(flags.rustTemplating));
|
|
5439
5946
|
Object.assign(backendChoices, {
|
|
5440
5947
|
rustWebFramework,
|
|
5441
5948
|
rustOrm,
|
|
@@ -5469,17 +5976,17 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5469
5976
|
dbSetup = databaseConfig.dbSetup;
|
|
5470
5977
|
}
|
|
5471
5978
|
const pythonOrm = database === "none" || pythonWebFramework === "none" ? "none" : promptValue(await getPythonOrmChoice(flags.pythonOrm));
|
|
5472
|
-
const pythonValidation = pythonWebFramework === "none" ? "none" :
|
|
5473
|
-
const pythonAi = pythonWebFramework === "none" ? [] :
|
|
5979
|
+
const pythonValidation = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonValidation", configScope, backendSections, () => getPythonValidationChoice(flags.pythonValidation));
|
|
5980
|
+
const pythonAi = pythonWebFramework === "none" ? [] : await scopedPromptValue("python", "pythonAi", configScope, backendSections, () => getPythonAiChoice(flags.pythonAi));
|
|
5474
5981
|
const pythonAuth = pythonWebFramework === "none" ? "none" : promptValue(await getPythonAuthChoice(flags.pythonAuth));
|
|
5475
|
-
const pythonTaskQueue = pythonWebFramework === "none" ? "none" :
|
|
5476
|
-
const pythonGraphql = pythonWebFramework === "none" ? "none" :
|
|
5477
|
-
const pythonQuality = pythonWebFramework === "none" ? "none" :
|
|
5478
|
-
const pythonTesting = pythonWebFramework === "none" ? [] :
|
|
5479
|
-
const pythonCaching = pythonWebFramework === "none" ? "none" :
|
|
5480
|
-
const pythonRealtime = pythonWebFramework === "none" ? "none" :
|
|
5481
|
-
const pythonObservability = pythonWebFramework === "none" ? "none" :
|
|
5482
|
-
const pythonCli = pythonWebFramework === "none" ? [] :
|
|
5982
|
+
const pythonTaskQueue = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonTaskQueue", configScope, backendSections, () => getPythonTaskQueueChoice(flags.pythonTaskQueue));
|
|
5983
|
+
const pythonGraphql = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonGraphql", configScope, backendSections, () => getPythonGraphqlChoice(flags.pythonGraphql));
|
|
5984
|
+
const pythonQuality = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonQuality", configScope, backendSections, () => getPythonQualityChoice(flags.pythonQuality));
|
|
5985
|
+
const pythonTesting = pythonWebFramework === "none" ? [] : await scopedPromptValue("python", "pythonTesting", configScope, backendSections, () => getPythonTestingChoice(flags.pythonTesting));
|
|
5986
|
+
const pythonCaching = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonCaching", configScope, backendSections, () => getPythonCachingChoice(flags.pythonCaching));
|
|
5987
|
+
const pythonRealtime = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonRealtime", configScope, backendSections, () => getPythonRealtimeChoice(flags.pythonRealtime));
|
|
5988
|
+
const pythonObservability = pythonWebFramework === "none" ? "none" : await scopedPromptValue("python", "pythonObservability", configScope, backendSections, () => getPythonObservabilityChoice(flags.pythonObservability));
|
|
5989
|
+
const pythonCli = pythonWebFramework === "none" ? [] : await scopedPromptValue("python", "pythonCli", configScope, backendSections, () => getPythonCliChoice(flags.pythonCli));
|
|
5483
5990
|
Object.assign(backendChoices, {
|
|
5484
5991
|
pythonWebFramework,
|
|
5485
5992
|
pythonOrm,
|
|
@@ -5508,6 +6015,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5508
6015
|
}
|
|
5509
6016
|
if (backendEcosystem === "java") {
|
|
5510
6017
|
const javaWebFramework = promptValue(await getJavaWebFrameworkChoice(flags.javaWebFramework));
|
|
6018
|
+
const javaLanguage = javaWebFramework !== "spring-boot" ? "java" : flags.javaLanguage !== void 0 ? promptValue(await getJavaLanguageChoice(flags.javaLanguage)) : flags.javaWebFramework !== void 0 ? "java" : promptValue(await getJavaLanguageChoice(flags.javaLanguage));
|
|
5511
6019
|
const javaBuildTool = promptValue(await getJavaBuildToolChoice(flags.javaBuildTool));
|
|
5512
6020
|
if (javaWebFramework !== "none" && javaBuildTool !== "none") {
|
|
5513
6021
|
const databaseConfig = await selectDatabaseConfig(flags);
|
|
@@ -5516,11 +6024,12 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5516
6024
|
}
|
|
5517
6025
|
const javaOrm = database === "none" || javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? "none" : promptValue(await getJavaOrmChoice(flags.javaOrm));
|
|
5518
6026
|
const javaAuth = javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? "none" : promptValue(await getJavaAuthChoice(flags.javaAuth));
|
|
5519
|
-
const javaLibraries = javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? [] :
|
|
5520
|
-
const javaTestingLibraries =
|
|
6027
|
+
const javaLibraries = javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? [] : await scopedPromptValue("java", "javaLibraries", configScope, backendSections, () => getJavaLibrariesChoice(flags.javaLibraries));
|
|
6028
|
+
const javaTestingLibraries = await scopedPromptValue("java", "javaTestingLibraries", configScope, backendSections, () => getJavaTestingLibrariesChoice(flags.javaTestingLibraries));
|
|
5521
6029
|
const javaApi = javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? "none" : promptValue(await getJavaApiChoice(flags.javaApi));
|
|
5522
|
-
const javaLogging = javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? "none" :
|
|
6030
|
+
const javaLogging = javaWebFramework !== "spring-boot" || javaBuildTool === "none" ? "none" : await scopedPromptValue("java", "javaLogging", configScope, backendSections, () => getJavaLoggingChoice(flags.javaLogging));
|
|
5523
6031
|
Object.assign(backendChoices, {
|
|
6032
|
+
javaLanguage,
|
|
5524
6033
|
javaWebFramework,
|
|
5525
6034
|
javaBuildTool,
|
|
5526
6035
|
javaOrm,
|
|
@@ -5531,6 +6040,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5531
6040
|
javaTestingLibraries
|
|
5532
6041
|
});
|
|
5533
6042
|
if (javaWebFramework !== "none") stackPartSpecs.push(`backend:java:${javaWebFramework}`);
|
|
6043
|
+
if (javaWebFramework !== "none") stackPartSpecs.push(`backend.language:java:${javaLanguage}`);
|
|
5534
6044
|
if (javaOrm !== "none") stackPartSpecs.push(`backend.orm:java:${javaOrm}`);
|
|
5535
6045
|
if (javaAuth !== "none") stackPartSpecs.push(`backend.auth:java:${javaAuth}`);
|
|
5536
6046
|
if (javaApi !== "none") stackPartSpecs.push(`backend.api:java:${javaApi}`);
|
|
@@ -5546,13 +6056,13 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5546
6056
|
const dotnetOrm = database === "none" || dotnetWebFramework === "none" ? "none" : promptValue(await getDotnetOrmChoice(flags.dotnetOrm));
|
|
5547
6057
|
const dotnetAuth = dotnetWebFramework === "none" ? "none" : promptValue(await getDotnetAuthChoice(flags.dotnetAuth));
|
|
5548
6058
|
const dotnetApi = dotnetWebFramework === "none" ? "none" : promptValue(await getDotnetApiChoice(flags.dotnetApi));
|
|
5549
|
-
const dotnetTesting = dotnetWebFramework === "none" ? [] :
|
|
5550
|
-
const dotnetJobQueue = dotnetWebFramework === "none" ? "none" :
|
|
5551
|
-
const dotnetRealtime = dotnetWebFramework === "none" ? "none" :
|
|
5552
|
-
const dotnetObservability = dotnetWebFramework === "none" ? [] :
|
|
5553
|
-
const dotnetValidation = dotnetWebFramework === "none" ? "none" :
|
|
5554
|
-
const dotnetCaching = dotnetWebFramework === "none" ? "none" :
|
|
5555
|
-
const dotnetDeploy = dotnetWebFramework === "none" ? "none" :
|
|
6059
|
+
const dotnetTesting = dotnetWebFramework === "none" ? [] : await scopedPromptValue("dotnet", "dotnetTesting", configScope, backendSections, () => getDotnetTestingChoice(flags.dotnetTesting));
|
|
6060
|
+
const dotnetJobQueue = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetJobQueue", configScope, backendSections, () => getDotnetJobQueueChoice(flags.dotnetJobQueue));
|
|
6061
|
+
const dotnetRealtime = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetRealtime", configScope, backendSections, () => getDotnetRealtimeChoice(flags.dotnetRealtime));
|
|
6062
|
+
const dotnetObservability = dotnetWebFramework === "none" ? [] : await scopedPromptValue("dotnet", "dotnetObservability", configScope, backendSections, () => getDotnetObservabilityChoice(flags.dotnetObservability));
|
|
6063
|
+
const dotnetValidation = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetValidation", configScope, backendSections, () => getDotnetValidationChoice(flags.dotnetValidation));
|
|
6064
|
+
const dotnetCaching = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetCaching", configScope, backendSections, () => getDotnetCachingChoice(flags.dotnetCaching));
|
|
6065
|
+
const dotnetDeploy = dotnetWebFramework === "none" ? "none" : await scopedPromptValue("dotnet", "dotnetDeploy", configScope, backendSections, () => getDotnetDeployChoice(flags.dotnetDeploy));
|
|
5556
6066
|
Object.assign(backendChoices, {
|
|
5557
6067
|
dotnetWebFramework,
|
|
5558
6068
|
dotnetOrm,
|
|
@@ -5588,18 +6098,18 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5588
6098
|
const elixirOrm = database === "none" || elixirWebFramework === "none" ? "none" : promptValue(await getElixirOrmChoice(flags.elixirOrm));
|
|
5589
6099
|
const elixirAuth = elixirWebFramework === "none" ? "none" : promptValue(await getElixirAuthChoice(flags.elixirAuth));
|
|
5590
6100
|
const elixirApi = elixirWebFramework === "none" ? "none" : promptValue(await getElixirApiChoice(flags.elixirApi));
|
|
5591
|
-
const elixirRealtime = elixirWebFramework === "none" ? "none" :
|
|
5592
|
-
const elixirJobs = elixirWebFramework === "none" ? "none" :
|
|
5593
|
-
const elixirValidation = elixirWebFramework === "none" ? "none" :
|
|
5594
|
-
const elixirHttp = elixirWebFramework === "none" ? "none" :
|
|
5595
|
-
const elixirJson = elixirWebFramework === "none" ? "none" :
|
|
5596
|
-
const elixirEmail = elixirWebFramework === "none" ? "none" :
|
|
5597
|
-
const elixirCaching = elixirWebFramework === "none" ? "none" :
|
|
5598
|
-
const elixirObservability = elixirWebFramework === "none" ? "none" :
|
|
5599
|
-
const elixirTesting = elixirWebFramework === "none" ? "none" :
|
|
5600
|
-
const elixirQuality = elixirWebFramework === "none" ? "none" :
|
|
5601
|
-
const elixirDeploy = elixirWebFramework === "none" ? "none" :
|
|
5602
|
-
const elixirLibraries = elixirWebFramework === "none" ? [] :
|
|
6101
|
+
const elixirRealtime = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirRealtime", configScope, backendSections, () => getElixirRealtimeChoice(flags.elixirRealtime));
|
|
6102
|
+
const elixirJobs = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirJobs", configScope, backendSections, () => getElixirJobsChoice(flags.elixirJobs));
|
|
6103
|
+
const elixirValidation = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirValidation", configScope, backendSections, () => getElixirValidationChoice(flags.elixirValidation));
|
|
6104
|
+
const elixirHttp = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirHttp", configScope, backendSections, () => getElixirHttpChoice(flags.elixirHttp));
|
|
6105
|
+
const elixirJson = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirJson", configScope, backendSections, () => getElixirJsonChoice(flags.elixirJson));
|
|
6106
|
+
const elixirEmail = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirEmail", configScope, backendSections, () => getElixirEmailChoice(flags.elixirEmail));
|
|
6107
|
+
const elixirCaching = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirCaching", configScope, backendSections, () => getElixirCachingChoice(flags.elixirCaching));
|
|
6108
|
+
const elixirObservability = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirObservability", configScope, backendSections, () => getElixirObservabilityChoice(flags.elixirObservability));
|
|
6109
|
+
const elixirTesting = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirTesting", configScope, backendSections, () => getElixirTestingChoice(flags.elixirTesting));
|
|
6110
|
+
const elixirQuality = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirQuality", configScope, backendSections, () => getElixirQualityChoice(flags.elixirQuality));
|
|
6111
|
+
const elixirDeploy = elixirWebFramework === "none" ? "none" : await scopedPromptValue("elixir", "elixirDeploy", configScope, backendSections, () => getElixirDeployChoice(flags.elixirDeploy));
|
|
6112
|
+
const elixirLibraries = elixirWebFramework === "none" ? [] : await scopedPromptValue("elixir", "elixirLibraries", configScope, backendSections, () => getElixirLibrariesChoice(flags.elixirLibraries));
|
|
5603
6113
|
Object.assign(backendChoices, {
|
|
5604
6114
|
elixirWebFramework,
|
|
5605
6115
|
elixirOrm,
|
|
@@ -5634,9 +6144,9 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5634
6144
|
if (database !== "none") stackPartSpecs.push(`database:universal:${database}`);
|
|
5635
6145
|
const stackParts = (0, types_exports.parseStackPartSpecs)(stackPartSpecs, "selected");
|
|
5636
6146
|
const graphPartial = (0, types_exports.stackPartsToLegacyProjectConfigPartial)(stackParts);
|
|
5637
|
-
const addons =
|
|
5638
|
-
const webDeploy =
|
|
5639
|
-
const serverDeploy = await selectServerDeployment(flags.serverDeploy);
|
|
6147
|
+
const addons = await scopedPromptValue("typescript", "addons", configScope, typeScriptSections, () => getAddonsChoice(flags.addons, frontendList, "none", "none", "bun"));
|
|
6148
|
+
const webDeploy = await scopedPromptValue("typescript", "webDeploy", configScope, typeScriptSections, () => getDeploymentChoice(flags.webDeploy, "bun", "none", frontendList));
|
|
6149
|
+
const serverDeploy = shouldAskConfigPromptKey("typescript", "serverDeploy", configScope, typeScriptSections) ? await selectServerDeployment(flags.serverDeploy) : getDefaultPromptValue("serverDeploy");
|
|
5640
6150
|
const aiDocs = promptValue(await getAiDocsChoice(flags.aiDocs));
|
|
5641
6151
|
const git = promptValue(await getGitChoice(flags.git));
|
|
5642
6152
|
const packageManager = promptValue(await getPackageManagerChoice(flags.packageManager));
|
|
@@ -5904,21 +6414,74 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
|
|
|
5904
6414
|
}
|
|
5905
6415
|
|
|
5906
6416
|
//#endregion
|
|
5907
|
-
//#region src/prompts/
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
6417
|
+
//#region src/prompts/workspace-shape.ts
|
|
6418
|
+
const SINGLE_APP_WEB_FRONTENDS = new Set(["next", "tanstack-start"]);
|
|
6419
|
+
/**
|
|
6420
|
+
* The flat single-app layout only makes sense for a "thin self" app: backend
|
|
6421
|
+
* `self` with exactly one Next.js or TanStack Start web frontend. For anything
|
|
6422
|
+
* else we never prompt and resolve to `monorepo` (the compatibility engine and
|
|
6423
|
+
* generator also normalize non-qualifying stacks back to monorepo).
|
|
6424
|
+
*/
|
|
6425
|
+
function stackCanUseSingleApp(backend, frontend) {
|
|
6426
|
+
if (backend !== "self") return false;
|
|
6427
|
+
const webFrontends = frontend.filter((f) => f && f !== "none");
|
|
6428
|
+
if (webFrontends.length !== 1) return false;
|
|
6429
|
+
return SINGLE_APP_WEB_FRONTENDS.has(webFrontends[0]);
|
|
6430
|
+
}
|
|
6431
|
+
async function getWorkspaceShapeChoice(workspaceShape, backend, frontend) {
|
|
6432
|
+
if (!stackCanUseSingleApp(backend, frontend ?? [])) return "monorepo";
|
|
6433
|
+
if (workspaceShape !== void 0) return workspaceShape;
|
|
6434
|
+
if (!canPromptInteractively()) return "monorepo";
|
|
6435
|
+
const response = await navigableSelect({
|
|
6436
|
+
message: "Choose workspace layout",
|
|
6437
|
+
options: [{
|
|
6438
|
+
value: "monorepo",
|
|
6439
|
+
label: "Monorepo",
|
|
6440
|
+
hint: "apps/* + packages/* workspaces (recommended)"
|
|
6441
|
+
}, {
|
|
6442
|
+
value: "single-app",
|
|
6443
|
+
label: "Single app",
|
|
6444
|
+
hint: "Flat app at the repo root (no workspaces)"
|
|
6445
|
+
}],
|
|
6446
|
+
initialValue: "monorepo"
|
|
6447
|
+
});
|
|
6448
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
6449
|
+
return response;
|
|
6450
|
+
}
|
|
6451
|
+
|
|
6452
|
+
//#endregion
|
|
6453
|
+
//#region src/prompts/payments.ts
|
|
6454
|
+
function resolvePaymentsPrompt(context = {}) {
|
|
6455
|
+
if (context.payments !== void 0) return {
|
|
5916
6456
|
shouldPrompt: false,
|
|
5917
6457
|
mode: "single",
|
|
5918
6458
|
options: [],
|
|
5919
|
-
autoValue:
|
|
6459
|
+
autoValue: context.payments
|
|
5920
6460
|
};
|
|
5921
6461
|
const isPolarCompatible = (context.auth === "better-auth" || context.auth === "better-auth-organizations") && (context.frontends?.length === 0 || splitFrontends$1(context.frontends).web.length > 0);
|
|
6462
|
+
const isRevenueCatCompatible = (context.frontends ?? []).some((frontend) => frontend === "native-bare" || frontend === "native-uniwind" || frontend === "native-unistyles");
|
|
6463
|
+
if (context.backend === "none") {
|
|
6464
|
+
if (isRevenueCatCompatible) return {
|
|
6465
|
+
shouldPrompt: true,
|
|
6466
|
+
mode: "single",
|
|
6467
|
+
options: [{
|
|
6468
|
+
value: "revenuecat",
|
|
6469
|
+
label: "RevenueCat",
|
|
6470
|
+
hint: "In-app subscriptions and cross-platform monetization for mobile."
|
|
6471
|
+
}, {
|
|
6472
|
+
value: "none",
|
|
6473
|
+
label: "None",
|
|
6474
|
+
hint: "No payments integration"
|
|
6475
|
+
}],
|
|
6476
|
+
initialValue: DEFAULT_CONFIG.payments
|
|
6477
|
+
};
|
|
6478
|
+
return {
|
|
6479
|
+
shouldPrompt: false,
|
|
6480
|
+
mode: "single",
|
|
6481
|
+
options: [],
|
|
6482
|
+
autoValue: "none"
|
|
6483
|
+
};
|
|
6484
|
+
}
|
|
5922
6485
|
const options = [];
|
|
5923
6486
|
if (isPolarCompatible) options.push({
|
|
5924
6487
|
value: "polar",
|
|
@@ -5941,11 +6504,28 @@ function resolvePaymentsPrompt(context = {}) {
|
|
|
5941
6504
|
value: "dodo",
|
|
5942
6505
|
label: "Dodo Payments",
|
|
5943
6506
|
hint: "Simple payment infrastructure for developers."
|
|
6507
|
+
}, {
|
|
6508
|
+
value: "creem",
|
|
6509
|
+
label: "Creem",
|
|
6510
|
+
hint: "Cheapest merchant-of-record payments & billing, with a Better Auth plugin."
|
|
6511
|
+
}, {
|
|
6512
|
+
value: "autumn",
|
|
6513
|
+
label: "Autumn",
|
|
6514
|
+
hint: "Usage-based pricing & billing for SaaS and AI apps."
|
|
6515
|
+
}, {
|
|
6516
|
+
value: "commet",
|
|
6517
|
+
label: "Commet",
|
|
6518
|
+
hint: "All-in-one plan-first billing for SaaS and AI products."
|
|
5944
6519
|
}, {
|
|
5945
6520
|
value: "none",
|
|
5946
6521
|
label: "None",
|
|
5947
6522
|
hint: "No payments integration"
|
|
5948
6523
|
});
|
|
6524
|
+
if (isRevenueCatCompatible) options.push({
|
|
6525
|
+
value: "revenuecat",
|
|
6526
|
+
label: "RevenueCat",
|
|
6527
|
+
hint: "In-app subscriptions and cross-platform monetization for mobile."
|
|
6528
|
+
});
|
|
5949
6529
|
return {
|
|
5950
6530
|
shouldPrompt: true,
|
|
5951
6531
|
mode: "single",
|
|
@@ -6150,164 +6730,6 @@ async function getRuntimeChoice(runtime, backend) {
|
|
|
6150
6730
|
return response;
|
|
6151
6731
|
}
|
|
6152
6732
|
|
|
6153
|
-
//#endregion
|
|
6154
|
-
//#region src/prompts/search.ts
|
|
6155
|
-
const SEARCH_PROMPT_OPTIONS = [
|
|
6156
|
-
{
|
|
6157
|
-
value: "meilisearch",
|
|
6158
|
-
label: "Meilisearch",
|
|
6159
|
-
hint: "Lightning-fast search engine with typo tolerance"
|
|
6160
|
-
},
|
|
6161
|
-
{
|
|
6162
|
-
value: "typesense",
|
|
6163
|
-
label: "Typesense",
|
|
6164
|
-
hint: "Fast, typo-tolerant search with built-in vector search"
|
|
6165
|
-
},
|
|
6166
|
-
{
|
|
6167
|
-
value: "elasticsearch",
|
|
6168
|
-
label: "Elasticsearch",
|
|
6169
|
-
hint: "Distributed search and analytics engine with local and cloud deployments"
|
|
6170
|
-
},
|
|
6171
|
-
{
|
|
6172
|
-
value: "opensearch",
|
|
6173
|
-
label: "OpenSearch",
|
|
6174
|
-
hint: "Open-source search and analytics suite compatible with Elasticsearch APIs"
|
|
6175
|
-
},
|
|
6176
|
-
{
|
|
6177
|
-
value: "algolia",
|
|
6178
|
-
label: "Algolia",
|
|
6179
|
-
hint: "Hosted search API with instant results, typo tolerance, and analytics"
|
|
6180
|
-
},
|
|
6181
|
-
{
|
|
6182
|
-
value: "none",
|
|
6183
|
-
label: "None",
|
|
6184
|
-
hint: "Skip search engine setup"
|
|
6185
|
-
}
|
|
6186
|
-
];
|
|
6187
|
-
const NON_TYPESCRIPT_SEARCH_PROMPT_OPTIONS = SEARCH_PROMPT_OPTIONS.filter((option) => option.value === "meilisearch" || option.value === "none");
|
|
6188
|
-
function resolveSearchPrompt(context = {}) {
|
|
6189
|
-
if (context.ecosystem === "react-native" || context.ecosystem === "elixir") return {
|
|
6190
|
-
shouldPrompt: false,
|
|
6191
|
-
mode: "single",
|
|
6192
|
-
options: [],
|
|
6193
|
-
autoValue: "none"
|
|
6194
|
-
};
|
|
6195
|
-
const options = context.ecosystem && context.ecosystem !== "typescript" ? NON_TYPESCRIPT_SEARCH_PROMPT_OPTIONS : SEARCH_PROMPT_OPTIONS;
|
|
6196
|
-
if ((!context.ecosystem || context.ecosystem === "typescript") && (context.backend === "none" || context.backend === "convex")) return {
|
|
6197
|
-
shouldPrompt: false,
|
|
6198
|
-
mode: "single",
|
|
6199
|
-
options: [],
|
|
6200
|
-
autoValue: "none"
|
|
6201
|
-
};
|
|
6202
|
-
return context.search !== void 0 ? {
|
|
6203
|
-
shouldPrompt: false,
|
|
6204
|
-
mode: "single",
|
|
6205
|
-
options,
|
|
6206
|
-
autoValue: context.search
|
|
6207
|
-
} : {
|
|
6208
|
-
shouldPrompt: true,
|
|
6209
|
-
mode: "single",
|
|
6210
|
-
options,
|
|
6211
|
-
initialValue: "none"
|
|
6212
|
-
};
|
|
6213
|
-
}
|
|
6214
|
-
async function getSearchChoice(search, backend, ecosystem) {
|
|
6215
|
-
const resolution = resolveSearchPrompt({
|
|
6216
|
-
search,
|
|
6217
|
-
backend,
|
|
6218
|
-
ecosystem
|
|
6219
|
-
});
|
|
6220
|
-
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
6221
|
-
const response = await navigableSelect({
|
|
6222
|
-
message: "Select search engine",
|
|
6223
|
-
options: resolution.options,
|
|
6224
|
-
initialValue: resolution.initialValue
|
|
6225
|
-
});
|
|
6226
|
-
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
6227
|
-
return response;
|
|
6228
|
-
}
|
|
6229
|
-
|
|
6230
|
-
//#endregion
|
|
6231
|
-
//#region src/prompts/vector-db.ts
|
|
6232
|
-
const VECTOR_DB_PROMPT_OPTIONS = [
|
|
6233
|
-
{
|
|
6234
|
-
value: "pgvector",
|
|
6235
|
-
label: "pgvector",
|
|
6236
|
-
hint: "Self-hosted Postgres + pgvector extension for embeddings"
|
|
6237
|
-
},
|
|
6238
|
-
{
|
|
6239
|
-
value: "qdrant",
|
|
6240
|
-
label: "Qdrant",
|
|
6241
|
-
hint: "High-performance open-source vector database"
|
|
6242
|
-
},
|
|
6243
|
-
{
|
|
6244
|
-
value: "chroma",
|
|
6245
|
-
label: "Chroma",
|
|
6246
|
-
hint: "Lightweight open-source embedding database"
|
|
6247
|
-
},
|
|
6248
|
-
{
|
|
6249
|
-
value: "pinecone",
|
|
6250
|
-
label: "Pinecone",
|
|
6251
|
-
hint: "Fully managed serverless vector database"
|
|
6252
|
-
},
|
|
6253
|
-
{
|
|
6254
|
-
value: "none",
|
|
6255
|
-
label: "None",
|
|
6256
|
-
hint: "Skip vector database setup"
|
|
6257
|
-
}
|
|
6258
|
-
];
|
|
6259
|
-
/**
|
|
6260
|
-
* Vector DB is a TypeScript-ecosystem feature backed by a standalone server.
|
|
6261
|
-
* Every provider (including pgvector via a dedicated Postgres instance) is a
|
|
6262
|
-
* separate service, so there is no dependency on the primary database choice.
|
|
6263
|
-
*/
|
|
6264
|
-
function resolveVectorDbPrompt(context = {}) {
|
|
6265
|
-
const skip = () => ({
|
|
6266
|
-
shouldPrompt: false,
|
|
6267
|
-
mode: "single",
|
|
6268
|
-
options: [],
|
|
6269
|
-
autoValue: "none"
|
|
6270
|
-
});
|
|
6271
|
-
if (context.ecosystem && context.ecosystem !== "typescript") return skip();
|
|
6272
|
-
if (context.backend === "none" || context.backend === "convex") return skip();
|
|
6273
|
-
return context.vectorDb !== void 0 ? {
|
|
6274
|
-
shouldPrompt: false,
|
|
6275
|
-
mode: "single",
|
|
6276
|
-
options: VECTOR_DB_PROMPT_OPTIONS,
|
|
6277
|
-
autoValue: context.vectorDb
|
|
6278
|
-
} : {
|
|
6279
|
-
shouldPrompt: true,
|
|
6280
|
-
mode: "single",
|
|
6281
|
-
options: VECTOR_DB_PROMPT_OPTIONS,
|
|
6282
|
-
initialValue: "none"
|
|
6283
|
-
};
|
|
6284
|
-
}
|
|
6285
|
-
async function getVectorDbChoice(vectorDb, backend, ecosystem) {
|
|
6286
|
-
const resolution = resolveVectorDbPrompt({
|
|
6287
|
-
vectorDb,
|
|
6288
|
-
backend,
|
|
6289
|
-
ecosystem
|
|
6290
|
-
});
|
|
6291
|
-
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
6292
|
-
const response = await navigableSelect({
|
|
6293
|
-
message: "Select vector database",
|
|
6294
|
-
options: resolution.options,
|
|
6295
|
-
initialValue: resolution.initialValue
|
|
6296
|
-
});
|
|
6297
|
-
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
6298
|
-
return response;
|
|
6299
|
-
}
|
|
6300
|
-
|
|
6301
|
-
//#endregion
|
|
6302
|
-
//#region src/prompts/server-deploy.ts
|
|
6303
|
-
async function getServerDeploymentChoice(deployment, runtime, backend, _webDeploy) {
|
|
6304
|
-
if (deployment !== void 0) return deployment;
|
|
6305
|
-
if (backend === "none" || backend === "convex") return "none";
|
|
6306
|
-
if (backend !== "hono") return "none";
|
|
6307
|
-
if (runtime === "workers") return "cloudflare";
|
|
6308
|
-
return "none";
|
|
6309
|
-
}
|
|
6310
|
-
|
|
6311
6733
|
//#endregion
|
|
6312
6734
|
//#region src/prompts/state-management.ts
|
|
6313
6735
|
function resolveStateManagementPrompt(context = {}) {
|
|
@@ -6508,14 +6930,1043 @@ async function getValidationChoice(validation) {
|
|
|
6508
6930
|
return response;
|
|
6509
6931
|
}
|
|
6510
6932
|
|
|
6933
|
+
//#endregion
|
|
6934
|
+
//#region src/prompts/prompt-resolver-registry.ts
|
|
6935
|
+
const PROMPT_RESOLVER_REGISTRY = {
|
|
6936
|
+
frontend: {
|
|
6937
|
+
schemaValues: types_exports.FRONTEND_VALUES,
|
|
6938
|
+
resolve: resolveFrontendPrompt,
|
|
6939
|
+
coverageContexts: [{ backend: "hono" }, { frontendOptions: ["none"] }]
|
|
6940
|
+
},
|
|
6941
|
+
backend: {
|
|
6942
|
+
schemaValues: types_exports.BACKEND_VALUES,
|
|
6943
|
+
resolve: resolveBackendPrompt,
|
|
6944
|
+
coverageContexts: [{ frontends: ["next"] }]
|
|
6945
|
+
},
|
|
6946
|
+
ai: {
|
|
6947
|
+
schemaValues: types_exports.AI_VALUES,
|
|
6948
|
+
resolve: ({ value } = {}) => resolveAIPrompt(value),
|
|
6949
|
+
coverageContexts: [{}]
|
|
6950
|
+
},
|
|
6951
|
+
animation: {
|
|
6952
|
+
schemaValues: types_exports.ANIMATION_VALUES,
|
|
6953
|
+
resolve: resolveAnimationPrompt,
|
|
6954
|
+
coverageContexts: [{ frontends: ["react-vite"] }]
|
|
6955
|
+
},
|
|
6956
|
+
api: {
|
|
6957
|
+
schemaValues: types_exports.API_VALUES,
|
|
6958
|
+
resolve: resolveApiPrompt,
|
|
6959
|
+
coverageContexts: [{
|
|
6960
|
+
frontend: ["next"],
|
|
6961
|
+
backend: "hono"
|
|
6962
|
+
}, { backend: "convex" }]
|
|
6963
|
+
},
|
|
6964
|
+
auth: {
|
|
6965
|
+
schemaValues: types_exports.AUTH_VALUES,
|
|
6966
|
+
resolve: resolveAuthPrompt,
|
|
6967
|
+
coverageContexts: [{
|
|
6968
|
+
ecosystem: "typescript",
|
|
6969
|
+
backend: "self",
|
|
6970
|
+
frontend: ["next"]
|
|
6971
|
+
}, {
|
|
6972
|
+
ecosystem: "go",
|
|
6973
|
+
backend: "none",
|
|
6974
|
+
frontend: []
|
|
6975
|
+
}]
|
|
6976
|
+
},
|
|
6977
|
+
caching: {
|
|
6978
|
+
schemaValues: types_exports.CACHING_VALUES,
|
|
6979
|
+
resolve: resolveCachingPrompt,
|
|
6980
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
6981
|
+
},
|
|
6982
|
+
rateLimit: {
|
|
6983
|
+
schemaValues: types_exports.RATE_LIMIT_VALUES,
|
|
6984
|
+
resolve: resolveRateLimitPrompt,
|
|
6985
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
6986
|
+
},
|
|
6987
|
+
cms: {
|
|
6988
|
+
schemaValues: types_exports.CMS_VALUES,
|
|
6989
|
+
resolve: resolveCMSPrompt,
|
|
6990
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
6991
|
+
},
|
|
6992
|
+
cssFramework: {
|
|
6993
|
+
schemaValues: types_exports.CSS_FRAMEWORK_VALUES,
|
|
6994
|
+
resolve: resolveCSSFrameworkPrompt,
|
|
6995
|
+
coverageContexts: [{}, { uiLibrary: "radix-ui" }]
|
|
6996
|
+
},
|
|
6997
|
+
database: {
|
|
6998
|
+
schemaValues: types_exports.DATABASE_VALUES,
|
|
6999
|
+
resolve: resolveDatabasePrompt,
|
|
7000
|
+
coverageContexts: [{
|
|
7001
|
+
backend: "hono",
|
|
7002
|
+
runtime: "node"
|
|
7003
|
+
}, { backend: "none" }]
|
|
7004
|
+
},
|
|
7005
|
+
dbSetup: {
|
|
7006
|
+
schemaValues: types_exports.DATABASE_SETUP_VALUES,
|
|
7007
|
+
resolve: resolveDBSetupPrompt,
|
|
7008
|
+
coverageContexts: [
|
|
7009
|
+
{
|
|
7010
|
+
databaseType: "sqlite",
|
|
7011
|
+
runtime: "workers"
|
|
7012
|
+
},
|
|
7013
|
+
{ databaseType: "postgres" },
|
|
7014
|
+
{ databaseType: "mongodb" },
|
|
7015
|
+
{ databaseType: "redis" }
|
|
7016
|
+
]
|
|
7017
|
+
},
|
|
7018
|
+
email: {
|
|
7019
|
+
schemaValues: types_exports.EMAIL_VALUES,
|
|
7020
|
+
resolve: resolveEmailPrompt,
|
|
7021
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
7022
|
+
},
|
|
7023
|
+
fileUpload: {
|
|
7024
|
+
schemaValues: types_exports.FILE_UPLOAD_VALUES,
|
|
7025
|
+
resolve: resolveFileUploadPrompt,
|
|
7026
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
7027
|
+
},
|
|
7028
|
+
forms: {
|
|
7029
|
+
schemaValues: types_exports.FORMS_VALUES,
|
|
7030
|
+
resolve: resolveFormsPrompt,
|
|
7031
|
+
coverageContexts: [{ frontends: ["react-vite"] }, { frontends: ["solid"] }]
|
|
7032
|
+
},
|
|
7033
|
+
jobQueue: {
|
|
7034
|
+
schemaValues: types_exports.JOB_QUEUE_VALUES,
|
|
7035
|
+
resolve: resolveJobQueuePrompt,
|
|
7036
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
7037
|
+
},
|
|
7038
|
+
logging: {
|
|
7039
|
+
schemaValues: types_exports.LOGGING_VALUES,
|
|
7040
|
+
resolve: resolveLoggingPrompt,
|
|
7041
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
7042
|
+
},
|
|
7043
|
+
observability: {
|
|
7044
|
+
schemaValues: types_exports.OBSERVABILITY_VALUES,
|
|
7045
|
+
resolve: resolveObservabilityPrompt,
|
|
7046
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
7047
|
+
},
|
|
7048
|
+
orm: {
|
|
7049
|
+
schemaValues: types_exports.ORM_VALUES,
|
|
7050
|
+
resolve: resolveORMPrompt,
|
|
7051
|
+
coverageContexts: [
|
|
7052
|
+
{
|
|
7053
|
+
hasDatabase: true,
|
|
7054
|
+
database: "postgres",
|
|
7055
|
+
runtime: "node"
|
|
7056
|
+
},
|
|
7057
|
+
{
|
|
7058
|
+
hasDatabase: true,
|
|
7059
|
+
database: "mongodb"
|
|
7060
|
+
},
|
|
7061
|
+
{ hasDatabase: false }
|
|
7062
|
+
]
|
|
7063
|
+
},
|
|
7064
|
+
payments: {
|
|
7065
|
+
schemaValues: types_exports.PAYMENTS_VALUES,
|
|
7066
|
+
resolve: resolvePaymentsPrompt,
|
|
7067
|
+
coverageContexts: [{
|
|
7068
|
+
auth: "better-auth",
|
|
7069
|
+
backend: "hono",
|
|
7070
|
+
frontends: ["next"]
|
|
7071
|
+
}, {
|
|
7072
|
+
auth: "better-auth",
|
|
7073
|
+
backend: "hono",
|
|
7074
|
+
frontends: ["native-bare"]
|
|
7075
|
+
}]
|
|
7076
|
+
},
|
|
7077
|
+
realtime: {
|
|
7078
|
+
schemaValues: types_exports.REALTIME_VALUES,
|
|
7079
|
+
resolve: resolveRealtimePrompt,
|
|
7080
|
+
coverageContexts: [{ backend: "hono" }, { backend: "none" }]
|
|
7081
|
+
},
|
|
7082
|
+
runtime: {
|
|
7083
|
+
schemaValues: types_exports.RUNTIME_VALUES,
|
|
7084
|
+
resolve: resolveRuntimePrompt,
|
|
7085
|
+
coverageContexts: [{ backend: "hono" }, { backend: "self" }]
|
|
7086
|
+
},
|
|
7087
|
+
stateManagement: {
|
|
7088
|
+
schemaValues: types_exports.STATE_MANAGEMENT_VALUES,
|
|
7089
|
+
resolve: resolveStateManagementPrompt,
|
|
7090
|
+
coverageContexts: [{ frontends: ["react-vite"] }]
|
|
7091
|
+
},
|
|
7092
|
+
testing: {
|
|
7093
|
+
schemaValues: types_exports.TESTING_VALUES,
|
|
7094
|
+
resolve: ({ value } = {}) => resolveTestingPrompt(value),
|
|
7095
|
+
coverageContexts: [{}]
|
|
7096
|
+
},
|
|
7097
|
+
mobileNavigation: {
|
|
7098
|
+
schemaValues: types_exports.MOBILE_NAVIGATION_VALUES,
|
|
7099
|
+
resolve: ({ value } = {}) => resolveMobileNavigationPrompt(value),
|
|
7100
|
+
coverageContexts: [{}]
|
|
7101
|
+
},
|
|
7102
|
+
mobileUI: {
|
|
7103
|
+
schemaValues: types_exports.MOBILE_UI_VALUES,
|
|
7104
|
+
resolve: ({ value } = {}) => resolveMobileUIPrompt(value),
|
|
7105
|
+
coverageContexts: [{}]
|
|
7106
|
+
},
|
|
7107
|
+
mobileStorage: {
|
|
7108
|
+
schemaValues: types_exports.MOBILE_STORAGE_VALUES,
|
|
7109
|
+
resolve: ({ value } = {}) => resolveMobileStoragePrompt(value),
|
|
7110
|
+
coverageContexts: [{}]
|
|
7111
|
+
},
|
|
7112
|
+
mobileTesting: {
|
|
7113
|
+
schemaValues: types_exports.MOBILE_TESTING_VALUES,
|
|
7114
|
+
resolve: ({ value } = {}) => resolveMobileTestingPrompt(value),
|
|
7115
|
+
coverageContexts: [{}]
|
|
7116
|
+
},
|
|
7117
|
+
mobilePush: {
|
|
7118
|
+
schemaValues: types_exports.MOBILE_PUSH_VALUES,
|
|
7119
|
+
resolve: ({ value } = {}) => resolveMobilePushPrompt(value),
|
|
7120
|
+
coverageContexts: [{}]
|
|
7121
|
+
},
|
|
7122
|
+
mobileOTA: {
|
|
7123
|
+
schemaValues: types_exports.MOBILE_OTA_VALUES,
|
|
7124
|
+
resolve: ({ value } = {}) => resolveMobileOTAPrompt(value),
|
|
7125
|
+
coverageContexts: [{}]
|
|
7126
|
+
},
|
|
7127
|
+
mobileDeepLinking: {
|
|
7128
|
+
schemaValues: types_exports.MOBILE_DEEP_LINKING_VALUES,
|
|
7129
|
+
resolve: ({ value } = {}) => resolveMobileDeepLinkingPrompt(value),
|
|
7130
|
+
coverageContexts: [{}]
|
|
7131
|
+
},
|
|
7132
|
+
uiLibrary: {
|
|
7133
|
+
schemaValues: types_exports.UI_LIBRARY_VALUES,
|
|
7134
|
+
resolve: resolveUILibraryPrompt,
|
|
7135
|
+
coverageContexts: [
|
|
7136
|
+
{ frontends: ["react-vite"] },
|
|
7137
|
+
{ frontends: ["svelte"] },
|
|
7138
|
+
{ frontends: ["solid"] },
|
|
7139
|
+
{ frontends: ["vue"] }
|
|
7140
|
+
]
|
|
7141
|
+
},
|
|
7142
|
+
validation: {
|
|
7143
|
+
schemaValues: types_exports.VALIDATION_VALUES,
|
|
7144
|
+
resolve: ({ value } = {}) => resolveValidationPrompt(value),
|
|
7145
|
+
coverageContexts: [{}]
|
|
7146
|
+
},
|
|
7147
|
+
astroIntegration: {
|
|
7148
|
+
schemaValues: types_exports.ASTRO_INTEGRATION_VALUES,
|
|
7149
|
+
resolve: ({ value } = {}) => resolveAstroIntegrationPrompt(value),
|
|
7150
|
+
coverageContexts: [{}]
|
|
7151
|
+
},
|
|
7152
|
+
rustWebFramework: {
|
|
7153
|
+
schemaValues: types_exports.RUST_WEB_FRAMEWORK_VALUES,
|
|
7154
|
+
resolve: ({ value } = {}) => resolveRustWebFrameworkPrompt(value),
|
|
7155
|
+
coverageContexts: [{}]
|
|
7156
|
+
},
|
|
7157
|
+
rustFrontend: {
|
|
7158
|
+
schemaValues: types_exports.RUST_FRONTEND_VALUES,
|
|
7159
|
+
resolve: ({ value } = {}) => resolveRustFrontendPrompt(value),
|
|
7160
|
+
coverageContexts: [{}]
|
|
7161
|
+
},
|
|
7162
|
+
rustOrm: {
|
|
7163
|
+
schemaValues: types_exports.RUST_ORM_VALUES,
|
|
7164
|
+
resolve: ({ value } = {}) => resolveRustOrmPrompt(value),
|
|
7165
|
+
coverageContexts: [{}]
|
|
7166
|
+
},
|
|
7167
|
+
rustApi: {
|
|
7168
|
+
schemaValues: types_exports.RUST_API_VALUES,
|
|
7169
|
+
resolve: ({ value } = {}) => resolveRustApiPrompt(value),
|
|
7170
|
+
coverageContexts: [{}]
|
|
7171
|
+
},
|
|
7172
|
+
rustCli: {
|
|
7173
|
+
schemaValues: types_exports.RUST_CLI_VALUES,
|
|
7174
|
+
resolve: ({ value } = {}) => resolveRustCliPrompt(value),
|
|
7175
|
+
coverageContexts: [{}]
|
|
7176
|
+
},
|
|
7177
|
+
rustLogging: {
|
|
7178
|
+
schemaValues: types_exports.RUST_LOGGING_VALUES,
|
|
7179
|
+
resolve: ({ value } = {}) => resolveRustLoggingPrompt(value),
|
|
7180
|
+
coverageContexts: [{}]
|
|
7181
|
+
},
|
|
7182
|
+
rustErrorHandling: {
|
|
7183
|
+
schemaValues: types_exports.RUST_ERROR_HANDLING_VALUES,
|
|
7184
|
+
resolve: ({ value } = {}) => resolveRustErrorHandlingPrompt(value),
|
|
7185
|
+
coverageContexts: [{}]
|
|
7186
|
+
},
|
|
7187
|
+
rustLibraries: {
|
|
7188
|
+
schemaValues: types_exports.RUST_LIBRARIES_VALUES,
|
|
7189
|
+
resolve: ({ value } = {}) => resolveRustLibrariesPrompt(value),
|
|
7190
|
+
coverageContexts: [{}, { value: ["none"] }]
|
|
7191
|
+
},
|
|
7192
|
+
rustCaching: {
|
|
7193
|
+
schemaValues: types_exports.RUST_CACHING_VALUES,
|
|
7194
|
+
resolve: ({ value } = {}) => resolveRustCachingPrompt(value),
|
|
7195
|
+
coverageContexts: [{}]
|
|
7196
|
+
},
|
|
7197
|
+
pythonWebFramework: {
|
|
7198
|
+
schemaValues: types_exports.PYTHON_WEB_FRAMEWORK_VALUES,
|
|
7199
|
+
resolve: ({ value } = {}) => resolvePythonWebFrameworkPrompt(value),
|
|
7200
|
+
coverageContexts: [{}]
|
|
7201
|
+
},
|
|
7202
|
+
pythonOrm: {
|
|
7203
|
+
schemaValues: types_exports.PYTHON_ORM_VALUES,
|
|
7204
|
+
resolve: ({ value } = {}) => resolvePythonOrmPrompt(value),
|
|
7205
|
+
coverageContexts: [{}]
|
|
7206
|
+
},
|
|
7207
|
+
pythonValidation: {
|
|
7208
|
+
schemaValues: types_exports.PYTHON_VALIDATION_VALUES,
|
|
7209
|
+
resolve: ({ value } = {}) => resolvePythonValidationPrompt(value),
|
|
7210
|
+
coverageContexts: [{}]
|
|
7211
|
+
},
|
|
7212
|
+
pythonAi: {
|
|
7213
|
+
schemaValues: types_exports.PYTHON_AI_VALUES,
|
|
7214
|
+
resolve: ({ value } = {}) => resolvePythonAiPrompt(value),
|
|
7215
|
+
coverageContexts: [{}, { value: ["none"] }]
|
|
7216
|
+
},
|
|
7217
|
+
pythonAuth: {
|
|
7218
|
+
schemaValues: types_exports.PYTHON_AUTH_VALUES,
|
|
7219
|
+
resolve: ({ value } = {}) => resolvePythonAuthPrompt(value),
|
|
7220
|
+
coverageContexts: [{}]
|
|
7221
|
+
},
|
|
7222
|
+
pythonApi: {
|
|
7223
|
+
schemaValues: types_exports.PYTHON_API_VALUES,
|
|
7224
|
+
resolve: ({ value } = {}) => resolvePythonApiPrompt(value),
|
|
7225
|
+
coverageContexts: [{}]
|
|
7226
|
+
},
|
|
7227
|
+
pythonTaskQueue: {
|
|
7228
|
+
schemaValues: types_exports.PYTHON_TASK_QUEUE_VALUES,
|
|
7229
|
+
resolve: ({ value } = {}) => resolvePythonTaskQueuePrompt(value),
|
|
7230
|
+
coverageContexts: [{}]
|
|
7231
|
+
},
|
|
7232
|
+
pythonGraphql: {
|
|
7233
|
+
schemaValues: types_exports.PYTHON_GRAPHQL_VALUES,
|
|
7234
|
+
resolve: ({ value } = {}) => resolvePythonGraphqlPrompt(value),
|
|
7235
|
+
coverageContexts: [{}]
|
|
7236
|
+
},
|
|
7237
|
+
pythonQuality: {
|
|
7238
|
+
schemaValues: types_exports.PYTHON_QUALITY_VALUES,
|
|
7239
|
+
resolve: ({ value } = {}) => resolvePythonQualityPrompt(value),
|
|
7240
|
+
coverageContexts: [{}]
|
|
7241
|
+
},
|
|
7242
|
+
goWebFramework: {
|
|
7243
|
+
schemaValues: types_exports.GO_WEB_FRAMEWORK_VALUES,
|
|
7244
|
+
resolve: ({ value } = {}) => resolveGoWebFrameworkPrompt(value),
|
|
7245
|
+
coverageContexts: [{}]
|
|
7246
|
+
},
|
|
7247
|
+
goOrm: {
|
|
7248
|
+
schemaValues: types_exports.GO_ORM_VALUES,
|
|
7249
|
+
resolve: ({ value } = {}) => resolveGoOrmPrompt(value),
|
|
7250
|
+
coverageContexts: [{}]
|
|
7251
|
+
},
|
|
7252
|
+
goApi: {
|
|
7253
|
+
schemaValues: types_exports.GO_API_VALUES,
|
|
7254
|
+
resolve: ({ value } = {}) => resolveGoApiPrompt(value),
|
|
7255
|
+
coverageContexts: [{}]
|
|
7256
|
+
},
|
|
7257
|
+
goCli: {
|
|
7258
|
+
schemaValues: types_exports.GO_CLI_VALUES,
|
|
7259
|
+
resolve: ({ value } = {}) => resolveGoCliPrompt(value),
|
|
7260
|
+
coverageContexts: [{}]
|
|
7261
|
+
},
|
|
7262
|
+
goLogging: {
|
|
7263
|
+
schemaValues: types_exports.GO_LOGGING_VALUES,
|
|
7264
|
+
resolve: ({ value } = {}) => resolveGoLoggingPrompt(value),
|
|
7265
|
+
coverageContexts: [{}]
|
|
7266
|
+
},
|
|
7267
|
+
goAuth: {
|
|
7268
|
+
schemaValues: types_exports.GO_AUTH_VALUES,
|
|
7269
|
+
resolve: ({ value } = {}) => resolveGoAuthPrompt(value),
|
|
7270
|
+
coverageContexts: [{}]
|
|
7271
|
+
},
|
|
7272
|
+
javaWebFramework: {
|
|
7273
|
+
schemaValues: types_exports.JAVA_WEB_FRAMEWORK_VALUES,
|
|
7274
|
+
resolve: ({ value } = {}) => resolveJavaWebFrameworkPrompt(value),
|
|
7275
|
+
coverageContexts: [{}]
|
|
7276
|
+
},
|
|
7277
|
+
javaBuildTool: {
|
|
7278
|
+
schemaValues: types_exports.JAVA_BUILD_TOOL_VALUES,
|
|
7279
|
+
resolve: ({ value } = {}) => resolveJavaBuildToolPrompt(value),
|
|
7280
|
+
coverageContexts: [{}]
|
|
7281
|
+
},
|
|
7282
|
+
javaOrm: {
|
|
7283
|
+
schemaValues: types_exports.JAVA_ORM_VALUES,
|
|
7284
|
+
resolve: ({ value } = {}) => resolveJavaOrmPrompt(value),
|
|
7285
|
+
coverageContexts: [{}]
|
|
7286
|
+
},
|
|
7287
|
+
javaAuth: {
|
|
7288
|
+
schemaValues: types_exports.JAVA_AUTH_VALUES,
|
|
7289
|
+
resolve: ({ value } = {}) => resolveJavaAuthPrompt(value),
|
|
7290
|
+
coverageContexts: [{}]
|
|
7291
|
+
},
|
|
7292
|
+
javaLibraries: {
|
|
7293
|
+
schemaValues: types_exports.JAVA_LIBRARIES_VALUES,
|
|
7294
|
+
resolve: ({ value } = {}) => resolveJavaLibrariesPrompt(value),
|
|
7295
|
+
coverageContexts: [{}, { value: ["none"] }]
|
|
7296
|
+
},
|
|
7297
|
+
javaTestingLibraries: {
|
|
7298
|
+
schemaValues: types_exports.JAVA_TESTING_LIBRARIES_VALUES,
|
|
7299
|
+
resolve: ({ value } = {}) => resolveJavaTestingLibrariesPrompt(value),
|
|
7300
|
+
coverageContexts: [{}, { value: ["none"] }]
|
|
7301
|
+
},
|
|
7302
|
+
dotnetWebFramework: {
|
|
7303
|
+
schemaValues: types_exports.DOTNET_WEB_FRAMEWORK_VALUES,
|
|
7304
|
+
resolve: ({ value } = {}) => resolveDotnetWebFrameworkPrompt(value),
|
|
7305
|
+
coverageContexts: [{}]
|
|
7306
|
+
},
|
|
7307
|
+
dotnetOrm: {
|
|
7308
|
+
schemaValues: types_exports.DOTNET_ORM_VALUES,
|
|
7309
|
+
resolve: ({ value } = {}) => resolveDotnetOrmPrompt(value),
|
|
7310
|
+
coverageContexts: [{}]
|
|
7311
|
+
},
|
|
7312
|
+
dotnetAuth: {
|
|
7313
|
+
schemaValues: types_exports.DOTNET_AUTH_VALUES,
|
|
7314
|
+
resolve: ({ value } = {}) => resolveDotnetAuthPrompt(value),
|
|
7315
|
+
coverageContexts: [{}]
|
|
7316
|
+
},
|
|
7317
|
+
dotnetApi: {
|
|
7318
|
+
schemaValues: types_exports.DOTNET_API_VALUES,
|
|
7319
|
+
resolve: ({ value } = {}) => resolveDotnetApiPrompt(value),
|
|
7320
|
+
coverageContexts: [{}]
|
|
7321
|
+
},
|
|
7322
|
+
dotnetTesting: {
|
|
7323
|
+
schemaValues: types_exports.DOTNET_TESTING_VALUES,
|
|
7324
|
+
resolve: ({ value } = {}) => resolveDotnetTestingPrompt(value),
|
|
7325
|
+
coverageContexts: [{}, { value: ["none"] }]
|
|
7326
|
+
},
|
|
7327
|
+
dotnetJobQueue: {
|
|
7328
|
+
schemaValues: types_exports.DOTNET_JOB_QUEUE_VALUES,
|
|
7329
|
+
resolve: ({ value } = {}) => resolveDotnetJobQueuePrompt(value),
|
|
7330
|
+
coverageContexts: [{}]
|
|
7331
|
+
},
|
|
7332
|
+
dotnetRealtime: {
|
|
7333
|
+
schemaValues: types_exports.DOTNET_REALTIME_VALUES,
|
|
7334
|
+
resolve: ({ value } = {}) => resolveDotnetRealtimePrompt(value),
|
|
7335
|
+
coverageContexts: [{}]
|
|
7336
|
+
},
|
|
7337
|
+
dotnetObservability: {
|
|
7338
|
+
schemaValues: types_exports.DOTNET_OBSERVABILITY_VALUES,
|
|
7339
|
+
resolve: ({ value } = {}) => resolveDotnetObservabilityPrompt(value),
|
|
7340
|
+
coverageContexts: [{}, { value: ["none"] }]
|
|
7341
|
+
},
|
|
7342
|
+
dotnetCaching: {
|
|
7343
|
+
schemaValues: types_exports.DOTNET_CACHING_VALUES,
|
|
7344
|
+
resolve: ({ value } = {}) => resolveDotnetCachingPrompt(value),
|
|
7345
|
+
coverageContexts: [{}]
|
|
7346
|
+
},
|
|
7347
|
+
dotnetDeploy: {
|
|
7348
|
+
schemaValues: types_exports.DOTNET_DEPLOY_VALUES,
|
|
7349
|
+
resolve: ({ value } = {}) => resolveDotnetDeployPrompt(value),
|
|
7350
|
+
coverageContexts: [{}]
|
|
7351
|
+
},
|
|
7352
|
+
elixirWebFramework: {
|
|
7353
|
+
schemaValues: types_exports.ELIXIR_WEB_FRAMEWORK_VALUES,
|
|
7354
|
+
resolve: ({ value } = {}) => resolveElixirWebFrameworkPrompt(value),
|
|
7355
|
+
coverageContexts: [{}]
|
|
7356
|
+
},
|
|
7357
|
+
elixirOrm: {
|
|
7358
|
+
schemaValues: types_exports.ELIXIR_ORM_VALUES,
|
|
7359
|
+
resolve: ({ value } = {}) => resolveElixirOrmPrompt(value),
|
|
7360
|
+
coverageContexts: [{}]
|
|
7361
|
+
},
|
|
7362
|
+
elixirAuth: {
|
|
7363
|
+
schemaValues: types_exports.ELIXIR_AUTH_VALUES,
|
|
7364
|
+
resolve: ({ value } = {}) => resolveElixirAuthPrompt(value),
|
|
7365
|
+
coverageContexts: [{}]
|
|
7366
|
+
},
|
|
7367
|
+
elixirApi: {
|
|
7368
|
+
schemaValues: types_exports.ELIXIR_API_VALUES,
|
|
7369
|
+
resolve: ({ value } = {}) => resolveElixirApiPrompt(value),
|
|
7370
|
+
coverageContexts: [{}]
|
|
7371
|
+
},
|
|
7372
|
+
elixirRealtime: {
|
|
7373
|
+
schemaValues: types_exports.ELIXIR_REALTIME_VALUES,
|
|
7374
|
+
resolve: ({ value } = {}) => resolveElixirRealtimePrompt(value),
|
|
7375
|
+
coverageContexts: [{}]
|
|
7376
|
+
},
|
|
7377
|
+
elixirJobs: {
|
|
7378
|
+
schemaValues: types_exports.ELIXIR_JOBS_VALUES,
|
|
7379
|
+
resolve: ({ value } = {}) => resolveElixirJobsPrompt(value),
|
|
7380
|
+
coverageContexts: [{}]
|
|
7381
|
+
},
|
|
7382
|
+
elixirValidation: {
|
|
7383
|
+
schemaValues: types_exports.ELIXIR_VALIDATION_VALUES,
|
|
7384
|
+
resolve: ({ value } = {}) => resolveElixirValidationPrompt(value),
|
|
7385
|
+
coverageContexts: [{}]
|
|
7386
|
+
},
|
|
7387
|
+
elixirHttp: {
|
|
7388
|
+
schemaValues: types_exports.ELIXIR_HTTP_VALUES,
|
|
7389
|
+
resolve: ({ value } = {}) => resolveElixirHttpPrompt(value),
|
|
7390
|
+
coverageContexts: [{}]
|
|
7391
|
+
},
|
|
7392
|
+
elixirJson: {
|
|
7393
|
+
schemaValues: types_exports.ELIXIR_JSON_VALUES,
|
|
7394
|
+
resolve: ({ value } = {}) => resolveElixirJsonPrompt(value),
|
|
7395
|
+
coverageContexts: [{}]
|
|
7396
|
+
},
|
|
7397
|
+
elixirEmail: {
|
|
7398
|
+
schemaValues: types_exports.ELIXIR_EMAIL_VALUES,
|
|
7399
|
+
resolve: ({ value } = {}) => resolveElixirEmailPrompt(value),
|
|
7400
|
+
coverageContexts: [{}]
|
|
7401
|
+
},
|
|
7402
|
+
elixirCaching: {
|
|
7403
|
+
schemaValues: types_exports.ELIXIR_CACHING_VALUES,
|
|
7404
|
+
resolve: ({ value } = {}) => resolveElixirCachingPrompt(value),
|
|
7405
|
+
coverageContexts: [{}]
|
|
7406
|
+
},
|
|
7407
|
+
elixirObservability: {
|
|
7408
|
+
schemaValues: types_exports.ELIXIR_OBSERVABILITY_VALUES,
|
|
7409
|
+
resolve: ({ value } = {}) => resolveElixirObservabilityPrompt(value),
|
|
7410
|
+
coverageContexts: [{}]
|
|
7411
|
+
},
|
|
7412
|
+
elixirTesting: {
|
|
7413
|
+
schemaValues: types_exports.ELIXIR_TESTING_VALUES,
|
|
7414
|
+
resolve: ({ value } = {}) => resolveElixirTestingPrompt(value),
|
|
7415
|
+
coverageContexts: [{}]
|
|
7416
|
+
},
|
|
7417
|
+
elixirQuality: {
|
|
7418
|
+
schemaValues: types_exports.ELIXIR_QUALITY_VALUES,
|
|
7419
|
+
resolve: ({ value } = {}) => resolveElixirQualityPrompt(value),
|
|
7420
|
+
coverageContexts: [{}]
|
|
7421
|
+
},
|
|
7422
|
+
elixirDeploy: {
|
|
7423
|
+
schemaValues: types_exports.ELIXIR_DEPLOY_VALUES,
|
|
7424
|
+
resolve: ({ value } = {}) => resolveElixirDeployPrompt(value),
|
|
7425
|
+
coverageContexts: [{}]
|
|
7426
|
+
}
|
|
7427
|
+
};
|
|
7428
|
+
|
|
7429
|
+
//#endregion
|
|
7430
|
+
//#region src/prompts/search.ts
|
|
7431
|
+
const SEARCH_PROMPT_OPTIONS = [
|
|
7432
|
+
{
|
|
7433
|
+
value: "meilisearch",
|
|
7434
|
+
label: "Meilisearch",
|
|
7435
|
+
hint: "Lightning-fast search engine with typo tolerance"
|
|
7436
|
+
},
|
|
7437
|
+
{
|
|
7438
|
+
value: "typesense",
|
|
7439
|
+
label: "Typesense",
|
|
7440
|
+
hint: "Fast, typo-tolerant search with built-in vector search"
|
|
7441
|
+
},
|
|
7442
|
+
{
|
|
7443
|
+
value: "elasticsearch",
|
|
7444
|
+
label: "Elasticsearch",
|
|
7445
|
+
hint: "Distributed search and analytics engine with local and cloud deployments"
|
|
7446
|
+
},
|
|
7447
|
+
{
|
|
7448
|
+
value: "opensearch",
|
|
7449
|
+
label: "OpenSearch",
|
|
7450
|
+
hint: "Open-source search and analytics suite compatible with Elasticsearch APIs"
|
|
7451
|
+
},
|
|
7452
|
+
{
|
|
7453
|
+
value: "algolia",
|
|
7454
|
+
label: "Algolia",
|
|
7455
|
+
hint: "Hosted search API with instant results, typo tolerance, and analytics"
|
|
7456
|
+
},
|
|
7457
|
+
{
|
|
7458
|
+
value: "none",
|
|
7459
|
+
label: "None",
|
|
7460
|
+
hint: "Skip search engine setup"
|
|
7461
|
+
}
|
|
7462
|
+
];
|
|
7463
|
+
const NON_TYPESCRIPT_SEARCH_PROMPT_OPTIONS = SEARCH_PROMPT_OPTIONS.filter((option) => option.value === "meilisearch" || option.value === "none");
|
|
7464
|
+
const PYTHON_SEARCH_PROMPT_OPTIONS = SEARCH_PROMPT_OPTIONS.filter((option) => option.value === "meilisearch" || option.value === "elasticsearch" || option.value === "none");
|
|
7465
|
+
const GO_SEARCH_PROMPT_OPTIONS = [
|
|
7466
|
+
{
|
|
7467
|
+
value: "meilisearch",
|
|
7468
|
+
label: "Meilisearch",
|
|
7469
|
+
hint: "Lightning-fast search engine with typo tolerance"
|
|
7470
|
+
},
|
|
7471
|
+
{
|
|
7472
|
+
value: "bleve",
|
|
7473
|
+
label: "Bleve",
|
|
7474
|
+
hint: "Embedded, server-less full-text search for Go (no external service)"
|
|
7475
|
+
},
|
|
7476
|
+
{
|
|
7477
|
+
value: "none",
|
|
7478
|
+
label: "None",
|
|
7479
|
+
hint: "Skip search engine setup"
|
|
7480
|
+
}
|
|
7481
|
+
];
|
|
7482
|
+
function resolveSearchPrompt(context = {}) {
|
|
7483
|
+
if (context.ecosystem === "react-native" || context.ecosystem === "elixir") return {
|
|
7484
|
+
shouldPrompt: false,
|
|
7485
|
+
mode: "single",
|
|
7486
|
+
options: [],
|
|
7487
|
+
autoValue: "none"
|
|
7488
|
+
};
|
|
7489
|
+
const options = context.ecosystem === "go" ? GO_SEARCH_PROMPT_OPTIONS : context.ecosystem === "python" ? PYTHON_SEARCH_PROMPT_OPTIONS : context.ecosystem && context.ecosystem !== "typescript" ? NON_TYPESCRIPT_SEARCH_PROMPT_OPTIONS : SEARCH_PROMPT_OPTIONS;
|
|
7490
|
+
if ((!context.ecosystem || context.ecosystem === "typescript") && (context.backend === "none" || context.backend === "convex")) return {
|
|
7491
|
+
shouldPrompt: false,
|
|
7492
|
+
mode: "single",
|
|
7493
|
+
options: [],
|
|
7494
|
+
autoValue: "none"
|
|
7495
|
+
};
|
|
7496
|
+
return context.search !== void 0 ? {
|
|
7497
|
+
shouldPrompt: false,
|
|
7498
|
+
mode: "single",
|
|
7499
|
+
options,
|
|
7500
|
+
autoValue: context.search
|
|
7501
|
+
} : {
|
|
7502
|
+
shouldPrompt: true,
|
|
7503
|
+
mode: "single",
|
|
7504
|
+
options,
|
|
7505
|
+
initialValue: "none"
|
|
7506
|
+
};
|
|
7507
|
+
}
|
|
7508
|
+
async function getSearchChoice(search, backend, ecosystem) {
|
|
7509
|
+
const resolution = resolveSearchPrompt({
|
|
7510
|
+
search,
|
|
7511
|
+
backend,
|
|
7512
|
+
ecosystem
|
|
7513
|
+
});
|
|
7514
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
7515
|
+
const response = await navigableSelect({
|
|
7516
|
+
message: "Select search engine",
|
|
7517
|
+
options: resolution.options,
|
|
7518
|
+
initialValue: resolution.initialValue
|
|
7519
|
+
});
|
|
7520
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
7521
|
+
return response;
|
|
7522
|
+
}
|
|
7523
|
+
|
|
7524
|
+
//#endregion
|
|
7525
|
+
//#region src/prompts/vector-db.ts
|
|
7526
|
+
const VECTOR_DB_PROMPT_OPTIONS = [
|
|
7527
|
+
{
|
|
7528
|
+
value: "pgvector",
|
|
7529
|
+
label: "pgvector",
|
|
7530
|
+
hint: "Self-hosted Postgres + pgvector extension for embeddings"
|
|
7531
|
+
},
|
|
7532
|
+
{
|
|
7533
|
+
value: "qdrant",
|
|
7534
|
+
label: "Qdrant",
|
|
7535
|
+
hint: "High-performance open-source vector database"
|
|
7536
|
+
},
|
|
7537
|
+
{
|
|
7538
|
+
value: "chroma",
|
|
7539
|
+
label: "Chroma",
|
|
7540
|
+
hint: "Lightweight open-source embedding database"
|
|
7541
|
+
},
|
|
7542
|
+
{
|
|
7543
|
+
value: "pinecone",
|
|
7544
|
+
label: "Pinecone",
|
|
7545
|
+
hint: "Fully managed serverless vector database"
|
|
7546
|
+
},
|
|
7547
|
+
{
|
|
7548
|
+
value: "none",
|
|
7549
|
+
label: "None",
|
|
7550
|
+
hint: "Skip vector database setup"
|
|
7551
|
+
}
|
|
7552
|
+
];
|
|
7553
|
+
/**
|
|
7554
|
+
* Vector DB is a TypeScript-ecosystem feature backed by a standalone server.
|
|
7555
|
+
* Every provider (including pgvector via a dedicated Postgres instance) is a
|
|
7556
|
+
* separate service, so there is no dependency on the primary database choice.
|
|
7557
|
+
*/
|
|
7558
|
+
function resolveVectorDbPrompt(context = {}) {
|
|
7559
|
+
const skip = () => ({
|
|
7560
|
+
shouldPrompt: false,
|
|
7561
|
+
mode: "single",
|
|
7562
|
+
options: [],
|
|
7563
|
+
autoValue: "none"
|
|
7564
|
+
});
|
|
7565
|
+
if (context.ecosystem && context.ecosystem !== "typescript") return skip();
|
|
7566
|
+
if (context.backend === "none" || context.backend === "convex") return skip();
|
|
7567
|
+
return context.vectorDb !== void 0 ? {
|
|
7568
|
+
shouldPrompt: false,
|
|
7569
|
+
mode: "single",
|
|
7570
|
+
options: VECTOR_DB_PROMPT_OPTIONS,
|
|
7571
|
+
autoValue: context.vectorDb
|
|
7572
|
+
} : {
|
|
7573
|
+
shouldPrompt: true,
|
|
7574
|
+
mode: "single",
|
|
7575
|
+
options: VECTOR_DB_PROMPT_OPTIONS,
|
|
7576
|
+
initialValue: "none"
|
|
7577
|
+
};
|
|
7578
|
+
}
|
|
7579
|
+
async function getVectorDbChoice(vectorDb, backend, ecosystem) {
|
|
7580
|
+
const resolution = resolveVectorDbPrompt({
|
|
7581
|
+
vectorDb,
|
|
7582
|
+
backend,
|
|
7583
|
+
ecosystem
|
|
7584
|
+
});
|
|
7585
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
7586
|
+
const response = await navigableSelect({
|
|
7587
|
+
message: "Select vector database",
|
|
7588
|
+
options: resolution.options,
|
|
7589
|
+
initialValue: resolution.initialValue
|
|
7590
|
+
});
|
|
7591
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
7592
|
+
return response;
|
|
7593
|
+
}
|
|
7594
|
+
|
|
7595
|
+
//#endregion
|
|
7596
|
+
//#region src/prompts/server-deploy.ts
|
|
7597
|
+
async function getServerDeploymentChoice(deployment, runtime, backend, _webDeploy) {
|
|
7598
|
+
if (deployment !== void 0) return deployment;
|
|
7599
|
+
if (backend === "none" || backend === "convex") return "none";
|
|
7600
|
+
if (backend !== "hono") return "none";
|
|
7601
|
+
if (runtime === "workers") return "cloudflare";
|
|
7602
|
+
const response = await navigableSelect({
|
|
7603
|
+
message: "Select server deployment",
|
|
7604
|
+
options: getServerDeploymentOptions(runtime),
|
|
7605
|
+
initialValue: DEFAULT_CONFIG.serverDeploy
|
|
7606
|
+
});
|
|
7607
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
7608
|
+
return response;
|
|
7609
|
+
}
|
|
7610
|
+
function getServerDeploymentOptions(runtime) {
|
|
7611
|
+
return [
|
|
7612
|
+
{
|
|
7613
|
+
value: "none",
|
|
7614
|
+
label: "None",
|
|
7615
|
+
hint: "Skip server deployment setup"
|
|
7616
|
+
},
|
|
7617
|
+
{
|
|
7618
|
+
value: "railway",
|
|
7619
|
+
label: "Railway",
|
|
7620
|
+
hint: "Deploy with Railway cloud development platform"
|
|
7621
|
+
},
|
|
7622
|
+
{
|
|
7623
|
+
value: "fly",
|
|
7624
|
+
label: "Fly.io",
|
|
7625
|
+
hint: "Deploy globally with Fly.io edge platform"
|
|
7626
|
+
},
|
|
7627
|
+
{
|
|
7628
|
+
value: "render",
|
|
7629
|
+
label: "Render",
|
|
7630
|
+
hint: "Deploy with Render's Blueprint and Docker builds"
|
|
7631
|
+
},
|
|
7632
|
+
...runtime === "node" ? [{
|
|
7633
|
+
value: "netlify",
|
|
7634
|
+
label: "Netlify",
|
|
7635
|
+
hint: "Deploy Hono APIs with Netlify Functions"
|
|
7636
|
+
}] : [],
|
|
7637
|
+
{
|
|
7638
|
+
value: "docker",
|
|
7639
|
+
label: "Docker",
|
|
7640
|
+
hint: "Container-based deployment with Dockerfile"
|
|
7641
|
+
},
|
|
7642
|
+
{
|
|
7643
|
+
value: "sst",
|
|
7644
|
+
label: "SST",
|
|
7645
|
+
hint: "Deploy to AWS with SST (Serverless Stack)"
|
|
7646
|
+
},
|
|
7647
|
+
{
|
|
7648
|
+
value: "vercel",
|
|
7649
|
+
label: "Vercel",
|
|
7650
|
+
hint: "Deploy to Vercel's edge network with zero config"
|
|
7651
|
+
}
|
|
7652
|
+
];
|
|
7653
|
+
}
|
|
7654
|
+
|
|
6511
7655
|
//#endregion
|
|
6512
7656
|
//#region src/prompts/config-prompts.ts
|
|
7657
|
+
const CONFIG_SCOPE_META_KEYS = new Set([
|
|
7658
|
+
"ecosystem",
|
|
7659
|
+
"configScope",
|
|
7660
|
+
"configSections"
|
|
7661
|
+
]);
|
|
7662
|
+
const SHADCN_FLAG_KEYS = new Set([
|
|
7663
|
+
"shadcnBase",
|
|
7664
|
+
"shadcnStyle",
|
|
7665
|
+
"shadcnIconLibrary",
|
|
7666
|
+
"shadcnColorTheme",
|
|
7667
|
+
"shadcnBaseColor",
|
|
7668
|
+
"shadcnFont",
|
|
7669
|
+
"shadcnRadius"
|
|
7670
|
+
]);
|
|
7671
|
+
const CONFIG_PROMPT_ENTRY_KEY_MAP = {
|
|
7672
|
+
ecosystem: true,
|
|
7673
|
+
configScope: true,
|
|
7674
|
+
configSections: true,
|
|
7675
|
+
frontend: true,
|
|
7676
|
+
astroIntegration: true,
|
|
7677
|
+
uiLibrary: true,
|
|
7678
|
+
shadcnOptions: true,
|
|
7679
|
+
cssFramework: true,
|
|
7680
|
+
backend: true,
|
|
7681
|
+
runtime: true,
|
|
7682
|
+
database: true,
|
|
7683
|
+
orm: true,
|
|
7684
|
+
api: true,
|
|
7685
|
+
auth: true,
|
|
7686
|
+
payments: true,
|
|
7687
|
+
email: true,
|
|
7688
|
+
effect: true,
|
|
7689
|
+
addons: true,
|
|
7690
|
+
examples: true,
|
|
7691
|
+
dbSetup: true,
|
|
7692
|
+
webDeploy: true,
|
|
7693
|
+
serverDeploy: true,
|
|
7694
|
+
ai: true,
|
|
7695
|
+
validation: true,
|
|
7696
|
+
forms: true,
|
|
7697
|
+
stateManagement: true,
|
|
7698
|
+
animation: true,
|
|
7699
|
+
testing: true,
|
|
7700
|
+
realtime: true,
|
|
7701
|
+
jobQueue: true,
|
|
7702
|
+
fileUpload: true,
|
|
7703
|
+
logging: true,
|
|
7704
|
+
observability: true,
|
|
7705
|
+
featureFlags: true,
|
|
7706
|
+
analytics: true,
|
|
7707
|
+
cms: true,
|
|
7708
|
+
caching: true,
|
|
7709
|
+
rateLimit: true,
|
|
7710
|
+
i18n: true,
|
|
7711
|
+
search: true,
|
|
7712
|
+
vectorDb: true,
|
|
7713
|
+
fileStorage: true,
|
|
7714
|
+
mobileNavigation: true,
|
|
7715
|
+
mobileUI: true,
|
|
7716
|
+
mobileStorage: true,
|
|
7717
|
+
mobileTesting: true,
|
|
7718
|
+
mobilePush: true,
|
|
7719
|
+
mobileOTA: true,
|
|
7720
|
+
mobileDeepLinking: true,
|
|
7721
|
+
rustWebFramework: true,
|
|
7722
|
+
rustFrontend: true,
|
|
7723
|
+
rustOrm: true,
|
|
7724
|
+
rustApi: true,
|
|
7725
|
+
rustCli: true,
|
|
7726
|
+
rustLibraries: true,
|
|
7727
|
+
rustLogging: true,
|
|
7728
|
+
rustErrorHandling: true,
|
|
7729
|
+
rustCaching: true,
|
|
7730
|
+
rustAuth: true,
|
|
7731
|
+
rustRealtime: true,
|
|
7732
|
+
rustMessageQueue: true,
|
|
7733
|
+
rustObservability: true,
|
|
7734
|
+
rustTemplating: true,
|
|
7735
|
+
pythonWebFramework: true,
|
|
7736
|
+
pythonOrm: true,
|
|
7737
|
+
pythonValidation: true,
|
|
7738
|
+
pythonAi: true,
|
|
7739
|
+
pythonAuth: true,
|
|
7740
|
+
pythonApi: true,
|
|
7741
|
+
pythonTaskQueue: true,
|
|
7742
|
+
pythonGraphql: true,
|
|
7743
|
+
pythonQuality: true,
|
|
7744
|
+
pythonTesting: true,
|
|
7745
|
+
pythonCaching: true,
|
|
7746
|
+
pythonRealtime: true,
|
|
7747
|
+
pythonObservability: true,
|
|
7748
|
+
pythonCli: true,
|
|
7749
|
+
goWebFramework: true,
|
|
7750
|
+
goOrm: true,
|
|
7751
|
+
goApi: true,
|
|
7752
|
+
goCli: true,
|
|
7753
|
+
goLogging: true,
|
|
7754
|
+
goAuth: true,
|
|
7755
|
+
goTesting: true,
|
|
7756
|
+
goRealtime: true,
|
|
7757
|
+
goMessageQueue: true,
|
|
7758
|
+
goCaching: true,
|
|
7759
|
+
goConfig: true,
|
|
7760
|
+
goObservability: true,
|
|
7761
|
+
javaWebFramework: true,
|
|
7762
|
+
javaLanguage: true,
|
|
7763
|
+
javaBuildTool: true,
|
|
7764
|
+
javaOrm: true,
|
|
7765
|
+
javaAuth: true,
|
|
7766
|
+
javaApi: true,
|
|
7767
|
+
javaLogging: true,
|
|
7768
|
+
javaLibraries: true,
|
|
7769
|
+
javaTestingLibraries: true,
|
|
7770
|
+
dotnetWebFramework: true,
|
|
7771
|
+
dotnetOrm: true,
|
|
7772
|
+
dotnetAuth: true,
|
|
7773
|
+
dotnetApi: true,
|
|
7774
|
+
dotnetTesting: true,
|
|
7775
|
+
dotnetJobQueue: true,
|
|
7776
|
+
dotnetRealtime: true,
|
|
7777
|
+
dotnetObservability: true,
|
|
7778
|
+
dotnetValidation: true,
|
|
7779
|
+
dotnetCaching: true,
|
|
7780
|
+
dotnetDeploy: true,
|
|
7781
|
+
elixirWebFramework: true,
|
|
7782
|
+
elixirOrm: true,
|
|
7783
|
+
elixirAuth: true,
|
|
7784
|
+
elixirApi: true,
|
|
7785
|
+
elixirRealtime: true,
|
|
7786
|
+
elixirJobs: true,
|
|
7787
|
+
elixirValidation: true,
|
|
7788
|
+
elixirHttp: true,
|
|
7789
|
+
elixirJson: true,
|
|
7790
|
+
elixirEmail: true,
|
|
7791
|
+
elixirCaching: true,
|
|
7792
|
+
elixirObservability: true,
|
|
7793
|
+
elixirTesting: true,
|
|
7794
|
+
elixirQuality: true,
|
|
7795
|
+
elixirDeploy: true,
|
|
7796
|
+
elixirLibraries: true,
|
|
7797
|
+
aiDocs: true,
|
|
7798
|
+
git: true,
|
|
7799
|
+
workspaceShape: true,
|
|
7800
|
+
packageManager: true,
|
|
7801
|
+
install: true
|
|
7802
|
+
};
|
|
7803
|
+
const CONFIG_PROMPT_ENTRY_KEYS = Object.keys(CONFIG_PROMPT_ENTRY_KEY_MAP);
|
|
7804
|
+
function hasStackPromptFlags(flags) {
|
|
7805
|
+
return Object.keys(flags).some((key) => {
|
|
7806
|
+
if (key === "projectName" || key === "projectDir" || key === "relativePath") return false;
|
|
7807
|
+
if (SHADCN_FLAG_KEYS.has(key)) return true;
|
|
7808
|
+
return CONFIG_PROMPT_ENTRY_KEYS.includes(key);
|
|
7809
|
+
});
|
|
7810
|
+
}
|
|
7811
|
+
function getPromptResolutionValue(key, results, flags) {
|
|
7812
|
+
const resolver = PROMPT_RESOLVER_REGISTRY[key];
|
|
7813
|
+
if (!resolver) return void 0;
|
|
7814
|
+
const frontends = results.frontend ?? flags.frontend;
|
|
7815
|
+
const contextByKey = {
|
|
7816
|
+
frontend: {
|
|
7817
|
+
frontend: flags.frontend,
|
|
7818
|
+
backend: flags.backend,
|
|
7819
|
+
auth: flags.auth
|
|
7820
|
+
},
|
|
7821
|
+
backend: {
|
|
7822
|
+
backendFramework: flags.backend,
|
|
7823
|
+
frontends
|
|
7824
|
+
},
|
|
7825
|
+
runtime: {
|
|
7826
|
+
runtime: flags.runtime,
|
|
7827
|
+
backend: results.backend
|
|
7828
|
+
},
|
|
7829
|
+
database: {
|
|
7830
|
+
database: flags.database,
|
|
7831
|
+
backend: results.backend,
|
|
7832
|
+
runtime: results.runtime
|
|
7833
|
+
},
|
|
7834
|
+
orm: {
|
|
7835
|
+
orm: flags.orm,
|
|
7836
|
+
hasDatabase: results.database !== void 0 && results.database !== "none",
|
|
7837
|
+
database: results.database,
|
|
7838
|
+
backend: results.backend,
|
|
7839
|
+
runtime: results.runtime
|
|
7840
|
+
},
|
|
7841
|
+
api: {
|
|
7842
|
+
api: flags.api,
|
|
7843
|
+
frontend: frontends,
|
|
7844
|
+
backend: results.backend,
|
|
7845
|
+
astroIntegration: results.astroIntegration
|
|
7846
|
+
},
|
|
7847
|
+
auth: {
|
|
7848
|
+
auth: flags.auth,
|
|
7849
|
+
backend: results.backend,
|
|
7850
|
+
frontend: frontends,
|
|
7851
|
+
ecosystem: results.ecosystem
|
|
7852
|
+
},
|
|
7853
|
+
payments: {
|
|
7854
|
+
payments: flags.payments,
|
|
7855
|
+
auth: results.auth,
|
|
7856
|
+
backend: results.backend,
|
|
7857
|
+
frontends
|
|
7858
|
+
},
|
|
7859
|
+
email: {
|
|
7860
|
+
email: flags.email,
|
|
7861
|
+
backend: results.backend,
|
|
7862
|
+
ecosystem: results.ecosystem
|
|
7863
|
+
},
|
|
7864
|
+
uiLibrary: {
|
|
7865
|
+
uiLibrary: flags.uiLibrary,
|
|
7866
|
+
frontends,
|
|
7867
|
+
astroIntegration: results.astroIntegration
|
|
7868
|
+
},
|
|
7869
|
+
cssFramework: {
|
|
7870
|
+
cssFramework: flags.cssFramework,
|
|
7871
|
+
uiLibrary: results.uiLibrary
|
|
7872
|
+
},
|
|
7873
|
+
forms: {
|
|
7874
|
+
forms: flags.forms,
|
|
7875
|
+
frontends
|
|
7876
|
+
},
|
|
7877
|
+
stateManagement: {
|
|
7878
|
+
stateManagement: flags.stateManagement,
|
|
7879
|
+
frontends
|
|
7880
|
+
},
|
|
7881
|
+
animation: {
|
|
7882
|
+
animation: flags.animation,
|
|
7883
|
+
frontends
|
|
7884
|
+
},
|
|
7885
|
+
caching: {
|
|
7886
|
+
caching: flags.caching,
|
|
7887
|
+
backend: results.backend,
|
|
7888
|
+
ecosystem: results.ecosystem
|
|
7889
|
+
},
|
|
7890
|
+
search: {
|
|
7891
|
+
search: flags.search,
|
|
7892
|
+
backend: results.backend,
|
|
7893
|
+
ecosystem: results.ecosystem
|
|
7894
|
+
},
|
|
7895
|
+
observability: {
|
|
7896
|
+
observability: flags.observability,
|
|
7897
|
+
backend: results.backend,
|
|
7898
|
+
ecosystem: results.ecosystem
|
|
7899
|
+
},
|
|
7900
|
+
realtime: {
|
|
7901
|
+
realtime: flags.realtime,
|
|
7902
|
+
backend: results.backend
|
|
7903
|
+
},
|
|
7904
|
+
jobQueue: {
|
|
7905
|
+
jobQueue: flags.jobQueue,
|
|
7906
|
+
backend: results.backend
|
|
7907
|
+
},
|
|
7908
|
+
fileUpload: {
|
|
7909
|
+
fileUpload: flags.fileUpload,
|
|
7910
|
+
backend: results.backend
|
|
7911
|
+
},
|
|
7912
|
+
logging: {
|
|
7913
|
+
logging: flags.logging,
|
|
7914
|
+
backend: results.backend
|
|
7915
|
+
},
|
|
7916
|
+
rateLimit: {
|
|
7917
|
+
rateLimit: flags.rateLimit,
|
|
7918
|
+
backend: results.backend
|
|
7919
|
+
},
|
|
7920
|
+
cms: {
|
|
7921
|
+
cms: flags.cms,
|
|
7922
|
+
backend: results.backend
|
|
7923
|
+
},
|
|
7924
|
+
vectorDb: {
|
|
7925
|
+
vectorDb: flags.vectorDb,
|
|
7926
|
+
backend: results.backend,
|
|
7927
|
+
ecosystem: results.ecosystem
|
|
7928
|
+
},
|
|
7929
|
+
fileStorage: {
|
|
7930
|
+
fileStorage: flags.fileStorage,
|
|
7931
|
+
backend: results.backend
|
|
7932
|
+
}
|
|
7933
|
+
};
|
|
7934
|
+
const selectedValue = flags[key];
|
|
7935
|
+
const context = contextByKey[key] ?? { value: selectedValue };
|
|
7936
|
+
const resolution = resolver.resolve(context);
|
|
7937
|
+
return resolution.autoValue ?? resolution.initialValue;
|
|
7938
|
+
}
|
|
7939
|
+
async function getScopedDefaultPromptValue(key, results, flags) {
|
|
7940
|
+
if (key === "serverDeploy" && results.ecosystem === "typescript") {
|
|
7941
|
+
if (flags.serverDeploy !== void 0) return flags.serverDeploy;
|
|
7942
|
+
if (results.backend !== "hono") return "none";
|
|
7943
|
+
if (results.runtime === "workers") return "cloudflare";
|
|
7944
|
+
return "none";
|
|
7945
|
+
}
|
|
7946
|
+
if (key === "effect" && results.ecosystem === "typescript") return flags.effect ?? (results.backend === "effect" ? "effect-full" : "none");
|
|
7947
|
+
if (key === "validation" && results.ecosystem === "typescript" && results.backend === "effect") return flags.validation ?? "effect-schema";
|
|
7948
|
+
const resolvedValue = getPromptResolutionValue(key, results, flags);
|
|
7949
|
+
if (resolvedValue !== void 0) return resolvedValue;
|
|
7950
|
+
return getDefaultPromptValue(key);
|
|
7951
|
+
}
|
|
7952
|
+
function scopedPrompt(key, flags, prompt) {
|
|
7953
|
+
return (opts) => {
|
|
7954
|
+
if (!CONFIG_SCOPE_META_KEYS.has(key) && !shouldAskConfigPromptKey(opts.results.ecosystem, key, opts.results.configScope, opts.results.configSections)) return getScopedDefaultPromptValue(key, opts.results, flags);
|
|
7955
|
+
return prompt(opts);
|
|
7956
|
+
};
|
|
7957
|
+
}
|
|
6513
7958
|
async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
6514
7959
|
if (flags.ecosystem === void 0 && flags.stackParts === void 0) {
|
|
6515
7960
|
if (await getCompositionModeChoice() === "multi") return gatherMultiEcosystemConfig(flags, projectName, projectDir, relativePath);
|
|
6516
7961
|
}
|
|
6517
|
-
const
|
|
7962
|
+
const shouldPromptForScope = !hasStackPromptFlags(flags);
|
|
7963
|
+
const result = await navigableGroup(Object.fromEntries(Object.entries({
|
|
6518
7964
|
ecosystem: () => getEcosystemChoice(flags.ecosystem),
|
|
7965
|
+
configScope: () => shouldPromptForScope ? getConfigScopeChoice() : Promise.resolve("full"),
|
|
7966
|
+
configSections: ({ results }) => {
|
|
7967
|
+
if (!shouldPromptForScope || results.configScope !== "custom") return Promise.resolve([]);
|
|
7968
|
+
return getConfigSectionsChoice(results.ecosystem ?? "typescript");
|
|
7969
|
+
},
|
|
6519
7970
|
frontend: ({ results }) => {
|
|
6520
7971
|
if (results.ecosystem === "react-native") return getNativeFrontendChoice(flags.frontend);
|
|
6521
7972
|
if (results.ecosystem !== "typescript") return Promise.resolve([]);
|
|
@@ -6578,7 +8029,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
6578
8029
|
return Promise.resolve("none");
|
|
6579
8030
|
},
|
|
6580
8031
|
payments: ({ results }) => {
|
|
6581
|
-
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
8032
|
+
if (results.ecosystem !== "typescript" && results.ecosystem !== "react-native") return Promise.resolve("none");
|
|
6582
8033
|
return getPaymentsChoice(flags.payments, results.auth, results.backend, results.frontend);
|
|
6583
8034
|
},
|
|
6584
8035
|
email: ({ results }) => {
|
|
@@ -6587,6 +8038,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
6587
8038
|
},
|
|
6588
8039
|
effect: ({ results }) => {
|
|
6589
8040
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
8041
|
+
if (results.backend === "effect" && flags.effect === void 0) return Promise.resolve("effect-full");
|
|
6590
8042
|
return getEffectChoice(flags.effect);
|
|
6591
8043
|
},
|
|
6592
8044
|
addons: ({ results }) => {
|
|
@@ -6619,6 +8071,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
6619
8071
|
},
|
|
6620
8072
|
validation: ({ results }) => {
|
|
6621
8073
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
8074
|
+
if (results.backend === "effect" && flags.validation === void 0) return Promise.resolve("effect-schema");
|
|
6622
8075
|
return getValidationChoice(flags.validation);
|
|
6623
8076
|
},
|
|
6624
8077
|
forms: ({ results }) => {
|
|
@@ -6895,6 +8348,13 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
6895
8348
|
if (results.ecosystem !== "java") return Promise.resolve("none");
|
|
6896
8349
|
return getJavaWebFrameworkChoice(flags.javaWebFramework);
|
|
6897
8350
|
},
|
|
8351
|
+
javaLanguage: ({ results }) => {
|
|
8352
|
+
if (results.ecosystem !== "java") return Promise.resolve("java");
|
|
8353
|
+
if (results.javaWebFramework !== "spring-boot") return Promise.resolve("java");
|
|
8354
|
+
if (flags.javaLanguage !== void 0) return getJavaLanguageChoice(flags.javaLanguage);
|
|
8355
|
+
if (flags.javaWebFramework !== void 0) return Promise.resolve("java");
|
|
8356
|
+
return getJavaLanguageChoice(flags.javaLanguage);
|
|
8357
|
+
},
|
|
6898
8358
|
javaBuildTool: ({ results }) => {
|
|
6899
8359
|
if (results.ecosystem !== "java") return Promise.resolve("none");
|
|
6900
8360
|
return getJavaBuildToolChoice(flags.javaBuildTool);
|
|
@@ -7046,12 +8506,13 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
7046
8506
|
},
|
|
7047
8507
|
aiDocs: () => getAiDocsChoice(flags.aiDocs),
|
|
7048
8508
|
git: () => getGitChoice(flags.git),
|
|
8509
|
+
workspaceShape: ({ results }) => getWorkspaceShapeChoice(flags.workspaceShape, results.backend, results.frontend),
|
|
7049
8510
|
packageManager: ({ results }) => {
|
|
7050
8511
|
if (results.ecosystem === "rust" || results.ecosystem === "python" || results.ecosystem === "go" || results.ecosystem === "java" || results.ecosystem === "dotnet" || results.ecosystem === "elixir") return Promise.resolve(flags.packageManager ?? getUserPkgManager());
|
|
7051
8512
|
return getPackageManagerChoice(flags.packageManager);
|
|
7052
8513
|
},
|
|
7053
8514
|
install: ({ results }) => getinstallChoice(flags.install, results.ecosystem, results.javaBuildTool)
|
|
7054
|
-
}, { onCancel: () => exitCancelled("Operation cancelled") });
|
|
8515
|
+
}).map(([key, prompt]) => [key, scopedPrompt(key, flags, prompt)])), { onCancel: () => exitCancelled("Operation cancelled") });
|
|
7055
8516
|
return {
|
|
7056
8517
|
projectName,
|
|
7057
8518
|
projectDir,
|
|
@@ -7073,6 +8534,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
7073
8534
|
examples: result.examples,
|
|
7074
8535
|
git: result.git,
|
|
7075
8536
|
packageManager: result.packageManager,
|
|
8537
|
+
workspaceShape: result.workspaceShape,
|
|
7076
8538
|
install: result.install,
|
|
7077
8539
|
dbSetup: result.dbSetup,
|
|
7078
8540
|
api: result.api,
|
|
@@ -7147,6 +8609,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
7147
8609
|
goConfig: result.goConfig,
|
|
7148
8610
|
goObservability: result.goObservability,
|
|
7149
8611
|
javaWebFramework: result.javaWebFramework,
|
|
8612
|
+
javaLanguage: result.javaLanguage,
|
|
7150
8613
|
javaBuildTool: result.javaBuildTool,
|
|
7151
8614
|
javaOrm: result.javaOrm,
|
|
7152
8615
|
javaAuth: result.javaAuth,
|
|
@@ -7586,32 +9049,14 @@ async function setupProjectDirectory(finalPathInput, shouldClearDirectory) {
|
|
|
7586
9049
|
}
|
|
7587
9050
|
|
|
7588
9051
|
//#endregion
|
|
7589
|
-
//#region src/utils/
|
|
7590
|
-
function
|
|
7591
|
-
|
|
7592
|
-
if (
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
return cliInputToProjectConfigPartial(options, projectName || derivedName);
|
|
7598
|
-
}
|
|
7599
|
-
function getProvidedFlags(options) {
|
|
7600
|
-
return new Set(Object.keys(options).filter((key) => options[key] !== void 0));
|
|
7601
|
-
}
|
|
7602
|
-
function validateNoneExclusivity(options, optionName) {
|
|
7603
|
-
if (!options || options.length === 0) return;
|
|
7604
|
-
if (options.includes("none") && options.length > 1) throw new Error(`Cannot combine 'none' with other ${optionName}.`);
|
|
7605
|
-
}
|
|
7606
|
-
function validateArrayOptions(options) {
|
|
7607
|
-
validateNoneExclusivity(options.frontend, "frontend options");
|
|
7608
|
-
validateNoneExclusivity(options.addons, "addons");
|
|
7609
|
-
validateNoneExclusivity(options.examples, "examples");
|
|
7610
|
-
validateNoneExclusivity(options.aiDocs, "ai docs");
|
|
7611
|
-
validateNoneExclusivity(options.rustLibraries, "rust libraries");
|
|
7612
|
-
validateNoneExclusivity(options.pythonAi, "python ai libraries");
|
|
7613
|
-
validateNoneExclusivity(options.javaLibraries, "java libraries");
|
|
7614
|
-
validateNoneExclusivity(options.javaTestingLibraries, "java testing libraries");
|
|
9052
|
+
//#region src/utils/open-url.ts
|
|
9053
|
+
async function openUrl(url) {
|
|
9054
|
+
const platform = process.platform;
|
|
9055
|
+
if (platform === "darwin") await $({ stdio: "ignore" })`open ${url}`;
|
|
9056
|
+
else if (platform === "win32") {
|
|
9057
|
+
const escapedUrl = url.replace(/&/g, "^&");
|
|
9058
|
+
await $({ stdio: "ignore" })`cmd /c start "" ${escapedUrl}`;
|
|
9059
|
+
} else await $({ stdio: "ignore" })`xdg-open ${url}`;
|
|
7615
9060
|
}
|
|
7616
9061
|
|
|
7617
9062
|
//#endregion
|
|
@@ -7658,6 +9103,7 @@ function extractAndValidateProjectName(projectName, projectDirectory, throwOnErr
|
|
|
7658
9103
|
function processAndValidateFlags(options, providedFlags, projectName) {
|
|
7659
9104
|
if (options.yolo) {
|
|
7660
9105
|
const cfg = processFlags(options, projectName);
|
|
9106
|
+
applyEffectBackendDefaults(cfg, getProvidedFlags(options));
|
|
7661
9107
|
const validatedProjectName$1 = extractAndValidateProjectName(projectName, options.projectDirectory, true);
|
|
7662
9108
|
if (validatedProjectName$1) cfg.projectName = validatedProjectName$1;
|
|
7663
9109
|
return cfg;
|
|
@@ -7669,6 +9115,7 @@ function processAndValidateFlags(options, providedFlags, projectName) {
|
|
|
7669
9115
|
exitWithError(error instanceof Error ? error.message : String(error));
|
|
7670
9116
|
}
|
|
7671
9117
|
const config = processFlags(options, projectName);
|
|
9118
|
+
applyEffectBackendDefaults(config, providedFlags);
|
|
7672
9119
|
const validatedProjectName = extractAndValidateProjectName(projectName, options.projectDirectory, false);
|
|
7673
9120
|
if (validatedProjectName) config.projectName = validatedProjectName;
|
|
7674
9121
|
validateFullConfig(config, providedFlags, options);
|
|
@@ -7683,7 +9130,9 @@ function processProvidedFlagsWithoutValidation(options, projectName) {
|
|
|
7683
9130
|
exitWithError(error instanceof Error ? error.message : String(error));
|
|
7684
9131
|
}
|
|
7685
9132
|
}
|
|
9133
|
+
const providedFlags = getProvidedFlags(options);
|
|
7686
9134
|
const config = processFlags(options, projectName);
|
|
9135
|
+
applyEffectBackendDefaults(config, providedFlags);
|
|
7687
9136
|
const validatedProjectName = extractAndValidateProjectName(projectName, options.projectDirectory, true);
|
|
7688
9137
|
if (validatedProjectName) config.projectName = validatedProjectName;
|
|
7689
9138
|
return config;
|
|
@@ -8955,6 +10404,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
8955
10404
|
const clerkInstructions = config.auth === "clerk" ? getClerkInstructions(config.backend, config.frontend ?? []) : "";
|
|
8956
10405
|
const authSetupInstructions = getAuthSetupInstructions(config.auth, backend, config.frontend ?? []);
|
|
8957
10406
|
const polarInstructions = config.payments === "polar" ? getPolarInstructions(backend, packageManager) : "";
|
|
10407
|
+
const revenueCatInstructions = config.payments === "revenuecat" ? getRevenueCatInstructions(backend, packageManager) : "";
|
|
8958
10408
|
const paymentSetupInstructions = getPaymentSetupInstructions(config.payments, backend);
|
|
8959
10409
|
const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
|
|
8960
10410
|
const vercelDeployInstructions = getVercelDeployInstructions(webDeploy, serverDeploy, backend);
|
|
@@ -9032,6 +10482,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
9032
10482
|
if (authSetupInstructions) output += `\n${authSetupInstructions.trim()}\n`;
|
|
9033
10483
|
if (betterAuthConvexInstructions) output += `\n${betterAuthConvexInstructions.trim()}\n`;
|
|
9034
10484
|
if (polarInstructions) output += `\n${polarInstructions.trim()}\n`;
|
|
10485
|
+
if (revenueCatInstructions) output += `\n${revenueCatInstructions.trim()}\n`;
|
|
9035
10486
|
if (paymentSetupInstructions) output += `\n${paymentSetupInstructions.trim()}\n`;
|
|
9036
10487
|
if (noOrmWarning) output += `\n${noOrmWarning.trim()}\n`;
|
|
9037
10488
|
if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
|
|
@@ -9152,6 +10603,9 @@ function getPaymentSetupInstructions(payments, backend) {
|
|
|
9152
10603
|
if (payments === "lemon-squeezy") return `${pc.bold("Lemon Squeezy Setup:")}\n${pc.cyan("•")} Get API key from ${pc.underline("https://app.lemonsqueezy.com/settings/api")}\n${pc.cyan("•")} Set ${pc.white("LEMONSQUEEZY_API_KEY")} and ${pc.white("LEMONSQUEEZY_STORE_ID")} in ${pc.white(envPath)}`;
|
|
9153
10604
|
if (payments === "paddle") return `${pc.bold("Paddle Setup:")}\n${pc.cyan("•")} Get API keys from ${pc.underline("https://vendors.paddle.com")}\n${pc.cyan("•")} Set ${pc.white("PADDLE_API_KEY")} and ${pc.white("PADDLE_WEBHOOK_SECRET")} in ${pc.white(envPath)}`;
|
|
9154
10605
|
if (payments === "dodo") return `${pc.bold("Dodo Payments Setup:")}\n${pc.cyan("•")} Get API key from ${pc.underline("https://app.dodopayments.com")}\n${pc.cyan("•")} Set ${pc.white("DODO_PAYMENTS_API_KEY")} and ${pc.white("DODO_PAYMENTS_WEBHOOK_SECRET")} in ${pc.white(envPath)}`;
|
|
10606
|
+
if (payments === "creem") return `${pc.bold("Creem Setup:")}\n${pc.cyan("•")} Get your API key from ${pc.underline("https://docs.creem.io")} (Developers > API Keys)\n${pc.cyan("•")} Set ${pc.white("CREEM_API_KEY")}, ${pc.white("CREEM_WEBHOOK_SECRET")}, and ${pc.white("CREEM_ENVIRONMENT")} (test|prod) in ${pc.white(envPath)}`;
|
|
10607
|
+
if (payments === "autumn") return `${pc.bold("Autumn Setup:")}\n${pc.cyan("•")} Sign up at ${pc.underline("https://useautumn.com")} and connect Stripe\n${pc.cyan("•")} Set ${pc.white("AUTUMN_SECRET_KEY")} in ${pc.white(envPath)} and mount handleAutumnRequest at ${pc.white("/api/autumn/*")}\n${pc.cyan("•")} Define plans/features with ${pc.white("npx atmn@latest")} (Autumn is webhookless)`;
|
|
10608
|
+
if (payments === "commet") return `${pc.bold("Commet Setup:")}\n${pc.cyan("•")} Get your API key from ${pc.underline("https://commet.co")} (Settings > API Keys)\n${pc.cyan("•")} Set ${pc.white("COMMET_API_KEY")} and ${pc.white("COMMET_WEBHOOK_SECRET")} in ${pc.white(envPath)}`;
|
|
9155
10609
|
return "";
|
|
9156
10610
|
}
|
|
9157
10611
|
function getBetterAuthConvexInstructions(hasWeb, webPort, packageManager) {
|
|
@@ -9166,6 +10620,14 @@ function getPolarInstructions(backend, packageManager) {
|
|
|
9166
10620
|
const envPath = backend === "self" ? "apps/web/.env" : "apps/server/.env";
|
|
9167
10621
|
return `${pc.bold("Polar Payments Setup:")}\n${pc.cyan("•")} Get access token & product ID from ${pc.underline("https://sandbox.polar.sh/")}\n${pc.cyan("•")} Set POLAR_ACCESS_TOKEN in ${envPath}`;
|
|
9168
10622
|
}
|
|
10623
|
+
function getRevenueCatInstructions(backend, packageManager) {
|
|
10624
|
+
const base = `${pc.bold("RevenueCat Payments Setup:")}\n${pc.cyan("•")} Create a project, entitlement, and offering in ${pc.underline("https://app.revenuecat.com/")}\n${pc.cyan("•")} Set the public SDK keys in ${pc.white("apps/native/.env")}:\n${pc.white(" EXPO_PUBLIC_REVENUECAT_IOS_KEY=appl_your_ios_key")}\n${pc.white(" EXPO_PUBLIC_REVENUECAT_ANDROID_KEY=goog_your_android_key")}\n${pc.white(" EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID=pro")}`;
|
|
10625
|
+
if (backend === "convex") {
|
|
10626
|
+
const cmd = packageManager === "npm" ? "npx" : packageManager;
|
|
10627
|
+
return `${base}\n${pc.cyan("•")} Set the webhook secret (min 32 chars) from ${pc.white("packages/backend")}:\n${pc.white(" cd packages/backend")}\n${pc.white(` ${cmd} convex env set REVENUECAT_WEBHOOK_AUTH your_webhook_secret`)}\n${pc.cyan("•")} Configure a RevenueCat webhook to ${pc.white("https://<your-convex-site-url>/webhooks/revenuecat")} using the same value as the Authorization header`;
|
|
10628
|
+
}
|
|
10629
|
+
return base;
|
|
10630
|
+
}
|
|
9169
10631
|
function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend) {
|
|
9170
10632
|
const instructions = [];
|
|
9171
10633
|
const isBackendSelf = backend === "self";
|
|
@@ -9596,6 +11058,7 @@ async function createProject(options, cliInput = {}) {
|
|
|
9596
11058
|
await applyDependencyVersionChannel(projectDir, options.versionChannel);
|
|
9597
11059
|
await writeBtsConfig(options);
|
|
9598
11060
|
await formatProject(projectDir);
|
|
11061
|
+
await recordScaffoldManifest(projectDir);
|
|
9599
11062
|
if (!isSilent()) log.success("Project template successfully scaffolded!");
|
|
9600
11063
|
if (options.install && (options.ecosystem === "typescript" || options.ecosystem === "react-native")) {
|
|
9601
11064
|
const result$1 = await installDependencies({
|
|
@@ -9637,11 +11100,10 @@ async function createProject(options, cliInput = {}) {
|
|
|
9637
11100
|
await rollbackPartialProject(projectDir, dirHadContentBefore);
|
|
9638
11101
|
if (error instanceof Error) {
|
|
9639
11102
|
if (!isSilent()) console.error(error.stack);
|
|
9640
|
-
|
|
9641
|
-
} else {
|
|
9642
|
-
if (!isSilent()) console.error(error);
|
|
9643
|
-
exitWithError(`An unexpected error occurred: ${String(error)}`);
|
|
11103
|
+
throw new CLIError(`Error during project creation: ${error.message}`);
|
|
9644
11104
|
}
|
|
11105
|
+
if (!isSilent()) console.error(error);
|
|
11106
|
+
throw new CLIError(`An unexpected error occurred: ${String(error)}`);
|
|
9645
11107
|
}
|
|
9646
11108
|
}
|
|
9647
11109
|
/**
|
|
@@ -9685,6 +11147,70 @@ async function ensurePackageManagerProjectFiles(projectDir, packageManager) {
|
|
|
9685
11147
|
|
|
9686
11148
|
//#endregion
|
|
9687
11149
|
//#region src/helpers/core/command-handlers.ts
|
|
11150
|
+
const NON_STACK_CREATE_OPTION_KEYS = new Set([
|
|
11151
|
+
"template",
|
|
11152
|
+
"fromHistory",
|
|
11153
|
+
"config",
|
|
11154
|
+
"yes",
|
|
11155
|
+
"yolo",
|
|
11156
|
+
"manualDb",
|
|
11157
|
+
"part",
|
|
11158
|
+
"verbose",
|
|
11159
|
+
"dryRun",
|
|
11160
|
+
"verify",
|
|
11161
|
+
"versionChannel",
|
|
11162
|
+
"directoryConflict",
|
|
11163
|
+
"renderTitle",
|
|
11164
|
+
"disableAnalytics"
|
|
11165
|
+
]);
|
|
11166
|
+
const CREATE_STACK_FLAG_KEYS = new Set(Object.keys(CreateCommandOptionsSchema.shape).filter((key) => !NON_STACK_CREATE_OPTION_KEYS.has(key)));
|
|
11167
|
+
function hasCreateStackFlags(input) {
|
|
11168
|
+
return Object.entries(input).some(([key, value]) => {
|
|
11169
|
+
if (value === void 0) return false;
|
|
11170
|
+
if (key === "template" && value === "none") return false;
|
|
11171
|
+
return CREATE_STACK_FLAG_KEYS.has(key);
|
|
11172
|
+
});
|
|
11173
|
+
}
|
|
11174
|
+
function shouldShowBuilderRecommendationPrompt({ input, hasConfigBase, environment = {} }) {
|
|
11175
|
+
if (environment.skipBuilderPrompt === "1") return false;
|
|
11176
|
+
if (!canPromptInteractively({
|
|
11177
|
+
silent: environment.silent,
|
|
11178
|
+
stdinIsTTY: environment.stdinIsTTY,
|
|
11179
|
+
stdoutIsTTY: environment.stdoutIsTTY,
|
|
11180
|
+
ci: environment.ci
|
|
11181
|
+
})) return false;
|
|
11182
|
+
if (input.yes || input.yolo || input.manualDb || input.dryRun || input.part?.length || hasConfigBase || input.config || input.fromHistory || input.template && input.template !== "none") return false;
|
|
11183
|
+
if (hasCreateStackFlags(input)) return false;
|
|
11184
|
+
if (environment.forceBuilderPrompt === "1") return true;
|
|
11185
|
+
return Boolean(environment.npmConfigUserAgent);
|
|
11186
|
+
}
|
|
11187
|
+
async function showBuilderRecommendationPrompt() {
|
|
11188
|
+
note(`The Web Builder walks the full stack visually — every option, live compatibility checks — and hands you back a single command to run.\n\n${BUILDER_URL}`, "Prefer a visual builder?");
|
|
11189
|
+
const response = await navigableSelect({
|
|
11190
|
+
message: "How would you like to continue?",
|
|
11191
|
+
options: [{
|
|
11192
|
+
value: "open",
|
|
11193
|
+
label: "Open the Web Builder",
|
|
11194
|
+
hint: "recommended — opens in your browser"
|
|
11195
|
+
}, {
|
|
11196
|
+
value: "continue",
|
|
11197
|
+
label: "Continue in the CLI"
|
|
11198
|
+
}],
|
|
11199
|
+
initialValue: "open"
|
|
11200
|
+
});
|
|
11201
|
+
if (isCancel$1(response) || isGoBack(response)) return exitCancelled("Operation cancelled");
|
|
11202
|
+
if (response === "open") {
|
|
11203
|
+
try {
|
|
11204
|
+
await openUrl(BUILDER_URL);
|
|
11205
|
+
log.success(pc.blue("Opened Web Builder in your browser."));
|
|
11206
|
+
} catch {
|
|
11207
|
+
log.message(`Please visit ${BUILDER_URL}`);
|
|
11208
|
+
}
|
|
11209
|
+
outro(pc.magenta("Web Builder is ready when you are."));
|
|
11210
|
+
return "opened";
|
|
11211
|
+
}
|
|
11212
|
+
return "continue";
|
|
11213
|
+
}
|
|
9688
11214
|
function getYesBaseConfig(flagConfig) {
|
|
9689
11215
|
const baseConfig = getDefaultConfig();
|
|
9690
11216
|
if (flagConfig.ecosystem !== "react-native") return baseConfig;
|
|
@@ -9741,6 +11267,7 @@ async function createProjectHandler(input, options = {}) {
|
|
|
9741
11267
|
return runWithContextAsync({ silent }, async () => {
|
|
9742
11268
|
const startTime = Date.now();
|
|
9743
11269
|
const timeScaffolded = (/* @__PURE__ */ new Date()).toISOString();
|
|
11270
|
+
let telemetrySource = silent ? "programmatic" : "cli-interactive";
|
|
9744
11271
|
try {
|
|
9745
11272
|
if (!isSilent() && input.renderTitle !== false) renderTitle();
|
|
9746
11273
|
if (!isSilent()) intro(pc.magenta("Creating a new Better Fullstack project"));
|
|
@@ -9748,6 +11275,17 @@ async function createProjectHandler(input, options = {}) {
|
|
|
9748
11275
|
if (!isSilent() && input.yolo) consola.fatal("YOLO mode enabled - skipping checks. Things may break!");
|
|
9749
11276
|
const configBase = await resolveCreateConfigBase(input);
|
|
9750
11277
|
const hasConfigBase = configBase !== void 0;
|
|
11278
|
+
if (shouldShowBuilderRecommendationPrompt({
|
|
11279
|
+
input,
|
|
11280
|
+
hasConfigBase,
|
|
11281
|
+
environment: {
|
|
11282
|
+
npmConfigUserAgent: process.env.npm_config_user_agent,
|
|
11283
|
+
forceBuilderPrompt: process.env.BFS_FORCE_BUILDER_PROMPT,
|
|
11284
|
+
skipBuilderPrompt: process.env.BFS_SKIP_BUILDER_PROMPT
|
|
11285
|
+
}
|
|
11286
|
+
})) {
|
|
11287
|
+
if (await showBuilderRecommendationPrompt() === "opened") return;
|
|
11288
|
+
}
|
|
9751
11289
|
if (hasConfigBase && !isSilent()) log.info(pc.cyan(input.config ? `Using stack from config file: ${input.config}` : `Using stack from history entry #${input.fromHistory}`));
|
|
9752
11290
|
const useDefaultsForName = Boolean(input.yes) || hasConfigBase;
|
|
9753
11291
|
let currentPathInput;
|
|
@@ -9960,6 +11498,7 @@ async function createProjectHandler(input, options = {}) {
|
|
|
9960
11498
|
const { validatePreflightConfig } = await import("@better-fullstack/template-generator");
|
|
9961
11499
|
let config;
|
|
9962
11500
|
if (cliInput.yes || cliInput.part?.length || hasConfigBase) {
|
|
11501
|
+
if (!silent) telemetrySource = "cli-flags";
|
|
9963
11502
|
const flagConfig = processProvidedFlagsWithoutValidation(cliInput, finalBaseName);
|
|
9964
11503
|
config = {
|
|
9965
11504
|
...getYesBaseConfig(flagConfig),
|
|
@@ -10039,7 +11578,12 @@ async function createProjectHandler(input, options = {}) {
|
|
|
10039
11578
|
if (cliInput.verify ?? input.verify) await runGeneratedChecks(config);
|
|
10040
11579
|
const reproducibleCommand = generateReproducibleCommand(config);
|
|
10041
11580
|
if (!isSilent()) log.success(pc.blue(`You can reproduce this setup with the following command:\n${reproducibleCommand}`));
|
|
10042
|
-
await trackProjectCreation(config, input.disableAnalytics
|
|
11581
|
+
await trackProjectCreation(config, input.disableAnalytics, {
|
|
11582
|
+
source: telemetrySource,
|
|
11583
|
+
success: true,
|
|
11584
|
+
setupFailures: setupFailures.map((failure) => failure.step),
|
|
11585
|
+
durationMs: Date.now() - startTime
|
|
11586
|
+
});
|
|
10043
11587
|
try {
|
|
10044
11588
|
await addToHistory(config, reproducibleCommand);
|
|
10045
11589
|
} catch (historyError) {
|
|
@@ -10079,6 +11623,12 @@ async function createProjectHandler(input, options = {}) {
|
|
|
10079
11623
|
};
|
|
10080
11624
|
return;
|
|
10081
11625
|
}
|
|
11626
|
+
await trackEvent("project_created", {}, {
|
|
11627
|
+
source: telemetrySource,
|
|
11628
|
+
success: false,
|
|
11629
|
+
errorName: error instanceof Error ? error.name : "UnknownError",
|
|
11630
|
+
durationMs: Date.now() - startTime
|
|
11631
|
+
}, input.disableAnalytics);
|
|
10082
11632
|
if (error instanceof CLIError) {
|
|
10083
11633
|
if (isSilent()) return {
|
|
10084
11634
|
success: false,
|
|
@@ -10133,21 +11683,6 @@ async function handleDirectoryConflictProgrammatically(currentPathInput, strateg
|
|
|
10133
11683
|
}
|
|
10134
11684
|
}
|
|
10135
11685
|
|
|
10136
|
-
//#endregion
|
|
10137
|
-
//#region src/utils/open-url.ts
|
|
10138
|
-
async function openUrl(url) {
|
|
10139
|
-
const platform = process.platform;
|
|
10140
|
-
try {
|
|
10141
|
-
if (platform === "darwin") await $({ stdio: "ignore" })`open ${url}`;
|
|
10142
|
-
else if (platform === "win32") {
|
|
10143
|
-
const escapedUrl = url.replace(/&/g, "^&");
|
|
10144
|
-
await $({ stdio: "ignore" })`cmd /c start "" ${escapedUrl}`;
|
|
10145
|
-
} else await $({ stdio: "ignore" })`xdg-open ${url}`;
|
|
10146
|
-
} catch {
|
|
10147
|
-
log.message(`Please open ${url} in your browser.`);
|
|
10148
|
-
}
|
|
10149
|
-
}
|
|
10150
|
-
|
|
10151
11686
|
//#endregion
|
|
10152
11687
|
//#region src/utils/sponsors.ts
|
|
10153
11688
|
const SPONSORS_JSON_URL = "https://better-fullstack-web.vercel.app/sponsors.json";
|
|
@@ -10204,8 +11739,12 @@ const AddCommandInputSchema = CreateCommandOptionsSchema.omit({
|
|
|
10204
11739
|
directoryConflict: true,
|
|
10205
11740
|
renderTitle: true,
|
|
10206
11741
|
disableAnalytics: true,
|
|
10207
|
-
manualDb: true
|
|
10208
|
-
|
|
11742
|
+
manualDb: true,
|
|
11743
|
+
workspaceShape: true
|
|
11744
|
+
}).extend({
|
|
11745
|
+
projectDir: z.string().optional().describe("Project directory (defaults to current)"),
|
|
11746
|
+
acknowledgeArchitectureChange: z.boolean().optional().describe("Acknowledge that this update replaces an existing database/orm/auth/api/backend/runtime choice (data/schema migration required)")
|
|
11747
|
+
});
|
|
10209
11748
|
const ProjectCheckInputSchema = z.tuple([z.string().optional().describe("Project directory to diagnose (defaults to current directory)"), z.object({
|
|
10210
11749
|
skipChecks: z.boolean().optional().default(false).describe("Skip the ecosystem build/type checks (config + deps + env only)"),
|
|
10211
11750
|
json: z.boolean().optional().default(false).describe("Output the diagnosis as JSON")
|
|
@@ -10242,7 +11781,6 @@ const router = os.router({
|
|
|
10242
11781
|
}
|
|
10243
11782
|
}),
|
|
10244
11783
|
builder: os.meta({ description: "Open the interactive web-based stack builder at better-fullstack.dev" }).handler(async () => {
|
|
10245
|
-
const BUILDER_URL = "https://better-fullstack-web.vercel.app/new";
|
|
10246
11784
|
try {
|
|
10247
11785
|
await openUrl(BUILDER_URL);
|
|
10248
11786
|
log.success(pc.blue("Opened builder in your default browser."));
|
|
@@ -10251,7 +11789,7 @@ const router = os.router({
|
|
|
10251
11789
|
}
|
|
10252
11790
|
}),
|
|
10253
11791
|
add: os.meta({ description: "Add addons, deploy targets, or stack capabilities to an existing Better Fullstack project using its bts.jsonc config" }).input(AddCommandInputSchema).handler(async ({ input }) => {
|
|
10254
|
-
const { addHandler } = await import("./add-handler-
|
|
11792
|
+
const { addHandler } = await import("./add-handler-ztNjzoMN.mjs");
|
|
10255
11793
|
await addHandler(input);
|
|
10256
11794
|
}),
|
|
10257
11795
|
history: os.meta({ description: "Show history of scaffolded projects with reproducible commands" }).input(z.object({
|
|
@@ -10279,7 +11817,7 @@ const router = os.router({
|
|
|
10279
11817
|
ecosystem: z.string().optional().describe("Filter by ecosystem (effect, tanstack, prisma, etc.)"),
|
|
10280
11818
|
"list-ecosystems": z.boolean().default(false).describe("List available ecosystems")
|
|
10281
11819
|
})).handler(async ({ input }) => {
|
|
10282
|
-
const { updateDepsHandler, showEcosystems } = await import("./update-deps-
|
|
11820
|
+
const { updateDepsHandler, showEcosystems } = await import("./update-deps-aD-iQw4U.mjs");
|
|
10283
11821
|
if (input["list-ecosystems"]) {
|
|
10284
11822
|
showEcosystems();
|
|
10285
11823
|
return;
|
|
@@ -10291,13 +11829,63 @@ const router = os.router({
|
|
|
10291
11829
|
ecosystem: input.ecosystem
|
|
10292
11830
|
});
|
|
10293
11831
|
}),
|
|
11832
|
+
gen: os.meta({ description: "Generate in-project code for an existing Better Fullstack project (e.g. `gen resource <name>` / `gen route <name>` for a new trpc/orpc API resource router)" }).input(z.tuple([
|
|
11833
|
+
z.enum(["resource", "route"]).describe("What to generate: resource (alias: route)"),
|
|
11834
|
+
z.string().describe("Name of the resource/route (e.g. post)"),
|
|
11835
|
+
z.object({
|
|
11836
|
+
dir: z.string().optional().describe("Project directory (defaults to current)"),
|
|
11837
|
+
dryRun: z.boolean().default(false).describe("Print the planned changes without writing any files")
|
|
11838
|
+
})
|
|
11839
|
+
])).handler(async ({ input }) => {
|
|
11840
|
+
const [kind, name, options] = input;
|
|
11841
|
+
const { genCommand } = await import("./gen-CCClL7Ve.mjs");
|
|
11842
|
+
await genCommand({
|
|
11843
|
+
kind,
|
|
11844
|
+
name,
|
|
11845
|
+
dir: options.dir,
|
|
11846
|
+
dryRun: options.dryRun
|
|
11847
|
+
});
|
|
11848
|
+
}),
|
|
11849
|
+
registry: os.meta({ description: "Manage community/private capability packs for an existing Better Fullstack project (`registry add <source>` installs a pack from a local path or file:// URL; `registry list` shows installed packs)" }).input(z.tuple([
|
|
11850
|
+
z.enum(["add", "list"]).optional().default("list").describe("Action to perform: add (install a pack) or list (default)"),
|
|
11851
|
+
z.string().optional().describe("Pack source: a local path or file:// URL (required for `add`)"),
|
|
11852
|
+
z.object({
|
|
11853
|
+
projectDir: z.string().optional().describe("Project directory (defaults to current)"),
|
|
11854
|
+
json: z.boolean().optional().default(false).describe("Output the result as JSON"),
|
|
11855
|
+
dryRun: z.boolean().optional().default(false).describe("Preview the install without writing any files")
|
|
11856
|
+
})
|
|
11857
|
+
])).handler(async ({ input }) => {
|
|
11858
|
+
const [action, source, options] = input;
|
|
11859
|
+
const { registryHandler } = await import("./registry-DSf2CEaU.mjs");
|
|
11860
|
+
await registryHandler({
|
|
11861
|
+
action,
|
|
11862
|
+
source,
|
|
11863
|
+
projectDir: options.projectDir,
|
|
11864
|
+
json: options.json,
|
|
11865
|
+
dryRun: options.dryRun
|
|
11866
|
+
});
|
|
11867
|
+
}),
|
|
11868
|
+
update: os.meta({ description: "Re-apply the current bundled templates to an existing Better Fullstack project, classifying template drift vs. your local edits from the bts.lock.json scaffold baseline. Default is a dry-run plan; `--apply` writes safe drift patches + new files. Distinct from the maintainer `update-deps` command." }).input(z.tuple([z.string().optional().describe("Project directory to update (defaults to current directory)"), z.object({
|
|
11869
|
+
dryRun: z.boolean().optional().default(false).describe("Preview the plan without writing (default behavior)"),
|
|
11870
|
+
apply: z.boolean().optional().default(false).describe("Write safe template-drift patches and new files, refreshing the baseline"),
|
|
11871
|
+
check: z.boolean().optional().default(false).describe("Exit non-zero when actionable template drift exists (CI gate)"),
|
|
11872
|
+
json: z.boolean().optional().default(false).describe("Output the plan as JSON"),
|
|
11873
|
+
recordBaseline: z.boolean().optional().default(false).describe("Adopt the current on-disk state as the scaffold baseline (for projects created before the update engine)")
|
|
11874
|
+
})])).handler(async ({ input }) => {
|
|
11875
|
+
const [projectDir, options] = input;
|
|
11876
|
+
const { updateCommand } = await import("./update-DJ8CI5KW.mjs");
|
|
11877
|
+
await updateCommand({
|
|
11878
|
+
projectDir,
|
|
11879
|
+
...options
|
|
11880
|
+
});
|
|
11881
|
+
}),
|
|
10294
11882
|
mcp: os.meta({ description: "Start the Better Fullstack MCP server so AI agents can inspect the schema, plan stacks, and scaffold projects over stdio" }).handler(async () => {
|
|
10295
11883
|
log.message("MCP server is started via the 'mcp' subcommand intercepted in cli.ts.");
|
|
10296
11884
|
log.message("Run: create-better-fullstack mcp");
|
|
10297
11885
|
}),
|
|
10298
11886
|
doctor: os.meta({ description: "Diagnose a scaffolded Better Fullstack project: verify its bts.jsonc, installed dependencies, required env vars, and run ecosystem build/type checks" }).input(ProjectCheckInputSchema).handler(async ({ input }) => {
|
|
10299
11887
|
const [projectDir, options] = input;
|
|
10300
|
-
const { doctorCommand } = await import("./doctor-
|
|
11888
|
+
const { doctorCommand } = await import("./doctor-a4ca3SMd.mjs");
|
|
10301
11889
|
await doctorCommand({
|
|
10302
11890
|
projectDir,
|
|
10303
11891
|
...options
|
|
@@ -10305,11 +11893,28 @@ const router = os.router({
|
|
|
10305
11893
|
}),
|
|
10306
11894
|
check: os.meta({ description: "Check a scaffolded Better Fullstack project for config, dependency, env, and generated build/type drift" }).input(ProjectCheckInputSchema).handler(async ({ input }) => {
|
|
10307
11895
|
const [projectDir, options] = input;
|
|
10308
|
-
const { doctorCommand } = await import("./doctor-
|
|
11896
|
+
const { doctorCommand } = await import("./doctor-a4ca3SMd.mjs");
|
|
10309
11897
|
await doctorCommand({
|
|
10310
11898
|
projectDir,
|
|
10311
11899
|
...options
|
|
10312
11900
|
});
|
|
11901
|
+
}),
|
|
11902
|
+
recommend: os.meta({ description: "Recommend a stack from a natural-language brief (prompt-to-stack): prints the suggested config, the rationale, and a ready-to-run create command" }).input(z.object({
|
|
11903
|
+
brief: z.string().min(1).describe("Natural-language description, e.g. \"a SaaS with Postgres, auth and payments\""),
|
|
11904
|
+
ecosystem: z.string().optional().describe("Force an ecosystem (typescript, react-native, rust, go, python, java, ...)"),
|
|
11905
|
+
json: z.boolean().default(false).describe("Output the recommendation as JSON")
|
|
11906
|
+
})).handler(async ({ input }) => {
|
|
11907
|
+
const { recommendStackFromBrief } = await import("./mcp-492OkjcS.mjs");
|
|
11908
|
+
const result = recommendStackFromBrief(input.brief, input.ecosystem);
|
|
11909
|
+
if (input.json) {
|
|
11910
|
+
log.message(JSON.stringify(result, null, 2));
|
|
11911
|
+
return;
|
|
11912
|
+
}
|
|
11913
|
+
log.message("Recommended stack:");
|
|
11914
|
+
for (const line of result.rationale) log.message(` • ${line}`);
|
|
11915
|
+
log.message(`\nConfig: ${JSON.stringify(result.input)}`);
|
|
11916
|
+
if (result.matchedPreset) log.message(`Nearest preset: ${result.matchedPreset}`);
|
|
11917
|
+
log.message("\nReview, then scaffold with: create-better-fullstack create <name> [flags]");
|
|
10313
11918
|
})
|
|
10314
11919
|
});
|
|
10315
11920
|
const caller = createRouterClient(router, { context: {} });
|
|
@@ -10374,9 +11979,12 @@ async function docs() {
|
|
|
10374
11979
|
async function builder() {
|
|
10375
11980
|
return caller.builder();
|
|
10376
11981
|
}
|
|
10377
|
-
async function add(input) {
|
|
10378
|
-
const { addHandler } = await import("./add-handler-
|
|
10379
|
-
return addHandler(input, {
|
|
11982
|
+
async function add(input, options) {
|
|
11983
|
+
const { addHandler } = await import("./add-handler-ztNjzoMN.mjs");
|
|
11984
|
+
return addHandler(input, {
|
|
11985
|
+
silent: true,
|
|
11986
|
+
telemetrySource: options?.telemetrySource ?? "programmatic"
|
|
11987
|
+
});
|
|
10380
11988
|
}
|
|
10381
11989
|
async function history(options) {
|
|
10382
11990
|
return caller.history({
|
|
@@ -10400,6 +12008,15 @@ async function check(projectDir, options) {
|
|
|
10400
12008
|
json: options?.json ?? false
|
|
10401
12009
|
}]);
|
|
10402
12010
|
}
|
|
12011
|
+
async function update(projectDir, options) {
|
|
12012
|
+
return caller.update([projectDir, {
|
|
12013
|
+
dryRun: options?.dryRun ?? false,
|
|
12014
|
+
apply: options?.apply ?? false,
|
|
12015
|
+
check: options?.check ?? false,
|
|
12016
|
+
json: options?.json ?? false,
|
|
12017
|
+
recordBaseline: options?.recordBaseline ?? false
|
|
12018
|
+
}]);
|
|
12019
|
+
}
|
|
10403
12020
|
|
|
10404
12021
|
//#endregion
|
|
10405
|
-
export { createBtsCli as a, history as c, telemetry as d, create as i, router as l, builder as n, docs as o, check as r, doctor as s, add as t, sponsors as u };
|
|
12022
|
+
export { createBtsCli as a, history as c, telemetry as d, update as f, create as i, router as l, builder as n, docs as o, check as r, doctor as s, add as t, sponsors as u };
|