create-better-fullstack 1.6.0 → 1.6.2

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 CHANGED
@@ -1,23 +1,28 @@
1
1
  # Better Fullstack
2
2
 
3
- Scaffold production-ready fullstack apps in seconds. Pick your stack from 270+ options — the CLI wires everything together.
3
+ Scaffold production-ready fullstack apps in seconds. Pick your stack from 424 options — the CLI wires everything together.
4
4
 
5
5
  ## Quick Start
6
6
 
7
7
  ```bash
8
- # Using bun (recommended)
9
- bun create better-fullstack@latest
8
+ # Using npm
9
+ npm create better-fullstack@latest
10
+
11
+ # Using npx
12
+ npx create-better-fullstack@latest
10
13
 
11
14
  # Using pnpm
12
15
  pnpm create better-fullstack@latest
13
16
 
14
- # Using npm
15
- npx create-better-fullstack@latest
17
+ # Using bun
18
+ bun create better-fullstack@latest
16
19
 
17
20
  # Using yarn
18
21
  yarn create better-fullstack@latest
19
22
  ```
20
23
 
24
+ Bun is required only when the generated project selects Bun as its runtime or package manager. Node.js with npm is enough for Node-based projects.
25
+
21
26
  ## Web Builder
22
27
 
23
28
  Configure your stack visually — pick every option from a UI, preview your choices, and get a ready-to-run command.
@@ -26,8 +31,8 @@ Configure your stack visually — pick every option from a UI, preview your choi
26
31
 
27
32
  ## Features
28
33
 
29
- - **270+ options** — frontend, backend, database, auth, payments, AI, DevOps, and more
30
- - **4 ecosystems** — TypeScript, Rust, Python, Go
34
+ - **424 options** — frontend, backend, database, auth, payments, AI, DevOps, and more
35
+ - **5 ecosystems** — TypeScript, Rust, Python, Go, Java
31
36
  - **Visual builder** — configure your stack in the browser
32
37
  - **Wired for you** — every picked integration is preconfigured and working out of the box
33
38
 
@@ -37,7 +42,7 @@ Configure your stack visually — pick every option from a UI, preview your choi
37
42
  --yes # Accept all defaults
38
43
  --yolo # Scaffold a random stack — good for exploring
39
44
  --template <name> # Use a preset (t3, mern, pern, uniwind)
40
- --ecosystem <lang> # Start in rust, python, or go mode
45
+ --ecosystem <lang> # Start in typescript, rust, python, go, or java mode
41
46
  --version-channel # Dependency channel: stable, latest, beta
42
47
  --no-git # Skip git initialization
43
48
  --no-install # Skip dependency installation
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import "./bts-config-B_rZ4_sj.mjs";
3
+ import { i as setupLefthook, n as setupBiome, r as setupHusky, t as setupAddons } from "./addons-setup-DQa6TRrx.mjs";
4
+
5
+ export { setupAddons };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { s as dependencyVersionMap, t as readBtsConfig } from "./bts-config-snHxP_EH.mjs";
2
+ import { s as dependencyVersionMap, t as readBtsConfig } from "./bts-config-B_rZ4_sj.mjs";
3
3
  import { autocompleteMultiselect, cancel, group, isCancel, log, multiselect, select, spinner } from "@clack/prompts";
4
4
  import pc from "picocolors";
5
5
  import fs from "fs-extra";
@@ -178,6 +178,48 @@ function getPackageRunnerPrefix(packageManager) {
178
178
  }
179
179
  }
180
180
 
