create-better-t-stack 3.14.1 → 3.15.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 CHANGED
@@ -41,7 +41,7 @@ Follow the prompts to configure your project or use the `--yes` flag for default
41
41
  | **Database Setup** | • Turso (SQLite)<br>• Cloudflare D1 (SQLite)<br>• Neon (PostgreSQL)<br>• Supabase (PostgreSQL)<br>• Prisma Postgres<br>• MongoDB Atlas<br>• None (manual setup) |
42
42
  | **Authentication** | Better-Auth (email/password, with more options coming soon) |
43
43
  | **Styling** | Tailwind CSS with shadcn/ui components |
44
- | **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Husky (Git hooks)<br>• Turborepo (optimized builds) |
44
+ | **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Lefthook, Husky (Git hooks)<br>• Turborepo (optimized builds) |
45
45
  | **Examples** | • Todo app<br>• AI Chat interface (using Vercel AI SDK) |
46
46
  | **Developer Experience** | • Automatic Git initialization<br>• Package manager choice (npm, pnpm, bun)<br>• Automatic dependency installation |
47
47
 
@@ -58,7 +58,7 @@ Options:
58
58
  --auth Include authentication
59
59
  --no-auth Exclude authentication
60
60
  --frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-bare, native-uniwind, native-unistyles, none)
61
- --addons <types...> Additional addons (pwa, tauri, starlight, biome, husky, turborepo, fumadocs, ultracite, oxlint, none)
61
+ --addons <types...> Additional addons (pwa, tauri, starlight, biome, lefthook, husky, turborepo, fumadocs, ultracite, oxlint, none)
62
62
  --examples <types...> Examples to include (todo, ai, none)
63
63
  --git Initialize git repository
64
64
  --no-git Skip git initialization
@@ -193,7 +193,7 @@ npx create-better-t-stack --frontend none --backend hono --api trpc --database n
193
193
  - **ORM 'none'**: Can be used when you want to handle database operations manually or use a different ORM.
194
194
  - **Runtime 'none'**: Only available with Convex backend or when backend is 'none'.
195
195
  - **Cloudflare Workers runtime**: Only compatible with Hono backend, Drizzle ORM (or no ORM), and SQLite database (with D1 setup). Not compatible with MongoDB.
196
- - **Addons 'none'**: Skips all addons (PWA, Tauri, Starlight, Biome, Husky, Turborepo).
196
+ - **Addons 'none'**: Skips all addons (PWA, Tauri, Starlight, Biome, Lefthook,Husky, Turborepo).
197
197
  - **Examples 'none'**: Skips all example implementations (todo, AI chat).
198
198
  - **SvelteKit, Nuxt, and SolidJS** frontends are only compatible with oRPC API layer
