create-better-fullstack 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/{add-handler-CE3XIs3y.mjs → add-handler-z4NCxoq6.mjs} +7 -6
- package/dist/addons-setup-COE1e1db.mjs +7 -0
- package/dist/{addons-setup-DR924M7b.mjs → addons-setup-DKtiNexf.mjs} +1 -1
- package/dist/{analytics-BXlOG6u6.mjs → analytics-BD8hZvIj.mjs} +1 -1
- package/dist/{bts-config-B_HhcMXL.mjs → bts-config-Bwd6GB7B.mjs} +29 -0
- package/dist/cli.mjs +2 -2
- package/dist/command-exists-DtX9ldL8.mjs +15 -0
- package/dist/{config-processing-DJisMeW-.mjs → config-processing-B-RT_mVE.mjs} +16 -3
- package/dist/{doctor-Cc7sLuow.mjs → doctor-LmNs-hDr.mjs} +4 -3
- package/dist/{file-formatter-BgbfpYf4.mjs → file-formatter-DxF56-mO.mjs} +109 -3
- package/dist/{gen-BZ0QCxCC.mjs → gen-CQfQU0uZ.mjs} +1 -1
- package/dist/{generated-checks-CbioGjCh.mjs → generated-checks-BUcI5VM2.mjs} +55 -22
- package/dist/index.d.mts +292 -40
- package/dist/index.mjs +19 -9
- package/dist/{install-dependencies-D__bmW4k.mjs → install-dependencies-CJiUklm3.mjs} +49 -8
- package/dist/{mcp-DNKAo8nO.mjs → mcp-BBammItk.mjs} +5 -5
- package/dist/mcp-entry.mjs +47 -19
- package/dist/{registry-Cm3D45oT.mjs → registry-D0JfLCoH.mjs} +1 -1
- package/dist/{run-DmN7QRt5.mjs → run-BAIeghcU.mjs} +819 -52
- package/dist/run-CAl4L4uU.mjs +16 -0
- package/dist/{scaffold-manifest-ByKtMhTd.mjs → scaffold-manifest-CQwvyttq.mjs} +1 -1
- package/dist/{update-B270pWHc.mjs → update-CnrBdWrh.mjs} +3 -3
- package/package.json +21 -4
- package/dist/addons-setup-Du2VSv8V.mjs +0 -7
- package/dist/run-C_S7ujfY.mjs +0 -15
- /package/dist/{scaffold-manifest-CNFz-lmH.mjs → scaffold-manifest-Dr3Anmlf.mjs} +0 -0
- /package/dist/{update-deps-aD-iQw4U.mjs → update-deps-G3FgqBlW.mjs} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Better Fullstack
|
|
2
2
|
|
|
3
|
-
Scaffold
|
|
3
|
+
Scaffold configurable fullstack apps across web, mobile, and backend ecosystems — the CLI wires your selected stack together.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -31,8 +31,8 @@ Configure your stack visually — pick every option from a UI, preview your choi
|
|
|
31
31
|
|
|
32
32
|
## Features
|
|
33
33
|
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
34
|
+
- **Broad stack catalog** — frontend, backend, database, auth, payments, AI, DevOps, and more
|
|
35
|
+
- **Multi-ecosystem projects** — compose web, mobile, and backend stacks across supported ecosystems
|
|
36
36
|
- **Visual builder** — configure your stack in the browser
|
|
37
37
|
- **Wired for you** — every picked integration is preconfigured and working out of the box
|
|
38
38
|
|
|
@@ -42,7 +42,7 @@ Configure your stack visually — pick every option from a UI, preview your choi
|
|
|
42
42
|
--yes # Accept all defaults
|
|
43
43
|
--yolo # Scaffold a random stack — good for exploring
|
|
44
44
|
--template <name> # Use a preset (t3, mern, pern, uniwind)
|
|
45
|
-
--ecosystem <lang> #
|
|
45
|
+
--ecosystem <lang> # Choose the primary project ecosystem
|
|
46
46
|
--part <binding> # Add a multi-ecosystem stack part, e.g. frontend:typescript:next
|
|
47
47
|
--version-channel # Dependency channel: stable, latest, beta
|
|
48
48
|
--no-git # Skip git initialization
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as updateBtsConfig, r as readBtsConfig, v as getDefaultConfig } from "./bts-config-
|
|
2
|
+
import { a as updateBtsConfig, r as readBtsConfig, v as getDefaultConfig } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
4
|
import { c as isSilent, l as runWithContextAsync, n as UserCancelledError, t as CLIError } from "./errors-ns_o2OKg.mjs";
|
|
5
5
|
import "./prompt-environment-BR0Kkw2W.mjs";
|
|
6
|
-
import { i as trackEvent, r as maybeShowTelemetryNotice } from "./analytics-
|
|
7
|
-
import "./file-formatter-
|
|
8
|
-
import { c as applyDependencyVersionChannel, t as installDependencies, u as getAddonsToAdd } from "./install-dependencies-
|
|
9
|
-
import "./
|
|
10
|
-
import
|
|
6
|
+
import { i as trackEvent, r as maybeShowTelemetryNotice } from "./analytics-BD8hZvIj.mjs";
|
|
7
|
+
import "./file-formatter-DxF56-mO.mjs";
|
|
8
|
+
import { c as applyDependencyVersionChannel, t as installDependencies, u as getAddonsToAdd } from "./install-dependencies-CJiUklm3.mjs";
|
|
9
|
+
import "./command-exists-DtX9ldL8.mjs";
|
|
10
|
+
import "./scaffold-manifest-Dr3Anmlf.mjs";
|
|
11
|
+
import { t as setupAddons } from "./addons-setup-DKtiNexf.mjs";
|
|
11
12
|
import { p as planStackUpdate, s as applyStackUpdate } from "./mcp-entry.mjs";
|
|
12
13
|
import { intro, log, outro } from "@clack/prompts";
|
|
13
14
|
import pc from "picocolors";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { r as readBtsConfig } from "./bts-config-
|
|
2
|
+
import { r as readBtsConfig } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
3
|
import { c as isSilent, r as exitCancelled } from "./errors-ns_o2OKg.mjs";
|
|
4
4
|
import { t as canPromptInteractively } from "./prompt-environment-BR0Kkw2W.mjs";
|
|
5
5
|
import { autocompleteMultiselect, group, isCancel, log, multiselect, select, spinner } from "@clack/prompts";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { m as getLatestCLIVersion } from "./bts-config-
|
|
2
|
+
import { m as getLatestCLIVersion } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
3
|
import { t as canPromptInteractively } from "./prompt-environment-BR0Kkw2W.mjs";
|
|
4
4
|
import { log } from "@clack/prompts";
|
|
5
5
|
import pc from "picocolors";
|
|
@@ -40,6 +40,8 @@ function getDefaultConfig() {
|
|
|
40
40
|
pythonAi: [...DEFAULT_CONFIG_BASE.pythonAi],
|
|
41
41
|
javaLibraries: [...DEFAULT_CONFIG_BASE.javaLibraries],
|
|
42
42
|
javaTestingLibraries: [...DEFAULT_CONFIG_BASE.javaTestingLibraries],
|
|
43
|
+
mobileLibraries: [...DEFAULT_CONFIG_BASE.mobileLibraries],
|
|
44
|
+
dotnetLibraries: [...DEFAULT_CONFIG_BASE.dotnetLibraries],
|
|
43
45
|
aiDocs: [...DEFAULT_CONFIG_BASE.aiDocs]
|
|
44
46
|
};
|
|
45
47
|
}
|
|
@@ -301,6 +303,13 @@ function normalizeGraphConfigForPersistence(projectConfig, stackParts) {
|
|
|
301
303
|
normalized.pythonRealtime = "none";
|
|
302
304
|
normalized.pythonObservability = "none";
|
|
303
305
|
normalized.pythonCli = [];
|
|
306
|
+
normalized.pythonCloudSdk = "none";
|
|
307
|
+
normalized.pythonHttpClient = "none";
|
|
308
|
+
normalized.pythonData = [];
|
|
309
|
+
normalized.pythonMedia = "none";
|
|
310
|
+
normalized.pythonServer = "none";
|
|
311
|
+
normalized.pythonPackageManager = "uv";
|
|
312
|
+
normalized.pythonMessageQueue = "none";
|
|
304
313
|
}
|
|
305
314
|
if (!selectedEcosystems.has("go")) {
|
|
306
315
|
normalized.goWebFramework = "none";
|
|
@@ -346,6 +355,7 @@ function normalizeGraphConfigForPersistence(projectConfig, stackParts) {
|
|
|
346
355
|
normalized.dotnetValidation = "none";
|
|
347
356
|
normalized.dotnetCaching = "none";
|
|
348
357
|
normalized.dotnetDeploy = "none";
|
|
358
|
+
normalized.dotnetLibraries = [];
|
|
349
359
|
}
|
|
350
360
|
if (!selectedEcosystems.has("elixir")) {
|
|
351
361
|
normalized.elixirWebFramework = "none";
|
|
@@ -381,6 +391,7 @@ function normalizeGraphConfigForPersistence(projectConfig, stackParts) {
|
|
|
381
391
|
normalized.mobilePush = "none";
|
|
382
392
|
normalized.mobileOTA = "none";
|
|
383
393
|
normalized.mobileDeepLinking = "none";
|
|
394
|
+
normalized.mobileLibraries = [];
|
|
384
395
|
}
|
|
385
396
|
return normalized;
|
|
386
397
|
}
|
|
@@ -497,6 +508,7 @@ function buildBtsConfigForPersistence(projectConfig, metadata = {}) {
|
|
|
497
508
|
mobilePush: persistedConfig.mobilePush,
|
|
498
509
|
mobileOTA: persistedConfig.mobileOTA,
|
|
499
510
|
mobileDeepLinking: persistedConfig.mobileDeepLinking,
|
|
511
|
+
mobileLibraries: persistedConfig.mobileLibraries,
|
|
500
512
|
cms: persistedConfig.cms,
|
|
501
513
|
caching: persistedConfig.caching,
|
|
502
514
|
rateLimit: persistedConfig.rateLimit,
|
|
@@ -532,6 +544,13 @@ function buildBtsConfigForPersistence(projectConfig, metadata = {}) {
|
|
|
532
544
|
pythonRealtime: persistedConfig.pythonRealtime,
|
|
533
545
|
pythonObservability: persistedConfig.pythonObservability,
|
|
534
546
|
pythonCli: persistedConfig.pythonCli,
|
|
547
|
+
pythonCloudSdk: persistedConfig.pythonCloudSdk,
|
|
548
|
+
pythonHttpClient: persistedConfig.pythonHttpClient,
|
|
549
|
+
pythonData: persistedConfig.pythonData,
|
|
550
|
+
pythonMedia: persistedConfig.pythonMedia,
|
|
551
|
+
pythonServer: persistedConfig.pythonServer,
|
|
552
|
+
pythonPackageManager: persistedConfig.pythonPackageManager,
|
|
553
|
+
pythonMessageQueue: persistedConfig.pythonMessageQueue,
|
|
535
554
|
goWebFramework: persistedConfig.goWebFramework,
|
|
536
555
|
goOrm: persistedConfig.goOrm,
|
|
537
556
|
goApi: persistedConfig.goApi,
|
|
@@ -570,6 +589,7 @@ function buildBtsConfigForPersistence(projectConfig, metadata = {}) {
|
|
|
570
589
|
dotnetValidation: persistedConfig.dotnetValidation,
|
|
571
590
|
dotnetCaching: persistedConfig.dotnetCaching,
|
|
572
591
|
dotnetDeploy: persistedConfig.dotnetDeploy,
|
|
592
|
+
dotnetLibraries: persistedConfig.dotnetLibraries,
|
|
573
593
|
elixirWebFramework: persistedConfig.elixirWebFramework,
|
|
574
594
|
elixirOrm: persistedConfig.elixirOrm,
|
|
575
595
|
elixirAuth: persistedConfig.elixirAuth,
|
|
@@ -665,6 +685,7 @@ async function writeBtsConfig(projectConfig, metadata = {}) {
|
|
|
665
685
|
mobilePush: btsConfig.mobilePush,
|
|
666
686
|
mobileOTA: btsConfig.mobileOTA,
|
|
667
687
|
mobileDeepLinking: btsConfig.mobileDeepLinking,
|
|
688
|
+
mobileLibraries: btsConfig.mobileLibraries,
|
|
668
689
|
cms: btsConfig.cms,
|
|
669
690
|
caching: btsConfig.caching,
|
|
670
691
|
rateLimit: btsConfig.rateLimit,
|
|
@@ -700,6 +721,13 @@ async function writeBtsConfig(projectConfig, metadata = {}) {
|
|
|
700
721
|
pythonRealtime: btsConfig.pythonRealtime,
|
|
701
722
|
pythonObservability: btsConfig.pythonObservability,
|
|
702
723
|
pythonCli: btsConfig.pythonCli,
|
|
724
|
+
pythonCloudSdk: btsConfig.pythonCloudSdk,
|
|
725
|
+
pythonHttpClient: btsConfig.pythonHttpClient,
|
|
726
|
+
pythonData: btsConfig.pythonData,
|
|
727
|
+
pythonMedia: btsConfig.pythonMedia,
|
|
728
|
+
pythonServer: btsConfig.pythonServer,
|
|
729
|
+
pythonPackageManager: btsConfig.pythonPackageManager,
|
|
730
|
+
pythonMessageQueue: btsConfig.pythonMessageQueue,
|
|
703
731
|
goWebFramework: btsConfig.goWebFramework,
|
|
704
732
|
goOrm: btsConfig.goOrm,
|
|
705
733
|
goApi: btsConfig.goApi,
|
|
@@ -738,6 +766,7 @@ async function writeBtsConfig(projectConfig, metadata = {}) {
|
|
|
738
766
|
dotnetValidation: btsConfig.dotnetValidation,
|
|
739
767
|
dotnetCaching: btsConfig.dotnetCaching,
|
|
740
768
|
dotnetDeploy: btsConfig.dotnetDeploy,
|
|
769
|
+
dotnetLibraries: btsConfig.dotnetLibraries,
|
|
741
770
|
elixirWebFramework: btsConfig.elixirWebFramework,
|
|
742
771
|
elixirOrm: btsConfig.elixirOrm,
|
|
743
772
|
elixirAuth: btsConfig.elixirAuth,
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
//#region src/cli.ts
|
|
3
|
-
if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-
|
|
4
|
-
else import("./run-
|
|
3
|
+
if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-BBammItk.mjs").then((m) => m.startMcpServer());
|
|
4
|
+
else import("./run-CAl4L4uU.mjs").then((m) => m.createBtsCli().run());
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { $ } from "execa";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/command-exists.ts
|
|
5
|
+
async function commandExists(command) {
|
|
6
|
+
try {
|
|
7
|
+
if (process.platform === "win32") return (await $({ reject: false })`where ${command}`).exitCode === 0;
|
|
8
|
+
return (await $({ reject: false })`which ${command}`).exitCode === 0;
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { commandExists as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { b as types_exports } from "./bts-config-
|
|
2
|
+
import { b as types_exports } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { cliInputToProjectConfigPartial } from "@better-fullstack/types/stack-translation";
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ function getBaseCommand(packageManager) {
|
|
|
13
13
|
default: return "npx create-better-fullstack@latest";
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
function formatArrayFlag(flag, values) {
|
|
16
|
+
function formatArrayFlag(flag, values = []) {
|
|
17
17
|
const normalizedValues = values.filter((value) => value !== "none");
|
|
18
18
|
if (normalizedValues.length === 0) return `--${flag} none`;
|
|
19
19
|
return `--${flag} ${normalizedValues.join(" ")}`;
|
|
@@ -75,7 +75,7 @@ function hasAnyOwnedGraphArrayPart(config, ownerRole, role, ecosystem) {
|
|
|
75
75
|
}
|
|
76
76
|
function appendChangedOwnedGraphArrayFlag(flags, config, ownerRole, role, ecosystem, flag, values, defaultValues) {
|
|
77
77
|
if (hasAnyOwnedGraphArrayPart(config, ownerRole, role, ecosystem)) return;
|
|
78
|
-
appendChangedArrayFlag(flags, flag, values, defaultValues);
|
|
78
|
+
appendChangedArrayFlag(flags, flag, values ?? [], defaultValues);
|
|
79
79
|
}
|
|
80
80
|
function appendChangedArrayFlag(flags, flag, values, defaultValues) {
|
|
81
81
|
if (values.length !== defaultValues.length || values.some((value, index) => value !== defaultValues[index])) flags.push(formatArrayFlag(flag, values));
|
|
@@ -141,6 +141,7 @@ function appendGraphExtraFlags(flags, config) {
|
|
|
141
141
|
appendChangedOwnedGraphStringFlag(flags, config, "mobile", "push", "react-native", "mobile-push", config.mobilePush, "none");
|
|
142
142
|
appendChangedOwnedGraphStringFlag(flags, config, "mobile", "ota", "react-native", "mobile-ota", config.mobileOTA, "none");
|
|
143
143
|
appendChangedOwnedGraphStringFlag(flags, config, "mobile", "deepLinking", "react-native", "mobile-deep-linking", config.mobileDeepLinking, "none");
|
|
144
|
+
appendChangedOwnedGraphArrayFlag(flags, config, "mobile", "libraries", "react-native", "mobile-libraries", config.mobileLibraries, []);
|
|
144
145
|
}
|
|
145
146
|
if (hasGraphPrimaryPart(config, "frontend", "rust")) appendChangedStringFlag(flags, "rust-frontend", config.rustFrontend, "none");
|
|
146
147
|
if (hasGraphPrimaryPart(config, "backend", "rust")) {
|
|
@@ -247,6 +248,7 @@ function getTypeScriptFlags(config) {
|
|
|
247
248
|
flags.push(`--mobile-push ${config.mobilePush}`);
|
|
248
249
|
flags.push(`--mobile-ota ${config.mobileOTA}`);
|
|
249
250
|
flags.push(`--mobile-deep-linking ${config.mobileDeepLinking}`);
|
|
251
|
+
if (config.mobileLibraries) flags.push(formatArrayFlag("mobile-libraries", config.mobileLibraries));
|
|
250
252
|
if (config.addons && config.addons.length > 0) flags.push(`--addons ${config.addons.join(" ")}`);
|
|
251
253
|
else flags.push("--addons none");
|
|
252
254
|
if (config.examples && config.examples.length > 0) flags.push(`--examples ${config.examples.join(" ")}`);
|
|
@@ -269,6 +271,7 @@ function getReactNativeFlags(config) {
|
|
|
269
271
|
flags.push(`--mobile-push ${config.mobilePush}`);
|
|
270
272
|
flags.push(`--mobile-ota ${config.mobileOTA}`);
|
|
271
273
|
flags.push(`--mobile-deep-linking ${config.mobileDeepLinking}`);
|
|
274
|
+
flags.push(formatArrayFlag("mobile-libraries", config.mobileLibraries));
|
|
272
275
|
appendCommonFlags(flags, config);
|
|
273
276
|
return flags;
|
|
274
277
|
}
|
|
@@ -308,6 +311,13 @@ function getPythonFlags(config) {
|
|
|
308
311
|
flags.push(`--python-realtime ${config.pythonRealtime}`);
|
|
309
312
|
flags.push(`--python-observability ${config.pythonObservability}`);
|
|
310
313
|
flags.push(formatArrayFlag("python-cli", config.pythonCli));
|
|
314
|
+
flags.push(`--python-cloud-sdk ${config.pythonCloudSdk}`);
|
|
315
|
+
flags.push(`--python-http-client ${config.pythonHttpClient}`);
|
|
316
|
+
flags.push(formatArrayFlag("python-data", config.pythonData));
|
|
317
|
+
flags.push(`--python-media ${config.pythonMedia}`);
|
|
318
|
+
flags.push(`--python-server ${config.pythonServer}`);
|
|
319
|
+
flags.push(`--python-package-manager ${config.pythonPackageManager}`);
|
|
320
|
+
flags.push(`--python-message-queue ${config.pythonMessageQueue}`);
|
|
311
321
|
appendSharedNonTypeScriptFlags(flags, config);
|
|
312
322
|
appendCommonFlags(flags, config);
|
|
313
323
|
return flags;
|
|
@@ -365,6 +375,7 @@ function getDotnetFlags(config) {
|
|
|
365
375
|
flags.push(`--dotnet-validation ${config.dotnetValidation}`);
|
|
366
376
|
flags.push(`--dotnet-caching ${config.dotnetCaching}`);
|
|
367
377
|
flags.push(`--dotnet-deploy ${config.dotnetDeploy}`);
|
|
378
|
+
if (config.dotnetLibraries) flags.push(formatArrayFlag("dotnet-libraries", config.dotnetLibraries));
|
|
368
379
|
appendCommonFlags(flags, config);
|
|
369
380
|
return flags;
|
|
370
381
|
}
|
|
@@ -562,6 +573,8 @@ function validateArrayOptions(options) {
|
|
|
562
573
|
validateNoneExclusivity(options.pythonAi, "python ai libraries");
|
|
563
574
|
validateNoneExclusivity(options.javaLibraries, "java libraries");
|
|
564
575
|
validateNoneExclusivity(options.javaTestingLibraries, "java testing libraries");
|
|
576
|
+
validateNoneExclusivity(options.mobileLibraries, "mobile libraries");
|
|
577
|
+
validateNoneExclusivity(options.dotnetLibraries, ".NET libraries");
|
|
565
578
|
}
|
|
566
579
|
|
|
567
580
|
//#endregion
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { r as readBtsConfig } from "./bts-config-
|
|
2
|
+
import { r as readBtsConfig } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
4
|
import { a as handleError } from "./errors-ns_o2OKg.mjs";
|
|
5
|
-
import
|
|
5
|
+
import "./command-exists-DtX9ldL8.mjs";
|
|
6
|
+
import { t as runGeneratedChecks } from "./generated-checks-BUcI5VM2.mjs";
|
|
6
7
|
import { intro, log, spinner } from "@clack/prompts";
|
|
7
8
|
import pc from "picocolors";
|
|
8
9
|
import fs from "fs-extra";
|
|
@@ -49,7 +50,7 @@ const NATIVE_LOCKFILES = {
|
|
|
49
50
|
},
|
|
50
51
|
python: {
|
|
51
52
|
file: "uv.lock",
|
|
52
|
-
hint: "uv sync"
|
|
53
|
+
hint: "uv sync --extra dev"
|
|
53
54
|
},
|
|
54
55
|
elixir: {
|
|
55
56
|
file: "mix.lock",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { b as types_exports } from "./bts-config-
|
|
2
|
+
import { b as types_exports } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
3
|
import { c as isSilent, i as exitWithError, t as CLIError } from "./errors-ns_o2OKg.mjs";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import z from "zod";
|
|
@@ -54,6 +54,7 @@ const CreateCommandOptionsSchema = z.object({
|
|
|
54
54
|
mobilePush: types_exports.MobilePushSchema.optional().describe("Mobile push notifications (expo-notifications)"),
|
|
55
55
|
mobileOTA: types_exports.MobileOTASchema.optional().describe("Mobile OTA updates (expo-updates)"),
|
|
56
56
|
mobileDeepLinking: types_exports.MobileDeepLinkingSchema.optional().describe("Mobile deep linking (expo-linking)"),
|
|
57
|
+
mobileLibraries: z.array(types_exports.MobileLibrariesSchema).optional().describe("Mobile application libraries"),
|
|
57
58
|
frontend: z.array(types_exports.FrontendSchema).optional(),
|
|
58
59
|
astroIntegration: types_exports.AstroIntegrationSchema.optional().describe("Astro UI framework integration (react, vue, svelte, solid)"),
|
|
59
60
|
addons: z.array(types_exports.AddonsSchema).optional(),
|
|
@@ -110,6 +111,13 @@ const CreateCommandOptionsSchema = z.object({
|
|
|
110
111
|
pythonRealtime: types_exports.PythonRealtimeSchema.optional().describe("Python realtime (python-socketio, websockets)"),
|
|
111
112
|
pythonObservability: types_exports.PythonObservabilitySchema.optional().describe("Python observability (opentelemetry)"),
|
|
112
113
|
pythonCli: z.array(types_exports.PythonCliSchema).optional().describe("Python CLI tooling (typer, click, rich)"),
|
|
114
|
+
pythonCloudSdk: types_exports.PythonCloudSdkSchema.optional().describe("Python cloud SDK (boto3)"),
|
|
115
|
+
pythonHttpClient: types_exports.PythonHttpClientSchema.optional().describe("Python HTTP client (requests)"),
|
|
116
|
+
pythonData: z.array(types_exports.PythonDataSchema).optional().describe("Python data and scientific libraries (numpy, pandas, scipy)"),
|
|
117
|
+
pythonMedia: types_exports.PythonMediaSchema.optional().describe("Python media library (pillow)"),
|
|
118
|
+
pythonServer: types_exports.PythonServerSchema.optional().describe("Python production server (gunicorn)"),
|
|
119
|
+
pythonPackageManager: types_exports.PythonPackageManagerSchema.optional().describe("Python package manager (uv, poetry)"),
|
|
120
|
+
pythonMessageQueue: types_exports.PythonMessageQueueSchema.optional().describe("Python message queue client (confluent-kafka)"),
|
|
113
121
|
goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework"),
|
|
114
122
|
goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database layer"),
|
|
115
123
|
goApi: types_exports.GoApiSchema.optional().describe("Go API layer"),
|
|
@@ -148,6 +156,7 @@ const CreateCommandOptionsSchema = z.object({
|
|
|
148
156
|
dotnetValidation: types_exports.DotnetValidationSchema.optional().describe(".NET validation (fluentvalidation, data-annotations)"),
|
|
149
157
|
dotnetCaching: types_exports.DotnetCachingSchema.optional().describe(".NET caching (redis, memory-cache, none)"),
|
|
150
158
|
dotnetDeploy: types_exports.DotnetDeploySchema.optional().describe(".NET deploy target (docker, azure, aws, none)"),
|
|
159
|
+
dotnetLibraries: z.array(types_exports.DotnetLibrariesSchema).optional().describe(".NET application libraries"),
|
|
151
160
|
elixirWebFramework: types_exports.ElixirWebFrameworkSchema.optional().describe("Elixir web framework (phoenix, phoenix-live-view, none)"),
|
|
152
161
|
elixirOrm: types_exports.ElixirOrmSchema.optional().describe("Elixir ORM/database (ecto, ecto-sql, none)"),
|
|
153
162
|
elixirAuth: types_exports.ElixirAuthSchema.optional().describe("Elixir auth (phx-gen-auth, ueberauth, guardian, none)"),
|
|
@@ -427,9 +436,9 @@ function validateAddonCompatibility$1(addon, frontend, _auth, backend, runtime,
|
|
|
427
436
|
isCompatible: false,
|
|
428
437
|
reason: `${title} for Java currently requires Spring Boot`
|
|
429
438
|
};
|
|
430
|
-
if (ecosystem === "python" && database && database !== "none" && database !== "sqlite" && database !== "postgres") return {
|
|
439
|
+
if (ecosystem === "python" && database && database !== "none" && database !== "sqlite" && database !== "postgres" && database !== "mongodb") return {
|
|
431
440
|
isCompatible: false,
|
|
432
|
-
reason: `${title} for Python ORM projects currently supports SQLite
|
|
441
|
+
reason: `${title} for Python ORM projects currently supports SQLite, Postgres, or MongoDB`
|
|
433
442
|
};
|
|
434
443
|
}
|
|
435
444
|
return { isCompatible: true };
|
|
@@ -607,6 +616,15 @@ function validateRustExpansionCompatibility(config) {
|
|
|
607
616
|
},
|
|
608
617
|
suggestions: ["Use --rust-web-framework axum", "Choose --rust-auth openidconnect or none"]
|
|
609
618
|
});
|
|
619
|
+
const orm = config.rustOrm ?? "none";
|
|
620
|
+
if (auth === "torii" && orm === "rusqlite") incompatibilityError({
|
|
621
|
+
message: "Torii's sqlx-based SQLite storage conflicts with rusqlite: both link the native sqlite3 library and cargo permits only one linker.",
|
|
622
|
+
provided: {
|
|
623
|
+
"rust-orm": orm,
|
|
624
|
+
"rust-auth": auth
|
|
625
|
+
},
|
|
626
|
+
suggestions: ["Use --rust-orm sqlx, sea-orm, or diesel with Torii", "Choose --rust-auth none"]
|
|
627
|
+
});
|
|
610
628
|
}
|
|
611
629
|
|
|
612
630
|
//#endregion
|
|
@@ -702,6 +720,7 @@ function buildCompatibilityInputFromConfig(config) {
|
|
|
702
720
|
mobilePush: asString(config.mobilePush),
|
|
703
721
|
mobileOTA: asString(config.mobileOTA),
|
|
704
722
|
mobileDeepLinking: asString(config.mobileDeepLinking),
|
|
723
|
+
mobileLibraries: asStringArray(config.mobileLibraries),
|
|
705
724
|
codeQuality,
|
|
706
725
|
documentation,
|
|
707
726
|
appPlatforms,
|
|
@@ -745,6 +764,13 @@ function buildCompatibilityInputFromConfig(config) {
|
|
|
745
764
|
pythonRealtime: asString(config.pythonRealtime),
|
|
746
765
|
pythonObservability: asString(config.pythonObservability),
|
|
747
766
|
pythonCli: asStringArray(config.pythonCli),
|
|
767
|
+
pythonCloudSdk: asString(config.pythonCloudSdk),
|
|
768
|
+
pythonHttpClient: asString(config.pythonHttpClient),
|
|
769
|
+
pythonData: asStringArray(config.pythonData),
|
|
770
|
+
pythonMedia: asString(config.pythonMedia),
|
|
771
|
+
pythonServer: asString(config.pythonServer),
|
|
772
|
+
pythonPackageManager: asString(config.pythonPackageManager),
|
|
773
|
+
pythonMessageQueue: asString(config.pythonMessageQueue),
|
|
748
774
|
goWebFramework: asString(config.goWebFramework),
|
|
749
775
|
goOrm: asString(config.goOrm),
|
|
750
776
|
goApi: asString(config.goApi),
|
|
@@ -783,6 +809,7 @@ function buildCompatibilityInputFromConfig(config) {
|
|
|
783
809
|
dotnetValidation: asString(config.dotnetValidation),
|
|
784
810
|
dotnetCaching: asString(config.dotnetCaching),
|
|
785
811
|
dotnetDeploy: asString(config.dotnetDeploy),
|
|
812
|
+
dotnetLibraries: asStringArray(config.dotnetLibraries),
|
|
786
813
|
elixirWebFramework: asString(config.elixirWebFramework),
|
|
787
814
|
elixirOrm: asString(config.elixirOrm),
|
|
788
815
|
elixirAuth: asString(config.elixirAuth),
|
|
@@ -1443,6 +1470,28 @@ function validateEffectBackendConstraints(config) {
|
|
|
1443
1470
|
suggestions: ["Use --validation effect-schema"]
|
|
1444
1471
|
});
|
|
1445
1472
|
}
|
|
1473
|
+
function validateScopedLibraryFlags(config) {
|
|
1474
|
+
const mobileLibraries = (config.mobileLibraries ?? []).filter((lib) => lib !== "none");
|
|
1475
|
+
const hasNativeFrontend = (config.frontend ?? []).some((f) => String(f).startsWith("native-")) || config.stackParts?.some((part) => part.ecosystem === "react-native");
|
|
1476
|
+
if (mobileLibraries.length > 0 && !hasNativeFrontend) incompatibilityError({
|
|
1477
|
+
message: "Mobile libraries require a native Expo frontend.",
|
|
1478
|
+
provided: {
|
|
1479
|
+
frontend: (config.frontend ?? []).join(" ") || "none",
|
|
1480
|
+
"mobile-libraries": mobileLibraries.join(" ")
|
|
1481
|
+
},
|
|
1482
|
+
suggestions: ["Add a native frontend (native-bare, native-uniwind, native-unistyles)", "Remove --mobile-libraries for web-only stacks"]
|
|
1483
|
+
});
|
|
1484
|
+
const dotnetLibraries = (config.dotnetLibraries ?? []).filter((lib) => lib !== "none");
|
|
1485
|
+
const hasDotnetPart = config.ecosystem === "dotnet" || config.stackParts?.some((part) => part.ecosystem === "dotnet");
|
|
1486
|
+
if (dotnetLibraries.length > 0 && !hasDotnetPart) incompatibilityError({
|
|
1487
|
+
message: ".NET libraries require a .NET backend.",
|
|
1488
|
+
provided: {
|
|
1489
|
+
ecosystem: config.ecosystem ?? "none",
|
|
1490
|
+
"dotnet-libraries": dotnetLibraries.join(" ")
|
|
1491
|
+
},
|
|
1492
|
+
suggestions: ["Use --ecosystem dotnet (or add a .NET graph part) with --dotnet-libraries", "Remove --dotnet-libraries for non-.NET stacks"]
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1446
1495
|
function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set()) {
|
|
1447
1496
|
if (config.ecosystem !== "java") return;
|
|
1448
1497
|
const hasSpringBoot = config.javaWebFramework === "spring-boot";
|
|
@@ -1755,6 +1804,59 @@ function validatePythonApiConstraints(config) {
|
|
|
1755
1804
|
suggestions: ["Use --python-web-framework django with --python-api django-rest-framework or django-ninja", "Set --python-api none for FastAPI, Flask, Litestar, or no Python web framework"]
|
|
1756
1805
|
});
|
|
1757
1806
|
}
|
|
1807
|
+
function validatePythonExpansionConstraints(config) {
|
|
1808
|
+
const pythonConfig = config.ecosystem === "python" ? config : config.stackParts?.some((part) => part.role === "backend" && part.ecosystem === "python" && part.source !== "provided") ? (0, types_exports.stackGraphToLegacyProjectConfigForEcosystem)(config, "python") : void 0;
|
|
1809
|
+
if (!pythonConfig) return;
|
|
1810
|
+
config = pythonConfig;
|
|
1811
|
+
if (config.pythonOrm === "pymongo" && config.database !== "mongodb") incompatibilityError({
|
|
1812
|
+
message: "PyMongo requires --database mongodb.",
|
|
1813
|
+
provided: {
|
|
1814
|
+
database: config.database || "none",
|
|
1815
|
+
"python-orm": "pymongo"
|
|
1816
|
+
},
|
|
1817
|
+
suggestions: ["Add --database mongodb when using --python-orm pymongo", "Choose another --python-orm for relational databases"]
|
|
1818
|
+
});
|
|
1819
|
+
if (config.database === "mongodb" && config.pythonOrm !== "pymongo" && config.pythonOrm !== "none" && config.pythonOrm !== void 0) incompatibilityError({
|
|
1820
|
+
message: "MongoDB requires --python-orm pymongo (relational ORMs cannot use it).",
|
|
1821
|
+
provided: {
|
|
1822
|
+
database: "mongodb",
|
|
1823
|
+
"python-orm": config.pythonOrm
|
|
1824
|
+
},
|
|
1825
|
+
suggestions: ["Use --python-orm pymongo with --database mongodb", "Choose a relational database (postgres, sqlite, mysql) for this ORM"]
|
|
1826
|
+
});
|
|
1827
|
+
if ((config.pythonWebFramework === "none" || config.pythonWebFramework === "aiohttp" || config.pythonWebFramework === "starlette" || config.pythonWebFramework === "streamlit") && config.pythonGraphql !== void 0 && config.pythonGraphql !== "none") incompatibilityError({
|
|
1828
|
+
message: "Python GraphQL is only wired for FastAPI, Django, Flask, and Litestar.",
|
|
1829
|
+
provided: {
|
|
1830
|
+
"python-web-framework": config.pythonWebFramework,
|
|
1831
|
+
"python-graphql": config.pythonGraphql
|
|
1832
|
+
},
|
|
1833
|
+
suggestions: ["Use FastAPI, Django, Flask, or Litestar with --python-graphql", "Set --python-graphql none"]
|
|
1834
|
+
});
|
|
1835
|
+
if ((config.pythonWebFramework === "none" || config.pythonWebFramework === "aiohttp" || config.pythonWebFramework === "starlette" || config.pythonWebFramework === "streamlit") && config.pythonAuth !== void 0 && config.pythonAuth !== "none") incompatibilityError({
|
|
1836
|
+
message: `Python auth routes are not wired for ${config.pythonWebFramework}.`,
|
|
1837
|
+
provided: {
|
|
1838
|
+
"python-web-framework": config.pythonWebFramework,
|
|
1839
|
+
"python-auth": config.pythonAuth
|
|
1840
|
+
},
|
|
1841
|
+
suggestions: ["Use FastAPI, Django, Flask, or Litestar with --python-auth", "Set --python-auth none"]
|
|
1842
|
+
});
|
|
1843
|
+
if ((config.pythonWebFramework === "streamlit" || config.pythonWebFramework === "none") && config.pythonObservability === "prometheus-client") incompatibilityError({
|
|
1844
|
+
message: "prometheus-client needs an HTTP server framework to expose /metrics.",
|
|
1845
|
+
provided: {
|
|
1846
|
+
"python-web-framework": config.pythonWebFramework,
|
|
1847
|
+
"python-observability": "prometheus-client"
|
|
1848
|
+
},
|
|
1849
|
+
suggestions: ["Use FastAPI, Django, Flask, Litestar, Starlette, or aiohttp", "Set --python-observability none"]
|
|
1850
|
+
});
|
|
1851
|
+
if (config.pythonServer === "gunicorn" && (config.pythonWebFramework === "streamlit" || config.pythonWebFramework === "none")) incompatibilityError({
|
|
1852
|
+
message: "Gunicorn requires a WSGI, ASGI, or aiohttp Python application.",
|
|
1853
|
+
provided: {
|
|
1854
|
+
"python-web-framework": config.pythonWebFramework,
|
|
1855
|
+
"python-server": "gunicorn"
|
|
1856
|
+
},
|
|
1857
|
+
suggestions: ["Use FastAPI, Django, Flask, Litestar, or aiohttp with --python-server gunicorn", "Set --python-server none for Streamlit or framework-free projects"]
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1758
1860
|
function validateI18nConstraints(config) {
|
|
1759
1861
|
if (config.i18n !== "intlayer") return;
|
|
1760
1862
|
const { web } = splitFrontends$1(config.frontend ?? []);
|
|
@@ -1786,6 +1888,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1786
1888
|
validateFrontendConstraints(config, providedFlags);
|
|
1787
1889
|
validateApiConstraints(config, options);
|
|
1788
1890
|
validatePythonApiConstraints(config);
|
|
1891
|
+
validatePythonExpansionConstraints(config);
|
|
1789
1892
|
validateRustExpansionCompatibility(config);
|
|
1790
1893
|
validateEmailConstraints(config);
|
|
1791
1894
|
validateObservabilityConstraints(config);
|
|
@@ -1794,6 +1897,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1794
1897
|
validateSearchConstraints(config);
|
|
1795
1898
|
validateJavaConstraints(config, providedFlags);
|
|
1796
1899
|
validateElixirConstraints(config);
|
|
1900
|
+
validateScopedLibraryFlags(config);
|
|
1797
1901
|
validateI18nConstraints(config);
|
|
1798
1902
|
const hasGraphBackend = config.stackParts?.some((part) => part.role === "backend" && !part.ownerPartId && part.source !== "provided" && part.ecosystem !== "typescript" && part.ecosystem !== "react-native" && part.ecosystem !== "universal");
|
|
1799
1903
|
if (!(providedFlags.has("serverDeploy") && !options.yes && !options.part?.length && options.ecosystem === void 0 && options.backend === void 0 && config.stackParts === void 0)) validateServerDeployRequiresBackend(config.serverDeploy, config.backend, Boolean(hasGraphBackend));
|
|
@@ -1858,6 +1962,7 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
1858
1962
|
if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
|
|
1859
1963
|
validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
|
|
1860
1964
|
validatePythonApiConstraints(config);
|
|
1965
|
+
validatePythonExpansionConstraints(config);
|
|
1861
1966
|
validateEmailConstraints(config);
|
|
1862
1967
|
validateObservabilityConstraints(config);
|
|
1863
1968
|
validateCachingConstraints(config);
|
|
@@ -1866,6 +1971,7 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
1866
1971
|
validateJavaConstraints(config);
|
|
1867
1972
|
validateElixirConstraints(config);
|
|
1868
1973
|
validateRustExpansionCompatibility(config);
|
|
1974
|
+
validateScopedLibraryFlags(config);
|
|
1869
1975
|
validateI18nConstraints(config);
|
|
1870
1976
|
validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
|
|
1871
1977
|
if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database, config.api);
|
|
@@ -1,35 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { f as getPrimaryGraphPart } from "./bts-config-
|
|
2
|
+
import { b as types_exports, f as getPrimaryGraphPart } from "./bts-config-Bwd6GB7B.mjs";
|
|
3
|
+
import { t as commandExists } from "./command-exists-DtX9ldL8.mjs";
|
|
3
4
|
import { log, spinner } from "@clack/prompts";
|
|
4
5
|
import pc from "picocolors";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { $ } from "execa";
|
|
7
8
|
|
|
8
|
-
//#region src/utils/command-exists.ts
|
|
9
|
-
async function commandExists(command) {
|
|
10
|
-
try {
|
|
11
|
-
if (process.platform === "win32") return (await $({ reject: false })`where ${command}`).exitCode === 0;
|
|
12
|
-
return (await $({ reject: false })`which ${command}`).exitCode === 0;
|
|
13
|
-
} catch {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
//#endregion
|
|
19
9
|
//#region src/utils/generated-checks.ts
|
|
20
10
|
function getGraphTarget(config) {
|
|
21
11
|
const backend = getPrimaryGraphPart(config, "backend");
|
|
22
12
|
if (!backend || backend.ecosystem === "typescript" || backend.ecosystem === "react-native" || backend.ecosystem === "universal") return null;
|
|
13
|
+
const projected = backend.ecosystem === "python" ? (0, types_exports.stackGraphToLegacyProjectConfigForEcosystem)(config, "python") : config;
|
|
23
14
|
return {
|
|
24
15
|
ecosystem: backend.ecosystem,
|
|
25
|
-
projectDir: path.join(config.projectDir, backend.targetPath ?? "apps/server")
|
|
16
|
+
projectDir: path.join(config.projectDir, backend.targetPath ?? "apps/server"),
|
|
17
|
+
pythonPackageManager: projected.pythonPackageManager,
|
|
18
|
+
pythonQuality: projected.pythonQuality
|
|
26
19
|
};
|
|
27
20
|
}
|
|
28
21
|
function getSingleEcosystemTarget(config) {
|
|
29
22
|
if (config.ecosystem === "typescript" || config.ecosystem === "react-native" || config.ecosystem === "java") return null;
|
|
30
23
|
return {
|
|
31
24
|
ecosystem: config.ecosystem,
|
|
32
|
-
projectDir: config.projectDir
|
|
25
|
+
projectDir: config.projectDir,
|
|
26
|
+
pythonPackageManager: config.pythonPackageManager,
|
|
27
|
+
pythonQuality: config.pythonQuality
|
|
33
28
|
};
|
|
34
29
|
}
|
|
35
30
|
async function runCommand(cwd, command, args) {
|
|
@@ -39,6 +34,19 @@ async function runCommand(cwd, command, args) {
|
|
|
39
34
|
stderr: "inherit"
|
|
40
35
|
})`${command} ${args}`;
|
|
41
36
|
}
|
|
37
|
+
function venvBin(tool) {
|
|
38
|
+
return process.platform === "win32" ? `.venv\\Scripts\\${tool}` : `.venv/bin/${tool}`;
|
|
39
|
+
}
|
|
40
|
+
async function runPythonQualityCheck(cwd, runner, quality) {
|
|
41
|
+
const run = (tool, args) => runner === "venv" ? runCommand(cwd, venvBin(tool), args) : runCommand(cwd, runner, [
|
|
42
|
+
"run",
|
|
43
|
+
tool,
|
|
44
|
+
...args
|
|
45
|
+
]);
|
|
46
|
+
if (quality === "ruff") await run("ruff", ["check", "."]);
|
|
47
|
+
else if (quality === "mypy") await run("mypy", []);
|
|
48
|
+
else if (quality === "pyright") await run("pyright", []);
|
|
49
|
+
}
|
|
42
50
|
async function verifyTarget(target) {
|
|
43
51
|
const s = spinner();
|
|
44
52
|
const cwd = target.projectDir;
|
|
@@ -56,13 +64,38 @@ async function verifyTarget(target) {
|
|
|
56
64
|
return;
|
|
57
65
|
case "python":
|
|
58
66
|
s.start("Verifying generated Python server...");
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
if (target.pythonPackageManager === "poetry") {
|
|
68
|
+
await runCommand(cwd, "poetry", [
|
|
69
|
+
"install",
|
|
70
|
+
"--extras",
|
|
71
|
+
"dev"
|
|
72
|
+
]);
|
|
73
|
+
await runPythonQualityCheck(cwd, "poetry", target.pythonQuality);
|
|
74
|
+
} else if (target.pythonPackageManager === "none") {
|
|
75
|
+
await runCommand(cwd, await commandExists("python") ? "python" : "python3", [
|
|
76
|
+
"-m",
|
|
77
|
+
"venv",
|
|
78
|
+
".venv"
|
|
79
|
+
]);
|
|
80
|
+
await runCommand(cwd, venvBin("pip"), [
|
|
81
|
+
"install",
|
|
82
|
+
"-e",
|
|
83
|
+
".[dev]"
|
|
84
|
+
]);
|
|
85
|
+
await runCommand(cwd, venvBin("python"), [
|
|
86
|
+
"-m",
|
|
87
|
+
"compileall",
|
|
88
|
+
"src"
|
|
89
|
+
]);
|
|
90
|
+
await runPythonQualityCheck(cwd, "venv", target.pythonQuality);
|
|
91
|
+
} else {
|
|
92
|
+
await runCommand(cwd, "uv", [
|
|
93
|
+
"sync",
|
|
94
|
+
"--extra",
|
|
95
|
+
"dev"
|
|
96
|
+
]);
|
|
97
|
+
await runPythonQualityCheck(cwd, "uv", target.pythonQuality);
|
|
98
|
+
}
|
|
66
99
|
s.stop("Generated Python server checks passed");
|
|
67
100
|
return;
|
|
68
101
|
case "elixir":
|
|
@@ -88,4 +121,4 @@ async function runGeneratedChecks(config) {
|
|
|
88
121
|
}
|
|
89
122
|
|
|
90
123
|
//#endregion
|
|
91
|
-
export {
|
|
124
|
+
export { runGeneratedChecks as t };
|