181
+ //#endregion
182
+ //#region src/utils/prompt-environment.ts
183
+ function hasOwnProperty(value, property) {
184
+ return Object.prototype.hasOwnProperty.call(value, property);
185
+ }
186
+ function resolveCiValue(environment) {
187
+ if (environment && hasOwnProperty(environment, "ci")) return environment.ci;
188
+ return process.env.CI;
189
+ }
190
+ function isCiEnvironment(value) {
191
+ if (!value) return false;
192
+ const normalizedValue = value.trim().toLowerCase();
193
+ return normalizedValue !== "" && normalizedValue !== "0" && normalizedValue !== "false";
194
+ }
195
+ function canPromptInteractively(environment = {}) {
196
+ const silent = environment.silent ?? isSilent();
197
+ const stdinIsTTY = environment.stdinIsTTY ?? process.stdin.isTTY === true;
198
+ const stdoutIsTTY = environment.stdoutIsTTY ?? process.stdout.isTTY === true;
199
+ const ci = resolveCiValue(environment);
200
+ return !silent && stdinIsTTY && stdoutIsTTY && !isCiEnvironment(ci);
201
+ }
202
+
203
+ //#endregion
204
+ //#region src/helpers/addons/interactive-selection.ts
205
+ function shouldPromptForAddonSelection(environment = {}) {
206
+ return canPromptInteractively(environment);
207
+ }
208
+ async function selectAddonOptionOrDefault({ addonName, message, options, defaultValue }) {
209
+ if (!shouldPromptForAddonSelection()) {
210
+ const fallback = options.find((option) => option.value === defaultValue);
211
+ if (!isSilent() && fallback) log.info(`Using default ${addonName} template: ${fallback.label}`);
212
+ return defaultValue;
213
+ }
214
+ const selection = await select({
215
+ message,
216
+ options,
217
+ initialValue: defaultValue
218
+ });
219
+ if (isCancel(selection)) return exitCancelled("Operation cancelled");
220
+ return selection;
221
+ }
222
+
181
223
  //#endregion
182
224
  //#region src/helpers/addons/fumadocs-setup.ts