199
199
  - **PWA support** requires React with TanStack Router, React Router, or SolidJS
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { o as createBtsCli } from "./src-CSz9J82Z.mjs";
2
+ import { o as createBtsCli } from "./src-CGRVv8L3.mjs";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.d.mts CHANGED
@@ -62,6 +62,7 @@ declare const router: {
62
62
  tauri: "tauri";
63
63
  starlight: "starlight";
64
64
  biome: "biome";
65
+ lefthook: "lefthook";
65
66
  husky: "husky";
66
67
  ruler: "ruler";
67
68
  turborepo: "turborepo";
@@ -142,7 +143,7 @@ declare const router: {
142
143
  backend: "none" | "hono" | "express" | "fastify" | "elysia" | "convex" | "self";
143
144
  runtime: "none" | "bun" | "node" | "workers";
144
145
  frontend: ("none" | "tanstack-router" | "react-router" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid")[];
145
- addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "husky" | "ruler" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt")[];
146
+ addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt")[];
146
147
  examples: ("none" | "todo" | "ai")[];
147
148
  auth: "none" | "better-auth" | "clerk";
148
149
  payments: "none" | "polar";
@@ -180,7 +181,7 @@ declare const router: {
180
181
  backend: "none" | "hono" | "express" | "fastify" | "elysia" | "convex" | "self";
181
182
  runtime: "none" | "bun" | "node" | "workers";
182
183
  frontend: ("none" | "tanstack-router" | "react-router" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid")[];
183
- addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "husky" | "ruler" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt")[];
184
+ addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt")[];
184
185
  examples: ("none" | "todo" | "ai")[];
185
186
  auth: "none" | "better-auth" | "clerk";
186
187
  payments: "none" | "polar";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { a as create, c as docs, d as sponsors, i as builder, l as generateVirtualProject, n as TEMPLATE_COUNT, o as createBtsCli, r as VirtualFileSystem, s as createVirtual, t as EMBEDDED_TEMPLATES, u as router } from "./src-CSz9J82Z.mjs";
2
+ import { a as create, c as docs, d as sponsors, i as builder, l as generateVirtualProject, n as TEMPLATE_COUNT, o as createBtsCli, r as VirtualFileSystem, s as createVirtual, t as EMBEDDED_TEMPLATES, u as router } from "./src-CGRVv8L3.mjs";
3
3
 
4
4
  export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, router, sponsors };
@@ -79,6 +79,7 @@ const ADDON_COMPATIBILITY = {
79
79
  ],
80
80
  biome: [],
81
81
  husky: [],
82
+ lefthook: [],
82
83
  turborepo: [],
83
84
  starlight: [],
84
85
  ultracite: [],
@@ -584,6 +585,10 @@ function getAddonDisplay(addon) {
584
585
  label = "Ruler";
585
586
  hint = "Centralize your AI rules";
586
587
  break;
588
+ case "lefthook":
589
+ label = "Lefthook";
590
+ hint = "Fast and powerful Git hooks manager";
591
+ break;
587
592
  case "husky":
588
593
  label = "Husky";
589
594
  hint = "Modern native Git hooks made easy";
@@ -619,7 +624,8 @@ const ADDON_GROUPS = {
619
624
  "biome",
620
625
  "oxlint",
621
626
  "ultracite",
622
- "husky"
627
+ "husky",
628
+ "lefthook"
623
629
  ],
624
630
  Documentation: ["starlight", "fumadocs"],
625
631
  Extensions: [
@@ -2553,11 +2559,15 @@ const AGENTS = {
2553
2559
  crush: { label: "Crush" },
2554
2560
  qwen: { label: "Qwen" },
2555
2561
  "amazon-q-cli": { label: "Amazon Q CLI" },
2556
- firebender: { label: "Firebender" }
2562
+ firebender: { label: "Firebender" },
2563
+ "cursor-cli": { label: "Cursor CLI" },
2564
+ "mistral-vibe": { label: "Mistral Vibe" },
2565
+ vercel: { label: "Vercel" }
2557
2566
  };
2558
2567
  const HOOKS = {
2559
2568
  cursor: { label: "Cursor" },
2560
- windsurf: { label: "Windsurf" }
2569
+ windsurf: { label: "Windsurf" },
2570
+ claude: { label: "Claude" }
2561
2571
  };
2562
2572
  function getFrameworksFromFrontend(frontend) {
2563
2573
  const frameworkMap = {
@@ -2576,7 +2586,7 @@ function getFrameworksFromFrontend(frontend) {
2576
2586
  for (const f of frontend) if (f !== "none" && frameworkMap[f]) frameworks.add(frameworkMap[f]);
2577
2587
  return Array.from(frameworks);
2578
2588
  }
2579
- async function setupUltracite(config, hasHusky) {
2589
+ async function setupUltracite(config, gitHooks) {
2580
2590
  const { packageManager, projectDir, frontend } = config;
2581
2591
  try {
2582
2592
  log.info("Setting up Ultracite...");
@@ -2632,7 +2642,11 @@ async function setupUltracite(config, hasHusky) {
2632
2642
  if (editors.length > 0) ultraciteArgs.push("--editors", ...editors);
2633
2643
  if (agents.length > 0) ultraciteArgs.push("--agents", ...agents);
2634
2644
  if (hooks.length > 0) ultraciteArgs.push("--hooks", ...hooks);
2635
- if (hasHusky) ultraciteArgs.push("--integrations", "husky", "lint-staged");
2645
+ if (gitHooks.length > 0) {
2646
+ const integrations = [...gitHooks];
2647
+ if (gitHooks.includes("husky")) integrations.push("lint-staged");
2648
+ ultraciteArgs.push("--integrations", ...integrations);
2649
+ }
2636
2650
  const args = getPackageExecutionArgs(packageManager, `ultracite@latest ${ultraciteArgs.join(" ")} --skip-install`);
2637
2651
  const s = spinner();
2638
2652
  s.start("Running Ultracite init command...");
@@ -2722,22 +2736,28 @@ async function setupAddons(config) {
2722
2736
  const hasUltracite = addons.includes("ultracite");
2723
2737
  const hasBiome = addons.includes("biome");
2724
2738
  const hasHusky = addons.includes("husky");
2739
+ const hasLefthook = addons.includes("lefthook");
2725
2740
  const hasOxlint = addons.includes("oxlint");
2726
- if (!hasUltracite) {
2741
+ if (hasUltracite) {
2742
+ const gitHooks = [];
2743
+ if (hasHusky) gitHooks.push("husky");
2744
+ if (hasLefthook) gitHooks.push("lefthook");
2745
+ await setupUltracite(config, gitHooks);
2746
+ } else {
2727
2747
  if (hasBiome) await setupBiome(projectDir);
2728
2748
  if (hasOxlint) await setupOxlint(projectDir, config.packageManager);
2729
- if (hasHusky) {
2749
+ if (hasHusky || hasLefthook) {
2730
2750
  let linter;
2731
2751
  if (hasOxlint) linter = "oxlint";
2732
2752
  else if (hasBiome) linter = "biome";
2733
- await setupHusky(projectDir, linter);
2753
+ if (hasHusky) await setupHusky(projectDir, linter);
2754
+ if (hasLefthook) await setupLefthook(projectDir);
2734
2755
  }
2735
2756
  }
2736
2757
  if (addons.includes("starlight")) await setupStarlight(config);
2737
2758
  if (addons.includes("fumadocs")) await setupFumadocs(config);
2738
2759
  if (addons.includes("opentui")) await setupTui(config);
2739
2760
  if (addons.includes("wxt")) await setupWxt(config);
2740
- if (hasUltracite) await setupUltracite(config, hasHusky);
2741
2761
  if (addons.includes("ruler")) await setupRuler(config);
2742
2762
  }
2743
2763
  async function setupBiome(projectDir) {
@@ -2773,6 +2793,12 @@ async function setupHusky(projectDir, linter) {
2773
2793
  await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
2774
2794
  }
2775
2795
  }
2796
+ async function setupLefthook(projectDir) {
2797
+ await addPackageDependency({
2798
+ devDependencies: ["lefthook"],
2799
+ projectDir
2800
+ });
2801
+ }
2776
2802
 
2777
2803
  //#endregion
2778
2804
  //#region src/utils/env-utils.ts
@@ -3851,11 +3877,13 @@ async function displayPostInstallInstructions(config) {
3851
3877
  const runCmd = packageManager === "npm" ? "npm run" : packageManager === "pnpm" ? "pnpm run" : "bun run";
3852
3878
  const cdCmd = `cd ${relativePath}`;
3853
3879
  const hasHusky = addons?.includes("husky");
3854
- const hasLinting = addons?.includes("biome") || addons?.includes("oxlint");
3880
+ const hasLefthook = addons?.includes("lefthook");
3881
+ const hasGitHooksOrLinting = addons?.includes("husky") || addons?.includes("biome") || addons?.includes("lefthook") || addons?.includes("oxlint");
3855
3882
  const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy, backend) : "";
3856
3883
  const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
3857
3884
  const huskyInstructions = hasHusky ? getHuskyInstructions(runCmd) : "";
3858
- const lintingInstructions = hasLinting ? getLintingInstructions(runCmd) : "";
3885
+ const lefthookInstructions = hasLefthook ? getLefthookInstructions(packageManager) : "";
3886
+ const lintingInstructions = hasGitHooksOrLinting ? getLintingInstructions(runCmd) : "";
3859
3887
  const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || [], runCmd) : "";
3860
3888
  const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
3861
3889
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
@@ -3910,6 +3938,7 @@ async function displayPostInstallInstructions(config) {
3910
3938
  if (databaseInstructions) output += `\n${databaseInstructions.trim()}\n`;
3911
3939
  if (tauriInstructions) output += `\n${tauriInstructions.trim()}\n`;
3912
3940
  if (huskyInstructions) output += `\n${huskyInstructions.trim()}\n`;
3941
+ if (lefthookInstructions) output += `\n${lefthookInstructions.trim()}\n`;
3913
3942
  if (lintingInstructions) output += `\n${lintingInstructions.trim()}\n`;
3914
3943
  if (pwaInstructions) output += `\n${pwaInstructions.trim()}\n`;
3915
3944
  if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
@@ -3938,6 +3967,10 @@ function getHuskyInstructions(runCmd) {
3938
3967
  function getLintingInstructions(runCmd) {
3939
3968
  return `${pc.bold("Linting and formatting:")}\n${pc.cyan("•")} Format and lint fix: ${`${runCmd} check`}\n`;
3940
3969
  }
3970
+ function getLefthookInstructions(packageManager) {
3971
+ const cmd = packageManager === "npm" ? "npx" : packageManager;
3972
+ return `${pc.bold("Git hooks with Lefthook:")}\n${pc.cyan("•")} Install hooks: ${cmd} lefthook install\n`;
3973
+ }
3941
3974
  async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup, serverDeploy, _backend) {
3942
3975
  const instructions = [];
3943
3976
  if (dbSetup === "docker") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.14.1",
3
+ "version": "3.15.0",
4
4
  "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
5
5
  "keywords": [
6
6
  "better-auth",
@@ -70,8 +70,8 @@
70
70
  "prepublishOnly": "npm run build"
71
71
  },
72
72
  "dependencies": {
73
- "@better-t-stack/template-generator": "^3.14.1",
74
- "@better-t-stack/types": "^3.14.1",
73
+ "@better-t-stack/template-generator": "^3.15.0",
74
+ "@better-t-stack/types": "^3.15.0",
75
75
  "@clack/core": "^0.5.0",
76
76
  "@clack/prompts": "^1.0.0-alpha.8",
77
77
  "@orpc/server": "^1.13.0",