@betterstart/cli 0.1.82 → 0.1.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -717,7 +717,7 @@ function generateColumnDef(col) {
717
717
  className="hover:bg-muted/50 px-0!"
718
718
  >
719
719
  ${col.header}
720
- <ArrowUpDown className="size-4" />
720
+ <ArrowUpDown className="size-3" />
721
721
  </Button>
722
722
  )` : `header: '${col.header}'`;
723
723
  let cellDef;
@@ -771,7 +771,7 @@ function generateColumns(fields, pascal, kebab, camel, customColumns) {
771
771
  className="hover:bg-muted/50 px-0!"
772
772
  >
773
773
  ${f.label}
774
- <ArrowUpDown className="size-4" />
774
+ <ArrowUpDown className="size-3" />
775
775
  </Button>
776
776
  ),
777
777
  cell: ({ row }) => {
@@ -4694,7 +4694,7 @@ function generateColumnDef2(column, fields) {
4694
4694
  aria-sort={sortDirection === 'asc' ? 'ascending' : sortDirection === 'desc' ? 'descending' : 'none'}
4695
4695
  >
4696
4696
  ${column.header}
4697
- <ArrowUpDown className="size-4" />
4697
+ <ArrowUpDown className="size-3" />
4698
4698
  </Button>
4699
4699
  )
4700
4700
  }` : `header: '${column.header}'`;
@@ -4842,7 +4842,7 @@ function generateFirstColumnDef(column, fields, schemaName) {
4842
4842
  aria-sort={sortDirection === 'asc' ? 'ascending' : sortDirection === 'desc' ? 'descending' : 'none'}
4843
4843
  >
4844
4844
  ${column.header}
4845
- <ArrowUpDown className="size-4" />
4845
+ <ArrowUpDown className="size-3" />
4846
4846
  </Button>
4847
4847
  </div>
4848
4848
  )
@@ -5483,12 +5483,12 @@ export default async function Create${Singular}Page() {
5483
5483
  await connection()
5484
5484
 
5485
5485
  return (
5486
- <>
5486
+ <div className="flex flex-col pt-14">
5487
5487
  <PageHeader title="Create ${singLabel}" back={<Button variant="ghost" size="icon" asChild><Link href="/cms/${schema.name}"><ChevronLeft /></Link></Button>} />
5488
5488
  <main className="container mx-auto max-w-5xl pt-10 pb-20 w-full">
5489
5489
  <${Singular}Form key={Date.now()} />
5490
5490
  </main>
5491
- </>
5491
+ </div>
5492
5492
  )
5493
5493
  }
5494
5494
  `;
@@ -5779,12 +5779,12 @@ export default async function Edit${Singular}Page({ params }: PageProps) {
5779
5779
  }
5780
5780
 
5781
5781
  return (
5782
- <>
5782
+ <div className="flex flex-col pt-14">
5783
5783
  <PageHeader title="Edit ${Singular}" back={<Button variant="ghost" size="icon" asChild><Link href="/cms/${schema.name}"><ChevronLeft /></Link></Button>} />
5784
5784
  <main className="container mx-auto max-w-5xl pt-10 pb-20 w-full">
5785
5785
  <${Singular}Form key={${camelSingular}.id} initialData={${camelSingular}} />
5786
5786
  </main>
5787
- </>
5787
+ </div>
5788
5788
  )
5789
5789
  }
5790
5790
  `;
@@ -7591,7 +7591,7 @@ export default function ${Plural}Page() {
7591
7591
  </div>
7592
7592
  }
7593
7593
  >
7594
- <div className="flex flex-col">
7594
+ <div className="flex flex-col pt-14">
7595
7595
  <${Plural}PageContent columns={columns} />
7596
7596
  </div>
7597
7597
  </React.Suspense>
