create-kofi-stack 1.2.3 → 1.2.5

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.
Files changed (2) hide show
  1. package/dist/index.js +90 -603
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -66,11 +66,6 @@ async function promptMarketingSite(defaultValue) {
66
66
  label: "Next.js",
67
67
  hint: "Simple static/SSG site"
68
68
  },
69
- {
70
- value: "astro",
71
- label: "Astro",
72
- hint: "Lightweight, content-focused"
73
- },
74
69
  {
75
70
  value: "none",
76
71
  label: "None",
@@ -713,7 +708,7 @@ ${extras.length > 0 ? `${pc.bold("Extras:")} ${extras.join(", ")}` : ""}`,
713
708
  }
714
709
 
715
710
  // src/generators/index.ts
716
- import path20 from "path";
711
+ import path19 from "path";
717
712
  import * as p7 from "@clack/prompts";
718
713
  import pc3 from "picocolors";
719
714
  import ora from "ora";
@@ -811,11 +806,11 @@ async function generatePackageJson(config, appDir) {
811
806
  next: "^16.0.0",
812
807
  react: "^19.0.0",
813
808
  "react-dom": "^19.0.0",
814
- "@convex-dev/better-auth": "^0.10.9",
815
- "better-auth": "^1.4.0",
809
+ "@convex-dev/better-auth": "^0.10.10",
810
+ "better-auth": "1.4.9",
816
811
  convex: "^1.25.0",
817
- "@t3-oss/env-nextjs": "^0.11.0",
818
- zod: "^3.25.0",
812
+ "@t3-oss/env-nextjs": "^0.13.0",
813
+ zod: "^4.0.0",
819
814
  "date-fns": "^4.0.0",
820
815
  clsx: "^2.1.0",
821
816
  "tailwind-merge": "^2.5.0",
@@ -1996,7 +1991,7 @@ async function generateConvexPackageJson(convexDir) {
1996
1991
  types: "./convex/index.ts",
1997
1992
  dependencies: {
1998
1993
  convex: "^1.25.0",
1999
- "@convex-dev/better-auth": "^0.10.9"
1994
+ "@convex-dev/better-auth": "^0.10.10"
2000
1995
  },
2001
1996
  devDependencies: {
2002
1997
  typescript: "^5.0.0"
@@ -3257,10 +3252,10 @@ async function generatePayloadPackageJson(marketingDir) {
3257
3252
  "db:seed": "tsx src/seed.ts"
3258
3253
  },
3259
3254
  dependencies: {
3260
- next: "^16.0.0",
3255
+ next: "^15.4.10",
3261
3256
  react: "^19.0.0",
3262
3257
  "react-dom": "^19.0.0",
3263
- payload: "^3.0.0",
3258
+ payload: "^3.70.0",
3264
3259
  "@payloadcms/db-postgres": "^3.0.0",
3265
3260
  "@payloadcms/next": "^3.0.0",
3266
3261
  "@payloadcms/richtext-lexical": "^3.0.0",
@@ -4643,539 +4638,8 @@ See the [Convex documentation](https://docs.convex.dev) for database API referen
4643
4638
  );
4644
4639
  }
4645
4640
 
4646
- // src/generators/astro.ts
4647
- import path17 from "path";
4648
- async function generateAstro(config, marketingDir) {
4649
- await ensureDir(path17.join(marketingDir, "src/components"));
4650
- await ensureDir(path17.join(marketingDir, "src/layouts"));
4651
- await ensureDir(path17.join(marketingDir, "src/pages"));
4652
- await ensureDir(path17.join(marketingDir, "src/content/blog"));
4653
- await ensureDir(path17.join(marketingDir, "src/styles"));
4654
- await ensureDir(path17.join(marketingDir, "public"));
4655
- await generateAstroPackageJson(marketingDir);
4656
- await generateAstroConfig(marketingDir);
4657
- await generateAstroTsConfig(marketingDir);
4658
- await generateAstroLayouts(config, marketingDir);
4659
- await generateAstroPages(config, marketingDir);
4660
- await generateAstroComponents(config, marketingDir);
4661
- await generateAstroStyles(marketingDir);
4662
- await generateAstroContent(config, marketingDir);
4663
- }
4664
- async function generateAstroPackageJson(marketingDir) {
4665
- const packageJson = {
4666
- name: "@repo/marketing",
4667
- version: "0.1.0",
4668
- private: true,
4669
- type: "module",
4670
- scripts: {
4671
- dev: "astro dev --port 3001",
4672
- build: "astro build",
4673
- preview: "astro preview",
4674
- lint: "biome check .",
4675
- "lint:fix": "biome check --write .",
4676
- typecheck: "astro check && tsc --noEmit"
4677
- },
4678
- dependencies: {
4679
- astro: "^5.0.0",
4680
- "@astrojs/mdx": "^4.0.0",
4681
- "@astrojs/sitemap": "^3.0.0",
4682
- "@astrojs/tailwind": "^6.0.0",
4683
- "@astrojs/react": "^4.0.0",
4684
- react: "^19.0.0",
4685
- "react-dom": "^19.0.0"
4686
- },
4687
- devDependencies: {
4688
- "@repo/config-typescript": "workspace:*",
4689
- "@types/react": "^19.0.0",
4690
- "@types/react-dom": "^19.0.0",
4691
- tailwindcss: "^4.0.0",
4692
- typescript: "^5.0.0"
4693
- }
4694
- };
4695
- await writeJSON(path17.join(marketingDir, "package.json"), packageJson);
4696
- }
4697
- async function generateAstroConfig(marketingDir) {
4698
- const content = `import { defineConfig } from 'astro/config'
4699
- import mdx from '@astrojs/mdx'
4700
- import sitemap from '@astrojs/sitemap'
4701
- import tailwind from '@astrojs/tailwind'
4702
- import react from '@astrojs/react'
4703
-
4704
- export default defineConfig({
4705
- site: 'https://example.com',
4706
- integrations: [
4707
- mdx(),
4708
- sitemap(),
4709
- tailwind(),
4710
- react(),
4711
- ],
4712
- markdown: {
4713
- shikiConfig: {
4714
- theme: 'github-dark',
4715
- wrap: true,
4716
- },
4717
- },
4718
- })
4719
- `;
4720
- await writeFile(path17.join(marketingDir, "astro.config.mjs"), content);
4721
- }
4722
- async function generateAstroTsConfig(marketingDir) {
4723
- const tsConfig = {
4724
- extends: "astro/tsconfigs/strict",
4725
- compilerOptions: {
4726
- jsx: "react-jsx",
4727
- jsxImportSource: "react",
4728
- paths: {
4729
- "@/*": ["./src/*"]
4730
- }
4731
- }
4732
- };
4733
- await writeJSON(path17.join(marketingDir, "tsconfig.json"), tsConfig);
4734
- }
4735
- async function generateAstroLayouts(config, marketingDir) {
4736
- const baseLayoutContent = `---
4737
- interface Props {
4738
- title: string
4739
- description?: string
4740
- }
4741
-
4742
- const { title, description = '${config.name} - Built with create-kofi-stack' } = Astro.props
4743
- ---
4744
-
4745
- <!doctype html>
4746
- <html lang="en">
4747
- <head>
4748
- <meta charset="UTF-8" />
4749
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
4750
- <meta name="description" content={description} />
4751
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
4752
- <title>{title}</title>
4753
- </head>
4754
- <body class="min-h-screen bg-background text-foreground">
4755
- <slot />
4756
- </body>
4757
- </html>
4758
-
4759
- <style is:global>
4760
- @import '../styles/global.css';
4761
- </style>
4762
- `;
4763
- await writeFile(
4764
- path17.join(marketingDir, "src/layouts/BaseLayout.astro"),
4765
- baseLayoutContent
4766
- );
4767
- const blogLayoutContent = `---
4768
- import BaseLayout from './BaseLayout.astro'
4769
- import { format } from 'date-fns'
4770
-
4771
- interface Props {
4772
- frontmatter: {
4773
- title: string
4774
- description: string
4775
- pubDate: Date
4776
- author?: string
4777
- }
4778
- }
4779
-
4780
- const { frontmatter } = Astro.props
4781
- ---
4782
-
4783
- <BaseLayout title={frontmatter.title} description={frontmatter.description}>
4784
- <article class="container mx-auto px-4 py-16 max-w-3xl">
4785
- <header class="mb-8">
4786
- <h1 class="text-4xl font-bold mb-4">{frontmatter.title}</h1>
4787
- <div class="text-muted-foreground">
4788
- <time datetime={frontmatter.pubDate.toISOString()}>
4789
- {format(frontmatter.pubDate, 'MMMM d, yyyy')}
4790
- </time>
4791
- {frontmatter.author && <span> \xB7 {frontmatter.author}</span>}
4792
- </div>
4793
- </header>
4794
- <div class="prose prose-lg dark:prose-invert max-w-none">
4795
- <slot />
4796
- </div>
4797
- </article>
4798
- </BaseLayout>
4799
- `;
4800
- await writeFile(
4801
- path17.join(marketingDir, "src/layouts/BlogLayout.astro"),
4802
- blogLayoutContent
4803
- );
4804
- }
4805
- async function generateAstroPages(config, marketingDir) {
4806
- const homePageContent = `---
4807
- import BaseLayout from '../layouts/BaseLayout.astro'
4808
- import Hero from '../components/Hero.astro'
4809
- import Features from '../components/Features.astro'
4810
- import CTA from '../components/CTA.astro'
4811
- ---
4812
-
4813
- <BaseLayout title="${config.name} - Home">
4814
- <main>
4815
- <Hero />
4816
- <Features />
4817
- <CTA />
4818
- </main>
4819
- </BaseLayout>
4820
- `;
4821
- await writeFile(
4822
- path17.join(marketingDir, "src/pages/index.astro"),
4823
- homePageContent
4824
- );
4825
- const blogIndexContent = `---
4826
- import BaseLayout from '../layouts/BaseLayout.astro'
4827
- import { getCollection } from 'astro:content'
4828
- import { format } from 'date-fns'
4829
-
4830
- const posts = (await getCollection('blog')).sort(
4831
- (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
4832
- )
4833
- ---
4834
-
4835
- <BaseLayout title="Blog - ${config.name}">
4836
- <main class="container mx-auto px-4 py-16">
4837
- <h1 class="text-4xl font-bold mb-8">Blog</h1>
4838
- <div class="grid gap-8">
4839
- {
4840
- posts.map((post) => (
4841
- <article class="border rounded-lg p-6 hover:shadow-md transition-shadow">
4842
- <a href={\`/blog/\${post.slug}\`}>
4843
- <h2 class="text-2xl font-semibold mb-2">{post.data.title}</h2>
4844
- <p class="text-muted-foreground mb-4">{post.data.description}</p>
4845
- <time class="text-sm text-muted-foreground">
4846
- {format(post.data.pubDate, 'MMMM d, yyyy')}
4847
- </time>
4848
- </a>
4849
- </article>
4850
- ))
4851
- }
4852
- </div>
4853
- </main>
4854
- </BaseLayout>
4855
- `;
4856
- await writeFile(
4857
- path17.join(marketingDir, "src/pages/blog/index.astro"),
4858
- blogIndexContent
4859
- );
4860
- await ensureDir(path17.join(marketingDir, "src/pages/blog"));
4861
- const blogPostContent = `---
4862
- import { getCollection } from 'astro:content'
4863
- import BlogLayout from '../../layouts/BlogLayout.astro'
4864
-
4865
- export async function getStaticPaths() {
4866
- const posts = await getCollection('blog')
4867
- return posts.map((post) => ({
4868
- params: { slug: post.slug },
4869
- props: post,
4870
- }))
4871
- }
4872
-
4873
- const post = Astro.props
4874
- const { Content } = await post.render()
4875
- ---
4876
-
4877
- <BlogLayout frontmatter={post.data}>
4878
- <Content />
4879
- </BlogLayout>
4880
- `;
4881
- await writeFile(
4882
- path17.join(marketingDir, "src/pages/blog/[slug].astro"),
4883
- blogPostContent
4884
- );
4885
- const notFoundContent = `---
4886
- import BaseLayout from '../layouts/BaseLayout.astro'
4887
- ---
4888
-
4889
- <BaseLayout title="404 - Page Not Found">
4890
- <main class="container mx-auto px-4 py-16 text-center">
4891
- <h1 class="text-6xl font-bold mb-4">404</h1>
4892
- <p class="text-xl text-muted-foreground mb-8">Page not found</p>
4893
- <a href="/" class="inline-block px-6 py-3 bg-primary text-primary-foreground rounded-lg">
4894
- Go Home
4895
- </a>
4896
- </main>
4897
- </BaseLayout>
4898
- `;
4899
- await writeFile(
4900
- path17.join(marketingDir, "src/pages/404.astro"),
4901
- notFoundContent
4902
- );
4903
- }
4904
- async function generateAstroComponents(config, marketingDir) {
4905
- const heroContent = `---
4906
-
4907
- ---
4908
-
4909
- <section class="py-20 lg:py-32">
4910
- <div class="container mx-auto px-4 text-center">
4911
- <h1 class="text-5xl lg:text-7xl font-bold mb-6">
4912
- Welcome to <span class="text-primary">${config.name}</span>
4913
- </h1>
4914
- <p class="text-xl lg:text-2xl text-muted-foreground mb-8 max-w-2xl mx-auto">
4915
- Build your next SaaS application with our modern, full-stack starter template.
4916
- </p>
4917
- <div class="flex flex-col sm:flex-row gap-4 justify-center">
4918
- <a
4919
- href="/docs"
4920
- class="px-8 py-3 bg-primary text-primary-foreground rounded-lg font-semibold hover:opacity-90 transition-opacity"
4921
- >
4922
- Get Started
4923
- </a>
4924
- <a
4925
- href="https://github.com"
4926
- class="px-8 py-3 border rounded-lg font-semibold hover:bg-accent transition-colors"
4927
- >
4928
- View on GitHub
4929
- </a>
4930
- </div>
4931
- </div>
4932
- </section>
4933
- `;
4934
- await writeFile(
4935
- path17.join(marketingDir, "src/components/Hero.astro"),
4936
- heroContent
4937
- );
4938
- const featuresContent = `---
4939
- const features = [
4940
- {
4941
- title: 'Next.js 15',
4942
- description: 'Built on the latest Next.js with App Router and React 19.',
4943
- },
4944
- {
4945
- title: 'Convex Database',
4946
- description: 'Real-time database with automatic syncing and TypeScript support.',
4947
- },
4948
- {
4949
- title: 'Better-Auth',
4950
- description: 'Flexible authentication with email, OAuth, and more.',
4951
- },
4952
- {
4953
- title: 'shadcn/ui',
4954
- description: 'Beautiful, accessible components built with Radix UI and Tailwind.',
4955
- },
4956
- {
4957
- title: 'Tailwind CSS v4',
4958
- description: 'CSS-first configuration with modern theming capabilities.',
4959
- },
4960
- {
4961
- title: 'TypeScript',
4962
- description: 'Full type safety from database to frontend.',
4963
- },
4964
- ]
4965
- ---
4966
-
4967
- <section class="py-20 bg-muted/50">
4968
- <div class="container mx-auto px-4">
4969
- <h2 class="text-3xl lg:text-4xl font-bold text-center mb-12">Features</h2>
4970
- <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
4971
- {
4972
- features.map((feature) => (
4973
- <div class="p-6 bg-background rounded-lg border">
4974
- <h3 class="text-xl font-semibold mb-2">{feature.title}</h3>
4975
- <p class="text-muted-foreground">{feature.description}</p>
4976
- </div>
4977
- ))
4978
- }
4979
- </div>
4980
- </div>
4981
- </section>
4982
- `;
4983
- await writeFile(
4984
- path17.join(marketingDir, "src/components/Features.astro"),
4985
- featuresContent
4986
- );
4987
- const ctaContent = `---
4988
-
4989
- ---
4990
-
4991
- <section class="py-20">
4992
- <div class="container mx-auto px-4 text-center">
4993
- <h2 class="text-3xl lg:text-4xl font-bold mb-4">Ready to get started?</h2>
4994
- <p class="text-xl text-muted-foreground mb-8 max-w-xl mx-auto">
4995
- Start building your SaaS application today with our fully-featured starter template.
4996
- </p>
4997
- <a
4998
- href="https://app.example.com"
4999
- class="inline-block px-8 py-3 bg-primary text-primary-foreground rounded-lg font-semibold hover:opacity-90 transition-opacity"
5000
- >
5001
- Launch App
5002
- </a>
5003
- </div>
5004
- </section>
5005
- `;
5006
- await writeFile(
5007
- path17.join(marketingDir, "src/components/CTA.astro"),
5008
- ctaContent
5009
- );
5010
- const headerContent = `---
5011
- const navItems = [
5012
- { label: 'Features', href: '/#features' },
5013
- { label: 'Blog', href: '/blog' },
5014
- { label: 'Docs', href: '/docs' },
5015
- ]
5016
- ---
5017
-
5018
- <header class="sticky top-0 z-50 bg-background/80 backdrop-blur border-b">
5019
- <div class="container mx-auto px-4">
5020
- <nav class="flex items-center justify-between h-16">
5021
- <a href="/" class="text-xl font-bold">${config.name}</a>
5022
- <div class="hidden md:flex items-center gap-6">
5023
- {
5024
- navItems.map((item) => (
5025
- <a href={item.href} class="text-muted-foreground hover:text-foreground transition-colors">
5026
- {item.label}
5027
- </a>
5028
- ))
5029
- }
5030
- <a
5031
- href="https://app.example.com"
5032
- class="px-4 py-2 bg-primary text-primary-foreground rounded-lg font-medium"
5033
- >
5034
- Launch App
5035
- </a>
5036
- </div>
5037
- </nav>
5038
- </div>
5039
- </header>
5040
- `;
5041
- await writeFile(
5042
- path17.join(marketingDir, "src/components/Header.astro"),
5043
- headerContent
5044
- );
5045
- const footerContent = `---
5046
- const currentYear = new Date().getFullYear()
5047
- ---
5048
-
5049
- <footer class="py-12 border-t">
5050
- <div class="container mx-auto px-4">
5051
- <div class="flex flex-col md:flex-row justify-between items-center gap-4">
5052
- <p class="text-muted-foreground">
5053
- &copy; {currentYear} ${config.name}. All rights reserved.
5054
- </p>
5055
- <div class="flex gap-6">
5056
- <a href="/privacy" class="text-muted-foreground hover:text-foreground transition-colors">
5057
- Privacy
5058
- </a>
5059
- <a href="/terms" class="text-muted-foreground hover:text-foreground transition-colors">
5060
- Terms
5061
- </a>
5062
- </div>
5063
- </div>
5064
- </div>
5065
- </footer>
5066
- `;
5067
- await writeFile(
5068
- path17.join(marketingDir, "src/components/Footer.astro"),
5069
- footerContent
5070
- );
5071
- }
5072
- async function generateAstroStyles(marketingDir) {
5073
- const globalStyles = `@import "tailwindcss";
5074
-
5075
- :root {
5076
- --background: 0 0% 100%;
5077
- --foreground: 0 0% 3.9%;
5078
- --muted: 0 0% 96.1%;
5079
- --muted-foreground: 0 0% 45.1%;
5080
- --primary: 0 0% 9%;
5081
- --primary-foreground: 0 0% 98%;
5082
- --accent: 0 0% 96.1%;
5083
- --accent-foreground: 0 0% 9%;
5084
- --border: 0 0% 89.8%;
5085
- }
5086
-
5087
- .dark {
5088
- --background: 0 0% 3.9%;
5089
- --foreground: 0 0% 98%;
5090
- --muted: 0 0% 14.9%;
5091
- --muted-foreground: 0 0% 63.9%;
5092
- --primary: 0 0% 98%;
5093
- --primary-foreground: 0 0% 9%;
5094
- --accent: 0 0% 14.9%;
5095
- --accent-foreground: 0 0% 98%;
5096
- --border: 0 0% 14.9%;
5097
- }
5098
-
5099
- @theme {
5100
- --color-background: hsl(var(--background));
5101
- --color-foreground: hsl(var(--foreground));
5102
- --color-muted: hsl(var(--muted));
5103
- --color-muted-foreground: hsl(var(--muted-foreground));
5104
- --color-primary: hsl(var(--primary));
5105
- --color-primary-foreground: hsl(var(--primary-foreground));
5106
- --color-accent: hsl(var(--accent));
5107
- --color-accent-foreground: hsl(var(--accent-foreground));
5108
- --color-border: hsl(var(--border));
5109
- }
5110
-
5111
- @layer base {
5112
- body {
5113
- @apply bg-background text-foreground;
5114
- }
5115
- }
5116
- `;
5117
- await writeFile(
5118
- path17.join(marketingDir, "src/styles/global.css"),
5119
- globalStyles
5120
- );
5121
- }
5122
- async function generateAstroContent(config, marketingDir) {
5123
- const contentConfigContent = `import { defineCollection, z } from 'astro:content'
5124
-
5125
- const blog = defineCollection({
5126
- type: 'content',
5127
- schema: z.object({
5128
- title: z.string(),
5129
- description: z.string(),
5130
- pubDate: z.coerce.date(),
5131
- updatedDate: z.coerce.date().optional(),
5132
- author: z.string().optional(),
5133
- heroImage: z.string().optional(),
5134
- }),
5135
- })
5136
-
5137
- export const collections = { blog }
5138
- `;
5139
- await writeFile(
5140
- path17.join(marketingDir, "src/content/config.ts"),
5141
- contentConfigContent
5142
- );
5143
- const samplePostContent = `---
5144
- title: 'Welcome to ${config.name}'
5145
- description: 'Learn about the features and capabilities of ${config.name}.'
5146
- pubDate: '${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}'
5147
- author: 'The Team'
5148
- ---
5149
-
5150
- # Welcome to ${config.name}
5151
-
5152
- This is a sample blog post to help you get started with your marketing site.
5153
-
5154
- ## Features
5155
-
5156
- Our platform includes:
5157
-
5158
- - **Modern Stack**: Built with Next.js 15 and React 19
5159
- - **Real-time Database**: Powered by Convex
5160
- - **Authentication**: Secure auth with Better-Auth
5161
- - **Beautiful UI**: Components from shadcn/ui
5162
-
5163
- ## Getting Started
5164
-
5165
- To get started, check out our [documentation](/docs) or [launch the app](https://app.example.com).
5166
-
5167
- ## Stay Updated
5168
-
5169
- Follow our blog for updates on new features and best practices.
5170
- `;
5171
- await writeFile(
5172
- path17.join(marketingDir, "src/content/blog/welcome.md"),
5173
- samplePostContent
5174
- );
5175
- }
5176
-
5177
4641
  // src/generators/design-system.ts
5178
- import path18 from "path";
4642
+ import path17 from "path";
5179
4643
  var fontImports = {
5180
4644
  inter: {
5181
4645
  import: "import { Inter } from 'next/font/google'",
@@ -5243,16 +4707,16 @@ var spacingMultipliers = {
5243
4707
  relaxed: 1.125
5244
4708
  };
5245
4709
  async function generateDesignSystemApp(config, targetDir) {
5246
- const appDir = path18.join(targetDir, "apps/design-system");
5247
- await ensureDir(path18.join(appDir, "src/app"));
5248
- await ensureDir(path18.join(appDir, "src/app/colors"));
5249
- await ensureDir(path18.join(appDir, "src/app/typography"));
5250
- await ensureDir(path18.join(appDir, "src/app/spacing"));
5251
- await ensureDir(path18.join(appDir, "src/app/brand"));
5252
- await ensureDir(path18.join(appDir, "src/app/blocks"));
5253
- await ensureDir(path18.join(appDir, "src/app/components"));
5254
- await ensureDir(path18.join(appDir, "src/lib"));
5255
- await ensureDir(path18.join(appDir, "public/brand"));
4710
+ const appDir = path17.join(targetDir, "apps/design-system");
4711
+ await ensureDir(path17.join(appDir, "src/app"));
4712
+ await ensureDir(path17.join(appDir, "src/app/colors"));
4713
+ await ensureDir(path17.join(appDir, "src/app/typography"));
4714
+ await ensureDir(path17.join(appDir, "src/app/spacing"));
4715
+ await ensureDir(path17.join(appDir, "src/app/brand"));
4716
+ await ensureDir(path17.join(appDir, "src/app/blocks"));
4717
+ await ensureDir(path17.join(appDir, "src/app/components"));
4718
+ await ensureDir(path17.join(appDir, "src/lib"));
4719
+ await ensureDir(path17.join(appDir, "public/brand"));
5256
4720
  await generatePackageJson2(config, appDir);
5257
4721
  await generateTsConfig2(appDir);
5258
4722
  await generateNextConfig2(appDir);
@@ -5304,7 +4768,7 @@ async function generatePackageJson2(config, appDir) {
5304
4768
  typescript: "^5.0.0"
5305
4769
  }
5306
4770
  };
5307
- await writeJSON(path18.join(appDir, "package.json"), packageJson);
4771
+ await writeJSON(path17.join(appDir, "package.json"), packageJson);
5308
4772
  }
5309
4773
  async function generateTsConfig2(appDir) {
5310
4774
  const tsConfig = {
@@ -5320,7 +4784,7 @@ async function generateTsConfig2(appDir) {
5320
4784
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
5321
4785
  exclude: ["node_modules"]
5322
4786
  };
5323
- await writeJSON(path18.join(appDir, "tsconfig.json"), tsConfig);
4787
+ await writeJSON(path17.join(appDir, "tsconfig.json"), tsConfig);
5324
4788
  }
5325
4789
  async function generateNextConfig2(appDir) {
5326
4790
  const content = `import type { NextConfig } from 'next'
@@ -5331,7 +4795,7 @@ const nextConfig: NextConfig = {
5331
4795
 
5332
4796
  export default nextConfig
5333
4797
  `;
5334
- await writeFile(path18.join(appDir, "next.config.ts"), content);
4798
+ await writeFile(path17.join(appDir, "next.config.ts"), content);
5335
4799
  }
5336
4800
  async function generatePostCssConfig2(appDir) {
5337
4801
  const content = `export default {
@@ -5340,7 +4804,7 @@ async function generatePostCssConfig2(appDir) {
5340
4804
  },
5341
4805
  }
5342
4806
  `;
5343
- await writeFile(path18.join(appDir, "postcss.config.mjs"), content);
4807
+ await writeFile(path17.join(appDir, "postcss.config.mjs"), content);
5344
4808
  }
5345
4809
  async function generateGlobalsCss2(config, appDir) {
5346
4810
  const { designSystem } = config;
@@ -5600,7 +5064,7 @@ h1, h2, h3, h4, h5, h6 {
5600
5064
  }
5601
5065
  }
5602
5066
  `;
5603
- await writeFile(path18.join(appDir, "src/app/globals.css"), content);
5067
+ await writeFile(path17.join(appDir, "src/app/globals.css"), content);
5604
5068
  }
5605
5069
  async function generateLayoutTsx(config, appDir) {
5606
5070
  const { designSystem } = config;
@@ -5799,7 +5263,7 @@ function ThemeToggle() {
5799
5263
  )
5800
5264
  }
5801
5265
  `;
5802
- await writeFile(path18.join(appDir, "src/app/layout.tsx"), content);
5266
+ await writeFile(path17.join(appDir, "src/app/layout.tsx"), content);
5803
5267
  }
5804
5268
  async function generateHomePage(config, appDir) {
5805
5269
  const content = `export default function DesignSystemHome() {
@@ -5965,7 +5429,7 @@ function Principle({
5965
5429
  )
5966
5430
  }
5967
5431
  `;
5968
- await writeFile(path18.join(appDir, "src/app/page.tsx"), content);
5432
+ await writeFile(path17.join(appDir, "src/app/page.tsx"), content);
5969
5433
  }
5970
5434
  async function generateColorsPage(config, appDir) {
5971
5435
  const content = `export default function ColorsPage() {
@@ -6134,7 +5598,7 @@ function ColorCard({
6134
5598
  )
6135
5599
  }
6136
5600
  `;
6137
- await writeFile(path18.join(appDir, "src/app/colors/page.tsx"), content);
5601
+ await writeFile(path17.join(appDir, "src/app/colors/page.tsx"), content);
6138
5602
  }
6139
5603
  async function generateTypographyPage(config, appDir) {
6140
5604
  const { designSystem } = config;
@@ -6291,7 +5755,7 @@ function WeightCard({ weight, name }: { weight: string; name: string }) {
6291
5755
  )
6292
5756
  }
6293
5757
  `;
6294
- await writeFile(path18.join(appDir, "src/app/typography/page.tsx"), content);
5758
+ await writeFile(path17.join(appDir, "src/app/typography/page.tsx"), content);
6295
5759
  }
6296
5760
  async function generateSpacingPage(config, appDir) {
6297
5761
  const { designSystem } = config;
@@ -6424,7 +5888,7 @@ function PatternCard({
6424
5888
  )
6425
5889
  }
6426
5890
  `;
6427
- await writeFile(path18.join(appDir, "src/app/spacing/page.tsx"), content);
5891
+ await writeFile(path17.join(appDir, "src/app/spacing/page.tsx"), content);
6428
5892
  }
6429
5893
  async function generateBrandPage(config, appDir) {
6430
5894
  const content = `export default function BrandPage() {
@@ -6562,7 +6026,7 @@ function DownloadCard({
6562
6026
  )
6563
6027
  }
6564
6028
  `;
6565
- await writeFile(path18.join(appDir, "src/app/brand/page.tsx"), content);
6029
+ await writeFile(path17.join(appDir, "src/app/brand/page.tsx"), content);
6566
6030
  }
6567
6031
  async function generateBlocksPage(appDir) {
6568
6032
  const content = `export default function BlocksPage() {
@@ -6624,7 +6088,7 @@ function BlockCard({ title, description }: { title: string; description: string
6624
6088
  )
6625
6089
  }
6626
6090
  `;
6627
- await writeFile(path18.join(appDir, "src/app/blocks/page.tsx"), content);
6091
+ await writeFile(path17.join(appDir, "src/app/blocks/page.tsx"), content);
6628
6092
  }
6629
6093
  async function generateComponentsPage(appDir) {
6630
6094
  const content = `export default function ComponentsPage() {
@@ -6704,7 +6168,7 @@ function CategoryCard({
6704
6168
  )
6705
6169
  }
6706
6170
  `;
6707
- await writeFile(path18.join(appDir, "src/app/components/page.tsx"), content);
6171
+ await writeFile(path17.join(appDir, "src/app/components/page.tsx"), content);
6708
6172
  }
6709
6173
  async function generateUtils(appDir) {
6710
6174
  const content = `import { clsx, type ClassValue } from 'clsx'
@@ -6714,7 +6178,7 @@ export function cn(...inputs: ClassValue[]) {
6714
6178
  return twMerge(clsx(inputs))
6715
6179
  }
6716
6180
  `;
6717
- await writeFile(path18.join(appDir, "src/lib/utils.ts"), content);
6181
+ await writeFile(path17.join(appDir, "src/lib/utils.ts"), content);
6718
6182
  }
6719
6183
 
6720
6184
  // src/setup/env-wizard.ts
@@ -6722,7 +6186,7 @@ import * as p6 from "@clack/prompts";
6722
6186
  import pc2 from "picocolors";
6723
6187
  import { exec } from "child_process";
6724
6188
  import { promisify } from "util";
6725
- import path19 from "path";
6189
+ import path18 from "path";
6726
6190
  var execAsync = promisify(exec);
6727
6191
  async function runEnvSetupWizard(config) {
6728
6192
  console.log();
@@ -6797,15 +6261,40 @@ async function setupConvex(config, envValues) {
6797
6261
  }
6798
6262
  if (convexChoice === "new") {
6799
6263
  p6.log.info(`
6800
- ${pc2.bold("To create a new Convex project:")}
6801
-
6802
- 1. Run ${pc2.cyan("pnpm convex dev")} in your project directory
6803
- 2. It will open your browser to create a new project
6804
- 3. Follow the prompts to set up your Convex project
6805
- 4. The CLI will automatically add the deployment URL to .env.local
6264
+ ${pc2.bold("Creating a new Convex project...")}
6806
6265
 
6266
+ This will open your browser to create a new project on Convex.
6807
6267
  ${pc2.dim("Note: Make sure you have a Convex account at https://convex.dev")}
6808
6268
  `);
6269
+ try {
6270
+ const convexDir = config.structure === "monorepo" ? path18.join(config.targetDir, "packages/backend") : config.targetDir;
6271
+ p6.log.info(`Running ${pc2.cyan("npx convex dev --once")} in ${pc2.dim(convexDir)}...`);
6272
+ const { spawn } = await import("child_process");
6273
+ await new Promise((resolve) => {
6274
+ const child = spawn("npx", ["convex", "dev", "--once"], {
6275
+ cwd: convexDir,
6276
+ stdio: "inherit",
6277
+ shell: true
6278
+ });
6279
+ child.on("close", (code) => {
6280
+ if (code === 0) {
6281
+ p6.log.success("Convex project created successfully!");
6282
+ resolve();
6283
+ } else {
6284
+ p6.log.warn(`Convex setup exited with code ${code}. You can run 'pnpm convex dev' manually later.`);
6285
+ resolve();
6286
+ }
6287
+ });
6288
+ child.on("error", (error) => {
6289
+ p6.log.warn(`Could not run Convex setup: ${error.message}`);
6290
+ p6.log.info(`Run ${pc2.cyan("pnpm convex dev")} manually in your project directory.`);
6291
+ resolve();
6292
+ });
6293
+ });
6294
+ } catch (error) {
6295
+ p6.log.warn("Could not run Convex setup automatically.");
6296
+ p6.log.info(`Run ${pc2.cyan("pnpm convex dev")} manually in your project directory.`);
6297
+ }
6809
6298
  } else if (convexChoice === "existing") {
6810
6299
  const deploymentName = await p6.text({
6811
6300
  message: "Enter your Convex deployment name (e.g., my-app-123):",
@@ -7029,7 +6518,7 @@ async function writeEnvFiles(config, envValues) {
7029
6518
  return;
7030
6519
  }
7031
6520
  p6.log.step("Writing environment files...");
7032
- const webEnvPath = config.structure === "monorepo" ? path19.join(config.targetDir, "apps/web/.env.local") : path19.join(config.targetDir, ".env.local");
6521
+ const webEnvPath = config.structure === "monorepo" ? path18.join(config.targetDir, "apps/web/.env.local") : path18.join(config.targetDir, ".env.local");
7033
6522
  if (await pathExists(webEnvPath)) {
7034
6523
  let content = await readFile(webEnvPath);
7035
6524
  for (const [key, value] of Object.entries(envValues)) {
@@ -7048,7 +6537,7 @@ ${key}="${value}"`;
7048
6537
  p6.log.success(`Updated ${config.structure === "monorepo" ? "apps/web/.env.local" : ".env.local"}`);
7049
6538
  }
7050
6539
  if (config.marketingSite === "payload" && config.structure === "monorepo") {
7051
- const marketingEnvPath = path19.join(config.targetDir, "apps/marketing/.env.local");
6540
+ const marketingEnvPath = path18.join(config.targetDir, "apps/marketing/.env.local");
7052
6541
  if (await pathExists(marketingEnvPath)) {
7053
6542
  let content = await readFile(marketingEnvPath);
7054
6543
  const payloadEnvKeys = ["PAYLOAD_SECRET", "DATABASE_URL", "S3_ENDPOINT", "S3_REGION", "S3_BUCKET", "S3_ACCESS_KEY_ID", "S3_SECRET_ACCESS_KEY", "CRON_SECRET", "PREVIEW_SECRET"];
@@ -7109,7 +6598,7 @@ async function generateSingleProject(config, spinner) {
7109
6598
  await generateShadcn(config, targetDir);
7110
6599
  spinner.succeed("shadcn/ui configured");
7111
6600
  spinner.start("Setting up Convex...");
7112
- await generateConvex(config, path20.join(targetDir, "convex"));
6601
+ await generateConvex(config, path19.join(targetDir, "convex"));
7113
6602
  spinner.succeed("Convex configured");
7114
6603
  spinner.start("Configuring Better-Auth...");
7115
6604
  await generateBetterAuth(config, targetDir);
@@ -7152,7 +6641,7 @@ async function generateMonorepoProject(config, spinner) {
7152
6641
  spinner.start("Creating shared UI package...");
7153
6642
  await generateUIPackage(config, targetDir);
7154
6643
  spinner.succeed("Shared UI package created");
7155
- const webDir = path20.join(targetDir, "apps/web");
6644
+ const webDir = path19.join(targetDir, "apps/web");
7156
6645
  spinner.start("Generating web application...");
7157
6646
  await generateBaseNextjs(config, webDir);
7158
6647
  await generateTailwind(config, webDir);
@@ -7162,10 +6651,10 @@ async function generateMonorepoProject(config, spinner) {
7162
6651
  await generateEmail(config, webDir);
7163
6652
  await updateWebTsConfig(webDir);
7164
6653
  spinner.succeed("Web application generated");
7165
- const backendDir = path20.join(targetDir, "packages/backend");
6654
+ const backendDir = path19.join(targetDir, "packages/backend");
7166
6655
  spinner.start("Setting up Convex backend...");
7167
6656
  await ensureDir(backendDir);
7168
- await generateConvex(config, path20.join(backendDir, "convex"));
6657
+ await generateConvex(config, path19.join(backendDir, "convex"));
7169
6658
  spinner.succeed("Convex backend configured");
7170
6659
  if (config.integrations.analytics !== "none") {
7171
6660
  spinner.start(`Setting up ${config.integrations.analytics} analytics...`);
@@ -7188,19 +6677,17 @@ async function generateMonorepoProject(config, spinner) {
7188
6677
  spinner.succeed(`${config.integrations.monitoring} monitoring configured`);
7189
6678
  }
7190
6679
  if (config.marketingSite !== "none") {
7191
- const marketingDir = path20.join(targetDir, "apps/marketing");
6680
+ const marketingDir = path19.join(targetDir, "apps/marketing");
7192
6681
  spinner.start(`Generating ${config.marketingSite} marketing site...`);
7193
6682
  if (config.marketingSite === "payload") {
7194
6683
  await generatePayload(config, marketingDir);
7195
- } else if (config.marketingSite === "astro") {
7196
- await generateAstro(config, marketingDir);
7197
6684
  } else if (config.marketingSite === "nextjs") {
7198
6685
  await generateNextjsMarketing(config, marketingDir);
7199
6686
  }
7200
6687
  spinner.succeed(`${config.marketingSite} marketing site generated`);
7201
6688
  }
7202
6689
  if (config.includeDocs) {
7203
- const docsDir = path20.join(targetDir, "apps/docs");
6690
+ const docsDir = path19.join(targetDir, "apps/docs");
7204
6691
  spinner.start("Generating Fumadocs documentation site...");
7205
6692
  await generateFumadocs(config, docsDir);
7206
6693
  spinner.succeed("Fumadocs documentation site generated");
@@ -7221,7 +6708,7 @@ async function runPostGenerationSteps(config, spinner) {
7221
6708
  }
7222
6709
  spinner.start("Installing shadcn/ui components...");
7223
6710
  try {
7224
- const shadcnDir = config.structure === "monorepo" ? path20.join(targetDir, "packages/ui") : targetDir;
6711
+ const shadcnDir = config.structure === "monorepo" ? path19.join(targetDir, "packages/ui") : targetDir;
7225
6712
  await runShadcnAdd(shadcnDir);
7226
6713
  spinner.succeed("shadcn/ui components installed");
7227
6714
  } catch (error) {
@@ -7281,7 +6768,7 @@ async function generateBiomeConfig(targetDir) {
7281
6768
  }
7282
6769
  };
7283
6770
  await writeFile(
7284
- path20.join(targetDir, "biome.json"),
6771
+ path19.join(targetDir, "biome.json"),
7285
6772
  JSON.stringify(biomeJson, null, 2)
7286
6773
  );
7287
6774
  }
@@ -7332,13 +6819,13 @@ yarn-error.log*
7332
6819
  *.pem
7333
6820
  .cache
7334
6821
  `;
7335
- await writeFile(path20.join(targetDir, ".gitignore"), gitignoreContent);
6822
+ await writeFile(path19.join(targetDir, ".gitignore"), gitignoreContent);
7336
6823
  }
7337
6824
  async function generateHuskyHooks(targetDir) {
7338
6825
  const preCommitContent = `pnpm lint-staged
7339
6826
  `;
7340
- await ensureDir(path20.join(targetDir, ".husky"));
7341
- await writeFile(path20.join(targetDir, ".husky/pre-commit"), preCommitContent);
6827
+ await ensureDir(path19.join(targetDir, ".husky"));
6828
+ await writeFile(path19.join(targetDir, ".husky/pre-commit"), preCommitContent);
7342
6829
  }
7343
6830
  async function updateWebTsConfig(webDir) {
7344
6831
  const tsConfig = {
@@ -7352,14 +6839,14 @@ async function updateWebTsConfig(webDir) {
7352
6839
  exclude: ["node_modules"]
7353
6840
  };
7354
6841
  await writeFile(
7355
- path20.join(webDir, "tsconfig.json"),
6842
+ path19.join(webDir, "tsconfig.json"),
7356
6843
  JSON.stringify(tsConfig, null, 2)
7357
6844
  );
7358
6845
  }
7359
6846
  async function generateNextjsMarketing(config, marketingDir) {
7360
- await ensureDir(path20.join(marketingDir, "src/app"));
7361
- await ensureDir(path20.join(marketingDir, "src/components"));
7362
- await ensureDir(path20.join(marketingDir, "public"));
6847
+ await ensureDir(path19.join(marketingDir, "src/app"));
6848
+ await ensureDir(path19.join(marketingDir, "src/components"));
6849
+ await ensureDir(path19.join(marketingDir, "public"));
7363
6850
  const packageJson = {
7364
6851
  name: "@repo/marketing",
7365
6852
  version: "0.1.0",
@@ -7390,7 +6877,7 @@ async function generateNextjsMarketing(config, marketingDir) {
7390
6877
  }
7391
6878
  };
7392
6879
  await writeFile(
7393
- path20.join(marketingDir, "package.json"),
6880
+ path19.join(marketingDir, "package.json"),
7394
6881
  JSON.stringify(packageJson, null, 2)
7395
6882
  );
7396
6883
  const homePageContent = `export default function HomePage() {
@@ -7413,7 +6900,7 @@ async function generateNextjsMarketing(config, marketingDir) {
7413
6900
  }
7414
6901
  `;
7415
6902
  await writeFile(
7416
- path20.join(marketingDir, "src/app/page.tsx"),
6903
+ path19.join(marketingDir, "src/app/page.tsx"),
7417
6904
  homePageContent
7418
6905
  );
7419
6906
  const layoutContent = `import type { Metadata } from 'next'
@@ -7437,7 +6924,7 @@ export default function RootLayout({
7437
6924
  }
7438
6925
  `;
7439
6926
  await writeFile(
7440
- path20.join(marketingDir, "src/app/layout.tsx"),
6927
+ path19.join(marketingDir, "src/app/layout.tsx"),
7441
6928
  layoutContent
7442
6929
  );
7443
6930
  const globalsCss = `@import "tailwindcss";
@@ -7449,7 +6936,7 @@ export default function RootLayout({
7449
6936
  }
7450
6937
  `;
7451
6938
  await writeFile(
7452
- path20.join(marketingDir, "src/app/globals.css"),
6939
+ path19.join(marketingDir, "src/app/globals.css"),
7453
6940
  globalsCss
7454
6941
  );
7455
6942
  const tsConfig = {
@@ -7463,7 +6950,7 @@ export default function RootLayout({
7463
6950
  exclude: ["node_modules"]
7464
6951
  };
7465
6952
  await writeFile(
7466
- path20.join(marketingDir, "tsconfig.json"),
6953
+ path19.join(marketingDir, "tsconfig.json"),
7467
6954
  JSON.stringify(tsConfig, null, 2)
7468
6955
  );
7469
6956
  const nextConfig = `import type { NextConfig } from 'next'
@@ -7474,14 +6961,14 @@ const nextConfig: NextConfig = {
7474
6961
 
7475
6962
  export default nextConfig
7476
6963
  `;
7477
- await writeFile(path20.join(marketingDir, "next.config.ts"), nextConfig);
6964
+ await writeFile(path19.join(marketingDir, "next.config.ts"), nextConfig);
7478
6965
  const postcssConfig = `export default {
7479
6966
  plugins: {
7480
6967
  '@tailwindcss/postcss': {},
7481
6968
  },
7482
6969
  }
7483
6970
  `;
7484
- await writeFile(path20.join(marketingDir, "postcss.config.mjs"), postcssConfig);
6971
+ await writeFile(path19.join(marketingDir, "postcss.config.mjs"), postcssConfig);
7485
6972
  }
7486
6973
  function displaySuccessMessage(config) {
7487
6974
  const apps = ["web"];
@@ -7551,7 +7038,7 @@ program.name("create-kofi-stack").description(
7551
7038
  "Scaffold opinionated full-stack projects with Next.js, Convex, Better-Auth, and more"
7552
7039
  ).version("1.0.0").argument("[project-name]", "Name of the project").option("--monorepo", "Use monorepo structure with Turborepo").option("--single", "Use single app structure").option(
7553
7040
  "--marketing <type>",
7554
- "Marketing site type: payload, nextjs, astro, none"
7041
+ "Marketing site type: payload, nextjs, none"
7555
7042
  ).option("--docs", "Include documentation site (Fumadocs)").option("--no-docs", "Exclude documentation site").option(
7556
7043
  "--component-library <library>",
7557
7044
  "Component library: base (Base UI), radix (Radix UI)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kofi-stack",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Scaffold opinionated full-stack projects with Next.js, Convex, Better-Auth, and more",
5
5
  "type": "module",
6
6
  "bin": {