183
225
  const TEMPLATES$2 = {
@@ -211,17 +253,16 @@ async function setupFumadocs(config) {
211
253
  const { packageManager, projectDir } = config;
212
254
  try {
213
255
  log.info("Setting up Fumadocs...");
214
- const template = await select({
256
+ const args = getPackageExecutionArgs(packageManager, `create-fumadocs-app@latest fumadocs --template ${TEMPLATES$2[await selectAddonOptionOrDefault({
257
+ addonName: "Fumadocs",
215
258
  message: "Choose a template",
216
- options: Object.entries(TEMPLATES$2).map(([key, template$1]) => ({
259
+ options: Object.entries(TEMPLATES$2).map(([key, template]) => ({
217
260
  value: key,
218
- label: template$1.label,
219
- hint: template$1.hint
261
+ label: template.label,
262
+ hint: template.hint
220
263
  })),
221
- initialValue: "next-mdx"
222
- });
223
- if (isCancel(template)) return exitCancelled("Operation cancelled");
224
- const args = getPackageExecutionArgs(packageManager, `create-fumadocs-app@latest fumadocs --template ${TEMPLATES$2[template].value} --src --pm ${packageManager} --no-git`);
264
+ defaultValue: "next-mdx"
265
+ })].value} --src --pm ${packageManager} --no-git`);
225
266
  const appsDir = path.join(projectDir, "apps");
226
267
  await fs.ensureDir(appsDir);
227
268
  const s = spinner();
@@ -445,51 +486,63 @@ function filterAgentsForScope(scope) {
445
486
  return MCP_AGENTS.filter((a) => a.scope === "both" || a.scope === scope);
446
487
  }
447
488
  async function setupMcp(config) {
448
- if (shouldSkipExternalCommands()) return;
449
489
  const { packageManager, projectDir } = config;
450
490
  log.info("Setting up MCP servers...");
451
- const scope = await select({
452
- message: "Where should MCP servers be installed?",
453
- options: [{
454
- value: "project",
455
- label: "Project",
456
- hint: "Writes to project config files (recommended for teams)"
457
- }, {
458
- value: "global",
459
- label: "Global",
460
- hint: "Writes to user-level config files (personal machine)"
461
- }],
462
- initialValue: "project"
463
- });
464
- if (isCancel(scope)) return;
491
+ const skipExternalCommands = shouldSkipExternalCommands();
492
+ const canPrompt = canPromptInteractively() && !skipExternalCommands;
465
493
  const recommendedServers = getRecommendedMcpServers(config);
466
494
  if (recommendedServers.length === 0) return;
467
- const selectedServerKeys = await multiselect({
468
- message: "Select MCP servers to install",
469
- options: recommendedServers.map((server) => ({
470
- value: server.key,
471
- label: server.label,
472
- hint: server.target
473
- })),
474
- required: false,
475
- initialValues: recommendedServers.map((server) => server.key)
476
- });
477
- if (isCancel(selectedServerKeys) || selectedServerKeys.length === 0) return;
495
+ let scope = "project";
496
+ let selectedServerKeys = recommendedServers.map((server) => server.key);
497
+ if (canPrompt) {
498
+ const promptedScope = await select({
499
+ message: "Where should MCP servers be installed?",
500
+ options: [{
501
+ value: "project",
502
+ label: "Project",
503
+ hint: "Writes to project config files (recommended for teams)"
504
+ }, {
505
+ value: "global",
506
+ label: "Global",
507
+ hint: "Writes to user-level config files (personal machine)"
508
+ }],
509
+ initialValue: "project"
510
+ });
511
+ if (isCancel(promptedScope)) return;
512
+ scope = promptedScope;
513
+ const promptedServerKeys = await multiselect({
514
+ message: "Select MCP servers to install",
515
+ options: recommendedServers.map((server) => ({
516
+ value: server.key,
517
+ label: server.label,
518
+ hint: server.target
519
+ })),
520
+ required: false,
521
+ initialValues: selectedServerKeys
522
+ });
523
+ if (isCancel(promptedServerKeys) || promptedServerKeys.length === 0) return;
524
+ selectedServerKeys = [...promptedServerKeys];
525
+ }
478
526
  const agentOptions = filterAgentsForScope(scope).map((a) => ({
479
527
  value: a.value,
480
528
  label: a.label
481
529
  }));
482
- const selectedAgents = await multiselect({
483
- message: "Select agents to install MCP servers to",
484
- options: agentOptions,
485
- required: false,
486
- initialValues: uniqueValues$1([
487
- "cursor",
488
- "claude-code",
489
- "vscode"
490
- ].filter((agent) => agentOptions.some((option) => option.value === agent)))
491
- });
492
- if (isCancel(selectedAgents) || selectedAgents.length === 0) return;
530
+ const defaultAgents = uniqueValues$1([
531
+ "cursor",
532
+ "claude-code",
533
+ "vscode"
534
+ ].filter((agent) => agentOptions.some((option) => option.value === agent)));
535
+ let selectedAgents = defaultAgents;
536
+ if (canPrompt) {
537
+ const promptedAgents = await multiselect({
538
+ message: "Select agents to install MCP servers to",
539
+ options: agentOptions,
540
+ required: false,
541
+ initialValues: defaultAgents
542
+ });
543
+ if (isCancel(promptedAgents) || promptedAgents.length === 0) return;
544
+ selectedAgents = [...promptedAgents];
545
+ }
493
546
  const serversByKey = new Map(recommendedServers.map((server) => [server.key, server]));
494
547
  const selectedServers = [];
495
548
  for (const key of selectedServerKeys) {
@@ -497,6 +550,7 @@ async function setupMcp(config) {
497
550
  if (server) selectedServers.push(server);
498
551
  }
499
552
  if (selectedServers.length === 0) return;
553
+ if (skipExternalCommands) return;
500
554
  const installSpinner = spinner();
501
555
  installSpinner.start("Installing MCP servers...");
502
556
  const runner = getPackageRunnerPrefix(packageManager);
@@ -572,45 +626,50 @@ async function setupRuler(config) {
572
626
  log.error(pc.red("Ruler template directory not found. Please ensure ruler addon is properly installed."));
573
627
  return;
574
628
  }
575
- const selectedEditors = await autocompleteMultiselect({
576
- message: "Select AI assistants for Ruler",
577
- options: Object.entries({
578
- agentsmd: { label: "Agents.md" },
579
- aider: { label: "Aider" },
580
- amazonqcli: { label: "Amazon Q CLI" },
581
- amp: { label: "AMP" },
582
- antigravity: { label: "Antigravity" },
583
- augmentcode: { label: "AugmentCode" },
584
- claude: { label: "Claude Code" },
585
- cline: { label: "Cline" },
586
- codex: { label: "OpenAI Codex CLI" },
587
- copilot: { label: "GitHub Copilot" },
588
- crush: { label: "Crush" },
589
- cursor: { label: "Cursor" },
590
- firebase: { label: "Firebase Studio" },
591
- firebender: { label: "Firebender" },
592
- "gemini-cli": { label: "Gemini CLI" },
593
- goose: { label: "Goose" },
594
- jules: { label: "Jules" },
595
- junie: { label: "Junie" },
596
- kilocode: { label: "Kilo Code" },
597
- kiro: { label: "Kiro" },
598
- mistral: { label: "Mistral" },
599
- opencode: { label: "OpenCode" },
600
- openhands: { label: "Open Hands" },
601
- qwen: { label: "Qwen" },
602
- roo: { label: "RooCode" },
603
- trae: { label: "Trae AI" },
604
- warp: { label: "Warp" },
605
- windsurf: { label: "Windsurf" },
606
- zed: { label: "Zed" }
607
- }).map(([key, v]) => ({
608
- value: key,
609
- label: v.label
610
- })),
611
- required: false
612
- });
613
- if (isCancel(selectedEditors)) return exitCancelled("Operation cancelled");
629
+ const EDITORS$1 = {
630
+ agentsmd: { label: "Agents.md" },
631
+ aider: { label: "Aider" },
632
+ amazonqcli: { label: "Amazon Q CLI" },
633
+ amp: { label: "AMP" },
634
+ antigravity: { label: "Antigravity" },
635
+ augmentcode: { label: "AugmentCode" },
636
+ claude: { label: "Claude Code" },
637
+ cline: { label: "Cline" },
638
+ codex: { label: "OpenAI Codex CLI" },
639
+ copilot: { label: "GitHub Copilot" },
640
+ crush: { label: "Crush" },
641
+ cursor: { label: "Cursor" },
642
+ firebase: { label: "Firebase Studio" },
643
+ firebender: { label: "Firebender" },
644
+ "gemini-cli": { label: "Gemini CLI" },
645
+ goose: { label: "Goose" },
646
+ jules: { label: "Jules" },
647
+ junie: { label: "Junie" },
648
+ kilocode: { label: "Kilo Code" },
649
+ kiro: { label: "Kiro" },
650
+ mistral: { label: "Mistral" },
651
+ opencode: { label: "OpenCode" },
652
+ openhands: { label: "Open Hands" },
653
+ qwen: { label: "Qwen" },
654
+ roo: { label: "RooCode" },
655
+ trae: { label: "Trae AI" },
656
+ warp: { label: "Warp" },
657
+ windsurf: { label: "Windsurf" },
658
+ zed: { label: "Zed" }
659
+ };
660
+ let selectedEditors = [];
661
+ if (canPromptInteractively()) {
662
+ const prompted = await autocompleteMultiselect({
663
+ message: "Select AI assistants for Ruler",
664
+ options: Object.entries(EDITORS$1).map(([key, v]) => ({
665
+ value: key,
666
+ label: v.label
667
+ })),
668
+ required: false
669
+ });
670
+ if (isCancel(prompted)) return exitCancelled("Operation cancelled");
671
+ selectedEditors = [...prompted];
672
+ } else log.info("Skipping AI assistant selection (non-interactive mode).");
614
673
  if (selectedEditors.length === 0) {
615
674
  log.info("No AI assistants selected. To apply rules later, run:");
616
675
  log.info(pc.cyan(`${getPackageExecutionCommand(packageManager, "@intellectronica/ruler@latest apply --local-only")}`));
@@ -886,6 +945,10 @@ async function setupSkills(config) {
886
945
  }));
887
946
  });
888
947
  if (skillOptions.length === 0) return;
948
+ if (!canPromptInteractively()) {
949
+ log.info("Skipping skills installation (non-interactive mode). Run the skills CLI manually to install.");
950
+ return;
951
+ }
889
952
  const scope = await select({
890
953
  message: "Where should skills be installed?",
891
954
  options: [{
@@ -1017,17 +1080,16 @@ async function setupTui(config) {
1017
1080
  const { packageManager, projectDir } = config;
1018
1081
  try {
1019
1082
  log.info("Setting up OpenTUI...");
1020
- const template = await select({
1083
+ const args = getPackageExecutionArgs(packageManager, `create-tui@latest --template ${await selectAddonOptionOrDefault({
1084
+ addonName: "OpenTUI",
1021
1085
  message: "Choose a template",
1022
- options: Object.entries(TEMPLATES$1).map(([key, template$1]) => ({
1086
+ options: Object.entries(TEMPLATES$1).map(([key, template]) => ({
1023
1087
  value: key,
1024
- label: template$1.label,
1025
- hint: template$1.hint
1088
+ label: template.label,
1089
+ hint: template.hint
1026
1090
  })),
1027
- initialValue: "core"
1028
- });
1029
- if (isCancel(template)) return exitCancelled("Operation cancelled");
1030
- const args = getPackageExecutionArgs(packageManager, `create-tui@latest --template ${template} --no-git --no-install tui`);
1091
+ defaultValue: "core"
1092
+ })} --no-git --no-install tui`);
1031
1093
  const appsDir = path.join(projectDir, "apps");
1032
1094
  await fs.ensureDir(appsDir);
1033
1095
  const s = spinner();
@@ -1123,7 +1185,9 @@ async function setupUltracite(config, gitHooks) {
1123
1185
  const { packageManager, projectDir, frontend } = config;
1124
1186
  try {
1125
1187
  log.info("Setting up Ultracite...");
1126
- const result = await group({
1188
+ const skipExternalCommands = shouldSkipExternalCommands();
1189
+ const canPrompt = canPromptInteractively() && !skipExternalCommands;
1190
+ const result = canPrompt ? await group({
1127
1191
  linter: () => select({
1128
1192
  message: "Choose linter/formatter",
1129
1193
  options: Object.entries(LINTERS).map(([key, linter$1]) => ({
@@ -1158,7 +1222,12 @@ async function setupUltracite(config, gitHooks) {
1158
1222
  })
1159
1223
  }, { onCancel: () => {
1160
1224
  exitCancelled("Operation cancelled");
1161
- } });
1225
+ } }) : {
1226
+ linter: "biome",
1227
+ editors: [],
1228
+ agents: [],
1229
+ hooks: []
1230
+ };
1162
1231
  const linter = result.linter;
1163
1232
  const editors = result.editors;
1164
1233
  const agents = result.agents;
@@ -1171,6 +1240,7 @@ async function setupUltracite(config, gitHooks) {
1171
1240
  "--linter",
1172
1241
  linter
1173
1242
  ];
1243
+ if (!canPrompt) ultraciteArgs.push("--quiet");
1174
1244
  if (frameworks.length > 0) ultraciteArgs.push("--frameworks", ...frameworks);
1175
1245
  if (editors.length > 0) ultraciteArgs.push("--editors", ...editors);
1176
1246
  if (agents.length > 0) ultraciteArgs.push("--agents", ...agents);
@@ -1180,6 +1250,7 @@ async function setupUltracite(config, gitHooks) {
1180
1250
  if (gitHooks.includes("husky")) integrations.push("lint-staged");
1181
1251
  ultraciteArgs.push("--integrations", ...integrations);
1182
1252
  }
1253
+ if (skipExternalCommands) return;
1183
1254
  const args = getPackageExecutionArgs(packageManager, `ultracite@latest ${ultraciteArgs.join(" ")} --skip-install`);
1184
1255
  const s = spinner();
1185
1256
  s.start("Running Ultracite init command...");
@@ -1222,17 +1293,16 @@ async function setupWxt(config) {
1222
1293
  const { packageManager, projectDir } = config;
1223
1294
  try {
1224
1295
  log.info("Setting up WXT...");
1225
- const template = await select({
1296
+ const args = getPackageExecutionArgs(packageManager, `wxt@latest init extension --template ${await selectAddonOptionOrDefault({
1297
+ addonName: "WXT",
1226
1298
  message: "Choose a template",
1227
- options: Object.entries(TEMPLATES).map(([key, template$1]) => ({
1299
+ options: Object.entries(TEMPLATES).map(([key, template]) => ({
1228
1300
  value: key,
1229
- label: template$1.label,
1230
- hint: template$1.hint
1301
+ label: template.label,
1302
+ hint: template.hint
1231
1303
  })),
1232
- initialValue: "react"
1233
- });
1234
- if (isCancel(template)) return exitCancelled("Operation cancelled");
1235
- const args = getPackageExecutionArgs(packageManager, `wxt@latest init extension --template ${template} --pm ${packageManager}`);
1304
+ defaultValue: "react"
1305
+ })} --pm ${packageManager}`);
1236
1306
  const appsDir = path.join(projectDir, "apps");
1237
1307
  await fs.ensureDir(appsDir);
1238
1308
  const s = spinner();
@@ -1346,4 +1416,4 @@ async function setupLefthook(projectDir) {
1346
1416
  }
1347
1417
 
1348
1418
  //#endregion
1349
- export { setLastPromptShownUI as _, getPackageExecutionArgs as a, UserCancelledError as c, handleError as d, didLastPromptShowUI as f, setIsFirstPrompt as g, runWithContextAsync as h, setupLefthook as i, exitCancelled as l, isSilent as m, setupBiome as n, addPackageDependency as o, isFirstPrompt as p, setupHusky as r, CLIError as s, setupAddons as t, exitWithError as u };
1419
+ export { setIsFirstPrompt as _, canPromptInteractively as a, CLIError as c, exitWithError as d, handleError as f, runWithContextAsync as g, isSilent as h, setupLefthook as i, UserCancelledError as l, isFirstPrompt as m, setupBiome as n, getPackageExecutionArgs as o, didLastPromptShowUI as p, setupHusky as r, addPackageDependency as s, setupAddons as t, exitCancelled as u, setLastPromptShownUI as v };
@@ -2,6 +2,7 @@
2
2
  import fs from "fs-extra";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { createCliDefaultProjectConfigBase } from "@better-fullstack/types";
5
6
  import { dependencyVersionMap } from "@better-fullstack/template-generator";
6
7
  import * as JSONC from "jsonc-parser";
7
8
 
@@ -10,6 +11,7 @@ const getUserPkgManager = () => {
10
11
  const userAgent = process.env.npm_config_user_agent;
11
12
  if (userAgent?.startsWith("pnpm")) return "pnpm";
12
13
  if (userAgent?.startsWith("bun")) return "bun";
14
+ if (userAgent?.startsWith("yarn")) return "yarn";
13
15
  return "npm";
14
16
  };
15
17
 
@@ -18,79 +20,7 @@ const getUserPkgManager = () => {
18
20
  const __filename = fileURLToPath(import.meta.url);
19
21
  const distPath = path.dirname(__filename);
20
22
  const PKG_ROOT = path.join(distPath, "../");
21
- const DEFAULT_CONFIG_BASE = {
22
- projectName: "my-app",
23
- relativePath: "my-app",
24
- ecosystem: "typescript",
25
- frontend: ["tanstack-router"],
26
- database: "sqlite",
27
- orm: "drizzle",
28
- auth: "better-auth",
29
- payments: "none",
30
- email: "none",
31
- fileUpload: "none",
32
- effect: "none",
33
- stateManagement: "none",
34
- validation: "zod",
35
- forms: "react-hook-form",
36
- testing: "vitest",
37
- ai: "none",
38
- realtime: "none",
39
- jobQueue: "none",
40
- caching: "none",
41
- i18n: "none",
42
- search: "none",
43
- fileStorage: "none",
44
- animation: "none",
45
- logging: "none",
46
- observability: "none",
47
- featureFlags: "none",
48
- analytics: "none",
49
- cms: "none",
50
- addons: ["turborepo"],
51
- examples: [],
52
- git: true,
53
- install: true,
54
- versionChannel: "stable",
55
- dbSetup: "none",
56
- backend: "hono",
57
- runtime: "bun",
58
- api: "trpc",
59
- webDeploy: "none",
60
- serverDeploy: "none",
61
- cssFramework: "tailwind",
62
- uiLibrary: "shadcn-ui",
63
- shadcnBase: "radix",
64
- shadcnStyle: "nova",
65
- shadcnIconLibrary: "lucide",
66
- shadcnColorTheme: "neutral",
67
- shadcnBaseColor: "neutral",
68
- shadcnFont: "inter",
69
- shadcnRadius: "default",
70
- rustWebFramework: "none",
71
- rustFrontend: "none",
72
- rustOrm: "none",
73
- rustApi: "none",
74
- rustCli: "none",
75
- rustLibraries: [],
76
- rustLogging: "tracing",
77
- rustErrorHandling: "anyhow-thiserror",
78
- rustCaching: "none",
79
- pythonWebFramework: "fastapi",
80
- pythonOrm: "sqlalchemy",
81
- pythonValidation: "pydantic",
82
- pythonAi: [],
83
- pythonAuth: "none",
84
- pythonTaskQueue: "none",
85
- pythonGraphql: "none",
86
- pythonQuality: "ruff",
87
- goWebFramework: "gin",
88
- goOrm: "gorm",
89
- goApi: "none",
90
- goCli: "none",
91
- goLogging: "zap",
92
- aiDocs: ["claude-md"]
93
- };
23
+ const DEFAULT_CONFIG_BASE = createCliDefaultProjectConfigBase(getUserPkgManager());
94
24
  function getDefaultConfig() {
95
25
  return {
96
26
  ...DEFAULT_CONFIG_BASE,
@@ -101,6 +31,8 @@ function getDefaultConfig() {
101
31
  examples: [...DEFAULT_CONFIG_BASE.examples],
102
32
  rustLibraries: [...DEFAULT_CONFIG_BASE.rustLibraries],
103
33
  pythonAi: [...DEFAULT_CONFIG_BASE.pythonAi],
34
+ javaLibraries: [...DEFAULT_CONFIG_BASE.javaLibraries],
35
+ javaTestingLibraries: [...DEFAULT_CONFIG_BASE.javaTestingLibraries],
104
36
  aiDocs: [...DEFAULT_CONFIG_BASE.aiDocs]
105
37
  };
106
38
  }
@@ -191,6 +123,7 @@ async function writeBtsConfig(projectConfig) {
191
123
  rustLogging: projectConfig.rustLogging,
192
124
  rustErrorHandling: projectConfig.rustErrorHandling,
193
125
  rustCaching: projectConfig.rustCaching,
126
+ rustAuth: projectConfig.rustAuth,
194
127
  pythonWebFramework: projectConfig.pythonWebFramework,
195
128
  pythonOrm: projectConfig.pythonOrm,
196
129
  pythonValidation: projectConfig.pythonValidation,
@@ -204,6 +137,13 @@ async function writeBtsConfig(projectConfig) {
204
137
  goApi: projectConfig.goApi,
205
138
  goCli: projectConfig.goCli,
206
139
  goLogging: projectConfig.goLogging,
140
+ goAuth: projectConfig.goAuth,
141
+ javaWebFramework: projectConfig.javaWebFramework,
142
+ javaBuildTool: projectConfig.javaBuildTool,
143
+ javaOrm: projectConfig.javaOrm,
144
+ javaAuth: projectConfig.javaAuth,
145
+ javaLibraries: projectConfig.javaLibraries,
146
+ javaTestingLibraries: projectConfig.javaTestingLibraries,
207
147
  aiDocs: projectConfig.aiDocs
208
148
  };
209
149
  const baseContent = {
@@ -257,6 +197,7 @@ async function writeBtsConfig(projectConfig) {
257
197
  rustLogging: btsConfig.rustLogging,
258
198
  rustErrorHandling: btsConfig.rustErrorHandling,
259
199
  rustCaching: btsConfig.rustCaching,
200
+ rustAuth: btsConfig.rustAuth,
260
201
  pythonWebFramework: btsConfig.pythonWebFramework,
261
202
  pythonOrm: btsConfig.pythonOrm,
262
203
  pythonValidation: btsConfig.pythonValidation,
@@ -269,6 +210,13 @@ async function writeBtsConfig(projectConfig) {
269
210
  goApi: btsConfig.goApi,
270
211
  goCli: btsConfig.goCli,
271
212
  goLogging: btsConfig.goLogging,
213
+ goAuth: btsConfig.goAuth,
214
+ javaWebFramework: btsConfig.javaWebFramework,
215
+ javaBuildTool: btsConfig.javaBuildTool,
216
+ javaOrm: btsConfig.javaOrm,
217
+ javaAuth: btsConfig.javaAuth,
218
+ javaLibraries: btsConfig.javaLibraries,
219
+ javaTestingLibraries: btsConfig.javaTestingLibraries,
272
220
  aiDocs: btsConfig.aiDocs
273
221
  };
274
222
  let configContent = JSON.stringify(baseContent);
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  //#region src/cli.ts
3
- if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-Bx_Esljk.mjs").then((m) => m.startMcpServer());
3
+ if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-CuEEG8e5.mjs").then((m) => m.startMcpServer());
4
4
  else import("./index.mjs").then((m) => m.createBtsCli().run());
5
5
 
6
6
  //#endregion