@@ -7862,12 +7862,12 @@ export function ${Plural}PageContent<TValue>({
7862
7862
  const queryClient = useQueryClient()
7863
7863
  ${searchLogic}${deleteLogic}
7864
7864
  return (
7865
- <>
7865
+ <div className="flex flex-col pt-14">
7866
7866
  <PageHeader title="${schema.label}" back={<Button variant="ghost" size="icon" onClick={() => router.back()}><ChevronLeft /></Button>} search={${searchInput}} actions={<div className="flex items-center gap-2">${deleteButton} ${createButton}</div>} />
7867
7867
  <main className="space-y-6 p-6">
7868
7868
  <${Plural}Table ${tableProps} />
7869
7869
  </main>
7870
- </>
7870
+ </div>
7871
7871
  )
7872
7872
  }
7873
7873
  `;
@@ -7902,12 +7902,12 @@ export default async function ${PageName}Page() {
7902
7902
  const data = await get${Singular}()
7903
7903
 
7904
7904
  return (
7905
- <>
7905
+ <div className="flex flex-col pt-14">
7906
7906
  <PageHeader title="${schema.label}" />
7907
7907
  <main className="container mx-auto max-w-5xl pt-10 pb-20 w-full">
7908
7908
  <${Singular}Form initialData={data} />
7909
7909
  </main>
7910
- </>
7910
+ </div>
7911
7911
  )
7912
7912
  }
7913
7913
  `;
@@ -8203,7 +8203,7 @@ export function ${Plural}Table<TValue>({ columns, selectedIds, setSelectedIds, $
8203
8203
 
8204
8204
  <div className="bg-card border overflow-hidden rounded-lg">
8205
8205
  <Table>
8206
- <TableHeader className="bg-secondary">
8206
+ <TableHeader>
8207
8207
  {table.getHeaderGroups().map((headerGroup) => (
8208
8208
  <TableRow key={headerGroup.id}>
8209
8209
  {headerGroup.headers.map((header) => {
@@ -8831,7 +8831,7 @@ async function generateAll(cwd, options) {
8831
8831
 
8832
8832
  // src/commands/init.ts
8833
8833
  import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
8834
- import fs40 from "fs";
8834
+ import fs39 from "fs";
8835
8835
  import path45 from "path";
8836
8836
  import * as p4 from "@clack/prompts";
8837
8837
  import { Command as Command3 } from "commander";
@@ -9027,7 +9027,6 @@ function scaffoldAuth({ cwd, config }) {
9027
9027
  }
9028
9028
 
9029
9029
  // src/init/scaffolders/base.ts
9030
- import fs31 from "fs";
9031
9030
  import path34 from "path";
9032
9031
  function scaffoldBase({ cwd, config }) {
9033
9032
  const created = [];
@@ -9069,16 +9068,8 @@ function scaffoldBase({ cwd, config }) {
9069
9068
  if (safeWriteFile(path34.resolve(cwd, "cms.config.ts"), configContent)) {
9070
9069
  created.push("cms.config.ts");
9071
9070
  }
9072
- const cmsDoc = generateCmsDoc(config, {});
9073
- if (safeWriteFile(path34.resolve(cwd, "CMS.md"), cmsDoc)) {
9074
- created.push("CMS.md");
9075
- }
9076
9071
  return created;
9077
9072
  }
9078
- function regenerateCmsDoc(cwd, config, options) {
9079
- const content = generateCmsDoc(config, options);
9080
- fs31.writeFileSync(path34.resolve(cwd, "CMS.md"), content, "utf-8");
9081
- }
9082
9073
  function generateConfigFile(config) {
9083
9074
  return `import { defineConfig } from '@betterstart/cli'
9084
9075
 
@@ -9112,126 +9103,9 @@ export default defineConfig({
9112
9103
  })
9113
9104
  `;
9114
9105
  }
9115
- function generateCmsDoc(config, options) {
9116
- const sections = [];
9117
- sections.push(`# CMS
9118
-
9119
- > Auto-generated by [BetterStart CLI](https://github.com/betterstart/cli).
9120
- > Regenerated on each \`betterstart init\`.`);
9121
- if (options.preset) {
9122
- sections.push(`## Preset
9123
-
9124
- This project was initialized with the **${options.preset}** preset.`);
9125
- }
9126
- sections.push(`## Directory Structure
9127
-
9128
- | Path | Description |
9129
- |------|-------------|
9130
- | \`cms/\` | All CMS source code (you own this) |
9131
- | \`cms/schemas/\` | Entity JSON schemas |
9132
- | \`cms/schemas/forms/\` | Form JSON schemas |
9133
- | \`cms/db/\` | Database client, schema, drizzle config |
9134
- | \`cms/lib/actions/\` | Server actions (CRUD) |
9135
- | \`cms/lib/auth/\` | Better Auth configuration |
9136
- | \`cms/lib/cache/\` | Cache tags, queries, revalidation |
9137
- | \`cms/lib/emails/\` | React Email templates |
9138
- | \`cms/hooks/\` | React Query hooks |
9139
- | \`cms/components/\` | UI components (shadcn-style) |
9140
- | \`cms/utils/\` | Utility functions |
9141
- | \`${config.paths.pages}/\` | Admin pages (auth-gated) |
9142
- | \`${config.paths.login}/\` | Login page |
9143
- | \`${config.paths.api}/\` | CMS API routes |`);
9144
- if (options.schemas && options.schemas.length > 0 || options.forms && options.forms.length > 0) {
9145
- const lines = ["## Generated Content", ""];
9146
- if (options.schemas && options.schemas.length > 0) {
9147
- lines.push("### Entities");
9148
- for (const s of options.schemas) {
9149
- lines.push(`- **${s}** \u2014 \`cms/schemas/${s}.json\` \u2192 admin at \`/cms/${s}\``);
9150
- }
9151
- }
9152
- if (options.forms && options.forms.length > 0) {
9153
- lines.push("");
9154
- lines.push("### Forms");
9155
- for (const f of options.forms) {
9156
- lines.push(`- **${f}** \u2014 \`cms/schemas/forms/${f}.json\` \u2192 admin at \`/cms/forms/${f}\``);
9157
- }
9158
- }
9159
- sections.push(lines.join("\n"));
9160
- }
9161
- sections.push(`## Commands
9162
-
9163
- \`\`\`bash
9164
- # Generate entity CRUD from a schema
9165
- npx betterstart generate <schema-name>
9166
-
9167
- # Generate with force overwrite
9168
- npx betterstart generate <schema-name> --force
9169
-
9170
- # Remove all generated files for an entity/form
9171
- npx betterstart remove <schema-name>
9172
-
9173
- # Create initial admin user
9174
- npx betterstart seed
9175
- \`\`\``);
9176
- sections.push(`## Schema Format
9177
-
9178
- ### Entity Schema (\`cms/schemas/<name>.json\`)
9179
-
9180
- \`\`\`json
9181
- {
9182
- "name": "posts",
9183
- "label": "Posts",
9184
- "icon": "FileText",
9185
- "fields": [
9186
- { "name": "title", "type": "string", "label": "Title", "required": true },
9187
- { "name": "content", "type": "richtext", "label": "Content" }
9188
- ]
9189
- }
9190
- \`\`\`
9191
-
9192
- Field types: \`string\`, \`text\`, \`richtext\`, \`number\`, \`boolean\`, \`date\`, \`image\`, \`select\`, \`relationship\`.
9193
-
9194
- ### Form Schema (\`cms/schemas/forms/<name>.json\`)
9195
-
9196
- \`\`\`json
9197
- {
9198
- "name": "contact",
9199
- "label": "Contact Form",
9200
- "submitButtonText": "Send Message",
9201
- "fields": [
9202
- { "name": "email", "type": "email", "label": "Email", "required": true },
9203
- { "name": "message", "type": "textarea", "label": "Message", "required": true }
9204
- ]
9205
- }
9206
- \`\`\`
9207
-
9208
- Field types: \`text\`, \`textarea\`, \`email\`, \`phone\`, \`number\`, \`url\`, \`date\`, \`select\`, \`radio\`, \`checkbox\`, \`multiselect\`, \`file\`.`);
9209
- sections.push(`## Path Aliases
9210
-
9211
- | Alias | Resolves to |
9212
- |-------|-------------|
9213
- | \`@cms/*\` | \`${config.paths.cms}/*\` |`);
9214
- sections.push(`## Environment Variables
9215
-
9216
- Required variables in \`.env.local\`:
9217
-
9218
- | Variable | Description |
9219
- |----------|-------------|
9220
- | \`BETTERSTART_DATABASE_URL\` | PostgreSQL connection string |
9221
- | \`BETTERSTART_AUTH_SECRET\` | Auth secret (\`openssl rand -base64 32\`) |
9222
- | \`BETTERSTART_AUTH_URL\` | App URL (e.g. \`http://localhost:3000\`) |
9223
- | \`BETTERSTART_R2_*\` | Cloudflare R2 storage credentials |
9224
- | \`BETTERSTART_RESEND_API_KEY\` | Resend API key (if email enabled) |
9225
- | \`NOTIFICATION_EMAIL\` | Fallback notification email address |`);
9226
- sections.push(`## Configuration
9227
-
9228
- Edit \`cms.config.ts\` to customize paths, database provider, and features.`);
9229
- return `${sections.join("\n\n")}
9230
- `;
9231
- }
9232
9106
 
9233
9107
  // src/init/scaffolders/biome.ts
9234
- import fs32 from "fs";
9108
+ import fs31 from "fs";
9235
9109
  import path35 from "path";
9236
9110
  function scaffoldBiome(cwd, linter) {
9237
9111
  if (linter.type !== "none") {
@@ -9241,7 +9115,7 @@ function scaffoldBiome(cwd, linter) {
9241
9115
  };
9242
9116
  }
9243
9117
  const configPath = path35.join(cwd, "biome.json");
9244
- if (fs32.existsSync(configPath)) {
9118
+ if (fs31.existsSync(configPath)) {
9245
9119
  return { installed: false, skippedReason: "biome.json already exists" };
9246
9120
  }
9247
9121
  const config = {
@@ -9292,24 +9166,24 @@ function scaffoldBiome(cwd, linter) {
9292
9166
  ]
9293
9167
  }
9294
9168
  };
9295
- fs32.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
9169
+ fs31.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
9296
9170
  `, "utf-8");
9297
9171
  return { installed: true, skippedReason: null };
9298
9172
  }
9299
9173
 
9300
9174
  // src/init/scaffolders/components.ts
9301
9175
  import path37 from "path";
9302
- import fs34 from "fs-extra";
9176
+ import fs33 from "fs-extra";
9303
9177
 
9304
9178
  // src/utils/detect.ts
9305
- import fs33 from "fs";
9179
+ import fs32 from "fs";
9306
9180
  import path36 from "path";
9307
9181
  var NEXT_CONFIG_FILES = ["next.config.ts", "next.config.js", "next.config.mjs"];
9308
9182
  function detectProjectName(cwd) {
9309
9183
  const pkgPath = path36.join(cwd, "package.json");
9310
- if (fs33.existsSync(pkgPath)) {
9184
+ if (fs32.existsSync(pkgPath)) {
9311
9185
  try {
9312
- const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
9186
+ const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
9313
9187
  if (typeof pkg.name === "string" && pkg.name.length > 0) {
9314
9188
  return formatProjectName(pkg.name);
9315
9189
  }
@@ -9323,21 +9197,21 @@ function formatProjectName(name) {
9323
9197
  return base.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
9324
9198
  }
9325
9199
  function detectProject(cwd) {
9326
- const isExisting = NEXT_CONFIG_FILES.some((f) => fs33.existsSync(path36.join(cwd, f)));
9327
- const hasSrcDir = fs33.existsSync(path36.join(cwd, "src"));
9328
- const hasTypeScript = fs33.existsSync(path36.join(cwd, "tsconfig.json")) || fs33.existsSync(path36.join(cwd, "tsconfig.app.json"));
9200
+ const isExisting = NEXT_CONFIG_FILES.some((f) => fs32.existsSync(path36.join(cwd, f)));
9201
+ const hasSrcDir = fs32.existsSync(path36.join(cwd, "src"));
9202
+ const hasTypeScript = fs32.existsSync(path36.join(cwd, "tsconfig.json")) || fs32.existsSync(path36.join(cwd, "tsconfig.app.json"));
9329
9203
  const hasTailwind = detectTailwind(cwd);
9330
9204
  const linter = detectLinter(cwd);
9331
9205
  const conflicts = [];
9332
9206
  if (isExisting) {
9333
- if (fs33.existsSync(path36.join(cwd, "cms"))) {
9207
+ if (fs32.existsSync(path36.join(cwd, "cms"))) {
9334
9208
  conflicts.push("cms/ directory already exists");
9335
9209
  }
9336
- if (fs33.existsSync(path36.join(cwd, "cms.config.ts"))) {
9210
+ if (fs32.existsSync(path36.join(cwd, "cms.config.ts"))) {
9337
9211
  conflicts.push("cms.config.ts already exists");
9338
9212
  }
9339
9213
  const appBase = hasSrcDir ? "src/app" : "app";
9340
- if (fs33.existsSync(path36.join(cwd, appBase, "(cms)"))) {
9214
+ if (fs32.existsSync(path36.join(cwd, appBase, "(cms)"))) {
9341
9215
  conflicts.push(`${appBase}/(cms)/ route group already exists`);
9342
9216
  }
9343
9217
  if (hasTsconfigCmsAliases(cwd)) {
@@ -9364,19 +9238,19 @@ var ESLINT_CONFIG_FILES = [
9364
9238
  ];
9365
9239
  function detectLinter(cwd) {
9366
9240
  for (const f of BIOME_CONFIG_FILES) {
9367
- if (fs33.existsSync(path36.join(cwd, f))) {
9241
+ if (fs32.existsSync(path36.join(cwd, f))) {
9368
9242
  return { type: "biome", configFile: f };
9369
9243
  }
9370
9244
  }
9371
9245
  for (const f of ESLINT_CONFIG_FILES) {
9372
- if (fs33.existsSync(path36.join(cwd, f))) {
9246
+ if (fs32.existsSync(path36.join(cwd, f))) {
9373
9247
  return { type: "eslint", configFile: f };
9374
9248
  }
9375
9249
  }
9376
9250
  const pkgPath = path36.join(cwd, "package.json");
9377
- if (fs33.existsSync(pkgPath)) {
9251
+ if (fs32.existsSync(pkgPath)) {
9378
9252
  try {
9379
- const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
9253
+ const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
9380
9254
  if (pkg.eslintConfig) {
9381
9255
  return { type: "eslint", configFile: "package.json (eslintConfig)" };
9382
9256
  }
@@ -9393,8 +9267,8 @@ function detectTailwind(cwd) {
9393
9267
  path36.join(cwd, f)
9394
9268
  ]);
9395
9269
  for (const cssFile of cssFiles) {
9396
- if (fs33.existsSync(cssFile)) {
9397
- const content = fs33.readFileSync(cssFile, "utf-8");
9270
+ if (fs32.existsSync(cssFile)) {
9271
+ const content = fs32.readFileSync(cssFile, "utf-8");
9398
9272
  if (content.includes('@import "tailwindcss"') || content.includes("@import 'tailwindcss'") || content.includes("@theme")) {
9399
9273
  return true;
9400
9274
  }
@@ -9402,8 +9276,8 @@ function detectTailwind(cwd) {
9402
9276
  }
9403
9277
  const postcssFiles = ["postcss.config.js", "postcss.config.mjs", "postcss.config.cjs"];
9404
9278
  for (const f of postcssFiles) {
9405
- if (fs33.existsSync(path36.join(cwd, f))) {
9406
- const content = fs33.readFileSync(path36.join(cwd, f), "utf-8");
9279
+ if (fs32.existsSync(path36.join(cwd, f))) {
9280
+ const content = fs32.readFileSync(path36.join(cwd, f), "utf-8");
9407
9281
  if (content.includes("tailwindcss") || content.includes("@tailwindcss")) {
9408
9282
  return true;
9409
9283
  }
@@ -9413,9 +9287,9 @@ function detectTailwind(cwd) {
9413
9287
  }
9414
9288
  function hasTsconfigCmsAliases(cwd) {
9415
9289
  const tsconfigPath = path36.join(cwd, "tsconfig.json");
9416
- if (!fs33.existsSync(tsconfigPath)) return false;
9290
+ if (!fs32.existsSync(tsconfigPath)) return false;
9417
9291
  try {
9418
- const content = fs33.readFileSync(tsconfigPath, "utf-8");
9292
+ const content = fs32.readFileSync(tsconfigPath, "utf-8");
9419
9293
  return content.includes("@cms/");
9420
9294
  } catch {
9421
9295
  return false;
@@ -9423,9 +9297,9 @@ function hasTsconfigCmsAliases(cwd) {
9423
9297
  }
9424
9298
  function hasEnvBetterstartVars(cwd) {
9425
9299
  const envPath = path36.join(cwd, ".env.local");
9426
- if (!fs33.existsSync(envPath)) return false;
9300
+ if (!fs32.existsSync(envPath)) return false;
9427
9301
  try {
9428
- const content = fs33.readFileSync(envPath, "utf-8");
9302
+ const content = fs32.readFileSync(envPath, "utf-8");
9429
9303
  return content.includes("BETTERSTART_");
9430
9304
  } catch {
9431
9305
  return false;
@@ -9499,14 +9373,14 @@ function copyUiTemplates(cwd, config) {
9499
9373
  const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui");
9500
9374
  const cliRoot = findCliRoot();
9501
9375
  const srcDir = path37.join(cliRoot, "templates", "ui");
9502
- if (!fs34.existsSync(srcDir)) {
9376
+ if (!fs33.existsSync(srcDir)) {
9503
9377
  return created;
9504
9378
  }
9505
- const files = fs34.readdirSync(srcDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
9379
+ const files = fs33.readdirSync(srcDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
9506
9380
  for (const file of files) {
9507
9381
  const destPath = path37.join(destDir, file);
9508
- if (!fs34.existsSync(destPath)) {
9509
- fs34.copyFileSync(path37.join(srcDir, file), destPath);
9382
+ if (!fs33.existsSync(destPath)) {
9383
+ fs33.copyFileSync(path37.join(srcDir, file), destPath);
9510
9384
  created.push(path37.join(config.paths.cms, "components", "ui", file));
9511
9385
  }
9512
9386
  }
@@ -9517,22 +9391,22 @@ function copyTiptapTemplates(cwd, config) {
9517
9391
  const cliRoot = findCliRoot();
9518
9392
  const srcDir = path37.join(cliRoot, "templates", "tiptap");
9519
9393
  const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui", "tiptap");
9520
- if (!fs34.existsSync(srcDir)) {
9394
+ if (!fs33.existsSync(srcDir)) {
9521
9395
  return created;
9522
9396
  }
9523
9397
  copyDirRecursive(srcDir, destDir, config.paths.cms, created);
9524
9398
  return created;
9525
9399
  }
9526
9400
  function copyDirRecursive(src, dest, cmsPrefix, created) {
9527
- fs34.ensureDirSync(dest);
9528
- const entries = fs34.readdirSync(src, { withFileTypes: true });
9401
+ fs33.ensureDirSync(dest);
9402
+ const entries = fs33.readdirSync(src, { withFileTypes: true });
9529
9403
  for (const entry of entries) {
9530
9404
  const srcPath = path37.join(src, entry.name);
9531
9405
  const destPath = path37.join(dest, entry.name);
9532
9406
  if (entry.isDirectory()) {
9533
9407
  copyDirRecursive(srcPath, destPath, cmsPrefix, created);
9534
- } else if (!fs34.existsSync(destPath)) {
9535
- fs34.copyFileSync(srcPath, destPath);
9408
+ } else if (!fs33.existsSync(destPath)) {
9409
+ fs33.copyFileSync(srcPath, destPath);
9536
9410
  const relFromCms = path37.relative(path37.resolve(dest, "..", "..", "..", ".."), destPath);
9537
9411
  created.push(relFromCms);
9538
9412
  }
@@ -9543,9 +9417,9 @@ function copySchemaMetaschema(cwd, config) {
9543
9417
  const cliRoot = findCliRoot();
9544
9418
  const srcPath = path37.join(cliRoot, "templates", "schema.json");
9545
9419
  const destPath = path37.resolve(cwd, config.paths.schemas, "schema.json");
9546
- if (fs34.existsSync(srcPath) && !fs34.existsSync(destPath)) {
9547
- fs34.ensureDirSync(path37.dirname(destPath));
9548
- fs34.copyFileSync(srcPath, destPath);
9420
+ if (fs33.existsSync(srcPath) && !fs33.existsSync(destPath)) {
9421
+ fs33.ensureDirSync(path37.dirname(destPath));
9422
+ fs33.copyFileSync(srcPath, destPath);
9549
9423
  created.push(path37.join(config.paths.schemas, "schema.json"));
9550
9424
  }
9551
9425
  return created;
@@ -9596,7 +9470,7 @@ var CORE_DEPS = [
9596
9470
  "clsx",
9597
9471
  "tailwind-merge",
9598
9472
  // Icons
9599
- "lucide-react",
9473
+ "lucide-react@1.7.0",
9600
9474
  // Storage (R2)
9601
9475
  "@aws-sdk/client-s3",
9602
9476
  // Radix UI (unified package + legacy scoped packages)
@@ -9738,11 +9612,11 @@ import { existsSync, readFileSync } from "fs";
9738
9612
  import { join } from "path";
9739
9613
 
9740
9614
  // src/utils/env.ts
9741
- import fs35 from "fs";
9615
+ import fs34 from "fs";
9742
9616
  import path39 from "path";
9743
9617
  function appendEnvVars(cwd, sections, overwrite) {
9744
9618
  const envPath = path39.join(cwd, ".env.local");
9745
- let existing = fs35.existsSync(envPath) ? fs35.readFileSync(envPath, "utf-8") : "";
9619
+ let existing = fs34.existsSync(envPath) ? fs34.readFileSync(envPath, "utf-8") : "";
9746
9620
  const existingKeys = new Set(
9747
9621
  existing.split("\n").filter((line) => line.trim() && !line.trim().startsWith("#")).map((line) => line.split("=")[0]?.trim()).filter(Boolean)
9748
9622
  );
@@ -9786,7 +9660,7 @@ function appendEnvVars(cwd, sections, overwrite) {
9786
9660
  const header = existing.trim() ? "" : "# ============================================\n# BetterStart CMS\n# ============================================\n";
9787
9661
  const content = existing.trim() ? `${existing.trimEnd()}
9788
9662
  ${lines.join("\n")}` : header + lines.join("\n");
9789
- fs35.writeFileSync(envPath, content);
9663
+ fs34.writeFileSync(envPath, content);
9790
9664
  }
9791
9665
  return { added, skipped, updated };
9792
9666
  }
@@ -9906,7 +9780,7 @@ function scaffoldLayout({ cwd, config }) {
9906
9780
  }
9907
9781
 
9908
9782
  // src/init/scaffolders/preset.ts
9909
- import fs36 from "fs";
9783
+ import fs35 from "fs";
9910
9784
  import path41 from "path";
9911
9785
 
9912
9786
  // src/init/templates/presets/blog-categories.ts
@@ -10331,10 +10205,10 @@ function scaffoldPreset({
10331
10205
  for (const ps of presetSchemas) {
10332
10206
  const filePath = path41.join(schemasDir, ps.filename);
10333
10207
  const dir = path41.dirname(filePath);
10334
- if (!fs36.existsSync(dir)) {
10335
- fs36.mkdirSync(dir, { recursive: true });
10208
+ if (!fs35.existsSync(dir)) {
10209
+ fs35.mkdirSync(dir, { recursive: true });
10336
10210
  }
10337
- fs36.writeFileSync(filePath, ps.content, "utf-8");
10211
+ fs35.writeFileSync(filePath, ps.content, "utf-8");
10338
10212
  result.schemas.push(ps.filename);
10339
10213
  }
10340
10214
  for (const ps of presetSchemas) {
@@ -10375,7 +10249,7 @@ function scaffoldPreset({
10375
10249
  }
10376
10250
 
10377
10251
  // src/init/scaffolders/tailwind.ts
10378
- import fs37 from "fs";
10252
+ import fs36 from "fs";
10379
10253
  import path42 from "path";
10380
10254
  var SOURCE_LINES = ['@source "../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
10381
10255
  var SOURCE_LINES_SRC = ['@source "../../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
@@ -10432,7 +10306,7 @@ function findMainCss(cwd) {
10432
10306
  ];
10433
10307
  for (const candidate of candidates) {
10434
10308
  const filePath = path42.join(cwd, candidate);
10435
- if (fs37.existsSync(filePath)) {
10309
+ if (fs36.existsSync(filePath)) {
10436
10310
  return filePath;
10437
10311
  }
10438
10312
  }
@@ -10443,7 +10317,7 @@ function scaffoldTailwind(cwd, hasSrcDir) {
10443
10317
  if (!cssFile) {
10444
10318
  return { file: null, appended: false };
10445
10319
  }
10446
- let content = fs37.readFileSync(cssFile, "utf-8");
10320
+ let content = fs36.readFileSync(cssFile, "utf-8");
10447
10321
  let changed = false;
10448
10322
  const sourceLines = hasSrcDir ? SOURCE_LINES_SRC : SOURCE_LINES;
10449
10323
  const missingLines = sourceLines.filter((sl) => !content.includes(sl));
@@ -10495,13 +10369,13 @@ ${CMS_THEME_BLOCK}
10495
10369
  }
10496
10370
  }
10497
10371
  if (changed) {
10498
- fs37.writeFileSync(cssFile, content, "utf-8");
10372
+ fs36.writeFileSync(cssFile, content, "utf-8");
10499
10373
  }
10500
10374
  return { file: cssFile, appended: changed };
10501
10375
  }
10502
10376
 
10503
10377
  // src/init/scaffolders/tsconfig.ts
10504
- import fs38 from "fs";
10378
+ import fs37 from "fs";
10505
10379
  import path43 from "path";
10506
10380
  function stripJsonComments(input) {
10507
10381
  let result = "";
@@ -10555,11 +10429,11 @@ function scaffoldTsconfig(cwd) {
10555
10429
  const tsconfigPath = path43.join(cwd, "tsconfig.json");
10556
10430
  const added = [];
10557
10431
  const skipped = [];
10558
- if (!fs38.existsSync(tsconfigPath)) {
10432
+ if (!fs37.existsSync(tsconfigPath)) {
10559
10433
  skipped.push("tsconfig.json not found");
10560
10434
  return { added, skipped };
10561
10435
  }
10562
- const raw = fs38.readFileSync(tsconfigPath, "utf-8");
10436
+ const raw = fs37.readFileSync(tsconfigPath, "utf-8");
10563
10437
  const stripped = stripJsonComments(raw).replace(/,\s*([\]}])/g, "$1");
10564
10438
  let tsconfig;
10565
10439
  try {
@@ -10580,13 +10454,13 @@ function scaffoldTsconfig(cwd) {
10580
10454
  }
10581
10455
  compilerOptions.paths = paths;
10582
10456
  tsconfig.compilerOptions = compilerOptions;
10583
- fs38.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
10457
+ fs37.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
10584
10458
  `, "utf-8");
10585
10459
  return { added, skipped };
10586
10460
  }
10587
10461
 
10588
10462
  // src/commands/seed.ts
10589
- import fs39 from "fs";
10463
+ import fs38 from "fs";
10590
10464
  import path44 from "path";
10591
10465
  import * as clack from "@clack/prompts";
10592
10466
  import { Command as Command2 } from "commander";
@@ -10748,10 +10622,10 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
10748
10622
  }
10749
10623
  const scriptsDir = path44.join(cwd, cmsDir, "scripts");
10750
10624
  const seedPath = path44.join(scriptsDir, "seed.ts");
10751
- if (!fs39.existsSync(scriptsDir)) {
10752
- fs39.mkdirSync(scriptsDir, { recursive: true });
10625
+ if (!fs38.existsSync(scriptsDir)) {
10626
+ fs38.mkdirSync(scriptsDir, { recursive: true });
10753
10627
  }
10754
- fs39.writeFileSync(seedPath, buildSeedScript(), "utf-8");
10628
+ fs38.writeFileSync(seedPath, buildSeedScript(), "utf-8");
10755
10629
  const { execFile } = await import("child_process");
10756
10630
  const tsxBin = path44.join(cwd, "node_modules", ".bin", "tsx");
10757
10631
  const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
@@ -10792,7 +10666,7 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
10792
10666
  if (clack.isCancel(overwrite) || !overwrite) {
10793
10667
  clack.cancel("Seed cancelled.");
10794
10668
  try {
10795
- fs39.unlinkSync(seedPath);
10669
+ fs38.unlinkSync(seedPath);
10796
10670
  } catch {
10797
10671
  }
10798
10672
  process.exit(0);
@@ -10815,9 +10689,9 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
10815
10689
  process.exit(1);
10816
10690
  }
10817
10691
  try {
10818
- fs39.unlinkSync(seedPath);
10819
- if (fs39.existsSync(scriptsDir) && fs39.readdirSync(scriptsDir).length === 0) {
10820
- fs39.rmdirSync(scriptsDir);
10692
+ fs38.unlinkSync(seedPath);
10693
+ if (fs38.existsSync(scriptsDir) && fs38.readdirSync(scriptsDir).length === 0) {
10694
+ fs38.rmdirSync(scriptsDir);
10821
10695
  }
10822
10696
  } catch {
10823
10697
  }
@@ -10825,7 +10699,7 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
10825
10699
  });
10826
10700
 
10827
10701
  // src/commands/init.ts
10828
- var initCommand = new Command3("init").description("Scaffold CMS into a new or existing Next.js project").argument("[name]", "Project name (creates new directory if fresh project)").option("--preset <preset>", "Starter preset: blank, blog, or full", "blog").option("-y, --yes", "Skip all prompts (accept defaults)").option(
10702
+ var initCommand = new Command3("init").description("Scaffold CMS into a new or existing Next.js project").argument("[name]", "Project name (creates new directory if fresh project)").option("--preset <preset>", "Starter preset: blank, blog, or full", "blog").option("-y, --yes", "Skip all prompts (accept defaults)").option("--skip-migration", "Skip running drizzle-kit push after scaffolding").option("--skip-admin-creation", "Skip prompting to create the initial admin user").option("--skip-dev-server-start", "Skip prompting to start the development server").option(
10829
10703
  "--database-url <url>",
10830
10704
  "PostgreSQL database connection string (postgres:// or postgresql://)"
10831
10705
  ).option("--force", "Overwrite all existing CMS files (nuclear option)").action(
@@ -10849,15 +10723,15 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
10849
10723
  let nuked = 0;
10850
10724
  for (const dir of nukeDirs) {
10851
10725
  const fullPath = path45.resolve(cwd, dir);
10852
- if (fs40.existsSync(fullPath)) {
10853
- fs40.rmSync(fullPath, { recursive: true, force: true });
10726
+ if (fs39.existsSync(fullPath)) {
10727
+ fs39.rmSync(fullPath, { recursive: true, force: true });
10854
10728
  nuked++;
10855
10729
  }
10856
10730
  }
10857
10731
  for (const file of nukeFiles) {
10858
10732
  const fullPath = path45.resolve(cwd, file);
10859
- if (fs40.existsSync(fullPath)) {
10860
- fs40.unlinkSync(fullPath);
10733
+ if (fs39.existsSync(fullPath)) {
10734
+ fs39.unlinkSync(fullPath);
10861
10735
  nuked++;
10862
10736
  }
10863
10737
  }
@@ -10937,9 +10811,9 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
10937
10811
  process.exit(1);
10938
10812
  }
10939
10813
  cwd = path45.resolve(cwd, projectPrompt.projectName);
10940
- const hasPackageJson = fs40.existsSync(path45.join(cwd, "package.json"));
10814
+ const hasPackageJson = fs39.existsSync(path45.join(cwd, "package.json"));
10941
10815
  const hasNextConfig = ["next.config.ts", "next.config.js", "next.config.mjs"].some(
10942
- (f) => fs40.existsSync(path45.join(cwd, f))
10816
+ (f) => fs39.existsSync(path45.join(cwd, f))
10943
10817
  );
10944
10818
  if (!hasPackageJson || !hasNextConfig) {
10945
10819
  p4.log.error(
@@ -11041,10 +10915,10 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
11041
10915
  process.stdout.write("\x1B[2A\x1B[J");
11042
10916
  p4.note(noteLines.join("\n"), "Scaffolded CMS");
11043
10917
  const drizzleConfigPath = path45.join(cwd, "drizzle.config.ts");
11044
- if (!dbFiles.includes("drizzle.config.ts") && fs40.existsSync(drizzleConfigPath)) {
10918
+ if (!dbFiles.includes("drizzle.config.ts") && fs39.existsSync(drizzleConfigPath)) {
11045
10919
  if (options.force) {
11046
10920
  const { readTemplate: readTemplate2 } = await import("./reader-2T45D7JZ.js");
11047
- fs40.writeFileSync(drizzleConfigPath, readTemplate2("drizzle.config.ts"), "utf-8");
10921
+ fs39.writeFileSync(drizzleConfigPath, readTemplate2("drizzle.config.ts"), "utf-8");
11048
10922
  p4.log.success("Updated drizzle.config.ts");
11049
10923
  } else if (!options.yes) {
11050
10924
  const overwrite = await p4.confirm({
@@ -11053,7 +10927,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
11053
10927
  });
11054
10928
  if (!p4.isCancel(overwrite) && overwrite) {
11055
10929
  const { readTemplate: readTemplate2 } = await import("./reader-2T45D7JZ.js");
11056
- fs40.writeFileSync(drizzleConfigPath, readTemplate2("drizzle.config.ts"), "utf-8");
10930
+ fs39.writeFileSync(drizzleConfigPath, readTemplate2("drizzle.config.ts"), "utf-8");
11057
10931
  p4.log.success("Updated drizzle.config.ts");
11058
10932
  }
11059
10933
  }
@@ -11083,27 +10957,6 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
11083
10957
  }
11084
10958
  s.start(`Applying ${features.preset} preset`);
11085
10959
  const presetResult = scaffoldPreset({ cwd, config, preset: features.preset });
11086
- {
11087
- const entityNames = [];
11088
- const formNames = [];
11089
- const schemasDir = path45.join(cwd, config.paths.schemas);
11090
- const formsDir = path45.join(schemasDir, "forms");
11091
- if (fs40.existsSync(schemasDir)) {
11092
- for (const f of fs40.readdirSync(schemasDir)) {
11093
- if (f.endsWith(".json")) entityNames.push(f.replace(".json", ""));
11094
- }
11095
- }
11096
- if (fs40.existsSync(formsDir)) {
11097
- for (const f of fs40.readdirSync(formsDir)) {
11098
- if (f.endsWith(".json")) formNames.push(f.replace(".json", ""));
11099
- }
11100
- }
11101
- regenerateCmsDoc(cwd, config, {
11102
- preset: features.preset,
11103
- schemas: entityNames,
11104
- forms: formNames
11105
- });
11106
- }
11107
10960
  s.stop("");
11108
10961
  process.stdout.write("\x1B[2A\x1B[J");
11109
10962
  const installLines = [];
@@ -11126,7 +10979,9 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
11126
10979
  }
11127
10980
  p4.note(installLines.join("\n"), "Installed");
11128
10981
  let dbPushed = false;
11129
- if (depsResult.success && hasDbUrl(cwd)) {
10982
+ if (depsResult.success && options.skipMigration && hasDbUrl(cwd)) {
10983
+ p4.log.info(`Skipping database schema push ${pc2.dim("(--skip-migration)")}`);
10984
+ } else if (depsResult.success && hasDbUrl(cwd)) {
11130
10985
  s.start("Pushing database schema (drizzle-kit push)");
11131
10986
  const pushResult = await runDrizzlePush(cwd);
11132
10987
  if (pushResult.success) {
@@ -11141,7 +10996,10 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
11141
10996
  let seedEmail;
11142
10997
  let seedPassword;
11143
10998
  let seedSuccess = false;
11144
- if (dbPushed && !options.yes) {
10999
+ if (dbPushed && options.skipAdminCreation) {
11000
+ p4.log.info(`Skipping admin user creation ${pc2.dim("(use npx betterstart seed later)")}`);
11001
+ }
11002
+ if (dbPushed && !options.yes && !options.skipAdminCreation) {
11145
11003
  p4.note(pc2.dim("Create your first admin user to access the CMS."), "Admin account");
11146
11004
  const credentials = await p4.group(
11147
11005
  {
@@ -11253,7 +11111,7 @@ Run manually: ${pc2.cyan("npx betterstart seed")}`,
11253
11111
  );
11254
11112
  summaryLines.push("", "Next steps:", ...nextSteps);
11255
11113
  p4.note(summaryLines.join("\n"), "CMS scaffolded successfully");
11256
- if (!options.yes) {
11114
+ if (!options.yes && !options.skipDevServerStart) {
11257
11115
  const devCmd = runCommand(pm, "dev");
11258
11116
  const startDev = await p4.confirm({
11259
11117
  message: "Start the development server?",
@@ -11274,8 +11132,8 @@ function isValidDbUrl(url) {
11274
11132
  }
11275
11133
  function readExistingDbUrl(cwd) {
11276
11134
  const envPath = path45.join(cwd, ".env.local");
11277
- if (!fs40.existsSync(envPath)) return void 0;
11278
- const content = fs40.readFileSync(envPath, "utf-8");
11135
+ if (!fs39.existsSync(envPath)) return void 0;
11136
+ const content = fs39.readFileSync(envPath, "utf-8");
11279
11137
  for (const line of content.split("\n")) {
11280
11138
  const trimmed = line.trim();
11281
11139
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -11299,8 +11157,8 @@ function maskDbUrl(url) {
11299
11157
  }
11300
11158
  function hasDbUrl(cwd) {
11301
11159
  const envPath = path45.join(cwd, ".env.local");
11302
- if (!fs40.existsSync(envPath)) return false;
11303
- const content = fs40.readFileSync(envPath, "utf-8");
11160
+ if (!fs39.existsSync(envPath)) return false;
11161
+ const content = fs39.readFileSync(envPath, "utf-8");
11304
11162
  for (const line of content.split("\n")) {
11305
11163
  const trimmed = line.trim();
11306
11164
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -11316,15 +11174,15 @@ function hasDbUrl(cwd) {
11316
11174
  function runSeed(cwd, cmsDir, email, password4, overwrite = false) {
11317
11175
  const scriptsDir = path45.join(cwd, cmsDir, "scripts");
11318
11176
  const seedPath = path45.join(scriptsDir, "seed.ts");
11319
- if (!fs40.existsSync(scriptsDir)) {
11320
- fs40.mkdirSync(scriptsDir, { recursive: true });
11177
+ if (!fs39.existsSync(scriptsDir)) {
11178
+ fs39.mkdirSync(scriptsDir, { recursive: true });
11321
11179
  }
11322
- fs40.writeFileSync(seedPath, buildSeedScript(), "utf-8");
11180
+ fs39.writeFileSync(seedPath, buildSeedScript(), "utf-8");
11323
11181
  const cleanup = () => {
11324
11182
  try {
11325
- fs40.unlinkSync(seedPath);
11326
- if (fs40.existsSync(scriptsDir) && fs40.readdirSync(scriptsDir).length === 0) {
11327
- fs40.rmdirSync(scriptsDir);
11183
+ fs39.unlinkSync(seedPath);
11184
+ if (fs39.existsSync(scriptsDir) && fs39.readdirSync(scriptsDir).length === 0) {
11185
+ fs39.rmdirSync(scriptsDir);
11328
11186
  }
11329
11187
  } catch {
11330
11188
  }
@@ -11416,7 +11274,7 @@ function runDrizzlePush(cwd) {
11416
11274
  }
11417
11275
 
11418
11276
  // src/commands/remove.ts
11419
- import fs41 from "fs";
11277
+ import fs40 from "fs";
11420
11278
  import path46 from "path";
11421
11279
  import readline from "readline";
11422
11280
  import { Command as Command4 } from "commander";
@@ -11448,8 +11306,8 @@ function findTableEnd3(content, startIndex) {
11448
11306
  return content.length;
11449
11307
  }
11450
11308
  function removeTableFromSchema(schemaFilePath, name) {
11451
- if (!fs41.existsSync(schemaFilePath)) return false;
11452
- let content = fs41.readFileSync(schemaFilePath, "utf-8");
11309
+ if (!fs40.existsSync(schemaFilePath)) return false;
11310
+ let content = fs40.readFileSync(schemaFilePath, "utf-8");
11453
11311
  const variableName = toCamelCase(name);
11454
11312
  let changed = false;
11455
11313
  if (content.includes(`export const ${variableName} =`)) {
@@ -11477,13 +11335,13 @@ function removeTableFromSchema(schemaFilePath, name) {
11477
11335
  }
11478
11336
  if (changed) {
11479
11337
  content = content.replace(/\n{3,}/g, "\n\n");
11480
- fs41.writeFileSync(schemaFilePath, content, "utf-8");
11338
+ fs40.writeFileSync(schemaFilePath, content, "utf-8");
11481
11339
  }
11482
11340
  return changed;
11483
11341
  }
11484
11342
  function removeFromNavigation(navFilePath, name) {
11485
- if (!fs41.existsSync(navFilePath)) return false;
11486
- const content = fs41.readFileSync(navFilePath, "utf-8");
11343
+ if (!fs40.existsSync(navFilePath)) return false;
11344
+ const content = fs40.readFileSync(navFilePath, "utf-8");
11487
11345
  const href = `/cms/${name}`;
11488
11346
  if (!content.includes(`'${href}'`)) return false;
11489
11347
  const lines = content.split("\n");
@@ -11514,7 +11372,7 @@ function removeFromNavigation(navFilePath, name) {
11514
11372
  if (startLine === -1 || endLine === -1) return false;
11515
11373
  lines.splice(startLine, endLine - startLine + 1);
11516
11374
  const updated = lines.join("\n").replace(/,\s*,/g, ",").replace(/\[\s*,/, "[");
11517
- fs41.writeFileSync(navFilePath, updated, "utf-8");
11375
+ fs40.writeFileSync(navFilePath, updated, "utf-8");
11518
11376
  return true;
11519
11377
  }
11520
11378
  async function promptConfirm(message) {
@@ -11544,7 +11402,7 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
11544
11402
  const kebabName = toKebabCase(schemaName);
11545
11403
  const targets = [];
11546
11404
  const entityPagesDir = path46.join(cwd, pagesDir, schemaName);
11547
- if (fs41.existsSync(entityPagesDir)) {
11405
+ if (fs40.existsSync(entityPagesDir)) {
11548
11406
  targets.push({
11549
11407
  path: entityPagesDir,
11550
11408
  label: `${path46.join(pagesDir, schemaName)}/`,
@@ -11553,13 +11411,13 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
11553
11411
  }
11554
11412
  const actionsDir = path46.join(cwd, cmsDir, "lib", "actions", kebabName);
11555
11413
  const actionsFile = path46.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
11556
- if (fs41.existsSync(actionsDir)) {
11414
+ if (fs40.existsSync(actionsDir)) {
11557
11415
  targets.push({
11558
11416
  path: actionsDir,
11559
11417
  label: `${path46.join(cmsDir, "lib", "actions", kebabName)}/`,
11560
11418
  isDir: true
11561
11419
  });
11562
- } else if (fs41.existsSync(actionsFile)) {
11420
+ } else if (fs40.existsSync(actionsFile)) {
11563
11421
  targets.push({
11564
11422
  path: actionsFile,
11565
11423
  label: path46.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
@@ -11567,7 +11425,7 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
11567
11425
  });
11568
11426
  }
11569
11427
  const hookFile = path46.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
11570
- if (fs41.existsSync(hookFile)) {
11428
+ if (fs40.existsSync(hookFile)) {
11571
11429
  targets.push({
11572
11430
  path: hookFile,
11573
11431
  label: path46.join(cmsDir, "hooks", `use-${kebabName}.ts`),
@@ -11575,9 +11433,9 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
11575
11433
  });
11576
11434
  }
11577
11435
  const schemaFilePath = path46.join(cwd, cmsDir, "db", "schema.ts");
11578
- const hasTable = fs41.existsSync(schemaFilePath) && fs41.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
11436
+ const hasTable = fs40.existsSync(schemaFilePath) && fs40.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
11579
11437
  const navFilePath = path46.join(cwd, cmsDir, "data", "navigation.ts");
11580
- const hasNavEntry = fs41.existsSync(navFilePath) && fs41.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
11438
+ const hasNavEntry = fs40.existsSync(navFilePath) && fs40.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
11581
11439
  if (targets.length === 0 && !hasTable && !hasNavEntry) {
11582
11440
  console.log(` No generated files found for: ${schemaName}`);
11583
11441
  return;
@@ -11603,9 +11461,9 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
11603
11461
  console.log("");
11604
11462
  for (const t of targets) {
11605
11463
  if (t.isDir) {
11606
- fs41.rmSync(t.path, { recursive: true, force: true });
11464
+ fs40.rmSync(t.path, { recursive: true, force: true });
11607
11465
  } else {
11608
- fs41.unlinkSync(t.path);
11466
+ fs40.unlinkSync(t.path);
11609
11467
  }
11610
11468
  console.log(` Removed: ${t.label}`);
11611
11469
  }
@@ -11627,7 +11485,7 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
11627
11485
 
11628
11486
  // src/commands/setup-r2.ts
11629
11487
  import { execFileSync as execFileSync5, spawnSync } from "child_process";
11630
- import fs42 from "fs";
11488
+ import fs41 from "fs";
11631
11489
  import os from "os";
11632
11490
  import path47 from "path";
11633
11491
  import * as p5 from "@clack/prompts";
@@ -11827,7 +11685,7 @@ var setupR2Command = new Command5("setup-r2").description("Create a Cloudflare R
11827
11685
  });
11828
11686
  function findWrangler(cwd) {
11829
11687
  const localBin = path47.join(cwd, "node_modules", ".bin", "wrangler");
11830
- if (fs42.existsSync(localBin)) return { bin: localBin, prefix: [] };
11688
+ if (fs41.existsSync(localBin)) return { bin: localBin, prefix: [] };
11831
11689
  const result = spawnSync("which", ["wrangler"], { stdio: "pipe", timeout: 5e3 });
11832
11690
  if (result.status === 0) {
11833
11691
  const found = result.stdout?.toString().trim();
@@ -11875,9 +11733,9 @@ function readWranglerToken() {
11875
11733
  );
11876
11734
  }
11877
11735
  for (const configPath of candidates) {
11878
- if (!fs42.existsSync(configPath)) continue;
11736
+ if (!fs41.existsSync(configPath)) continue;
11879
11737
  try {
11880
- const content = fs42.readFileSync(configPath, "utf-8");
11738
+ const content = fs41.readFileSync(configPath, "utf-8");
11881
11739
  const match = content.match(/^oauth_token\s*=\s*"([^"]+)"/m);
11882
11740
  if (match) return match[1];
11883
11741
  } catch {
@@ -11909,14 +11767,14 @@ async function enablePublicDomain(accountId, bucketName, token) {
11909
11767
  }
11910
11768
 
11911
11769
  // src/commands/uninstall.ts
11912
- import fs44 from "fs";
11770
+ import fs43 from "fs";
11913
11771
  import path48 from "path";
11914
11772
  import * as p6 from "@clack/prompts";
11915
11773
  import { Command as Command6 } from "commander";
11916
11774
  import pc4 from "picocolors";
11917
11775
 
11918
11776
  // src/commands/uninstall-cleaners.ts
11919
- import fs43 from "fs";
11777
+ import fs42 from "fs";
11920
11778
  function stripJsonComments2(input) {
11921
11779
  let result = "";
11922
11780
  let i = 0;
@@ -11950,8 +11808,8 @@ function stripJsonComments2(input) {
11950
11808
  return result;
11951
11809
  }
11952
11810
  function cleanTsconfig(tsconfigPath) {
11953
- if (!fs43.existsSync(tsconfigPath)) return [];
11954
- const raw = fs43.readFileSync(tsconfigPath, "utf-8");
11811
+ if (!fs42.existsSync(tsconfigPath)) return [];
11812
+ const raw = fs42.readFileSync(tsconfigPath, "utf-8");
11955
11813
  const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
11956
11814
  let tsconfig;
11957
11815
  try {
@@ -11975,13 +11833,13 @@ function cleanTsconfig(tsconfigPath) {
11975
11833
  compilerOptions.paths = paths;
11976
11834
  }
11977
11835
  tsconfig.compilerOptions = compilerOptions;
11978
- fs43.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
11836
+ fs42.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
11979
11837
  `, "utf-8");
11980
11838
  return removed;
11981
11839
  }
11982
11840
  function cleanCss(cssPath) {
11983
- if (!fs43.existsSync(cssPath)) return [];
11984
- const content = fs43.readFileSync(cssPath, "utf-8");
11841
+ if (!fs42.existsSync(cssPath)) return [];
11842
+ const content = fs42.readFileSync(cssPath, "utf-8");
11985
11843
  const lines = content.split("\n");
11986
11844
  const sourcePattern = /^@source\s+"[^"]*cms[^"]*";\s*$/;
11987
11845
  const removed = [];
@@ -11995,12 +11853,12 @@ function cleanCss(cssPath) {
11995
11853
  }
11996
11854
  if (removed.length === 0) return [];
11997
11855
  const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
11998
- fs43.writeFileSync(cssPath, cleaned, "utf-8");
11856
+ fs42.writeFileSync(cssPath, cleaned, "utf-8");
11999
11857
  return removed;
12000
11858
  }
12001
11859
  function cleanEnvFile(envPath) {
12002
- if (!fs43.existsSync(envPath)) return [];
12003
- const content = fs43.readFileSync(envPath, "utf-8");
11860
+ if (!fs42.existsSync(envPath)) return [];
11861
+ const content = fs42.readFileSync(envPath, "utf-8");
12004
11862
  const lines = content.split("\n");
12005
11863
  const removed = [];
12006
11864
  const kept = [];
@@ -12033,9 +11891,9 @@ function cleanEnvFile(envPath) {
12033
11891
  if (removed.length === 0) return [];
12034
11892
  const result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
12035
11893
  if (result === "") {
12036
- fs43.unlinkSync(envPath);
11894
+ fs42.unlinkSync(envPath);
12037
11895
  } else {
12038
- fs43.writeFileSync(envPath, `${result}
11896
+ fs42.writeFileSync(envPath, `${result}
12039
11897
  `, "utf-8");
12040
11898
  }
12041
11899
  return removed;
@@ -12062,14 +11920,14 @@ function findMainCss2(cwd) {
12062
11920
  ];
12063
11921
  for (const candidate of candidates) {
12064
11922
  const filePath = path48.join(cwd, candidate);
12065
- if (fs44.existsSync(filePath)) return filePath;
11923
+ if (fs43.existsSync(filePath)) return filePath;
12066
11924
  }
12067
11925
  return void 0;
12068
11926
  }
12069
11927
  function isCLICreatedBiome(biomePath) {
12070
- if (!fs44.existsSync(biomePath)) return false;
11928
+ if (!fs43.existsSync(biomePath)) return false;
12071
11929
  try {
12072
- const content = JSON.parse(fs44.readFileSync(biomePath, "utf-8"));
11930
+ const content = JSON.parse(fs43.readFileSync(biomePath, "utf-8"));
12073
11931
  return content.$schema?.includes("biomejs.dev") && content.formatter?.indentStyle === "space" && content.javascript?.formatter?.quoteStyle === "single" && Array.isArray(content.files?.ignore) && content.files.ignore.includes(".next");
12074
11932
  } catch {
12075
11933
  return false;
@@ -12077,13 +11935,13 @@ function isCLICreatedBiome(biomePath) {
12077
11935
  }
12078
11936
  function buildUninstallPlan(cwd) {
12079
11937
  const steps = [];
12080
- const hasSrc = fs44.existsSync(path48.join(cwd, "src"));
11938
+ const hasSrc = fs43.existsSync(path48.join(cwd, "src"));
12081
11939
  const appBase = hasSrc ? "src/app" : "app";
12082
11940
  const dirs = [];
12083
11941
  const cmsDir = path48.join(cwd, "cms");
12084
11942
  const cmsRouteGroup = path48.join(cwd, appBase, "(cms)");
12085
- if (fs44.existsSync(cmsDir)) dirs.push("cms/");
12086
- if (fs44.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
11943
+ if (fs43.existsSync(cmsDir)) dirs.push("cms/");
11944
+ if (fs43.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
12087
11945
  if (dirs.length > 0) {
12088
11946
  steps.push({
12089
11947
  label: "CMS directories",
@@ -12091,8 +11949,8 @@ function buildUninstallPlan(cwd) {
12091
11949
  count: dirs.length,
12092
11950
  unit: dirs.length === 1 ? "directory" : "directories",
12093
11951
  execute() {
12094
- if (fs44.existsSync(cmsDir)) fs44.rmSync(cmsDir, { recursive: true, force: true });
12095
- if (fs44.existsSync(cmsRouteGroup)) fs44.rmSync(cmsRouteGroup, { recursive: true, force: true });
11952
+ if (fs43.existsSync(cmsDir)) fs43.rmSync(cmsDir, { recursive: true, force: true });
11953
+ if (fs43.existsSync(cmsRouteGroup)) fs43.rmSync(cmsRouteGroup, { recursive: true, force: true });
12096
11954
  }
12097
11955
  });
12098
11956
  }
@@ -12104,7 +11962,7 @@ function buildUninstallPlan(cwd) {
12104
11962
  ["CMS.md", path48.join(cwd, "CMS.md")]
12105
11963
  ];
12106
11964
  for (const [label, fullPath] of candidates) {
12107
- if (fs44.existsSync(fullPath)) {
11965
+ if (fs43.existsSync(fullPath)) {
12108
11966
  configFiles.push(label);
12109
11967
  configPaths.push(fullPath);
12110
11968
  }
@@ -12122,14 +11980,14 @@ function buildUninstallPlan(cwd) {
12122
11980
  unit: configFiles.length === 1 ? "file" : "files",
12123
11981
  execute() {
12124
11982
  for (const p7 of configPaths) {
12125
- if (fs44.existsSync(p7)) fs44.unlinkSync(p7);
11983
+ if (fs43.existsSync(p7)) fs43.unlinkSync(p7);
12126
11984
  }
12127
11985
  }
12128
11986
  });
12129
11987
  }
12130
11988
  const tsconfigPath = path48.join(cwd, "tsconfig.json");
12131
- if (fs44.existsSync(tsconfigPath)) {
12132
- const content = fs44.readFileSync(tsconfigPath, "utf-8");
11989
+ if (fs43.existsSync(tsconfigPath)) {
11990
+ const content = fs43.readFileSync(tsconfigPath, "utf-8");
12133
11991
  const aliasMatches = content.match(/"@cms\//g);
12134
11992
  if (aliasMatches && aliasMatches.length > 0) {
12135
11993
  const aliasCount = aliasMatches.length;
@@ -12146,7 +12004,7 @@ function buildUninstallPlan(cwd) {
12146
12004
  }
12147
12005
  const cssFile = findMainCss2(cwd);
12148
12006
  if (cssFile) {
12149
- const cssContent = fs44.readFileSync(cssFile, "utf-8");
12007
+ const cssContent = fs43.readFileSync(cssFile, "utf-8");
12150
12008
  const sourceLines = cssContent.split("\n").filter((l) => /^@source\s+"[^"]*cms[^"]*";\s*$/.test(l));
12151
12009
  if (sourceLines.length > 0) {
12152
12010
  const relCss = path48.relative(cwd, cssFile);
@@ -12162,8 +12020,8 @@ function buildUninstallPlan(cwd) {
12162
12020
  }
12163
12021
  }
12164
12022
  const envPath = path48.join(cwd, ".env.local");
12165
- if (fs44.existsSync(envPath)) {
12166
- const envContent = fs44.readFileSync(envPath, "utf-8");
12023
+ if (fs43.existsSync(envPath)) {
12024
+ const envContent = fs43.readFileSync(envPath, "utf-8");
12167
12025
  const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
12168
12026
  if (bsVars.length > 0) {
12169
12027
  steps.push({
@@ -12217,7 +12075,7 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
12217
12075
  });
12218
12076
 
12219
12077
  // src/commands/update-component.ts
12220
- import fs45 from "fs";
12078
+ import fs44 from "fs";
12221
12079
  import path49 from "path";
12222
12080
  import * as clack2 from "@clack/prompts";
12223
12081
  import { Command as Command7 } from "commander";
@@ -12284,8 +12142,8 @@ var TEMPLATE_REGISTRY = {
12284
12142
  function getStaticUiComponents() {
12285
12143
  const cliRoot = findCliRoot();
12286
12144
  const uiDir = path49.join(cliRoot, "templates", "ui");
12287
- if (!fs45.existsSync(uiDir)) return [];
12288
- return fs45.readdirSync(uiDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => f.replace(/\.(tsx|ts)$/, ""));
12145
+ if (!fs44.existsSync(uiDir)) return [];
12146
+ return fs44.readdirSync(uiDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => f.replace(/\.(tsx|ts)$/, ""));
12289
12147
  }
12290
12148
  function getAllComponentNames() {
12291
12149
  const staticUi = getStaticUiComponents();
@@ -12329,7 +12187,7 @@ var updateComponentCommand = new Command7("update").alias("update-component").de
12329
12187
  }
12330
12188
  const config = await resolveConfig(cwd);
12331
12189
  const cms = path49.resolve(cwd, config.paths.cms);
12332
- if (!fs45.existsSync(cms)) {
12190
+ if (!fs44.existsSync(cms)) {
12333
12191
  clack2.cancel(`CMS directory not found at ${config.paths.cms}. Run 'betterstart init' first.`);
12334
12192
  process.exit(1);
12335
12193
  }
@@ -12345,18 +12203,18 @@ var updateComponentCommand = new Command7("update").alias("update-component").de
12345
12203
  const baseDir = entry.base === "cwd" ? cwd : cms;
12346
12204
  const destPath = path49.join(baseDir, entry.relPath);
12347
12205
  fsExtra.ensureDirSync(path49.dirname(destPath));
12348
- fs45.writeFileSync(destPath, entry.content(), "utf-8");
12206
+ fs44.writeFileSync(destPath, entry.content(), "utf-8");
12349
12207
  clack2.log.success(`Updated ${entry.relPath}`);
12350
12208
  updated++;
12351
12209
  continue;
12352
12210
  }
12353
- const uiFile = fs45.readdirSync(uiDir).find(
12211
+ const uiFile = fs44.readdirSync(uiDir).find(
12354
12212
  (f) => f.replace(/\.(tsx|ts)$/, "") === name
12355
12213
  );
12356
12214
  if (uiFile) {
12357
12215
  const destPath = path49.join(cms, "components", "ui", uiFile);
12358
12216
  fsExtra.ensureDirSync(path49.dirname(destPath));
12359
- fs45.copyFileSync(path49.join(uiDir, uiFile), destPath);
12217
+ fs44.copyFileSync(path49.join(uiDir, uiFile), destPath);
12360
12218
  clack2.log.success(`Updated components/ui/${uiFile}`);
12361
12219
  updated++;
12362
12220
  continue;
@@ -12364,7 +12222,7 @@ var updateComponentCommand = new Command7("update").alias("update-component").de
12364
12222
  if (name === "tiptap") {
12365
12223
  const srcDir = path49.join(cliRoot, "templates", "tiptap");
12366
12224
  const destDir = path49.join(cms, "components", "ui", "tiptap");
12367
- if (fs45.existsSync(srcDir)) {
12225
+ if (fs44.existsSync(srcDir)) {
12368
12226
  fsExtra.copySync(srcDir, destDir, { overwrite: true });
12369
12227
  clack2.log.success("Updated components/ui/tiptap/ (all files)");
12370
12228
  updated++;
@@ -12410,7 +12268,7 @@ var updateDepsCommand = new Command8("update-deps").description("Install or upda
12410
12268
  });
12411
12269
 
12412
12270
  // src/commands/update-styles.ts
12413
- import fs46 from "fs";
12271
+ import fs45 from "fs";
12414
12272
  import path51 from "path";
12415
12273
  import * as clack4 from "@clack/prompts";
12416
12274
  import { Command as Command9 } from "commander";
@@ -12420,11 +12278,11 @@ var updateStylesCommand = new Command9("update-styles").description("Replace cms
12420
12278
  const config = await resolveConfig(cwd);
12421
12279
  const cmsDir = config.paths?.cms ?? "./cms";
12422
12280
  const targetPath = path51.join(cwd, cmsDir, "cms-globals.css");
12423
- if (!fs46.existsSync(targetPath)) {
12281
+ if (!fs45.existsSync(targetPath)) {
12424
12282
  clack4.cancel(`cms-globals.css not found at ${path51.relative(cwd, targetPath)}`);
12425
12283
  process.exit(1);
12426
12284
  }
12427
- fs46.writeFileSync(targetPath, readTemplate("cms-globals.css"), "utf-8");
12285
+ fs45.writeFileSync(targetPath, readTemplate("cms-globals.css"), "utf-8");
12428
12286
  clack4.log.success(`Updated ${path51.relative(cwd, targetPath)}`);
12429
12287
  clack4.outro("Styles updated");
12430
12288
  });