@betterstart/cli 0.1.41 → 0.1.43

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
@@ -7,7 +7,7 @@ import {
7
7
  import { Command as Command9 } from "commander";
8
8
 
9
9
  // src/commands/generate.ts
10
- import path28 from "path";
10
+ import path30 from "path";
11
11
  import { Command } from "commander";
12
12
 
13
13
  // src/config/resolver.ts
@@ -159,6 +159,9 @@ function getManyToManyFields(fields) {
159
159
  }
160
160
 
161
161
  // src/core/field-helpers/form-fields.ts
162
+ function isMultiStepForm(schema) {
163
+ return Array.isArray(schema.steps) && schema.steps.length > 0;
164
+ }
162
165
  function getAllFormSchemaFields(schema) {
163
166
  const flatten = (fields) => {
164
167
  return fields.flatMap((field) => {
@@ -171,6 +174,22 @@ function getAllFormSchemaFields(schema) {
171
174
  if (schema.steps) return schema.steps.flatMap((step) => flatten(step.fields));
172
175
  return [];
173
176
  }
177
+ function getStepFieldNames(step) {
178
+ const names = [];
179
+ const collect = (fields) => {
180
+ for (const field of fields) {
181
+ if (field.hidden) continue;
182
+ if (field.type === "dynamicFields") continue;
183
+ if (field.type === "group" && field.fields) {
184
+ collect(field.fields);
185
+ } else if (field.name) {
186
+ names.push(field.name);
187
+ }
188
+ }
189
+ };
190
+ collect(step.fields);
191
+ return names;
192
+ }
174
193
  function hasDynamicFields(schema) {
175
194
  const check = (fields) => {
176
195
  for (const f of fields) {
@@ -1927,7 +1946,11 @@ export async function export${pascal}SubmissionsJSON(): Promise<string> {
1927
1946
  return { files: [path6.relative(cwd, filePath)] };
1928
1947
  }
1929
1948
 
1930
- // src/generators/form-pipeline/form-component.ts
1949
+ // src/generators/form-pipeline/form-component-multistep.ts
1950
+ import fs8 from "fs";
1951
+ import path8 from "path";
1952
+
1953
+ // src/generators/form-pipeline/form-component-shared.ts
1931
1954
  import fs7 from "fs";
1932
1955
  import path7 from "path";
1933
1956
 
@@ -2225,7 +2248,7 @@ function toTypeScriptType(field, mode = "output") {
2225
2248
  }
2226
2249
  }
2227
2250
 
2228
- // src/generators/form-pipeline/form-component.ts
2251
+ // src/generators/form-pipeline/form-component-shared.ts
2229
2252
  function resolveUiImport(cwd, componentName) {
2230
2253
  const locations = ["components/ui", "src/components/ui"];
2231
2254
  for (const loc of locations) {
@@ -2238,160 +2261,63 @@ function resolveUiImport(cwd, componentName) {
2238
2261
  function escapeJsx(str) {
2239
2262
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2240
2263
  }
2241
- function generateFormComponent(schema, cwd, cmsDir, options) {
2242
- const formName = schema.name;
2243
- const pascal = toPascalCase(formName);
2244
- const fields = getAllFormSchemaFields(schema);
2245
- const kebab = toKebabCase(formName);
2246
- const filePath = path7.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2247
- const dir = path7.dirname(filePath);
2248
- if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
2249
- if (fs7.existsSync(filePath) && !options.force) {
2250
- return { files: [path7.relative(cwd, filePath)] };
2251
- }
2252
- const zodFields = fields.filter((f) => f.name).map((f) => ` ${f.name}: ${formFieldToZodType(f)}`).join(",\n");
2253
- const defaults = fields.filter((f) => f.name).map((f) => {
2264
+ function flattenFormFields(fields) {
2265
+ return fields.flatMap((field) => {
2266
+ if (field.type === "dynamicFields") return [];
2267
+ if (field.type === "group" && field.fields) return flattenFormFields(field.fields);
2268
+ return field.type === "group" ? [] : [field];
2269
+ });
2270
+ }
2271
+ function buildZodFields(fields) {
2272
+ return fields.filter((f) => f.name).map((f) => ` ${f.name}: ${formFieldToZodType(f)}`).join(",\n");
2273
+ }
2274
+ function buildDefaultValues(fields) {
2275
+ return fields.filter((f) => f.name).map((f) => {
2254
2276
  if (f.type === "checkbox") return ` ${f.name}: false`;
2255
2277
  if (f.type === "number") return ` ${f.name}: undefined`;
2256
2278
  if (f.type === "multiselect" || f.type === "list") return ` ${f.name}: []`;
2279
+ if (f.type === "radio" && f.defaultValue !== void 0) return ` ${f.name}: '${f.defaultValue}'`;
2257
2280
  if (f.type === "select" || f.type === "radio") return ` ${f.name}: undefined`;
2258
2281
  if (f.defaultValue !== void 0) return ` ${f.name}: '${f.defaultValue}'`;
2259
2282
  return ` ${f.name}: ''`;
2260
2283
  }).join(",\n");
2261
- const listFields = fields.filter(
2262
- (f) => f.name && f.type === "list" && f.fields && f.fields.length > 0
2263
- );
2264
- const hasListFields = listFields.length > 0;
2265
- const fieldArrayDecls = listFields.map(
2284
+ }
2285
+ function buildFieldArrayDecls(listFields) {
2286
+ return listFields.map(
2266
2287
  (f) => ` const ${f.name}FieldArray = useFieldArray({ control: form.control, name: '${f.name}' })`
2267
2288
  ).join("\n");
2289
+ }
2290
+ function buildWatchDecls(fields) {
2268
2291
  const watchFields = /* @__PURE__ */ new Set();
2269
2292
  for (const f of fields) {
2270
2293
  if (f.showWhen) {
2271
2294
  watchFields.add(f.showWhen.field);
2272
2295
  }
2273
2296
  }
2274
- const watchDecls = Array.from(watchFields).map((wf) => ` const ${wf}Value = form.watch('${wf}')`).join("\n");
2275
- const watchSetup = watchFields.size > 0 ? `
2276
- ${watchDecls}
2277
- ` : "";
2278
- const fieldJSX = fields.filter((f) => f.name && !f.hidden).map((f) => {
2279
- let jsx = generateFieldJSX(f);
2280
- if (f.showWhen) {
2281
- const watchVar = `${f.showWhen.field}Value`;
2282
- const { value } = f.showWhen;
2283
- if (Array.isArray(value)) {
2284
- const vals = value.map((v) => `'${v}'`).join(", ");
2285
- jsx = ` {[${vals}].includes(${watchVar} as string) && (
2297
+ if (watchFields.size === 0) return { setup: "", hasWatch: false };
2298
+ const decls = Array.from(watchFields).map((wf) => ` const ${wf}Value = form.watch('${wf}')`).join("\n");
2299
+ return { setup: `
2300
+ ${decls}
2301
+ `, hasWatch: true };
2302
+ }
2303
+ function getListFields(fields) {
2304
+ return fields.filter(
2305
+ (f) => f.name && f.type === "list" && f.fields && f.fields.length > 0
2306
+ );
2307
+ }
2308
+ function wrapShowWhen(field, jsx) {
2309
+ if (!field.showWhen) return jsx;
2310
+ const watchVar = `${field.showWhen.field}Value`;
2311
+ const { value } = field.showWhen;
2312
+ if (Array.isArray(value)) {
2313
+ const vals = value.map((v) => `'${v}'`).join(", ");
2314
+ return ` {[${vals}].includes(${watchVar} as string) && (
2286
2315
  ${jsx}
2287
2316
  )}`;
2288
- } else {
2289
- jsx = ` {${watchVar} === '${value}' && (
2317
+ }
2318
+ return ` {${watchVar} === '${value}' && (
2290
2319
  ${jsx}
2291
2320
  )}`;
2292
- }
2293
- }
2294
- return jsx;
2295
- }).join("\n\n");
2296
- const submitText = schema.submitButtonText || "Submit";
2297
- const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2298
- const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2299
- const fieldArraySetup = hasListFields ? `
2300
- ${fieldArrayDecls}
2301
- ` : "";
2302
- const buttonImport = resolveUiImport(cwd, "button");
2303
- const formImport = resolveUiImport(cwd, "form");
2304
- const inputImport = resolveUiImport(cwd, "input");
2305
- const textareaImport = resolveUiImport(cwd, "textarea");
2306
- const selectImport = resolveUiImport(cwd, "select");
2307
- const content = `'use client'
2308
-
2309
- import { zodResolver } from '@hookform/resolvers/zod'
2310
- import { useState } from 'react'
2311
- ${rhfImport}
2312
- import { z } from 'zod/v3'
2313
- import { create${pascal}Submission } from '@cms/actions/${kebab}-form'
2314
- import { Button } from '${buttonImport}'
2315
- import {
2316
- Form,
2317
- FormControl,
2318
- FormDescription,
2319
- FormField,
2320
- FormItem,
2321
- FormLabel,
2322
- FormMessage,
2323
- } from '${formImport}'
2324
- import { Input } from '${inputImport}'
2325
- import { Textarea } from '${textareaImport}'
2326
- import {
2327
- Select,
2328
- SelectContent,
2329
- SelectItem,
2330
- SelectTrigger,
2331
- SelectValue,
2332
- } from '${selectImport}'
2333
-
2334
- const formSchema = z.object({
2335
- ${zodFields}
2336
- })
2337
-
2338
- type FormValues = z.infer<typeof formSchema>
2339
-
2340
- export function ${pascal}Form() {
2341
- const [submitted, setSubmitted] = useState(false)
2342
- const [submitting, setSubmitting] = useState(false)
2343
-
2344
- const form = useForm<FormValues>({
2345
- resolver: zodResolver(formSchema),
2346
- defaultValues: {
2347
- ${defaults}
2348
- },
2349
- })
2350
- ${fieldArraySetup}${watchSetup}
2351
- async function onSubmit(values: FormValues) {
2352
- setSubmitting(true)
2353
- try {
2354
- const result = await create${pascal}Submission(values)
2355
- if (result.success) {
2356
- setSubmitted(true)
2357
- } else {
2358
- form.setError('root', { message: result.error || 'Something went wrong' })
2359
- }
2360
- } catch {
2361
- form.setError('root', { message: 'Something went wrong. Please try again.' })
2362
- } finally {
2363
- setSubmitting(false)
2364
- }
2365
- }
2366
-
2367
- if (submitted) {
2368
- return (
2369
- <div className="rounded-lg border p-6 text-center">
2370
- <h3 className="text-lg font-semibold">Thank you!</h3>
2371
- <p className="mt-2 text-muted-foreground">${successMessage}</p>
2372
- </div>
2373
- )
2374
- }
2375
-
2376
- return (
2377
- <Form {...form}>
2378
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
2379
- ${fieldJSX}
2380
-
2381
- {form.formState.errors.root && (
2382
- <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2383
- )}
2384
-
2385
- <Button type="submit" disabled={submitting}>
2386
- {submitting ? 'Submitting...' : '${submitText}'}
2387
- </Button>
2388
- </form>
2389
- </Form>
2390
- )
2391
- }
2392
- `;
2393
- fs7.writeFileSync(filePath, content, "utf-8");
2394
- return { files: [path7.relative(cwd, filePath)] };
2395
2321
  }
2396
2322
  function generateFieldJSX(field) {
2397
2323
  const name = field.name || "";
@@ -2418,8 +2344,32 @@ function generateFieldJSX(field) {
2418
2344
  </FormItem>
2419
2345
  )}
2420
2346
  />`;
2421
- case "select":
2422
2347
  case "radio":
2348
+ if (field.options && field.options.length > 0) {
2349
+ const radioItems = field.options.map(
2350
+ (opt) => ` <div className="flex items-center space-x-2">
2351
+ <RadioGroupItem value="${opt.value}" id="${name}-${opt.value}" />
2352
+ <Label htmlFor="${name}-${opt.value}">${escapeJsx(opt.label)}</Label>
2353
+ </div>`
2354
+ ).join("\n");
2355
+ return ` <FormField
2356
+ control={form.control}
2357
+ name="${name}"
2358
+ render={({ field }) => (
2359
+ <FormItem className="space-y-3">
2360
+ <FormLabel>${label}${requiredStar}</FormLabel>
2361
+ <FormControl>
2362
+ <RadioGroup onValueChange={field.onChange} defaultValue={field.value} className="flex flex-col space-y-1">
2363
+ ${radioItems}
2364
+ </RadioGroup>
2365
+ </FormControl>${hintJSX}
2366
+ <FormMessage />
2367
+ </FormItem>
2368
+ )}
2369
+ />`;
2370
+ }
2371
+ return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "text");
2372
+ case "select":
2423
2373
  if (field.options && field.options.length > 0) {
2424
2374
  const optionItems = field.options.map(
2425
2375
  (opt) => ` <SelectItem value="${opt.value}">${escapeJsx(opt.label)}</SelectItem>`
@@ -2468,36 +2418,15 @@ ${optionItems}
2468
2418
  )}
2469
2419
  />`;
2470
2420
  case "email":
2471
- return generateTextFieldJSX(
2472
- name,
2473
- label,
2474
- placeholder || "email@example.com",
2475
- hintJSX,
2476
- requiredStar,
2477
- "email"
2478
- );
2421
+ return generateTextFieldJSX(name, label, placeholder || "email@example.com", hintJSX, requiredStar, "email");
2479
2422
  case "number":
2480
2423
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "number");
2481
2424
  case "date":
2482
2425
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "date");
2483
2426
  case "url":
2484
- return generateTextFieldJSX(
2485
- name,
2486
- label,
2487
- placeholder || "https://",
2488
- hintJSX,
2489
- requiredStar,
2490
- "url"
2491
- );
2427
+ return generateTextFieldJSX(name, label, placeholder || "https://", hintJSX, requiredStar, "url");
2492
2428
  case "phone":
2493
- return generateTextFieldJSX(
2494
- name,
2495
- label,
2496
- placeholder || "+1 (555) 000-0000",
2497
- hintJSX,
2498
- requiredStar,
2499
- "tel"
2500
- );
2429
+ return generateTextFieldJSX(name, label, placeholder || "+1 (555) 000-0000", hintJSX, requiredStar, "tel");
2501
2430
  case "file":
2502
2431
  case "upload":
2503
2432
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "file");
@@ -2598,9 +2527,415 @@ ${nestedFieldsJSX}
2598
2527
  </div>`;
2599
2528
  }
2600
2529
 
2530
+ // src/generators/form-pipeline/form-component-multistep.ts
2531
+ function generateMultiStepForm(schema, cwd, cmsDir, options) {
2532
+ const formName = schema.name;
2533
+ const pascal = toPascalCase(formName);
2534
+ const kebab = toKebabCase(formName);
2535
+ const steps = schema.steps;
2536
+ const filePath = path8.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2537
+ const dir = path8.dirname(filePath);
2538
+ if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
2539
+ if (fs8.existsSync(filePath) && !options.force) {
2540
+ return { files: [path8.relative(cwd, filePath)] };
2541
+ }
2542
+ const allFields = getAllFormSchemaFields(schema);
2543
+ const zodFields = buildZodFields(allFields);
2544
+ const defaults = buildDefaultValues(allFields);
2545
+ const listFields = getListFields(allFields);
2546
+ const hasListFields = listFields.length > 0;
2547
+ const { setup: watchSetup } = buildWatchDecls(allFields);
2548
+ const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2549
+ const fieldArraySetup = hasListFields ? `
2550
+ ${buildFieldArrayDecls(listFields)}
2551
+ ` : "";
2552
+ const stepsConst = buildStepsConstant(steps, schema);
2553
+ const stepContentBlocks = steps.map((step, index) => {
2554
+ const stepFields = flattenFormFields(step.fields);
2555
+ const fieldsJSX = stepFields.filter((f) => f.name && !f.hidden).map((f) => wrapShowWhen(f, generateFieldJSX(f))).join("\n\n");
2556
+ return ` {currentStep === ${index} && (
2557
+ <>
2558
+ ${fieldsJSX}
2559
+ </>
2560
+ )}`;
2561
+ }).join("\n");
2562
+ const submitText = schema.submitButtonText || "Submit";
2563
+ const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2564
+ const hasRadio = allFields.some((f) => f.type === "radio");
2565
+ const buttonImport = resolveUiImport(cwd, "button");
2566
+ const formImport = resolveUiImport(cwd, "form");
2567
+ const inputImport = resolveUiImport(cwd, "input");
2568
+ const labelImport = resolveUiImport(cwd, "label");
2569
+ const textareaImport = resolveUiImport(cwd, "textarea");
2570
+ const selectImport = resolveUiImport(cwd, "select");
2571
+ const radioGroupImport = resolveUiImport(cwd, "radio-group");
2572
+ const progressImport = resolveUiImport(cwd, "progress");
2573
+ const content = buildComponentSource({
2574
+ pascal,
2575
+ kebab,
2576
+ rhfImport,
2577
+ hasRadio,
2578
+ buttonImport,
2579
+ formImport,
2580
+ inputImport,
2581
+ labelImport,
2582
+ textareaImport,
2583
+ selectImport,
2584
+ radioGroupImport,
2585
+ progressImport,
2586
+ zodFields,
2587
+ defaults,
2588
+ stepsConst,
2589
+ fieldArraySetup,
2590
+ watchSetup,
2591
+ stepContentBlocks,
2592
+ submitText,
2593
+ successMessage
2594
+ });
2595
+ fs8.writeFileSync(filePath, content, "utf-8");
2596
+ return { files: [path8.relative(cwd, filePath)] };
2597
+ }
2598
+ function buildStepsConstant(steps, schema) {
2599
+ const entries = steps.map((step) => {
2600
+ const fieldNames = getStepFieldNames(step);
2601
+ const fieldsStr = fieldNames.map((n) => `'${n}'`).join(", ");
2602
+ const desc = step.description ? `, description: '${escapeQuotes(step.description)}'` : "";
2603
+ return ` { name: '${step.name}', label: '${escapeQuotes(step.label)}'${desc}, fields: [${fieldsStr}] }`;
2604
+ });
2605
+ return `const STEPS = [
2606
+ ${entries.join(",\n")}
2607
+ ]`;
2608
+ }
2609
+ function escapeQuotes(str) {
2610
+ return str.replace(/'/g, "\\'");
2611
+ }
2612
+ function buildComponentSource(p7) {
2613
+ return `'use client'
2614
+
2615
+ import { zodResolver } from '@hookform/resolvers/zod'
2616
+ import { Check, ChevronLeft, ChevronRight } from 'lucide-react'
2617
+ import { useState } from 'react'
2618
+ ${p7.rhfImport}
2619
+ import { z } from 'zod/v3'
2620
+ import { create${p7.pascal}Submission } from '@cms/actions/${p7.kebab}-form'
2621
+ import { Button } from '${p7.buttonImport}'
2622
+ import {
2623
+ Form,
2624
+ FormControl,
2625
+ FormDescription,
2626
+ FormField,
2627
+ FormItem,
2628
+ FormLabel,
2629
+ FormMessage,
2630
+ } from '${p7.formImport}'
2631
+ import { Input } from '${p7.inputImport}'
2632
+ import { Label } from '${p7.labelImport}'
2633
+ import { Progress } from '${p7.progressImport}'${p7.hasRadio ? `
2634
+ import { RadioGroup, RadioGroupItem } from '${p7.radioGroupImport}'` : ""}
2635
+ import { Textarea } from '${p7.textareaImport}'
2636
+ import {
2637
+ Select,
2638
+ SelectContent,
2639
+ SelectItem,
2640
+ SelectTrigger,
2641
+ SelectValue,
2642
+ } from '${p7.selectImport}'
2643
+
2644
+ const formSchema = z.object({
2645
+ ${p7.zodFields}
2646
+ })
2647
+
2648
+ type FormValues = z.infer<typeof formSchema>
2649
+
2650
+ ${p7.stepsConst}
2651
+
2652
+ export function ${p7.pascal}Form() {
2653
+ const [currentStep, setCurrentStep] = useState(0)
2654
+ const [completedSteps, setCompletedSteps] = useState<Set<number>>(new Set())
2655
+ const [submitted, setSubmitted] = useState(false)
2656
+ const [submitting, setSubmitting] = useState(false)
2657
+
2658
+ const form = useForm<FormValues>({
2659
+ resolver: zodResolver(formSchema),
2660
+ mode: 'onTouched',
2661
+ defaultValues: {
2662
+ ${p7.defaults}
2663
+ },
2664
+ })
2665
+ ${p7.fieldArraySetup}${p7.watchSetup}
2666
+ async function handleNext() {
2667
+ const isValid = await form.trigger(
2668
+ STEPS[currentStep].fields as (keyof FormValues)[]
2669
+ )
2670
+ if (isValid) {
2671
+ setCompletedSteps((prev) => new Set(prev).add(currentStep))
2672
+ setCurrentStep((prev) => prev + 1)
2673
+ }
2674
+ }
2675
+
2676
+ function handleBack() {
2677
+ setCurrentStep((prev) => prev - 1)
2678
+ }
2679
+
2680
+ function handleStepClick(index: number) {
2681
+ if (index < currentStep || completedSteps.has(index)) {
2682
+ setCurrentStep(index)
2683
+ }
2684
+ }
2685
+
2686
+ async function onSubmit(values: FormValues) {
2687
+ setSubmitting(true)
2688
+ try {
2689
+ const result = await create${p7.pascal}Submission(values)
2690
+ if (result.success) {
2691
+ setSubmitted(true)
2692
+ } else {
2693
+ form.setError('root', { message: result.error || 'Something went wrong' })
2694
+ }
2695
+ } catch {
2696
+ form.setError('root', { message: 'Something went wrong. Please try again.' })
2697
+ } finally {
2698
+ setSubmitting(false)
2699
+ }
2700
+ }
2701
+
2702
+ if (submitted) {
2703
+ return (
2704
+ <div className="rounded-lg border p-6 text-center">
2705
+ <h3 className="text-lg font-semibold">Thank you!</h3>
2706
+ <p className="mt-2 text-muted-foreground">${p7.successMessage}</p>
2707
+ </div>
2708
+ )
2709
+ }
2710
+
2711
+ return (
2712
+ <Form {...form}>
2713
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
2714
+ {/* Mobile step indicator */}
2715
+ <div className="md:hidden space-y-2">
2716
+ <p className="text-sm text-muted-foreground">
2717
+ Step {currentStep + 1} of {STEPS.length} &mdash; {STEPS[currentStep].label}
2718
+ </p>
2719
+ <Progress value={((currentStep + 1) / STEPS.length) * 100} />
2720
+ </div>
2721
+
2722
+ {/* Desktop step indicator */}
2723
+ <nav className="hidden md:flex items-center justify-center" aria-label="Form progress">
2724
+ {STEPS.map((step, index) => (
2725
+ <div key={step.name} className="flex items-center">
2726
+ <button
2727
+ type="button"
2728
+ onClick={() => handleStepClick(index)}
2729
+ disabled={index > currentStep && !completedSteps.has(index)}
2730
+ aria-current={index === currentStep ? 'step' : undefined}
2731
+ className={\`flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium transition-colors \${
2732
+ completedSteps.has(index)
2733
+ ? 'bg-primary text-primary-foreground cursor-pointer'
2734
+ : index === currentStep
2735
+ ? 'border-2 border-primary text-primary'
2736
+ : 'border-2 border-muted text-muted-foreground'
2737
+ }\`}
2738
+ >
2739
+ {completedSteps.has(index) ? (
2740
+ <Check className="h-4 w-4" />
2741
+ ) : (
2742
+ index + 1
2743
+ )}
2744
+ </button>
2745
+ {index < STEPS.length - 1 && (
2746
+ <div
2747
+ className={\`h-0.5 w-8 mx-1 \${
2748
+ completedSteps.has(index) ? 'bg-primary' : 'bg-muted'
2749
+ }\`}
2750
+ />
2751
+ )}
2752
+ </div>
2753
+ ))}
2754
+ </nav>
2755
+
2756
+ {/* Step header */}
2757
+ <div>
2758
+ <h3 className="text-lg font-semibold">{STEPS[currentStep].label}</h3>
2759
+ {'description' in STEPS[currentStep] && STEPS[currentStep].description && (
2760
+ <p className="text-sm text-muted-foreground mt-1">{STEPS[currentStep].description}</p>
2761
+ )}
2762
+ </div>
2763
+
2764
+ {/* Step content */}
2765
+ <div key={currentStep} className="animate-in fade-in duration-300 space-y-6">
2766
+ ${p7.stepContentBlocks}
2767
+ </div>
2768
+
2769
+ {form.formState.errors.root && (
2770
+ <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2771
+ )}
2772
+
2773
+ {/* Navigation */}
2774
+ <div className="flex justify-between">
2775
+ <Button
2776
+ type="button"
2777
+ variant="outline"
2778
+ onClick={handleBack}
2779
+ disabled={currentStep === 0}
2780
+ >
2781
+ <ChevronLeft className="mr-2 h-4 w-4" />
2782
+ Back
2783
+ </Button>
2784
+ {currentStep < STEPS.length - 1 ? (
2785
+ <Button type="button" onClick={handleNext}>
2786
+ Next
2787
+ <ChevronRight className="ml-2 h-4 w-4" />
2788
+ </Button>
2789
+ ) : (
2790
+ <Button type="submit" disabled={submitting}>
2791
+ {submitting ? 'Submitting...' : '${p7.submitText}'}
2792
+ </Button>
2793
+ )}
2794
+ </div>
2795
+ </form>
2796
+ </Form>
2797
+ )
2798
+ }
2799
+ `;
2800
+ }
2801
+
2802
+ // src/generators/form-pipeline/form-component-single.ts
2803
+ import fs9 from "fs";
2804
+ import path9 from "path";
2805
+ function generateSingleStepForm(schema, cwd, cmsDir, options) {
2806
+ const formName = schema.name;
2807
+ const pascal = toPascalCase(formName);
2808
+ const fields = getAllFormSchemaFields(schema);
2809
+ const kebab = toKebabCase(formName);
2810
+ const filePath = path9.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2811
+ const dir = path9.dirname(filePath);
2812
+ if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
2813
+ if (fs9.existsSync(filePath) && !options.force) {
2814
+ return { files: [path9.relative(cwd, filePath)] };
2815
+ }
2816
+ const zodFields = buildZodFields(fields);
2817
+ const defaults = buildDefaultValues(fields);
2818
+ const listFields = getListFields(fields);
2819
+ const hasListFields = listFields.length > 0;
2820
+ const { setup: watchSetup } = buildWatchDecls(fields);
2821
+ const fieldJSX = fields.filter((f) => f.name && !f.hidden).map((f) => wrapShowWhen(f, generateFieldJSX(f))).join("\n\n");
2822
+ const submitText = schema.submitButtonText || "Submit";
2823
+ const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2824
+ const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2825
+ const fieldArraySetup = hasListFields ? `
2826
+ ${buildFieldArrayDecls(listFields)}
2827
+ ` : "";
2828
+ const hasRadio = fields.some((f) => f.type === "radio");
2829
+ const buttonImport = resolveUiImport(cwd, "button");
2830
+ const formImport = resolveUiImport(cwd, "form");
2831
+ const inputImport = resolveUiImport(cwd, "input");
2832
+ const labelImport = resolveUiImport(cwd, "label");
2833
+ const textareaImport = resolveUiImport(cwd, "textarea");
2834
+ const selectImport = resolveUiImport(cwd, "select");
2835
+ const radioGroupImport = resolveUiImport(cwd, "radio-group");
2836
+ const content = `'use client'
2837
+
2838
+ import { zodResolver } from '@hookform/resolvers/zod'
2839
+ import { useState } from 'react'
2840
+ ${rhfImport}
2841
+ import { z } from 'zod/v3'
2842
+ import { create${pascal}Submission } from '@cms/actions/${kebab}-form'
2843
+ import { Button } from '${buttonImport}'
2844
+ import {
2845
+ Form,
2846
+ FormControl,
2847
+ FormDescription,
2848
+ FormField,
2849
+ FormItem,
2850
+ FormLabel,
2851
+ FormMessage,
2852
+ } from '${formImport}'
2853
+ import { Input } from '${inputImport}'
2854
+ import { Label } from '${labelImport}'${hasRadio ? `
2855
+ import { RadioGroup, RadioGroupItem } from '${radioGroupImport}'` : ""}
2856
+ import { Textarea } from '${textareaImport}'
2857
+ import {
2858
+ Select,
2859
+ SelectContent,
2860
+ SelectItem,
2861
+ SelectTrigger,
2862
+ SelectValue,
2863
+ } from '${selectImport}'
2864
+
2865
+ const formSchema = z.object({
2866
+ ${zodFields}
2867
+ })
2868
+
2869
+ type FormValues = z.infer<typeof formSchema>
2870
+
2871
+ export function ${pascal}Form() {
2872
+ const [submitted, setSubmitted] = useState(false)
2873
+ const [submitting, setSubmitting] = useState(false)
2874
+
2875
+ const form = useForm<FormValues>({
2876
+ resolver: zodResolver(formSchema),
2877
+ defaultValues: {
2878
+ ${defaults}
2879
+ },
2880
+ })
2881
+ ${fieldArraySetup}${watchSetup}
2882
+ async function onSubmit(values: FormValues) {
2883
+ setSubmitting(true)
2884
+ try {
2885
+ const result = await create${pascal}Submission(values)
2886
+ if (result.success) {
2887
+ setSubmitted(true)
2888
+ } else {
2889
+ form.setError('root', { message: result.error || 'Something went wrong' })
2890
+ }
2891
+ } catch {
2892
+ form.setError('root', { message: 'Something went wrong. Please try again.' })
2893
+ } finally {
2894
+ setSubmitting(false)
2895
+ }
2896
+ }
2897
+
2898
+ if (submitted) {
2899
+ return (
2900
+ <div className="rounded-lg border p-6 text-center">
2901
+ <h3 className="text-lg font-semibold">Thank you!</h3>
2902
+ <p className="mt-2 text-muted-foreground">${successMessage}</p>
2903
+ </div>
2904
+ )
2905
+ }
2906
+
2907
+ return (
2908
+ <Form {...form}>
2909
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
2910
+ ${fieldJSX}
2911
+
2912
+ {form.formState.errors.root && (
2913
+ <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2914
+ )}
2915
+
2916
+ <Button type="submit" disabled={submitting}>
2917
+ {submitting ? 'Submitting...' : '${submitText}'}
2918
+ </Button>
2919
+ </form>
2920
+ </Form>
2921
+ )
2922
+ }
2923
+ `;
2924
+ fs9.writeFileSync(filePath, content, "utf-8");
2925
+ return { files: [path9.relative(cwd, filePath)] };
2926
+ }
2927
+
2928
+ // src/generators/form-pipeline/form-component.ts
2929
+ function generateFormComponent(schema, cwd, cmsDir, options) {
2930
+ if (isMultiStepForm(schema) && schema.steps.length > 1) {
2931
+ return generateMultiStepForm(schema, cwd, cmsDir, options);
2932
+ }
2933
+ return generateSingleStepForm(schema, cwd, cmsDir, options);
2934
+ }
2935
+
2601
2936
  // src/generators/form-pipeline/form-database.ts
2602
- import fs8 from "fs";
2603
- import path8 from "path";
2937
+ import fs10 from "fs";
2938
+ import path10 from "path";
2604
2939
  function findTableEnd(content, startIndex) {
2605
2940
  let depth = 0;
2606
2941
  let inString = false;
@@ -2655,8 +2990,8 @@ ${fieldDefs}${customFieldsCol}
2655
2990
  updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\`CURRENT_TIMESTAMP\`).notNull()
2656
2991
  })
2657
2992
  `;
2658
- const filePath = path8.join(cwd, dbSchemaPath);
2659
- let content = fs8.readFileSync(filePath, "utf-8");
2993
+ const filePath = path10.join(cwd, dbSchemaPath);
2994
+ let content = fs10.readFileSync(filePath, "utf-8");
2660
2995
  const pgCoreMatch = content.match(/import\s+\{([^}]+)\}\s+from\s+['"]drizzle-orm\/pg-core['"]/);
2661
2996
  if (pgCoreMatch) {
2662
2997
  const existing = new Set(
@@ -2692,23 +3027,23 @@ ${match}`
2692
3027
  }
2693
3028
  content += `
2694
3029
  ${tableSchema}`;
2695
- fs8.writeFileSync(filePath, content, "utf-8");
3030
+ fs10.writeFileSync(filePath, content, "utf-8");
2696
3031
  return { files: [dbSchemaPath] };
2697
3032
  }
2698
3033
 
2699
3034
  // src/generators/form-pipeline/form-hook.ts
2700
- import fs9 from "fs";
2701
- import path9 from "path";
3035
+ import fs11 from "fs";
3036
+ import path11 from "path";
2702
3037
  function generateFormHook(schema, cwd, hooksDir, options) {
2703
3038
  const formName = schema.name;
2704
3039
  const pascal = toPascalCase(formName);
2705
3040
  const camel = toCamelCase(formName);
2706
3041
  const kebab = toKebabCase(formName);
2707
- const filePath = path9.join(cwd, hooksDir, `use-${kebab}-form.ts`);
2708
- const dir = path9.dirname(filePath);
2709
- if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
2710
- if (fs9.existsSync(filePath) && !options.force) {
2711
- return { files: [path9.relative(cwd, filePath)] };
3042
+ const filePath = path11.join(cwd, hooksDir, `use-${kebab}-form.ts`);
3043
+ const dir = path11.dirname(filePath);
3044
+ if (!fs11.existsSync(dir)) fs11.mkdirSync(dir, { recursive: true });
3045
+ if (fs11.existsSync(filePath) && !options.force) {
3046
+ return { files: [path11.relative(cwd, filePath)] };
2712
3047
  }
2713
3048
  const successMsg = (schema.successMessage || "Form submitted successfully").replace(/'/g, "\\'");
2714
3049
  const content = `import {
@@ -2814,8 +3149,8 @@ export function useExport${pascal}SubmissionsJSON() {
2814
3149
  })
2815
3150
  }
2816
3151
  `;
2817
- fs9.writeFileSync(filePath, content, "utf-8");
2818
- return { files: [path9.relative(cwd, filePath)] };
3152
+ fs11.writeFileSync(filePath, content, "utf-8");
3153
+ return { files: [path11.relative(cwd, filePath)] };
2819
3154
  }
2820
3155
 
2821
3156
  // src/generators/form-pipeline/pipeline.ts
@@ -2881,8 +3216,8 @@ function runFormPipeline(schema, cwd, config, options = {}) {
2881
3216
  }
2882
3217
 
2883
3218
  // src/generators/actions/entity-actions.ts
2884
- import fs10 from "fs";
2885
- import path10 from "path";
3219
+ import fs12 from "fs";
3220
+ import path12 from "path";
2886
3221
 
2887
3222
  // src/generators/actions/action-helpers.ts
2888
3223
  function generateFieldMapping(field, source = "input") {
@@ -3021,9 +3356,9 @@ ${blocks.join("\n\n")}
3021
3356
 
3022
3357
  // src/generators/actions/entity-actions.ts
3023
3358
  function generateActions(schema, cwd, actionsDir, options = {}) {
3024
- const absActionsDir = path10.join(cwd, actionsDir);
3025
- const filePath = path10.join(absActionsDir, `${schema.name}.ts`);
3026
- if (fs10.existsSync(filePath) && !options.force) {
3359
+ const absActionsDir = path12.join(cwd, actionsDir);
3360
+ const filePath = path12.join(absActionsDir, `${schema.name}.ts`);
3361
+ if (fs12.existsSync(filePath) && !options.force) {
3027
3362
  return { files: [] };
3028
3363
  }
3029
3364
  const singular = singularize(schema.name);
@@ -3509,20 +3844,20 @@ export async function bulkUpdate${Plural}SortOrder(
3509
3844
  }
3510
3845
  }${m2mHelpers}
3511
3846
  `;
3512
- if (!fs10.existsSync(absActionsDir)) {
3513
- fs10.mkdirSync(absActionsDir, { recursive: true });
3847
+ if (!fs12.existsSync(absActionsDir)) {
3848
+ fs12.mkdirSync(absActionsDir, { recursive: true });
3514
3849
  }
3515
- fs10.writeFileSync(filePath, content, "utf-8");
3516
- return { files: [path10.join(actionsDir, `${schema.name}.ts`)] };
3850
+ fs12.writeFileSync(filePath, content, "utf-8");
3851
+ return { files: [path12.join(actionsDir, `${schema.name}.ts`)] };
3517
3852
  }
3518
3853
 
3519
3854
  // src/generators/actions/single-actions.ts
3520
- import fs11 from "fs";
3521
- import path11 from "path";
3855
+ import fs13 from "fs";
3856
+ import path13 from "path";
3522
3857
  function generateSingleActions(schema, cwd, actionsDir, options = {}) {
3523
- const absActionsDir = path11.join(cwd, actionsDir);
3524
- const filePath = path11.join(absActionsDir, `${schema.name}.ts`);
3525
- if (fs11.existsSync(filePath) && !options.force) {
3858
+ const absActionsDir = path13.join(cwd, actionsDir);
3859
+ const filePath = path13.join(absActionsDir, `${schema.name}.ts`);
3860
+ if (fs13.existsSync(filePath) && !options.force) {
3526
3861
  return { files: [] };
3527
3862
  }
3528
3863
  const singular = singularize(schema.name);
@@ -3645,24 +3980,24 @@ ${upsertMappings},${singleHasHtmlOutput ? "\n" + singleHtmlOutputFields.map((f)
3645
3980
  }
3646
3981
  }
3647
3982
  `;
3648
- if (!fs11.existsSync(absActionsDir)) {
3649
- fs11.mkdirSync(absActionsDir, { recursive: true });
3983
+ if (!fs13.existsSync(absActionsDir)) {
3984
+ fs13.mkdirSync(absActionsDir, { recursive: true });
3650
3985
  }
3651
- fs11.writeFileSync(filePath, content, "utf-8");
3652
- return { files: [path11.join(actionsDir, `${schema.name}.ts`)] };
3986
+ fs13.writeFileSync(filePath, content, "utf-8");
3987
+ return { files: [path13.join(actionsDir, `${schema.name}.ts`)] };
3653
3988
  }
3654
3989
 
3655
3990
  // src/generators/cache.ts
3656
- import fs12 from "fs";
3657
- import path12 from "path";
3991
+ import fs14 from "fs";
3992
+ import path14 from "path";
3658
3993
  function loadAllSchemas(cwd, schemasDir) {
3659
- const dir = path12.join(cwd, schemasDir);
3660
- if (!fs12.existsSync(dir)) return [];
3661
- const files = fs12.readdirSync(dir).filter((f) => f.endsWith(".json"));
3994
+ const dir = path14.join(cwd, schemasDir);
3995
+ if (!fs14.existsSync(dir)) return [];
3996
+ const files = fs14.readdirSync(dir).filter((f) => f.endsWith(".json"));
3662
3997
  const seen = /* @__PURE__ */ new Map();
3663
3998
  for (const file of files) {
3664
3999
  if (file === "schema.json") continue;
3665
- const content = fs12.readFileSync(path12.join(dir, file), "utf-8");
4000
+ const content = fs14.readFileSync(path14.join(dir, file), "utf-8");
3666
4001
  const schema = JSON.parse(content);
3667
4002
  if (!schema.name) continue;
3668
4003
  seen.set(schema.name, schema);
@@ -3852,27 +4187,27 @@ export * from './revalidate'
3852
4187
  `;
3853
4188
  }
3854
4189
  function generateCache(_schema, cwd, cmsDir, _options = {}) {
3855
- const cacheDir = path12.join(cwd, cmsDir, "lib", "cache");
3856
- const schemasDir = path12.join(cmsDir, "schemas");
4190
+ const cacheDir = path14.join(cwd, cmsDir, "lib", "cache");
4191
+ const schemasDir = path14.join(cmsDir, "schemas");
3857
4192
  const schemas = loadAllSchemas(cwd, schemasDir);
3858
4193
  const configs = schemas.map(buildCacheConfig).sort((a, b) => a.name.localeCompare(b.name));
3859
- if (!fs12.existsSync(cacheDir)) {
3860
- fs12.mkdirSync(cacheDir, { recursive: true });
4194
+ if (!fs14.existsSync(cacheDir)) {
4195
+ fs14.mkdirSync(cacheDir, { recursive: true });
3861
4196
  }
3862
4197
  const files = [];
3863
- fs12.writeFileSync(path12.join(cacheDir, "tags.ts"), generateTags(configs), "utf-8");
3864
- files.push(path12.join(cmsDir, "lib", "cache", "tags.ts"));
3865
- fs12.writeFileSync(
3866
- path12.join(cacheDir, "cached-queries.ts"),
4198
+ fs14.writeFileSync(path14.join(cacheDir, "tags.ts"), generateTags(configs), "utf-8");
4199
+ files.push(path14.join(cmsDir, "lib", "cache", "tags.ts"));
4200
+ fs14.writeFileSync(
4201
+ path14.join(cacheDir, "cached-queries.ts"),
3867
4202
  generateCachedQueries(configs),
3868
4203
  "utf-8"
3869
4204
  );
3870
- files.push(path12.join(cmsDir, "lib", "cache", "cached-queries.ts"));
3871
- fs12.writeFileSync(path12.join(cacheDir, "revalidate.ts"), generateRevalidate(configs), "utf-8");
3872
- files.push(path12.join(cmsDir, "lib", "cache", "revalidate.ts"));
3873
- const customQueriesPath = path12.join(cacheDir, "cached-queries-custom.ts");
3874
- if (!fs12.existsSync(customQueriesPath)) {
3875
- fs12.writeFileSync(
4205
+ files.push(path14.join(cmsDir, "lib", "cache", "cached-queries.ts"));
4206
+ fs14.writeFileSync(path14.join(cacheDir, "revalidate.ts"), generateRevalidate(configs), "utf-8");
4207
+ files.push(path14.join(cmsDir, "lib", "cache", "revalidate.ts"));
4208
+ const customQueriesPath = path14.join(cacheDir, "cached-queries-custom.ts");
4209
+ if (!fs14.existsSync(customQueriesPath)) {
4210
+ fs14.writeFileSync(
3876
4211
  customQueriesPath,
3877
4212
  `/**
3878
4213
  * Custom cached query functions (not auto-generated)
@@ -3883,16 +4218,16 @@ export {}
3883
4218
  `,
3884
4219
  "utf-8"
3885
4220
  );
3886
- files.push(path12.join(cmsDir, "lib", "cache", "cached-queries-custom.ts"));
4221
+ files.push(path14.join(cmsDir, "lib", "cache", "cached-queries-custom.ts"));
3887
4222
  }
3888
- fs12.writeFileSync(path12.join(cacheDir, "index.ts"), generateIndex(), "utf-8");
3889
- files.push(path12.join(cmsDir, "lib", "cache", "index.ts"));
4223
+ fs14.writeFileSync(path14.join(cacheDir, "index.ts"), generateIndex(), "utf-8");
4224
+ files.push(path14.join(cmsDir, "lib", "cache", "index.ts"));
3890
4225
  return { files };
3891
4226
  }
3892
4227
 
3893
4228
  // src/generators/columns/generate-columns.ts
3894
- import fs14 from "fs";
3895
- import path14 from "path";
4229
+ import fs16 from "fs";
4230
+ import path16 from "path";
3896
4231
 
3897
4232
  // src/generators/columns/column-defs.ts
3898
4233
  function isSortableColumn(column) {
@@ -4510,12 +4845,12 @@ function truncateStr(str: string, maxLength: number): string {
4510
4845
  }
4511
4846
 
4512
4847
  // src/generators/columns/custom-cell.ts
4513
- import fs13 from "fs";
4514
- import path13 from "path";
4848
+ import fs15 from "fs";
4849
+ import path15 from "path";
4515
4850
  function createCustomCellComponent(schema, componentName, cwd, pagesDir, options) {
4516
- const cellsDir = path13.join(cwd, pagesDir, schema.name, "cells");
4517
- const componentFilePath = path13.join(cellsDir, `${componentName}.tsx`);
4518
- if (fs13.existsSync(componentFilePath) && !options.force) return;
4851
+ const cellsDir = path15.join(cwd, pagesDir, schema.name, "cells");
4852
+ const componentFilePath = path15.join(cellsDir, `${componentName}.tsx`);
4853
+ if (fs15.existsSync(componentFilePath) && !options.force) return;
4519
4854
  const singular = singularize(schema.name);
4520
4855
  const Singular = toPascalCase(singular);
4521
4856
  const content = `import type { ${Singular}Data } from '@cms/actions/${schema.name}'
@@ -4532,17 +4867,17 @@ export function ${componentName}({ data }: ${componentName}Props) {
4532
4867
  )
4533
4868
  }
4534
4869
  `;
4535
- if (!fs13.existsSync(cellsDir)) {
4536
- fs13.mkdirSync(cellsDir, { recursive: true });
4870
+ if (!fs15.existsSync(cellsDir)) {
4871
+ fs15.mkdirSync(cellsDir, { recursive: true });
4537
4872
  }
4538
- fs13.writeFileSync(componentFilePath, content, "utf-8");
4873
+ fs15.writeFileSync(componentFilePath, content, "utf-8");
4539
4874
  }
4540
4875
 
4541
4876
  // src/generators/columns/generate-columns.ts
4542
4877
  function generateColumns2(schema, cwd, pagesDir, options = {}) {
4543
- const entityDir = path14.join(cwd, pagesDir, schema.name);
4544
- const columnsFilePath = path14.join(entityDir, "columns.tsx");
4545
- if (fs14.existsSync(columnsFilePath) && !options.force) {
4878
+ const entityDir = path16.join(cwd, pagesDir, schema.name);
4879
+ const columnsFilePath = path16.join(entityDir, "columns.tsx");
4880
+ if (fs16.existsSync(columnsFilePath) && !options.force) {
4546
4881
  return { files: [] };
4547
4882
  }
4548
4883
  const singular = singularize(schema.name);
@@ -4684,22 +5019,22 @@ ${restColDefs}` : ""},
4684
5019
  ${actionsColumn}
4685
5020
  ]
4686
5021
  `;
4687
- if (!fs14.existsSync(entityDir)) {
4688
- fs14.mkdirSync(entityDir, { recursive: true });
5022
+ if (!fs16.existsSync(entityDir)) {
5023
+ fs16.mkdirSync(entityDir, { recursive: true });
4689
5024
  }
4690
- fs14.writeFileSync(columnsFilePath, content, "utf-8");
5025
+ fs16.writeFileSync(columnsFilePath, content, "utf-8");
4691
5026
  return {
4692
- files: [path14.join(pagesDir, schema.name, "columns.tsx")]
5027
+ files: [path16.join(pagesDir, schema.name, "columns.tsx")]
4693
5028
  };
4694
5029
  }
4695
5030
 
4696
5031
  // src/generators/create-page.ts
4697
- import fs15 from "fs";
4698
- import path15 from "path";
5032
+ import fs17 from "fs";
5033
+ import path17 from "path";
4699
5034
  function generateCreatePage(schema, cwd, pagesDir, options = {}) {
4700
- const newDir = path15.join(cwd, pagesDir, schema.name, "new");
4701
- const pageFilePath = path15.join(newDir, "page.tsx");
4702
- if (fs15.existsSync(pageFilePath) && !options.force) {
5035
+ const newDir = path17.join(cwd, pagesDir, schema.name, "new");
5036
+ const pageFilePath = path17.join(newDir, "page.tsx");
5037
+ if (fs17.existsSync(pageFilePath) && !options.force) {
4703
5038
  return { files: [] };
4704
5039
  }
4705
5040
  const singular = singularize(schema.name);
@@ -4726,18 +5061,18 @@ export default async function Create${Singular}Page() {
4726
5061
  )
4727
5062
  }
4728
5063
  `;
4729
- if (!fs15.existsSync(newDir)) {
4730
- fs15.mkdirSync(newDir, { recursive: true });
5064
+ if (!fs17.existsSync(newDir)) {
5065
+ fs17.mkdirSync(newDir, { recursive: true });
4731
5066
  }
4732
- fs15.writeFileSync(pageFilePath, content, "utf-8");
5067
+ fs17.writeFileSync(pageFilePath, content, "utf-8");
4733
5068
  return {
4734
- files: [path15.join(pagesDir, schema.name, "new", "page.tsx")]
5069
+ files: [path17.join(pagesDir, schema.name, "new", "page.tsx")]
4735
5070
  };
4736
5071
  }
4737
5072
 
4738
5073
  // src/generators/database.ts
4739
- import fs16 from "fs";
4740
- import path16 from "path";
5074
+ import fs18 from "fs";
5075
+ import path18 from "path";
4741
5076
  function getFieldModifiers(field, needsSql) {
4742
5077
  const modifiers = [];
4743
5078
  if (field.primaryKey) {
@@ -4918,11 +5253,11 @@ function findTableEnd2(content, startIndex) {
4918
5253
  return content.length;
4919
5254
  }
4920
5255
  function generateDatabase(schema, cwd, schemaDir, options = {}) {
4921
- const schemaFilePath = path16.join(cwd, schemaDir);
5256
+ const schemaFilePath = path18.join(cwd, schemaDir);
4922
5257
  const files = [];
4923
5258
  let content = "";
4924
- if (fs16.existsSync(schemaFilePath)) {
4925
- content = fs16.readFileSync(schemaFilePath, "utf-8");
5259
+ if (fs18.existsSync(schemaFilePath)) {
5260
+ content = fs18.readFileSync(schemaFilePath, "utf-8");
4926
5261
  }
4927
5262
  const variableName = toCamelCase(schema.name);
4928
5263
  if (content.includes(`export const ${variableName} =`) && !options.force) {
@@ -4962,11 +5297,11 @@ ${junctionDefs[i]}`;
4962
5297
  }
4963
5298
  }
4964
5299
  updated = mergeImports(updated, requiredImports, needsSql.value);
4965
- const dir = path16.dirname(schemaFilePath);
4966
- if (!fs16.existsSync(dir)) {
4967
- fs16.mkdirSync(dir, { recursive: true });
5300
+ const dir = path18.dirname(schemaFilePath);
5301
+ if (!fs18.existsSync(dir)) {
5302
+ fs18.mkdirSync(dir, { recursive: true });
4968
5303
  }
4969
- fs16.writeFileSync(schemaFilePath, updated, "utf-8");
5304
+ fs18.writeFileSync(schemaFilePath, updated, "utf-8");
4970
5305
  files.push(schemaDir);
4971
5306
  return {
4972
5307
  files,
@@ -4976,12 +5311,12 @@ ${junctionDefs[i]}`;
4976
5311
  }
4977
5312
 
4978
5313
  // src/generators/edit-page.ts
4979
- import fs17 from "fs";
4980
- import path17 from "path";
5314
+ import fs19 from "fs";
5315
+ import path19 from "path";
4981
5316
  function generateEditPage(schema, cwd, pagesDir, options = {}) {
4982
- const editDir = path17.join(cwd, pagesDir, schema.name, "[id]", "edit");
4983
- const pageFilePath = path17.join(editDir, "page.tsx");
4984
- if (fs17.existsSync(pageFilePath) && !options.force) {
5317
+ const editDir = path19.join(cwd, pagesDir, schema.name, "[id]", "edit");
5318
+ const pageFilePath = path19.join(editDir, "page.tsx");
5319
+ if (fs19.existsSync(pageFilePath) && !options.force) {
4985
5320
  return { files: [] };
4986
5321
  }
4987
5322
  const singular = singularize(schema.name);
@@ -5020,18 +5355,18 @@ export default async function Edit${Singular}Page({ params }: PageProps) {
5020
5355
  )
5021
5356
  }
5022
5357
  `;
5023
- if (!fs17.existsSync(editDir)) {
5024
- fs17.mkdirSync(editDir, { recursive: true });
5358
+ if (!fs19.existsSync(editDir)) {
5359
+ fs19.mkdirSync(editDir, { recursive: true });
5025
5360
  }
5026
- fs17.writeFileSync(pageFilePath, content, "utf-8");
5361
+ fs19.writeFileSync(pageFilePath, content, "utf-8");
5027
5362
  return {
5028
- files: [path17.join(pagesDir, schema.name, "[id]", "edit", "page.tsx")]
5363
+ files: [path19.join(pagesDir, schema.name, "[id]", "edit", "page.tsx")]
5029
5364
  };
5030
5365
  }
5031
5366
 
5032
5367
  // src/generators/form/form-entity.ts
5033
- import fs18 from "fs";
5034
- import path18 from "path";
5368
+ import fs20 from "fs";
5369
+ import path20 from "path";
5035
5370
 
5036
5371
  // src/generators/form/zod-schema.ts
5037
5372
  function getFormFieldType(field) {
@@ -5829,7 +6164,7 @@ function generateDefaultValue(f) {
5829
6164
  }
5830
6165
  return ` ${f.name}: initialData?.${f.name} ?? ''`;
5831
6166
  }
5832
- function buildZodFields(flatFields) {
6167
+ function buildZodFields2(flatFields) {
5833
6168
  return flatFields.filter((f) => f.type !== "tabs").flatMap((f) => {
5834
6169
  const defs = [];
5835
6170
  const zodType = getZodType(f);
@@ -5841,7 +6176,7 @@ function buildZodFields(flatFields) {
5841
6176
  return defs;
5842
6177
  }).join(",\n");
5843
6178
  }
5844
- function buildDefaultValues(flatFields) {
6179
+ function buildDefaultValues2(flatFields) {
5845
6180
  return flatFields.filter((f) => f.type !== "tabs").flatMap((f) => {
5846
6181
  const defs = [generateDefaultValue(f)];
5847
6182
  if (f.hasIcon) defs.push(` ${f.name}Icon: initialData?.${f.name}Icon ?? ''`);
@@ -5928,9 +6263,9 @@ function buildUiImports(ctx) {
5928
6263
 
5929
6264
  // src/generators/form/form-entity.ts
5930
6265
  function generateForm(schema, cwd, pagesDir, options = {}) {
5931
- const entityDir = path18.join(cwd, pagesDir, schema.name);
5932
- const formFilePath = path18.join(entityDir, `${schema.name}-form.tsx`);
5933
- if (fs18.existsSync(formFilePath) && !options.force) {
6266
+ const entityDir = path20.join(cwd, pagesDir, schema.name);
6267
+ const formFilePath = path20.join(entityDir, `${schema.name}-form.tsx`);
6268
+ if (fs20.existsSync(formFilePath) && !options.force) {
5934
6269
  return { files: [] };
5935
6270
  }
5936
6271
  const singular = singularize(schema.name);
@@ -5984,8 +6319,8 @@ function generateForm(schema, cwd, pagesDir, options = {}) {
5984
6319
  const hasList = hasFieldType(schema.fields, "list");
5985
6320
  const hasNestedList = listFieldsWithNested.length > 0;
5986
6321
  const hasSimpleList = hasList && flatFields.some((f) => f.type === "list" && (!f.fields || f.fields.length === 0));
5987
- const zodFields = buildZodFields(flatFields);
5988
- const defaultValues = buildDefaultValues(flatFields);
6322
+ const zodFields = buildZodFields2(flatFields);
6323
+ const defaultValues = buildDefaultValues2(flatFields);
5989
6324
  const formFieldsJSX = allFormFields.filter((f) => !(hasDraft && f.name === "published")).map((f) => {
5990
6325
  if (f.type === "tabs" && f.tabs) {
5991
6326
  const tabsList = f.tabs.map((t) => ` <TabsTrigger value="${t.name}">${t.label}</TabsTrigger>`).join("\n");
@@ -6186,22 +6521,22 @@ ${hasDraft ? ` <Button
6186
6521
  )
6187
6522
  }
6188
6523
  `;
6189
- if (!fs18.existsSync(entityDir)) {
6190
- fs18.mkdirSync(entityDir, { recursive: true });
6524
+ if (!fs20.existsSync(entityDir)) {
6525
+ fs20.mkdirSync(entityDir, { recursive: true });
6191
6526
  }
6192
- fs18.writeFileSync(formFilePath, content, "utf-8");
6527
+ fs20.writeFileSync(formFilePath, content, "utf-8");
6193
6528
  return {
6194
- files: [path18.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6529
+ files: [path20.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6195
6530
  };
6196
6531
  }
6197
6532
 
6198
6533
  // src/generators/form/form-single.ts
6199
- import fs19 from "fs";
6200
- import path19 from "path";
6534
+ import fs21 from "fs";
6535
+ import path21 from "path";
6201
6536
  function generateSingleForm(schema, cwd, pagesDir, options = {}) {
6202
- const entityDir = path19.join(cwd, pagesDir, schema.name);
6203
- const formFilePath = path19.join(entityDir, `${schema.name}-form.tsx`);
6204
- if (fs19.existsSync(formFilePath) && !options.force) {
6537
+ const entityDir = path21.join(cwd, pagesDir, schema.name);
6538
+ const formFilePath = path21.join(entityDir, `${schema.name}-form.tsx`);
6539
+ if (fs21.existsSync(formFilePath) && !options.force) {
6205
6540
  return { files: [] };
6206
6541
  }
6207
6542
  const singular = singularize(schema.name);
@@ -6253,8 +6588,8 @@ function generateSingleForm(schema, cwd, pagesDir, options = {}) {
6253
6588
  const hasList = hasFieldType(schema.fields, "list");
6254
6589
  const hasNestedList = listFieldsWithNested.length > 0;
6255
6590
  const hasSimpleList = hasList && flatFields.some((f) => f.type === "list" && (!f.fields || f.fields.length === 0));
6256
- const zodFields = buildZodFields(flatFields);
6257
- const defaultValues = buildDefaultValues(flatFields);
6591
+ const zodFields = buildZodFields2(flatFields);
6592
+ const defaultValues = buildDefaultValues2(flatFields);
6258
6593
  const formFieldsJSX = allFormFields.map((f) => {
6259
6594
  if (f.type === "tabs" && f.tabs) {
6260
6595
  const tabsList = f.tabs.map((t) => ` <TabsTrigger value="${t.name}">${t.label}</TabsTrigger>`).join("\n");
@@ -6404,21 +6739,21 @@ ${formFieldsJSX}
6404
6739
  )
6405
6740
  }
6406
6741
  `;
6407
- if (!fs19.existsSync(entityDir)) {
6408
- fs19.mkdirSync(entityDir, { recursive: true });
6742
+ if (!fs21.existsSync(entityDir)) {
6743
+ fs21.mkdirSync(entityDir, { recursive: true });
6409
6744
  }
6410
- fs19.writeFileSync(formFilePath, content, "utf-8");
6745
+ fs21.writeFileSync(formFilePath, content, "utf-8");
6411
6746
  return {
6412
- files: [path19.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6747
+ files: [path21.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6413
6748
  };
6414
6749
  }
6415
6750
 
6416
6751
  // src/generators/hook.ts
6417
- import fs20 from "fs";
6418
- import path20 from "path";
6752
+ import fs22 from "fs";
6753
+ import path22 from "path";
6419
6754
  function generateHook(schema, cwd, hooksDir, options = {}) {
6420
6755
  const hookFileName = `use-${schema.name}.ts`;
6421
- const hookFilePath = path20.join(cwd, hooksDir, hookFileName);
6756
+ const hookFilePath = path22.join(cwd, hooksDir, hookFileName);
6422
6757
  const singular = singularize(schema.name);
6423
6758
  const plural = pluralize(schema.name);
6424
6759
  const Singular = toPascalCase(singular);
@@ -6428,7 +6763,7 @@ function generateHook(schema, cwd, hooksDir, options = {}) {
6428
6763
  const hasHtmlOutput = dbFields.some(
6429
6764
  (f) => (f.type === "richtext" || f.type === "markdown") && f.output === "html"
6430
6765
  );
6431
- if (fs20.existsSync(hookFilePath) && !options.force) {
6766
+ if (fs22.existsSync(hookFilePath) && !options.force) {
6432
6767
  return { files: [], hookName: `use${Plural}` };
6433
6768
  }
6434
6769
  const hasFilters = schema.filters && schema.filters.length > 0;
@@ -6503,22 +6838,22 @@ export function use${Plural}(
6503
6838
  }
6504
6839
  ${singularHook}${slugHook}${distinctHooks}
6505
6840
  `;
6506
- const dir = path20.dirname(hookFilePath);
6507
- if (!fs20.existsSync(dir)) {
6508
- fs20.mkdirSync(dir, { recursive: true });
6841
+ const dir = path22.dirname(hookFilePath);
6842
+ if (!fs22.existsSync(dir)) {
6843
+ fs22.mkdirSync(dir, { recursive: true });
6509
6844
  }
6510
- fs20.writeFileSync(hookFilePath, content, "utf-8");
6845
+ fs22.writeFileSync(hookFilePath, content, "utf-8");
6511
6846
  return {
6512
- files: [path20.join(hooksDir, hookFileName)],
6847
+ files: [path22.join(hooksDir, hookFileName)],
6513
6848
  hookName: `use${Plural}`
6514
6849
  };
6515
6850
  }
6516
6851
  function generateSingleHook(schema, cwd, hooksDir, options = {}) {
6517
6852
  const hookFileName = `use-${schema.name}.ts`;
6518
- const hookFilePath = path20.join(cwd, hooksDir, hookFileName);
6853
+ const hookFilePath = path22.join(cwd, hooksDir, hookFileName);
6519
6854
  const singular = singularize(schema.name);
6520
6855
  const Singular = toPascalCase(singular);
6521
- if (fs20.existsSync(hookFilePath) && !options.force) {
6856
+ if (fs22.existsSync(hookFilePath) && !options.force) {
6522
6857
  return { files: [], hookName: `use${Singular}` };
6523
6858
  }
6524
6859
  const content = `import {
@@ -6535,20 +6870,20 @@ export function use${Singular}(): UseQueryResult<${Singular}Data | null, Error>
6535
6870
  })
6536
6871
  }
6537
6872
  `;
6538
- const dir = path20.dirname(hookFilePath);
6539
- if (!fs20.existsSync(dir)) {
6540
- fs20.mkdirSync(dir, { recursive: true });
6873
+ const dir = path22.dirname(hookFilePath);
6874
+ if (!fs22.existsSync(dir)) {
6875
+ fs22.mkdirSync(dir, { recursive: true });
6541
6876
  }
6542
- fs20.writeFileSync(hookFilePath, content, "utf-8");
6877
+ fs22.writeFileSync(hookFilePath, content, "utf-8");
6543
6878
  return {
6544
- files: [path20.join(hooksDir, hookFileName)],
6879
+ files: [path22.join(hooksDir, hookFileName)],
6545
6880
  hookName: `use${Singular}`
6546
6881
  };
6547
6882
  }
6548
6883
 
6549
6884
  // src/generators/navigation.ts
6550
- import fs21 from "fs";
6551
- import path21 from "path";
6885
+ import fs23 from "fs";
6886
+ import path23 from "path";
6552
6887
  function parseNavigationFile2(content) {
6553
6888
  const iconImportMatch = content.match(/import\s*\{([^}]+)\}\s*from\s*['"]lucide-react['"]/);
6554
6889
  const iconImports = iconImportMatch ? iconImportMatch[1].split(",").map((s) => s.trim()).filter((s) => s && s !== "LucideIcon") : [];
@@ -6651,14 +6986,14 @@ function appendItem2(lines, item, isLast) {
6651
6986
  lines.push(` }${isLast ? "" : ","}`);
6652
6987
  }
6653
6988
  function updateNavigation(schema, cwd, cmsDir, options = {}) {
6654
- const navFilePath = path21.join(cwd, cmsDir, "data", "navigation.ts");
6989
+ const navFilePath = path23.join(cwd, cmsDir, "data", "navigation.ts");
6655
6990
  if (schema.name === "settings") {
6656
6991
  return { files: [] };
6657
6992
  }
6658
6993
  let items = [];
6659
6994
  let iconImports = [];
6660
- if (fs21.existsSync(navFilePath)) {
6661
- const content = fs21.readFileSync(navFilePath, "utf-8");
6995
+ if (fs23.existsSync(navFilePath)) {
6996
+ const content = fs23.readFileSync(navFilePath, "utf-8");
6662
6997
  const parsed = parseNavigationFile2(content);
6663
6998
  items = parsed.items;
6664
6999
  iconImports = parsed.iconImports;
@@ -6695,24 +7030,24 @@ function updateNavigation(schema, cwd, cmsDir, options = {}) {
6695
7030
  iconImports.push(schema.icon);
6696
7031
  }
6697
7032
  iconImports.sort();
6698
- const dir = path21.dirname(navFilePath);
6699
- if (!fs21.existsSync(dir)) {
6700
- fs21.mkdirSync(dir, { recursive: true });
7033
+ const dir = path23.dirname(navFilePath);
7034
+ if (!fs23.existsSync(dir)) {
7035
+ fs23.mkdirSync(dir, { recursive: true });
6701
7036
  }
6702
7037
  const code = generateNavigationCode2(items, iconImports);
6703
- fs21.writeFileSync(navFilePath, code, "utf-8");
7038
+ fs23.writeFileSync(navFilePath, code, "utf-8");
6704
7039
  return {
6705
- files: [path21.join(cmsDir, "data", "navigation.ts")]
7040
+ files: [path23.join(cmsDir, "data", "navigation.ts")]
6706
7041
  };
6707
7042
  }
6708
7043
 
6709
7044
  // src/generators/page.ts
6710
- import fs22 from "fs";
6711
- import path22 from "path";
7045
+ import fs24 from "fs";
7046
+ import path24 from "path";
6712
7047
  function generatePage2(schema, cwd, pagesDir, options = {}) {
6713
- const entityDir = path22.join(cwd, pagesDir, schema.name);
6714
- const pageFilePath = path22.join(entityDir, "page.tsx");
6715
- if (fs22.existsSync(pageFilePath) && !options.force) {
7048
+ const entityDir = path24.join(cwd, pagesDir, schema.name);
7049
+ const pageFilePath = path24.join(entityDir, "page.tsx");
7050
+ if (fs24.existsSync(pageFilePath) && !options.force) {
6716
7051
  return { files: [] };
6717
7052
  }
6718
7053
  const plural = pluralize(schema.name);
@@ -6738,27 +7073,27 @@ export default function ${Plural}Page() {
6738
7073
  )
6739
7074
  }
6740
7075
  `;
6741
- if (!fs22.existsSync(entityDir)) {
6742
- fs22.mkdirSync(entityDir, { recursive: true });
7076
+ if (!fs24.existsSync(entityDir)) {
7077
+ fs24.mkdirSync(entityDir, { recursive: true });
6743
7078
  }
6744
- fs22.writeFileSync(pageFilePath, content, "utf-8");
7079
+ fs24.writeFileSync(pageFilePath, content, "utf-8");
6745
7080
  return {
6746
- files: [path22.join(pagesDir, schema.name, "page.tsx")]
7081
+ files: [path24.join(pagesDir, schema.name, "page.tsx")]
6747
7082
  };
6748
7083
  }
6749
7084
 
6750
7085
  // src/generators/page-content.ts
6751
- import fs23 from "fs";
6752
- import path23 from "path";
7086
+ import fs25 from "fs";
7087
+ import path25 from "path";
6753
7088
  function generatePageContent2(schema, cwd, pagesDir, options = {}) {
6754
- const entityDir = path23.join(cwd, pagesDir, schema.name);
7089
+ const entityDir = path25.join(cwd, pagesDir, schema.name);
6755
7090
  const singular = singularize(schema.name);
6756
7091
  const plural = pluralize(schema.name);
6757
7092
  const Singular = toPascalCase(singular);
6758
7093
  const Plural = toPascalCase(plural);
6759
7094
  const fileName = `${toKebabCase(plural)}-page-content.tsx`;
6760
- const filePath = path23.join(entityDir, fileName);
6761
- if (fs23.existsSync(filePath) && !options.force) {
7095
+ const filePath = path25.join(entityDir, fileName);
7096
+ if (fs25.existsSync(filePath) && !options.force) {
6762
7097
  return { files: [] };
6763
7098
  }
6764
7099
  const hasCreate = schema.actions?.create ?? false;
@@ -7011,22 +7346,22 @@ ${searchLogic}${deleteLogic}
7011
7346
  )
7012
7347
  }
7013
7348
  `;
7014
- if (!fs23.existsSync(entityDir)) {
7015
- fs23.mkdirSync(entityDir, { recursive: true });
7349
+ if (!fs25.existsSync(entityDir)) {
7350
+ fs25.mkdirSync(entityDir, { recursive: true });
7016
7351
  }
7017
- fs23.writeFileSync(filePath, content, "utf-8");
7352
+ fs25.writeFileSync(filePath, content, "utf-8");
7018
7353
  return {
7019
- files: [path23.join(pagesDir, schema.name, fileName)]
7354
+ files: [path25.join(pagesDir, schema.name, fileName)]
7020
7355
  };
7021
7356
  }
7022
7357
 
7023
7358
  // src/generators/single-page.ts
7024
- import fs24 from "fs";
7025
- import path24 from "path";
7359
+ import fs26 from "fs";
7360
+ import path26 from "path";
7026
7361
  function generateSinglePage(schema, cwd, pagesDir, options = {}) {
7027
- const entityDir = path24.join(cwd, pagesDir, schema.name);
7028
- const pageFilePath = path24.join(entityDir, "page.tsx");
7029
- if (fs24.existsSync(pageFilePath) && !options.force) {
7362
+ const entityDir = path26.join(cwd, pagesDir, schema.name);
7363
+ const pageFilePath = path26.join(entityDir, "page.tsx");
7364
+ if (fs26.existsSync(pageFilePath) && !options.force) {
7030
7365
  return { files: [] };
7031
7366
  }
7032
7367
  const singular = singularize(schema.name);
@@ -7049,20 +7384,20 @@ export default async function ${PageName}Page() {
7049
7384
  )
7050
7385
  }
7051
7386
  `;
7052
- if (!fs24.existsSync(entityDir)) {
7053
- fs24.mkdirSync(entityDir, { recursive: true });
7387
+ if (!fs26.existsSync(entityDir)) {
7388
+ fs26.mkdirSync(entityDir, { recursive: true });
7054
7389
  }
7055
- fs24.writeFileSync(pageFilePath, content, "utf-8");
7390
+ fs26.writeFileSync(pageFilePath, content, "utf-8");
7056
7391
  return {
7057
- files: [path24.join(pagesDir, schema.name, "page.tsx")]
7392
+ files: [path26.join(pagesDir, schema.name, "page.tsx")]
7058
7393
  };
7059
7394
  }
7060
7395
 
7061
7396
  // src/generators/table.ts
7062
- import fs25 from "fs";
7063
- import path25 from "path";
7397
+ import fs27 from "fs";
7398
+ import path27 from "path";
7064
7399
  function generateTable2(schema, cwd, pagesDir, options = {}) {
7065
- const entityDir = path25.join(cwd, pagesDir, schema.name);
7400
+ const entityDir = path27.join(cwd, pagesDir, schema.name);
7066
7401
  const singular = singularize(schema.name);
7067
7402
  const plural = pluralize(schema.name);
7068
7403
  const Singular = toPascalCase(singular);
@@ -7070,8 +7405,8 @@ function generateTable2(schema, cwd, pagesDir, options = {}) {
7070
7405
  const camelPlural = toCamelCase(plural);
7071
7406
  const camelSingular = toCamelCase(singular);
7072
7407
  const tableFileName = `${toKebabCase(plural)}-table.tsx`;
7073
- const tableFilePath = path25.join(entityDir, tableFileName);
7074
- if (fs25.existsSync(tableFilePath) && !options.force) {
7408
+ const tableFilePath = path27.join(entityDir, tableFileName);
7409
+ if (fs27.existsSync(tableFilePath) && !options.force) {
7075
7410
  return { files: [] };
7076
7411
  }
7077
7412
  const hasFilters = schema.filters && schema.filters.length > 0;
@@ -7435,12 +7770,12 @@ export function ${Plural}Table<TValue>({ columns, selectedIds, setSelectedIds, $
7435
7770
  )
7436
7771
  }
7437
7772
  `;
7438
- if (!fs25.existsSync(entityDir)) {
7439
- fs25.mkdirSync(entityDir, { recursive: true });
7773
+ if (!fs27.existsSync(entityDir)) {
7774
+ fs27.mkdirSync(entityDir, { recursive: true });
7440
7775
  }
7441
- fs25.writeFileSync(tableFilePath, content, "utf-8");
7776
+ fs27.writeFileSync(tableFilePath, content, "utf-8");
7442
7777
  return {
7443
- files: [path25.join(pagesDir, schema.name, tableFileName)]
7778
+ files: [path27.join(pagesDir, schema.name, tableFileName)]
7444
7779
  };
7445
7780
  }
7446
7781
 
@@ -7598,13 +7933,13 @@ function runSinglePipeline(schema, cwd, config, options = {}) {
7598
7933
 
7599
7934
  // src/generators/post-generate.ts
7600
7935
  import { execFileSync as execFileSync2 } from "child_process";
7601
- import fs27 from "fs";
7602
- import path27 from "path";
7936
+ import fs29 from "fs";
7937
+ import path29 from "path";
7603
7938
 
7604
7939
  // src/utils/package-manager.ts
7605
7940
  import { execFileSync } from "child_process";
7606
- import fs26 from "fs";
7607
- import path26 from "path";
7941
+ import fs28 from "fs";
7942
+ import path28 from "path";
7608
7943
  var LOCKFILE_MAP = {
7609
7944
  "pnpm-lock.yaml": "pnpm",
7610
7945
  "package-lock.json": "npm",
@@ -7613,18 +7948,18 @@ var LOCKFILE_MAP = {
7613
7948
  "bun.lock": "bun"
7614
7949
  };
7615
7950
  function detectPackageManager(cwd) {
7616
- let dir = path26.resolve(cwd);
7617
- const root = path26.parse(dir).root;
7951
+ let dir = path28.resolve(cwd);
7952
+ const root = path28.parse(dir).root;
7618
7953
  while (dir !== root) {
7619
7954
  for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {
7620
- if (fs26.existsSync(path26.join(dir, lockfile))) {
7955
+ if (fs28.existsSync(path28.join(dir, lockfile))) {
7621
7956
  return pm;
7622
7957
  }
7623
7958
  }
7624
- const pkgPath = path26.join(dir, "package.json");
7625
- if (fs26.existsSync(pkgPath)) {
7959
+ const pkgPath = path28.join(dir, "package.json");
7960
+ if (fs28.existsSync(pkgPath)) {
7626
7961
  try {
7627
- const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
7962
+ const pkg = JSON.parse(fs28.readFileSync(pkgPath, "utf-8"));
7628
7963
  if (typeof pkg.packageManager === "string") {
7629
7964
  const name = pkg.packageManager.split("@")[0];
7630
7965
  if (name === "pnpm" || name === "npm" || name === "yarn" || name === "bun") {
@@ -7634,7 +7969,7 @@ function detectPackageManager(cwd) {
7634
7969
  } catch {
7635
7970
  }
7636
7971
  }
7637
- dir = path26.dirname(dir);
7972
+ dir = path28.dirname(dir);
7638
7973
  }
7639
7974
  return "npm";
7640
7975
  }
@@ -7665,9 +8000,9 @@ function createNextAppCommand(pm) {
7665
8000
 
7666
8001
  // src/generators/post-generate.ts
7667
8002
  function loadEnvFile(cwd) {
7668
- const envPath = path27.join(cwd, ".env.local");
7669
- if (!fs27.existsSync(envPath)) return;
7670
- const content = fs27.readFileSync(envPath, "utf-8");
8003
+ const envPath = path29.join(cwd, ".env.local");
8004
+ if (!fs29.existsSync(envPath)) return;
8005
+ const content = fs29.readFileSync(envPath, "utf-8");
7671
8006
  for (const line of content.split("\n")) {
7672
8007
  const trimmed = line.trim();
7673
8008
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -7697,10 +8032,10 @@ function runPmScript(pm, script, cwd) {
7697
8032
  }
7698
8033
  }
7699
8034
  function hasPkgScript(cwd, script) {
7700
- const pkgPath = path27.join(cwd, "package.json");
7701
- if (!fs27.existsSync(pkgPath)) return false;
8035
+ const pkgPath = path29.join(cwd, "package.json");
8036
+ if (!fs29.existsSync(pkgPath)) return false;
7702
8037
  try {
7703
- const pkg = JSON.parse(fs27.readFileSync(pkgPath, "utf-8"));
8038
+ const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf-8"));
7704
8039
  const scripts = pkg.scripts;
7705
8040
  return !!scripts?.[script];
7706
8041
  } catch {
@@ -7727,7 +8062,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7727
8062
  console.log(ok ? " Database schema synced" : " Database push failed (run db:push manually)");
7728
8063
  } else {
7729
8064
  console.log("\n Running drizzle-kit push...");
7730
- const drizzleBin = path27.join(cwd, "node_modules", ".bin", "drizzle-kit");
8065
+ const drizzleBin = path29.join(cwd, "node_modules", ".bin", "drizzle-kit");
7731
8066
  try {
7732
8067
  execFileSync2(drizzleBin, ["push", "--force"], { cwd, stdio: "inherit" });
7733
8068
  result.dbPush = "success";
@@ -7746,7 +8081,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7746
8081
  result.lintFix = ok ? "success" : "failed";
7747
8082
  console.log(ok ? " Code formatted" : " Lint fix had issues (run lint:fix manually)");
7748
8083
  } else {
7749
- const biomeBin = path27.join(cwd, "node_modules", ".bin", "biome");
8084
+ const biomeBin = path29.join(cwd, "node_modules", ".bin", "biome");
7750
8085
  try {
7751
8086
  execFileSync2(biomeBin, ["check", "--write", "."], { cwd, stdio: "pipe" });
7752
8087
  result.lintFix = "success";
@@ -7769,7 +8104,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7769
8104
  // src/commands/generate.ts
7770
8105
  var generateCommand = new Command("generate").alias("g").description("Generate entity or form from a JSON schema").argument("<schema>", "Schema name (e.g. posts, categories, contact)").option("-f, --force", "Overwrite existing generated files", false).option("--skip-migration", "Skip running db:push after generation", false).option("--cwd <path>", "Project root path").action(
7771
8106
  async (schemaName, options) => {
7772
- const cwd = options.cwd ? path28.resolve(options.cwd) : process.cwd();
8107
+ const cwd = options.cwd ? path30.resolve(options.cwd) : process.cwd();
7773
8108
  console.log("\n BetterStart Generator\n");
7774
8109
  let config;
7775
8110
  try {
@@ -7778,7 +8113,7 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7778
8113
  console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`);
7779
8114
  process.exit(1);
7780
8115
  }
7781
- const schemasDir = path28.join(cwd, config.paths?.schemas ?? "./cms/schemas");
8116
+ const schemasDir = path30.join(cwd, config.paths?.schemas ?? "./cms/schemas");
7782
8117
  console.log(` Project root: ${cwd}`);
7783
8118
  console.log(` Loading schema: ${schemaName}.json
7784
8119
  `);
@@ -7790,7 +8125,7 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7790
8125
  console.error(` ${err.message}`);
7791
8126
  console.error(
7792
8127
  `
7793
- Create a schema file at: ${path28.join(schemasDir, `${schemaName}.json`)}`
8128
+ Create a schema file at: ${path30.join(schemasDir, `${schemaName}.json`)}`
7794
8129
  );
7795
8130
  } else {
7796
8131
  console.error(
@@ -7883,8 +8218,8 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7883
8218
 
7884
8219
  // src/commands/init.ts
7885
8220
  import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
7886
- import fs38 from "fs";
7887
- import path43 from "path";
8221
+ import fs40 from "fs";
8222
+ import path45 from "path";
7888
8223
  import * as p4 from "@clack/prompts";
7889
8224
  import { Command as Command3 } from "commander";
7890
8225
  import pc2 from "picocolors";
@@ -8027,21 +8362,21 @@ async function promptProject(defaultName) {
8027
8362
  }
8028
8363
 
8029
8364
  // src/init/scaffolders/api-routes.ts
8030
- import path30 from "path";
8365
+ import path32 from "path";
8031
8366
 
8032
8367
  // src/utils/fs.ts
8033
- import fs28 from "fs";
8034
- import path29 from "path";
8368
+ import fs30 from "fs";
8369
+ import path31 from "path";
8035
8370
  import fse from "fs-extra";
8036
8371
  function ensureDir(dirPath) {
8037
8372
  fse.ensureDirSync(dirPath);
8038
8373
  }
8039
8374
  function safeWriteFile(filePath, content, force = false) {
8040
- if (!force && fs28.existsSync(filePath)) {
8375
+ if (!force && fs30.existsSync(filePath)) {
8041
8376
  return false;
8042
8377
  }
8043
- ensureDir(path29.dirname(filePath));
8044
- fs28.writeFileSync(filePath, content, "utf-8");
8378
+ ensureDir(path31.dirname(filePath));
8379
+ fs30.writeFileSync(filePath, content, "utf-8");
8045
8380
  return true;
8046
8381
  }
8047
8382
 
@@ -8135,21 +8470,21 @@ export async function POST(request: NextRequest) {
8135
8470
  // src/init/scaffolders/api-routes.ts
8136
8471
  function scaffoldApiRoutes({ cwd, config }) {
8137
8472
  const created = [];
8138
- const apiDir = path30.resolve(cwd, config.paths.api);
8473
+ const apiDir = path32.resolve(cwd, config.paths.api);
8139
8474
  function write(relPath, content) {
8140
- const fullPath = path30.join(apiDir, relPath);
8141
- ensureDir(path30.dirname(fullPath));
8475
+ const fullPath = path32.join(apiDir, relPath);
8476
+ ensureDir(path32.dirname(fullPath));
8142
8477
  if (safeWriteFile(fullPath, content)) {
8143
- created.push(path30.join(config.paths.api, relPath));
8478
+ created.push(path32.join(config.paths.api, relPath));
8144
8479
  }
8145
8480
  }
8146
- write(path30.join("auth", "[...all]", "route.ts"), authRouteTemplate());
8147
- write(path30.join("upload", "route.ts"), uploadRouteTemplate());
8481
+ write(path32.join("auth", "[...all]", "route.ts"), authRouteTemplate());
8482
+ write(path32.join("upload", "route.ts"), uploadRouteTemplate());
8148
8483
  return created;
8149
8484
  }
8150
8485
 
8151
8486
  // src/init/scaffolders/auth.ts
8152
- import path31 from "path";
8487
+ import path33 from "path";
8153
8488
 
8154
8489
  // src/init/templates/lib/auth/auth.ts
8155
8490
  function authTemplate() {
@@ -8268,11 +8603,11 @@ export async function requireRole(allowedRoles: UserRole[]): Promise<User> {
8268
8603
  // src/init/scaffolders/auth.ts
8269
8604
  function scaffoldAuth({ cwd, config }) {
8270
8605
  const created = [];
8271
- const authDir = path31.resolve(cwd, config.paths.cms, "lib", "auth");
8606
+ const authDir = path33.resolve(cwd, config.paths.cms, "lib", "auth");
8272
8607
  function write(filename, content) {
8273
- const fullPath = path31.join(authDir, filename);
8608
+ const fullPath = path33.join(authDir, filename);
8274
8609
  if (safeWriteFile(fullPath, content)) {
8275
- created.push(path31.join(config.paths.cms, "lib", "auth", filename));
8610
+ created.push(path33.join(config.paths.cms, "lib", "auth", filename));
8276
8611
  }
8277
8612
  }
8278
8613
  write("auth.ts", authTemplate());
@@ -8282,51 +8617,51 @@ function scaffoldAuth({ cwd, config }) {
8282
8617
  }
8283
8618
 
8284
8619
  // src/init/scaffolders/base.ts
8285
- import fs29 from "fs";
8286
- import path32 from "path";
8620
+ import fs31 from "fs";
8621
+ import path34 from "path";
8287
8622
  function scaffoldBase({ cwd, config }) {
8288
8623
  const created = [];
8289
8624
  const cmsDirs = [
8290
8625
  config.paths.cms,
8291
8626
  config.paths.schemas,
8292
- path32.join(config.paths.cms, "db"),
8293
- path32.join(config.paths.cms, "db", "migrations"),
8294
- path32.join(config.paths.cms, "lib", "auth"),
8295
- path32.join(config.paths.cms, "lib", "actions"),
8296
- path32.join(config.paths.cms, "lib", "cache"),
8297
- path32.join(config.paths.cms, "lib", "markdown"),
8298
- path32.join(config.paths.cms, "lib", "emails"),
8299
- path32.join(config.paths.cms, "lib"),
8300
- path32.join(config.paths.cms, "hooks"),
8301
- path32.join(config.paths.cms, "components", "ui"),
8302
- path32.join(config.paths.cms, "components", "form"),
8303
- path32.join(config.paths.cms, "components", "data-table"),
8304
- path32.join(config.paths.cms, "components", "layout"),
8305
- path32.join(config.paths.cms, "components", "shared"),
8306
- path32.join(config.paths.cms, "types"),
8307
- path32.join(config.paths.cms, "utils"),
8308
- path32.join(config.paths.cms, "data")
8627
+ path34.join(config.paths.cms, "db"),
8628
+ path34.join(config.paths.cms, "db", "migrations"),
8629
+ path34.join(config.paths.cms, "lib", "auth"),
8630
+ path34.join(config.paths.cms, "lib", "actions"),
8631
+ path34.join(config.paths.cms, "lib", "cache"),
8632
+ path34.join(config.paths.cms, "lib", "markdown"),
8633
+ path34.join(config.paths.cms, "lib", "emails"),
8634
+ path34.join(config.paths.cms, "lib"),
8635
+ path34.join(config.paths.cms, "hooks"),
8636
+ path34.join(config.paths.cms, "components", "ui"),
8637
+ path34.join(config.paths.cms, "components", "form"),
8638
+ path34.join(config.paths.cms, "components", "data-table"),
8639
+ path34.join(config.paths.cms, "components", "layout"),
8640
+ path34.join(config.paths.cms, "components", "shared"),
8641
+ path34.join(config.paths.cms, "types"),
8642
+ path34.join(config.paths.cms, "utils"),
8643
+ path34.join(config.paths.cms, "data")
8309
8644
  ];
8310
8645
  for (const dir of cmsDirs) {
8311
- ensureDir(path32.resolve(cwd, dir));
8646
+ ensureDir(path34.resolve(cwd, dir));
8312
8647
  }
8313
8648
  const appDirs = [config.paths.pages, config.paths.login, config.paths.api];
8314
8649
  for (const dir of appDirs) {
8315
- ensureDir(path32.resolve(cwd, dir));
8650
+ ensureDir(path34.resolve(cwd, dir));
8316
8651
  }
8317
8652
  const configContent = generateConfigFile(config);
8318
- if (safeWriteFile(path32.resolve(cwd, "cms.config.ts"), configContent)) {
8653
+ if (safeWriteFile(path34.resolve(cwd, "cms.config.ts"), configContent)) {
8319
8654
  created.push("cms.config.ts");
8320
8655
  }
8321
8656
  const cmsDoc = generateCmsDoc(config, {});
8322
- if (safeWriteFile(path32.resolve(cwd, "CMS.md"), cmsDoc)) {
8657
+ if (safeWriteFile(path34.resolve(cwd, "CMS.md"), cmsDoc)) {
8323
8658
  created.push("CMS.md");
8324
8659
  }
8325
8660
  return created;
8326
8661
  }
8327
8662
  function regenerateCmsDoc(cwd, config, options) {
8328
8663
  const content = generateCmsDoc(config, options);
8329
- fs29.writeFileSync(path32.resolve(cwd, "CMS.md"), content, "utf-8");
8664
+ fs31.writeFileSync(path34.resolve(cwd, "CMS.md"), content, "utf-8");
8330
8665
  }
8331
8666
  function generateConfigFile(config) {
8332
8667
  return `import { defineConfig } from '@betterstart/cli'
@@ -8480,8 +8815,8 @@ Edit \`cms.config.ts\` to customize paths, database provider, and features.`);
8480
8815
  }
8481
8816
 
8482
8817
  // src/init/scaffolders/biome.ts
8483
- import fs30 from "fs";
8484
- import path33 from "path";
8818
+ import fs32 from "fs";
8819
+ import path35 from "path";
8485
8820
  function scaffoldBiome(cwd, linter) {
8486
8821
  if (linter.type !== "none") {
8487
8822
  return {
@@ -8489,8 +8824,8 @@ function scaffoldBiome(cwd, linter) {
8489
8824
  skippedReason: `${linter.type} already configured (${linter.configFile})`
8490
8825
  };
8491
8826
  }
8492
- const configPath = path33.join(cwd, "biome.json");
8493
- if (fs30.existsSync(configPath)) {
8827
+ const configPath = path35.join(cwd, "biome.json");
8828
+ if (fs32.existsSync(configPath)) {
8494
8829
  return { installed: false, skippedReason: "biome.json already exists" };
8495
8830
  }
8496
8831
  const config = {
@@ -8541,52 +8876,52 @@ function scaffoldBiome(cwd, linter) {
8541
8876
  ]
8542
8877
  }
8543
8878
  };
8544
- fs30.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
8879
+ fs32.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
8545
8880
  `, "utf-8");
8546
8881
  return { installed: true, skippedReason: null };
8547
8882
  }
8548
8883
 
8549
8884
  // src/init/scaffolders/components.ts
8550
- import path35 from "path";
8551
- import fs32 from "fs-extra";
8885
+ import path37 from "path";
8886
+ import fs34 from "fs-extra";
8552
8887
 
8553
8888
  // src/utils/detect.ts
8554
- import fs31 from "fs";
8555
- import path34 from "path";
8889
+ import fs33 from "fs";
8890
+ import path36 from "path";
8556
8891
  var NEXT_CONFIG_FILES = ["next.config.ts", "next.config.js", "next.config.mjs"];
8557
8892
  function detectProjectName(cwd) {
8558
- const pkgPath = path34.join(cwd, "package.json");
8559
- if (fs31.existsSync(pkgPath)) {
8893
+ const pkgPath = path36.join(cwd, "package.json");
8894
+ if (fs33.existsSync(pkgPath)) {
8560
8895
  try {
8561
- const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
8896
+ const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
8562
8897
  if (typeof pkg.name === "string" && pkg.name.length > 0) {
8563
8898
  return formatProjectName(pkg.name);
8564
8899
  }
8565
8900
  } catch {
8566
8901
  }
8567
8902
  }
8568
- return formatProjectName(path34.basename(cwd));
8903
+ return formatProjectName(path36.basename(cwd));
8569
8904
  }
8570
8905
  function formatProjectName(name) {
8571
8906
  const base = name.includes("/") ? name.split("/").pop() : name;
8572
8907
  return base.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
8573
8908
  }
8574
8909
  function detectProject(cwd) {
8575
- const isExisting = NEXT_CONFIG_FILES.some((f) => fs31.existsSync(path34.join(cwd, f)));
8576
- const hasSrcDir = fs31.existsSync(path34.join(cwd, "src"));
8577
- const hasTypeScript = fs31.existsSync(path34.join(cwd, "tsconfig.json")) || fs31.existsSync(path34.join(cwd, "tsconfig.app.json"));
8910
+ const isExisting = NEXT_CONFIG_FILES.some((f) => fs33.existsSync(path36.join(cwd, f)));
8911
+ const hasSrcDir = fs33.existsSync(path36.join(cwd, "src"));
8912
+ const hasTypeScript = fs33.existsSync(path36.join(cwd, "tsconfig.json")) || fs33.existsSync(path36.join(cwd, "tsconfig.app.json"));
8578
8913
  const hasTailwind = detectTailwind(cwd);
8579
8914
  const linter = detectLinter(cwd);
8580
8915
  const conflicts = [];
8581
8916
  if (isExisting) {
8582
- if (fs31.existsSync(path34.join(cwd, "cms"))) {
8917
+ if (fs33.existsSync(path36.join(cwd, "cms"))) {
8583
8918
  conflicts.push("cms/ directory already exists");
8584
8919
  }
8585
- if (fs31.existsSync(path34.join(cwd, "cms.config.ts"))) {
8920
+ if (fs33.existsSync(path36.join(cwd, "cms.config.ts"))) {
8586
8921
  conflicts.push("cms.config.ts already exists");
8587
8922
  }
8588
8923
  const appBase = hasSrcDir ? "src/app" : "app";
8589
- if (fs31.existsSync(path34.join(cwd, appBase, "(cms)"))) {
8924
+ if (fs33.existsSync(path36.join(cwd, appBase, "(cms)"))) {
8590
8925
  conflicts.push(`${appBase}/(cms)/ route group already exists`);
8591
8926
  }
8592
8927
  if (hasTsconfigCmsAliases(cwd)) {
@@ -8613,19 +8948,19 @@ var ESLINT_CONFIG_FILES = [
8613
8948
  ];
8614
8949
  function detectLinter(cwd) {
8615
8950
  for (const f of BIOME_CONFIG_FILES) {
8616
- if (fs31.existsSync(path34.join(cwd, f))) {
8951
+ if (fs33.existsSync(path36.join(cwd, f))) {
8617
8952
  return { type: "biome", configFile: f };
8618
8953
  }
8619
8954
  }
8620
8955
  for (const f of ESLINT_CONFIG_FILES) {
8621
- if (fs31.existsSync(path34.join(cwd, f))) {
8956
+ if (fs33.existsSync(path36.join(cwd, f))) {
8622
8957
  return { type: "eslint", configFile: f };
8623
8958
  }
8624
8959
  }
8625
- const pkgPath = path34.join(cwd, "package.json");
8626
- if (fs31.existsSync(pkgPath)) {
8960
+ const pkgPath = path36.join(cwd, "package.json");
8961
+ if (fs33.existsSync(pkgPath)) {
8627
8962
  try {
8628
- const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
8963
+ const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
8629
8964
  if (pkg.eslintConfig) {
8630
8965
  return { type: "eslint", configFile: "package.json (eslintConfig)" };
8631
8966
  }
@@ -8636,14 +8971,14 @@ function detectLinter(cwd) {
8636
8971
  }
8637
8972
  function detectTailwind(cwd) {
8638
8973
  const cssFiles = ["globals.css", "app.css", "index.css"].flatMap((f) => [
8639
- path34.join(cwd, "src", "app", f),
8640
- path34.join(cwd, "app", f),
8641
- path34.join(cwd, "src", f),
8642
- path34.join(cwd, f)
8974
+ path36.join(cwd, "src", "app", f),
8975
+ path36.join(cwd, "app", f),
8976
+ path36.join(cwd, "src", f),
8977
+ path36.join(cwd, f)
8643
8978
  ]);
8644
8979
  for (const cssFile of cssFiles) {
8645
- if (fs31.existsSync(cssFile)) {
8646
- const content = fs31.readFileSync(cssFile, "utf-8");
8980
+ if (fs33.existsSync(cssFile)) {
8981
+ const content = fs33.readFileSync(cssFile, "utf-8");
8647
8982
  if (content.includes('@import "tailwindcss"') || content.includes("@import 'tailwindcss'") || content.includes("@theme")) {
8648
8983
  return true;
8649
8984
  }
@@ -8651,8 +8986,8 @@ function detectTailwind(cwd) {
8651
8986
  }
8652
8987
  const postcssFiles = ["postcss.config.js", "postcss.config.mjs", "postcss.config.cjs"];
8653
8988
  for (const f of postcssFiles) {
8654
- if (fs31.existsSync(path34.join(cwd, f))) {
8655
- const content = fs31.readFileSync(path34.join(cwd, f), "utf-8");
8989
+ if (fs33.existsSync(path36.join(cwd, f))) {
8990
+ const content = fs33.readFileSync(path36.join(cwd, f), "utf-8");
8656
8991
  if (content.includes("tailwindcss") || content.includes("@tailwindcss")) {
8657
8992
  return true;
8658
8993
  }
@@ -8661,20 +8996,20 @@ function detectTailwind(cwd) {
8661
8996
  return false;
8662
8997
  }
8663
8998
  function hasTsconfigCmsAliases(cwd) {
8664
- const tsconfigPath = path34.join(cwd, "tsconfig.json");
8665
- if (!fs31.existsSync(tsconfigPath)) return false;
8999
+ const tsconfigPath = path36.join(cwd, "tsconfig.json");
9000
+ if (!fs33.existsSync(tsconfigPath)) return false;
8666
9001
  try {
8667
- const content = fs31.readFileSync(tsconfigPath, "utf-8");
9002
+ const content = fs33.readFileSync(tsconfigPath, "utf-8");
8668
9003
  return content.includes("@cms/");
8669
9004
  } catch {
8670
9005
  return false;
8671
9006
  }
8672
9007
  }
8673
9008
  function hasEnvBetterstartVars(cwd) {
8674
- const envPath = path34.join(cwd, ".env.local");
8675
- if (!fs31.existsSync(envPath)) return false;
9009
+ const envPath = path36.join(cwd, ".env.local");
9010
+ if (!fs33.existsSync(envPath)) return false;
8676
9011
  try {
8677
- const content = fs31.readFileSync(envPath, "utf-8");
9012
+ const content = fs33.readFileSync(envPath, "utf-8");
8678
9013
  return content.includes("BETTERSTART_");
8679
9014
  } catch {
8680
9015
  return false;
@@ -11373,12 +11708,12 @@ export function addToMailchimpAudience(email: string): void {
11373
11708
 
11374
11709
  // src/init/scaffolders/components.ts
11375
11710
  function scaffoldComponents({ cwd, config }) {
11376
- const cms = path35.resolve(cwd, config.paths.cms);
11711
+ const cms = path37.resolve(cwd, config.paths.cms);
11377
11712
  const created = [];
11378
11713
  function write(relPath, content) {
11379
- const fullPath = path35.join(cms, relPath);
11714
+ const fullPath = path37.join(cms, relPath);
11380
11715
  if (safeWriteFile(fullPath, content)) {
11381
- created.push(path35.join(config.paths.cms, relPath));
11716
+ created.push(path37.join(config.paths.cms, relPath));
11382
11717
  }
11383
11718
  }
11384
11719
  write("cms-globals.css", cmsGlobalsCssTemplate());
@@ -11427,18 +11762,18 @@ function scaffoldComponents({ cwd, config }) {
11427
11762
  }
11428
11763
  function copyUiTemplates(cwd, config) {
11429
11764
  const created = [];
11430
- const destDir = path35.resolve(cwd, config.paths.cms, "components", "ui");
11765
+ const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui");
11431
11766
  const cliRoot = findCliRoot();
11432
- const srcDir = path35.join(cliRoot, "templates", "ui");
11433
- if (!fs32.existsSync(srcDir)) {
11767
+ const srcDir = path37.join(cliRoot, "templates", "ui");
11768
+ if (!fs34.existsSync(srcDir)) {
11434
11769
  return created;
11435
11770
  }
11436
- const files = fs32.readdirSync(srcDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
11771
+ const files = fs34.readdirSync(srcDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
11437
11772
  for (const file of files) {
11438
- const destPath = path35.join(destDir, file);
11439
- if (!fs32.existsSync(destPath)) {
11440
- fs32.copyFileSync(path35.join(srcDir, file), destPath);
11441
- created.push(path35.join(config.paths.cms, "components", "ui", file));
11773
+ const destPath = path37.join(destDir, file);
11774
+ if (!fs34.existsSync(destPath)) {
11775
+ fs34.copyFileSync(path37.join(srcDir, file), destPath);
11776
+ created.push(path37.join(config.paths.cms, "components", "ui", file));
11442
11777
  }
11443
11778
  }
11444
11779
  return created;
@@ -11446,25 +11781,25 @@ function copyUiTemplates(cwd, config) {
11446
11781
  function copyTiptapTemplates(cwd, config) {
11447
11782
  const created = [];
11448
11783
  const cliRoot = findCliRoot();
11449
- const srcDir = path35.join(cliRoot, "templates", "tiptap");
11450
- const destDir = path35.resolve(cwd, config.paths.cms, "components", "ui", "tiptap");
11451
- if (!fs32.existsSync(srcDir)) {
11784
+ const srcDir = path37.join(cliRoot, "templates", "tiptap");
11785
+ const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui", "tiptap");
11786
+ if (!fs34.existsSync(srcDir)) {
11452
11787
  return created;
11453
11788
  }
11454
11789
  copyDirRecursive(srcDir, destDir, config.paths.cms, created);
11455
11790
  return created;
11456
11791
  }
11457
11792
  function copyDirRecursive(src, dest, cmsPrefix, created) {
11458
- fs32.ensureDirSync(dest);
11459
- const entries = fs32.readdirSync(src, { withFileTypes: true });
11793
+ fs34.ensureDirSync(dest);
11794
+ const entries = fs34.readdirSync(src, { withFileTypes: true });
11460
11795
  for (const entry of entries) {
11461
- const srcPath = path35.join(src, entry.name);
11462
- const destPath = path35.join(dest, entry.name);
11796
+ const srcPath = path37.join(src, entry.name);
11797
+ const destPath = path37.join(dest, entry.name);
11463
11798
  if (entry.isDirectory()) {
11464
11799
  copyDirRecursive(srcPath, destPath, cmsPrefix, created);
11465
- } else if (!fs32.existsSync(destPath)) {
11466
- fs32.copyFileSync(srcPath, destPath);
11467
- const relFromCms = path35.relative(path35.resolve(dest, "..", "..", "..", ".."), destPath);
11800
+ } else if (!fs34.existsSync(destPath)) {
11801
+ fs34.copyFileSync(srcPath, destPath);
11802
+ const relFromCms = path37.relative(path37.resolve(dest, "..", "..", "..", ".."), destPath);
11468
11803
  created.push(relFromCms);
11469
11804
  }
11470
11805
  }
@@ -11472,35 +11807,35 @@ function copyDirRecursive(src, dest, cmsPrefix, created) {
11472
11807
  function copySchemaMetaschema(cwd, config) {
11473
11808
  const created = [];
11474
11809
  const cliRoot = findCliRoot();
11475
- const srcPath = path35.join(cliRoot, "templates", "schema.json");
11476
- const destPath = path35.resolve(cwd, config.paths.schemas, "schema.json");
11477
- if (fs32.existsSync(srcPath) && !fs32.existsSync(destPath)) {
11478
- fs32.ensureDirSync(path35.dirname(destPath));
11479
- fs32.copyFileSync(srcPath, destPath);
11480
- created.push(path35.join(config.paths.schemas, "schema.json"));
11810
+ const srcPath = path37.join(cliRoot, "templates", "schema.json");
11811
+ const destPath = path37.resolve(cwd, config.paths.schemas, "schema.json");
11812
+ if (fs34.existsSync(srcPath) && !fs34.existsSync(destPath)) {
11813
+ fs34.ensureDirSync(path37.dirname(destPath));
11814
+ fs34.copyFileSync(srcPath, destPath);
11815
+ created.push(path37.join(config.paths.schemas, "schema.json"));
11481
11816
  }
11482
11817
  return created;
11483
11818
  }
11484
11819
  function findCliRoot() {
11485
11820
  let dir = new URL(".", import.meta.url).pathname;
11486
11821
  for (let i = 0; i < 5; i++) {
11487
- const pkgPath = path35.join(dir, "package.json");
11488
- if (fs32.existsSync(pkgPath)) {
11822
+ const pkgPath = path37.join(dir, "package.json");
11823
+ if (fs34.existsSync(pkgPath)) {
11489
11824
  try {
11490
- const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
11825
+ const pkg = JSON.parse(fs34.readFileSync(pkgPath, "utf-8"));
11491
11826
  if (pkg.name === "@betterstart/cli") {
11492
11827
  return dir;
11493
11828
  }
11494
11829
  } catch {
11495
11830
  }
11496
11831
  }
11497
- dir = path35.dirname(dir);
11832
+ dir = path37.dirname(dir);
11498
11833
  }
11499
- return path35.resolve(new URL(".", import.meta.url).pathname, "..", "..");
11834
+ return path37.resolve(new URL(".", import.meta.url).pathname, "..", "..");
11500
11835
  }
11501
11836
 
11502
11837
  // src/init/scaffolders/database.ts
11503
- import path36 from "path";
11838
+ import path38 from "path";
11504
11839
 
11505
11840
  // src/init/templates/db/client.ts
11506
11841
  function dbClientTemplate() {
@@ -11611,16 +11946,16 @@ export const formSettings = pgTable(
11611
11946
  // src/init/scaffolders/database.ts
11612
11947
  function scaffoldDatabase({ cwd, config }) {
11613
11948
  const created = [];
11614
- const dbDir = path36.resolve(cwd, config.paths.cms, "db");
11949
+ const dbDir = path38.resolve(cwd, config.paths.cms, "db");
11615
11950
  function write(filename, content) {
11616
- const fullPath = path36.join(dbDir, filename);
11951
+ const fullPath = path38.join(dbDir, filename);
11617
11952
  if (safeWriteFile(fullPath, content)) {
11618
- created.push(path36.join(config.paths.cms, "db", filename));
11953
+ created.push(path38.join(config.paths.cms, "db", filename));
11619
11954
  }
11620
11955
  }
11621
11956
  write("client.ts", dbClientTemplate());
11622
11957
  write("schema.ts", dbSchemaTemplate());
11623
- const drizzleConfigPath = path36.resolve(cwd, "drizzle.config.ts");
11958
+ const drizzleConfigPath = path38.resolve(cwd, "drizzle.config.ts");
11624
11959
  if (safeWriteFile(drizzleConfigPath, drizzleConfigTemplate())) {
11625
11960
  created.push("drizzle.config.ts");
11626
11961
  }
@@ -11792,11 +12127,11 @@ import { existsSync, readFileSync } from "fs";
11792
12127
  import { join } from "path";
11793
12128
 
11794
12129
  // src/utils/env.ts
11795
- import fs33 from "fs";
11796
- import path37 from "path";
12130
+ import fs35 from "fs";
12131
+ import path39 from "path";
11797
12132
  function appendEnvVars(cwd, sections, overwrite) {
11798
- const envPath = path37.join(cwd, ".env.local");
11799
- let existing = fs33.existsSync(envPath) ? fs33.readFileSync(envPath, "utf-8") : "";
12133
+ const envPath = path39.join(cwd, ".env.local");
12134
+ let existing = fs35.existsSync(envPath) ? fs35.readFileSync(envPath, "utf-8") : "";
11800
12135
  const existingKeys = new Set(
11801
12136
  existing.split("\n").filter((line) => line.trim() && !line.trim().startsWith("#")).map((line) => line.split("=")[0]?.trim()).filter(Boolean)
11802
12137
  );
@@ -11840,7 +12175,7 @@ function appendEnvVars(cwd, sections, overwrite) {
11840
12175
  const header = existing.trim() ? "" : "# ============================================\n# BetterStart CMS\n# ============================================\n";
11841
12176
  const content = existing.trim() ? `${existing.trimEnd()}
11842
12177
  ${lines.join("\n")}` : header + lines.join("\n");
11843
- fs33.writeFileSync(envPath, content);
12178
+ fs35.writeFileSync(envPath, content);
11844
12179
  }
11845
12180
  return { added, skipped, updated };
11846
12181
  }
@@ -11919,7 +12254,7 @@ function scaffoldEnv(cwd, options) {
11919
12254
  }
11920
12255
 
11921
12256
  // src/init/scaffolders/layout.ts
11922
- import path38 from "path";
12257
+ import path40 from "path";
11923
12258
 
11924
12259
  // src/init/templates/pages/authenticated-layout.ts
11925
12260
  function authenticatedLayoutTemplate() {
@@ -12806,30 +13141,30 @@ export function UsersTable<TValue>({ columns }: UsersTableProps<TValue>) {
12806
13141
  function scaffoldLayout({ cwd, config }) {
12807
13142
  const created = [];
12808
13143
  function write(relPath, content) {
12809
- const fullPath = path38.resolve(cwd, relPath);
12810
- ensureDir(path38.dirname(fullPath));
13144
+ const fullPath = path40.resolve(cwd, relPath);
13145
+ ensureDir(path40.dirname(fullPath));
12811
13146
  if (safeWriteFile(fullPath, content)) {
12812
13147
  created.push(relPath);
12813
13148
  }
12814
13149
  }
12815
- const cmsDir = path38.dirname(config.paths.pages);
12816
- write(path38.join(cmsDir, "layout.tsx"), cmsLayoutTemplate());
12817
- write(path38.join(config.paths.pages, "layout.tsx"), authenticatedLayoutTemplate());
12818
- write(path38.join(config.paths.login, "page.tsx"), loginPageTemplate());
12819
- write(path38.join(config.paths.login, "login-form.tsx"), loginFormTemplate());
12820
- write(path38.join(config.paths.pages, "page.tsx"), dashboardPageTemplate());
12821
- const usersDir = path38.join(config.paths.pages, "users");
12822
- write(path38.join(usersDir, "page.tsx"), usersPageTemplate());
12823
- write(path38.join(usersDir, "users-table.tsx"), usersTableTemplate());
12824
- write(path38.join(usersDir, "columns.tsx"), usersColumnsTemplate());
12825
- write(path38.join(usersDir, "create-user-dialog.tsx"), createUserDialogTemplate());
12826
- write(path38.join(usersDir, "edit-role-dialog.tsx"), editRoleDialogTemplate());
13150
+ const cmsDir = path40.dirname(config.paths.pages);
13151
+ write(path40.join(cmsDir, "layout.tsx"), cmsLayoutTemplate());
13152
+ write(path40.join(config.paths.pages, "layout.tsx"), authenticatedLayoutTemplate());
13153
+ write(path40.join(config.paths.login, "page.tsx"), loginPageTemplate());
13154
+ write(path40.join(config.paths.login, "login-form.tsx"), loginFormTemplate());
13155
+ write(path40.join(config.paths.pages, "page.tsx"), dashboardPageTemplate());
13156
+ const usersDir = path40.join(config.paths.pages, "users");
13157
+ write(path40.join(usersDir, "page.tsx"), usersPageTemplate());
13158
+ write(path40.join(usersDir, "users-table.tsx"), usersTableTemplate());
13159
+ write(path40.join(usersDir, "columns.tsx"), usersColumnsTemplate());
13160
+ write(path40.join(usersDir, "create-user-dialog.tsx"), createUserDialogTemplate());
13161
+ write(path40.join(usersDir, "edit-role-dialog.tsx"), editRoleDialogTemplate());
12827
13162
  return created;
12828
13163
  }
12829
13164
 
12830
13165
  // src/init/scaffolders/preset.ts
12831
- import fs34 from "fs";
12832
- import path39 from "path";
13166
+ import fs36 from "fs";
13167
+ import path41 from "path";
12833
13168
 
12834
13169
  // src/init/templates/presets/blog-categories.ts
12835
13170
  function blogCategoriesSchema() {
@@ -13234,15 +13569,15 @@ function scaffoldPreset({
13234
13569
  generatedFiles: [],
13235
13570
  errors: []
13236
13571
  };
13237
- const schemasDir = path39.join(cwd, config.paths?.schemas ?? "./cms/schemas");
13572
+ const schemasDir = path41.join(cwd, config.paths?.schemas ?? "./cms/schemas");
13238
13573
  const presetSchemas = getPresetSchemas(preset);
13239
13574
  for (const ps of presetSchemas) {
13240
- const filePath = path39.join(schemasDir, ps.filename);
13241
- const dir = path39.dirname(filePath);
13242
- if (!fs34.existsSync(dir)) {
13243
- fs34.mkdirSync(dir, { recursive: true });
13575
+ const filePath = path41.join(schemasDir, ps.filename);
13576
+ const dir = path41.dirname(filePath);
13577
+ if (!fs36.existsSync(dir)) {
13578
+ fs36.mkdirSync(dir, { recursive: true });
13244
13579
  }
13245
- fs34.writeFileSync(filePath, ps.content, "utf-8");
13580
+ fs36.writeFileSync(filePath, ps.content, "utf-8");
13246
13581
  result.schemas.push(ps.filename);
13247
13582
  }
13248
13583
  for (const ps of presetSchemas) {
@@ -13283,8 +13618,8 @@ function scaffoldPreset({
13283
13618
  }
13284
13619
 
13285
13620
  // src/init/scaffolders/tailwind.ts
13286
- import fs35 from "fs";
13287
- import path40 from "path";
13621
+ import fs37 from "fs";
13622
+ import path42 from "path";
13288
13623
  var SOURCE_LINES = ['@source "../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
13289
13624
  var SOURCE_LINES_SRC = ['@source "../../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
13290
13625
  var CMS_THEME_BLOCK = `
@@ -13339,8 +13674,8 @@ function findMainCss(cwd) {
13339
13674
  "globals.css"
13340
13675
  ];
13341
13676
  for (const candidate of candidates) {
13342
- const filePath = path40.join(cwd, candidate);
13343
- if (fs35.existsSync(filePath)) {
13677
+ const filePath = path42.join(cwd, candidate);
13678
+ if (fs37.existsSync(filePath)) {
13344
13679
  return filePath;
13345
13680
  }
13346
13681
  }
@@ -13351,7 +13686,7 @@ function scaffoldTailwind(cwd, hasSrcDir) {
13351
13686
  if (!cssFile) {
13352
13687
  return { file: null, appended: false };
13353
13688
  }
13354
- let content = fs35.readFileSync(cssFile, "utf-8");
13689
+ let content = fs37.readFileSync(cssFile, "utf-8");
13355
13690
  let changed = false;
13356
13691
  const sourceLines = hasSrcDir ? SOURCE_LINES_SRC : SOURCE_LINES;
13357
13692
  const missingLines = sourceLines.filter((sl) => !content.includes(sl));
@@ -13403,14 +13738,14 @@ ${CMS_THEME_BLOCK}
13403
13738
  }
13404
13739
  }
13405
13740
  if (changed) {
13406
- fs35.writeFileSync(cssFile, content, "utf-8");
13741
+ fs37.writeFileSync(cssFile, content, "utf-8");
13407
13742
  }
13408
13743
  return { file: cssFile, appended: changed };
13409
13744
  }
13410
13745
 
13411
13746
  // src/init/scaffolders/tsconfig.ts
13412
- import fs36 from "fs";
13413
- import path41 from "path";
13747
+ import fs38 from "fs";
13748
+ import path43 from "path";
13414
13749
  function stripJsonComments(input) {
13415
13750
  let result = "";
13416
13751
  let i = 0;
@@ -13460,14 +13795,14 @@ var CMS_PATH_ALIASES = {
13460
13795
  "@cms/cache/*": ["./cms/lib/cache/*"]
13461
13796
  };
13462
13797
  function scaffoldTsconfig(cwd) {
13463
- const tsconfigPath = path41.join(cwd, "tsconfig.json");
13798
+ const tsconfigPath = path43.join(cwd, "tsconfig.json");
13464
13799
  const added = [];
13465
13800
  const skipped = [];
13466
- if (!fs36.existsSync(tsconfigPath)) {
13801
+ if (!fs38.existsSync(tsconfigPath)) {
13467
13802
  skipped.push("tsconfig.json not found");
13468
13803
  return { added, skipped };
13469
13804
  }
13470
- const raw = fs36.readFileSync(tsconfigPath, "utf-8");
13805
+ const raw = fs38.readFileSync(tsconfigPath, "utf-8");
13471
13806
  const stripped = stripJsonComments(raw).replace(/,\s*([\]}])/g, "$1");
13472
13807
  let tsconfig;
13473
13808
  try {
@@ -13488,14 +13823,14 @@ function scaffoldTsconfig(cwd) {
13488
13823
  }
13489
13824
  compilerOptions.paths = paths;
13490
13825
  tsconfig.compilerOptions = compilerOptions;
13491
- fs36.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
13826
+ fs38.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
13492
13827
  `, "utf-8");
13493
13828
  return { added, skipped };
13494
13829
  }
13495
13830
 
13496
13831
  // src/commands/seed.ts
13497
- import fs37 from "fs";
13498
- import path42 from "path";
13832
+ import fs39 from "fs";
13833
+ import path44 from "path";
13499
13834
  import * as clack from "@clack/prompts";
13500
13835
  import { Command as Command2 } from "commander";
13501
13836
  function buildSeedScript() {
@@ -13614,7 +13949,7 @@ main().catch((err) => {
13614
13949
  `;
13615
13950
  }
13616
13951
  var seedCommand = new Command2("seed").description("Create the initial admin user").option("--cwd <path>", "Project root path").action(async (options) => {
13617
- const cwd = options.cwd ? path42.resolve(options.cwd) : process.cwd();
13952
+ const cwd = options.cwd ? path44.resolve(options.cwd) : process.cwd();
13618
13953
  clack.intro("BetterStart Seed");
13619
13954
  let config;
13620
13955
  try {
@@ -13654,14 +13989,14 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13654
13989
  clack.cancel("Cancelled.");
13655
13990
  process.exit(0);
13656
13991
  }
13657
- const scriptsDir = path42.join(cwd, cmsDir, "scripts");
13658
- const seedPath = path42.join(scriptsDir, "seed.ts");
13659
- if (!fs37.existsSync(scriptsDir)) {
13660
- fs37.mkdirSync(scriptsDir, { recursive: true });
13992
+ const scriptsDir = path44.join(cwd, cmsDir, "scripts");
13993
+ const seedPath = path44.join(scriptsDir, "seed.ts");
13994
+ if (!fs39.existsSync(scriptsDir)) {
13995
+ fs39.mkdirSync(scriptsDir, { recursive: true });
13661
13996
  }
13662
- fs37.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13997
+ fs39.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13663
13998
  const { execFile } = await import("child_process");
13664
- const tsxBin = path42.join(cwd, "node_modules", ".bin", "tsx");
13999
+ const tsxBin = path44.join(cwd, "node_modules", ".bin", "tsx");
13665
14000
  const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
13666
14001
  execFile(
13667
14002
  tsxBin,
@@ -13700,7 +14035,7 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13700
14035
  if (clack.isCancel(overwrite) || !overwrite) {
13701
14036
  clack.cancel("Seed cancelled.");
13702
14037
  try {
13703
- fs37.unlinkSync(seedPath);
14038
+ fs39.unlinkSync(seedPath);
13704
14039
  } catch {
13705
14040
  }
13706
14041
  process.exit(0);
@@ -13717,15 +14052,15 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13717
14052
  clack.log.error(errMsg);
13718
14053
  clack.log.info("You can run the seed script manually:");
13719
14054
  clack.log.info(
13720
- ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path42.relative(cwd, seedPath)}`
14055
+ ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path44.relative(cwd, seedPath)}`
13721
14056
  );
13722
14057
  clack.outro("");
13723
14058
  process.exit(1);
13724
14059
  }
13725
14060
  try {
13726
- fs37.unlinkSync(seedPath);
13727
- if (fs37.existsSync(scriptsDir) && fs37.readdirSync(scriptsDir).length === 0) {
13728
- fs37.rmdirSync(scriptsDir);
14061
+ fs39.unlinkSync(seedPath);
14062
+ if (fs39.existsSync(scriptsDir) && fs39.readdirSync(scriptsDir).length === 0) {
14063
+ fs39.rmdirSync(scriptsDir);
13729
14064
  }
13730
14065
  } catch {
13731
14066
  }
@@ -13756,16 +14091,16 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13756
14091
  const nukeFiles = ["cms.config.ts", "CMS.md", "drizzle.config.ts"];
13757
14092
  let nuked = 0;
13758
14093
  for (const dir of nukeDirs) {
13759
- const fullPath = path43.resolve(cwd, dir);
13760
- if (fs38.existsSync(fullPath)) {
13761
- fs38.rmSync(fullPath, { recursive: true, force: true });
14094
+ const fullPath = path45.resolve(cwd, dir);
14095
+ if (fs40.existsSync(fullPath)) {
14096
+ fs40.rmSync(fullPath, { recursive: true, force: true });
13762
14097
  nuked++;
13763
14098
  }
13764
14099
  }
13765
14100
  for (const file of nukeFiles) {
13766
- const fullPath = path43.resolve(cwd, file);
13767
- if (fs38.existsSync(fullPath)) {
13768
- fs38.unlinkSync(fullPath);
14101
+ const fullPath = path45.resolve(cwd, file);
14102
+ if (fs40.existsSync(fullPath)) {
14103
+ fs40.unlinkSync(fullPath);
13769
14104
  nuked++;
13770
14105
  }
13771
14106
  }
@@ -13812,7 +14147,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13812
14147
  }
13813
14148
  pm = pmChoice;
13814
14149
  }
13815
- const displayName = projectPrompt.projectName === "." ? path43.basename(cwd) : projectPrompt.projectName;
14150
+ const displayName = projectPrompt.projectName === "." ? path45.basename(cwd) : projectPrompt.projectName;
13816
14151
  const { bin, prefix } = createNextAppCommand(pm);
13817
14152
  const cnaArgs = [
13818
14153
  ...prefix,
@@ -13844,10 +14179,10 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13844
14179
  );
13845
14180
  process.exit(1);
13846
14181
  }
13847
- cwd = path43.resolve(cwd, projectPrompt.projectName);
13848
- const hasPackageJson = fs38.existsSync(path43.join(cwd, "package.json"));
14182
+ cwd = path45.resolve(cwd, projectPrompt.projectName);
14183
+ const hasPackageJson = fs40.existsSync(path45.join(cwd, "package.json"));
13849
14184
  const hasNextConfig = ["next.config.ts", "next.config.js", "next.config.mjs"].some(
13850
- (f) => fs38.existsSync(path43.join(cwd, f))
14185
+ (f) => fs40.existsSync(path45.join(cwd, f))
13851
14186
  );
13852
14187
  if (!hasPackageJson || !hasNextConfig) {
13853
14188
  p4.log.error(
@@ -13948,11 +14283,11 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13948
14283
  s.stop("");
13949
14284
  process.stdout.write("\x1B[2A\x1B[J");
13950
14285
  p4.note(noteLines.join("\n"), "Scaffolded CMS");
13951
- const drizzleConfigPath = path43.join(cwd, "drizzle.config.ts");
13952
- if (!dbFiles.includes("drizzle.config.ts") && fs38.existsSync(drizzleConfigPath)) {
14286
+ const drizzleConfigPath = path45.join(cwd, "drizzle.config.ts");
14287
+ if (!dbFiles.includes("drizzle.config.ts") && fs40.existsSync(drizzleConfigPath)) {
13953
14288
  if (options.force) {
13954
14289
  const { drizzleConfigTemplate: drizzleConfigTemplate2 } = await import("./drizzle-config-EDKOEZ6G.js");
13955
- fs38.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
14290
+ fs40.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
13956
14291
  p4.log.success("Updated drizzle.config.ts");
13957
14292
  } else if (!options.yes) {
13958
14293
  const overwrite = await p4.confirm({
@@ -13961,7 +14296,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13961
14296
  });
13962
14297
  if (!p4.isCancel(overwrite) && overwrite) {
13963
14298
  const { drizzleConfigTemplate: drizzleConfigTemplate2 } = await import("./drizzle-config-EDKOEZ6G.js");
13964
- fs38.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
14299
+ fs40.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
13965
14300
  p4.log.success("Updated drizzle.config.ts");
13966
14301
  }
13967
14302
  }
@@ -13994,15 +14329,15 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13994
14329
  {
13995
14330
  const entityNames = [];
13996
14331
  const formNames = [];
13997
- const schemasDir = path43.join(cwd, config.paths.schemas);
13998
- const formsDir = path43.join(schemasDir, "forms");
13999
- if (fs38.existsSync(schemasDir)) {
14000
- for (const f of fs38.readdirSync(schemasDir)) {
14332
+ const schemasDir = path45.join(cwd, config.paths.schemas);
14333
+ const formsDir = path45.join(schemasDir, "forms");
14334
+ if (fs40.existsSync(schemasDir)) {
14335
+ for (const f of fs40.readdirSync(schemasDir)) {
14001
14336
  if (f.endsWith(".json")) entityNames.push(f.replace(".json", ""));
14002
14337
  }
14003
14338
  }
14004
- if (fs38.existsSync(formsDir)) {
14005
- for (const f of fs38.readdirSync(formsDir)) {
14339
+ if (fs40.existsSync(formsDir)) {
14340
+ for (const f of fs40.readdirSync(formsDir)) {
14006
14341
  if (f.endsWith(".json")) formNames.push(f.replace(".json", ""));
14007
14342
  }
14008
14343
  }
@@ -14181,9 +14516,9 @@ function isValidDbUrl(url) {
14181
14516
  return url.startsWith("postgres://") || url.startsWith("postgresql://");
14182
14517
  }
14183
14518
  function readExistingDbUrl(cwd) {
14184
- const envPath = path43.join(cwd, ".env.local");
14185
- if (!fs38.existsSync(envPath)) return void 0;
14186
- const content = fs38.readFileSync(envPath, "utf-8");
14519
+ const envPath = path45.join(cwd, ".env.local");
14520
+ if (!fs40.existsSync(envPath)) return void 0;
14521
+ const content = fs40.readFileSync(envPath, "utf-8");
14187
14522
  for (const line of content.split("\n")) {
14188
14523
  const trimmed = line.trim();
14189
14524
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -14206,9 +14541,9 @@ function maskDbUrl(url) {
14206
14541
  }
14207
14542
  }
14208
14543
  function hasDbUrl(cwd) {
14209
- const envPath = path43.join(cwd, ".env.local");
14210
- if (!fs38.existsSync(envPath)) return false;
14211
- const content = fs38.readFileSync(envPath, "utf-8");
14544
+ const envPath = path45.join(cwd, ".env.local");
14545
+ if (!fs40.existsSync(envPath)) return false;
14546
+ const content = fs40.readFileSync(envPath, "utf-8");
14212
14547
  for (const line of content.split("\n")) {
14213
14548
  const trimmed = line.trim();
14214
14549
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -14222,23 +14557,23 @@ function hasDbUrl(cwd) {
14222
14557
  return false;
14223
14558
  }
14224
14559
  function runSeed(cwd, cmsDir, email, password4, overwrite = false) {
14225
- const scriptsDir = path43.join(cwd, cmsDir, "scripts");
14226
- const seedPath = path43.join(scriptsDir, "seed.ts");
14227
- if (!fs38.existsSync(scriptsDir)) {
14228
- fs38.mkdirSync(scriptsDir, { recursive: true });
14560
+ const scriptsDir = path45.join(cwd, cmsDir, "scripts");
14561
+ const seedPath = path45.join(scriptsDir, "seed.ts");
14562
+ if (!fs40.existsSync(scriptsDir)) {
14563
+ fs40.mkdirSync(scriptsDir, { recursive: true });
14229
14564
  }
14230
- fs38.writeFileSync(seedPath, buildSeedScript(), "utf-8");
14565
+ fs40.writeFileSync(seedPath, buildSeedScript(), "utf-8");
14231
14566
  const cleanup = () => {
14232
14567
  try {
14233
- fs38.unlinkSync(seedPath);
14234
- if (fs38.existsSync(scriptsDir) && fs38.readdirSync(scriptsDir).length === 0) {
14235
- fs38.rmdirSync(scriptsDir);
14568
+ fs40.unlinkSync(seedPath);
14569
+ if (fs40.existsSync(scriptsDir) && fs40.readdirSync(scriptsDir).length === 0) {
14570
+ fs40.rmdirSync(scriptsDir);
14236
14571
  }
14237
14572
  } catch {
14238
14573
  }
14239
14574
  };
14240
14575
  return new Promise((resolve) => {
14241
- const tsxBin = path43.join(cwd, "node_modules", ".bin", "tsx");
14576
+ const tsxBin = path45.join(cwd, "node_modules", ".bin", "tsx");
14242
14577
  const child = spawn2(tsxBin, [seedPath], {
14243
14578
  cwd,
14244
14579
  stdio: "pipe",
@@ -14303,7 +14638,7 @@ ${stderr}`;
14303
14638
  }
14304
14639
  function runDrizzlePush(cwd) {
14305
14640
  return new Promise((resolve) => {
14306
- const drizzleBin = path43.join(cwd, "node_modules", ".bin", "drizzle-kit");
14641
+ const drizzleBin = path45.join(cwd, "node_modules", ".bin", "drizzle-kit");
14307
14642
  const child = spawn2(drizzleBin, ["push", "--force"], {
14308
14643
  cwd,
14309
14644
  stdio: "pipe",
@@ -14324,8 +14659,8 @@ function runDrizzlePush(cwd) {
14324
14659
  }
14325
14660
 
14326
14661
  // src/commands/remove.ts
14327
- import fs39 from "fs";
14328
- import path44 from "path";
14662
+ import fs41 from "fs";
14663
+ import path46 from "path";
14329
14664
  import readline from "readline";
14330
14665
  import { Command as Command4 } from "commander";
14331
14666
  function findTableEnd3(content, startIndex) {
@@ -14356,8 +14691,8 @@ function findTableEnd3(content, startIndex) {
14356
14691
  return content.length;
14357
14692
  }
14358
14693
  function removeTableFromSchema(schemaFilePath, name) {
14359
- if (!fs39.existsSync(schemaFilePath)) return false;
14360
- let content = fs39.readFileSync(schemaFilePath, "utf-8");
14694
+ if (!fs41.existsSync(schemaFilePath)) return false;
14695
+ let content = fs41.readFileSync(schemaFilePath, "utf-8");
14361
14696
  const variableName = toCamelCase(name);
14362
14697
  let changed = false;
14363
14698
  if (content.includes(`export const ${variableName} =`)) {
@@ -14385,13 +14720,13 @@ function removeTableFromSchema(schemaFilePath, name) {
14385
14720
  }
14386
14721
  if (changed) {
14387
14722
  content = content.replace(/\n{3,}/g, "\n\n");
14388
- fs39.writeFileSync(schemaFilePath, content, "utf-8");
14723
+ fs41.writeFileSync(schemaFilePath, content, "utf-8");
14389
14724
  }
14390
14725
  return changed;
14391
14726
  }
14392
14727
  function removeFromNavigation(navFilePath, name) {
14393
- if (!fs39.existsSync(navFilePath)) return false;
14394
- const content = fs39.readFileSync(navFilePath, "utf-8");
14728
+ if (!fs41.existsSync(navFilePath)) return false;
14729
+ const content = fs41.readFileSync(navFilePath, "utf-8");
14395
14730
  const href = `/cms/${name}`;
14396
14731
  if (!content.includes(`'${href}'`)) return false;
14397
14732
  const lines = content.split("\n");
@@ -14422,7 +14757,7 @@ function removeFromNavigation(navFilePath, name) {
14422
14757
  if (startLine === -1 || endLine === -1) return false;
14423
14758
  lines.splice(startLine, endLine - startLine + 1);
14424
14759
  const updated = lines.join("\n").replace(/,\s*,/g, ",").replace(/\[\s*,/, "[");
14425
- fs39.writeFileSync(navFilePath, updated, "utf-8");
14760
+ fs41.writeFileSync(navFilePath, updated, "utf-8");
14426
14761
  return true;
14427
14762
  }
14428
14763
  async function promptConfirm(message) {
@@ -14438,7 +14773,7 @@ async function promptConfirm(message) {
14438
14773
  });
14439
14774
  }
14440
14775
  var removeCommand = new Command4("remove").alias("rm").description("Remove all generated files for an entity or form").argument("<schema>", "Schema name to remove (e.g. posts, categories, contact)").option("-f, --force", "Skip confirmation prompt", false).option("--cwd <path>", "Project root path").action(async (schemaName, options) => {
14441
- const cwd = options.cwd ? path44.resolve(options.cwd) : process.cwd();
14776
+ const cwd = options.cwd ? path46.resolve(options.cwd) : process.cwd();
14442
14777
  console.log("\n BetterStart Remove\n");
14443
14778
  let config;
14444
14779
  try {
@@ -14451,34 +14786,34 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14451
14786
  const pagesDir = config.paths?.pages ?? "./src/app/(cms)/cms/(authenticated)";
14452
14787
  const kebabName = toKebabCase(schemaName);
14453
14788
  const targets = [];
14454
- const entityPagesDir = path44.join(cwd, pagesDir, schemaName);
14455
- if (fs39.existsSync(entityPagesDir)) {
14789
+ const entityPagesDir = path46.join(cwd, pagesDir, schemaName);
14790
+ if (fs41.existsSync(entityPagesDir)) {
14456
14791
  targets.push({
14457
14792
  path: entityPagesDir,
14458
- label: `${path44.join(pagesDir, schemaName)}/`,
14793
+ label: `${path46.join(pagesDir, schemaName)}/`,
14459
14794
  isDir: true
14460
14795
  });
14461
14796
  }
14462
- const actionsFile = path44.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
14463
- if (fs39.existsSync(actionsFile)) {
14797
+ const actionsFile = path46.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
14798
+ if (fs41.existsSync(actionsFile)) {
14464
14799
  targets.push({
14465
14800
  path: actionsFile,
14466
- label: path44.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
14801
+ label: path46.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
14467
14802
  isDir: false
14468
14803
  });
14469
14804
  }
14470
- const hookFile = path44.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
14471
- if (fs39.existsSync(hookFile)) {
14805
+ const hookFile = path46.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
14806
+ if (fs41.existsSync(hookFile)) {
14472
14807
  targets.push({
14473
14808
  path: hookFile,
14474
- label: path44.join(cmsDir, "hooks", `use-${kebabName}.ts`),
14809
+ label: path46.join(cmsDir, "hooks", `use-${kebabName}.ts`),
14475
14810
  isDir: false
14476
14811
  });
14477
14812
  }
14478
- const schemaFilePath = path44.join(cwd, cmsDir, "db", "schema.ts");
14479
- const hasTable = fs39.existsSync(schemaFilePath) && fs39.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
14480
- const navFilePath = path44.join(cwd, cmsDir, "data", "navigation.ts");
14481
- const hasNavEntry = fs39.existsSync(navFilePath) && fs39.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
14813
+ const schemaFilePath = path46.join(cwd, cmsDir, "db", "schema.ts");
14814
+ const hasTable = fs41.existsSync(schemaFilePath) && fs41.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
14815
+ const navFilePath = path46.join(cwd, cmsDir, "data", "navigation.ts");
14816
+ const hasNavEntry = fs41.existsSync(navFilePath) && fs41.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
14482
14817
  if (targets.length === 0 && !hasTable && !hasNavEntry) {
14483
14818
  console.log(` No generated files found for: ${schemaName}`);
14484
14819
  return;
@@ -14488,10 +14823,10 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14488
14823
  console.log(` ${t.isDir ? "[dir]" : " "} ${t.label}`);
14489
14824
  }
14490
14825
  if (hasTable) {
14491
- console.log(` [edit] ${path44.join(cmsDir, "db", "schema.ts")} (remove table)`);
14826
+ console.log(` [edit] ${path46.join(cmsDir, "db", "schema.ts")} (remove table)`);
14492
14827
  }
14493
14828
  if (hasNavEntry) {
14494
- console.log(` [edit] ${path44.join(cmsDir, "data", "navigation.ts")} (remove entry)`);
14829
+ console.log(` [edit] ${path46.join(cmsDir, "data", "navigation.ts")} (remove entry)`);
14495
14830
  }
14496
14831
  if (!options.force) {
14497
14832
  console.log("");
@@ -14504,19 +14839,19 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14504
14839
  console.log("");
14505
14840
  for (const t of targets) {
14506
14841
  if (t.isDir) {
14507
- fs39.rmSync(t.path, { recursive: true, force: true });
14842
+ fs41.rmSync(t.path, { recursive: true, force: true });
14508
14843
  } else {
14509
- fs39.unlinkSync(t.path);
14844
+ fs41.unlinkSync(t.path);
14510
14845
  }
14511
14846
  console.log(` Removed: ${t.label}`);
14512
14847
  }
14513
14848
  if (hasTable) {
14514
14849
  removeTableFromSchema(schemaFilePath, schemaName);
14515
- console.log(` Cleaned: ${path44.join(cmsDir, "db", "schema.ts")}`);
14850
+ console.log(` Cleaned: ${path46.join(cmsDir, "db", "schema.ts")}`);
14516
14851
  }
14517
14852
  if (hasNavEntry) {
14518
14853
  removeFromNavigation(navFilePath, schemaName);
14519
- console.log(` Cleaned: ${path44.join(cmsDir, "data", "navigation.ts")}`);
14854
+ console.log(` Cleaned: ${path46.join(cmsDir, "data", "navigation.ts")}`);
14520
14855
  }
14521
14856
  console.log("\n Removal complete!");
14522
14857
  console.log("\n Note: You may need to manually:");
@@ -14528,14 +14863,14 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14528
14863
 
14529
14864
  // src/commands/setup-r2.ts
14530
14865
  import { execFileSync as execFileSync5, spawnSync } from "child_process";
14531
- import fs40 from "fs";
14866
+ import fs42 from "fs";
14532
14867
  import os from "os";
14533
- import path45 from "path";
14868
+ import path47 from "path";
14534
14869
  import * as p5 from "@clack/prompts";
14535
14870
  import { Command as Command5 } from "commander";
14536
14871
  import pc3 from "picocolors";
14537
14872
  var setupR2Command = new Command5("setup-r2").description("Create a Cloudflare R2 bucket and configure storage env vars").option("--cwd <path>", "Project root path").option("--bucket <name>", "Bucket name (skips prompt)").action(async (options) => {
14538
- const cwd = options.cwd ? path45.resolve(options.cwd) : process.cwd();
14873
+ const cwd = options.cwd ? path47.resolve(options.cwd) : process.cwd();
14539
14874
  p5.intro(pc3.bgCyan(pc3.black(" BetterStart \u2014 R2 Storage Setup ")));
14540
14875
  const s = p5.spinner();
14541
14876
  s.start("Looking for wrangler CLI");
@@ -14727,8 +15062,8 @@ var setupR2Command = new Command5("setup-r2").description("Create a Cloudflare R
14727
15062
  p5.outro("Done! Your CMS can now upload files to R2.");
14728
15063
  });
14729
15064
  function findWrangler(cwd) {
14730
- const localBin = path45.join(cwd, "node_modules", ".bin", "wrangler");
14731
- if (fs40.existsSync(localBin)) return { bin: localBin, prefix: [] };
15065
+ const localBin = path47.join(cwd, "node_modules", ".bin", "wrangler");
15066
+ if (fs42.existsSync(localBin)) return { bin: localBin, prefix: [] };
14732
15067
  const result = spawnSync("which", ["wrangler"], { stdio: "pipe", timeout: 5e3 });
14733
15068
  if (result.status === 0) {
14734
15069
  const found = result.stdout?.toString().trim();
@@ -14760,11 +15095,11 @@ function extractAccountId(ref, cwd) {
14760
15095
  }
14761
15096
  function readWranglerToken() {
14762
15097
  const candidates = [
14763
- path45.join(os.homedir(), "Library", "Preferences", ".wrangler", "config", "default.toml"),
15098
+ path47.join(os.homedir(), "Library", "Preferences", ".wrangler", "config", "default.toml"),
14764
15099
  // macOS
14765
- path45.join(os.homedir(), ".config", ".wrangler", "config", "default.toml"),
15100
+ path47.join(os.homedir(), ".config", ".wrangler", "config", "default.toml"),
14766
15101
  // Linux
14767
- path45.join(os.homedir(), ".wrangler", "config", "default.toml")
15102
+ path47.join(os.homedir(), ".wrangler", "config", "default.toml")
14768
15103
  // fallback
14769
15104
  ];
14770
15105
  if (process.env.WRANGLER_CONFIG_PATH) {
@@ -14772,13 +15107,13 @@ function readWranglerToken() {
14772
15107
  }
14773
15108
  if (process.env.XDG_CONFIG_HOME) {
14774
15109
  candidates.unshift(
14775
- path45.join(process.env.XDG_CONFIG_HOME, ".wrangler", "config", "default.toml")
15110
+ path47.join(process.env.XDG_CONFIG_HOME, ".wrangler", "config", "default.toml")
14776
15111
  );
14777
15112
  }
14778
15113
  for (const configPath of candidates) {
14779
- if (!fs40.existsSync(configPath)) continue;
15114
+ if (!fs42.existsSync(configPath)) continue;
14780
15115
  try {
14781
- const content = fs40.readFileSync(configPath, "utf-8");
15116
+ const content = fs42.readFileSync(configPath, "utf-8");
14782
15117
  const match = content.match(/^oauth_token\s*=\s*"([^"]+)"/m);
14783
15118
  if (match) return match[1];
14784
15119
  } catch {
@@ -14810,14 +15145,14 @@ async function enablePublicDomain(accountId, bucketName, token) {
14810
15145
  }
14811
15146
 
14812
15147
  // src/commands/uninstall.ts
14813
- import fs42 from "fs";
14814
- import path46 from "path";
15148
+ import fs44 from "fs";
15149
+ import path48 from "path";
14815
15150
  import * as p6 from "@clack/prompts";
14816
15151
  import { Command as Command6 } from "commander";
14817
15152
  import pc4 from "picocolors";
14818
15153
 
14819
15154
  // src/commands/uninstall-cleaners.ts
14820
- import fs41 from "fs";
15155
+ import fs43 from "fs";
14821
15156
  function stripJsonComments2(input) {
14822
15157
  let result = "";
14823
15158
  let i = 0;
@@ -14851,8 +15186,8 @@ function stripJsonComments2(input) {
14851
15186
  return result;
14852
15187
  }
14853
15188
  function cleanTsconfig(tsconfigPath) {
14854
- if (!fs41.existsSync(tsconfigPath)) return [];
14855
- const raw = fs41.readFileSync(tsconfigPath, "utf-8");
15189
+ if (!fs43.existsSync(tsconfigPath)) return [];
15190
+ const raw = fs43.readFileSync(tsconfigPath, "utf-8");
14856
15191
  const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
14857
15192
  let tsconfig;
14858
15193
  try {
@@ -14876,13 +15211,13 @@ function cleanTsconfig(tsconfigPath) {
14876
15211
  compilerOptions.paths = paths;
14877
15212
  }
14878
15213
  tsconfig.compilerOptions = compilerOptions;
14879
- fs41.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
15214
+ fs43.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
14880
15215
  `, "utf-8");
14881
15216
  return removed;
14882
15217
  }
14883
15218
  function cleanCss(cssPath) {
14884
- if (!fs41.existsSync(cssPath)) return [];
14885
- const content = fs41.readFileSync(cssPath, "utf-8");
15219
+ if (!fs43.existsSync(cssPath)) return [];
15220
+ const content = fs43.readFileSync(cssPath, "utf-8");
14886
15221
  const lines = content.split("\n");
14887
15222
  const sourcePattern = /^@source\s+"[^"]*cms[^"]*";\s*$/;
14888
15223
  const removed = [];
@@ -14896,12 +15231,12 @@ function cleanCss(cssPath) {
14896
15231
  }
14897
15232
  if (removed.length === 0) return [];
14898
15233
  const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
14899
- fs41.writeFileSync(cssPath, cleaned, "utf-8");
15234
+ fs43.writeFileSync(cssPath, cleaned, "utf-8");
14900
15235
  return removed;
14901
15236
  }
14902
15237
  function cleanEnvFile(envPath) {
14903
- if (!fs41.existsSync(envPath)) return [];
14904
- const content = fs41.readFileSync(envPath, "utf-8");
15238
+ if (!fs43.existsSync(envPath)) return [];
15239
+ const content = fs43.readFileSync(envPath, "utf-8");
14905
15240
  const lines = content.split("\n");
14906
15241
  const removed = [];
14907
15242
  const kept = [];
@@ -14934,9 +15269,9 @@ function cleanEnvFile(envPath) {
14934
15269
  if (removed.length === 0) return [];
14935
15270
  const result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
14936
15271
  if (result === "") {
14937
- fs41.unlinkSync(envPath);
15272
+ fs43.unlinkSync(envPath);
14938
15273
  } else {
14939
- fs41.writeFileSync(envPath, `${result}
15274
+ fs43.writeFileSync(envPath, `${result}
14940
15275
  `, "utf-8");
14941
15276
  }
14942
15277
  return removed;
@@ -14962,15 +15297,15 @@ function findMainCss2(cwd) {
14962
15297
  "globals.css"
14963
15298
  ];
14964
15299
  for (const candidate of candidates) {
14965
- const filePath = path46.join(cwd, candidate);
14966
- if (fs42.existsSync(filePath)) return filePath;
15300
+ const filePath = path48.join(cwd, candidate);
15301
+ if (fs44.existsSync(filePath)) return filePath;
14967
15302
  }
14968
15303
  return void 0;
14969
15304
  }
14970
15305
  function isCLICreatedBiome(biomePath) {
14971
- if (!fs42.existsSync(biomePath)) return false;
15306
+ if (!fs44.existsSync(biomePath)) return false;
14972
15307
  try {
14973
- const content = JSON.parse(fs42.readFileSync(biomePath, "utf-8"));
15308
+ const content = JSON.parse(fs44.readFileSync(biomePath, "utf-8"));
14974
15309
  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");
14975
15310
  } catch {
14976
15311
  return false;
@@ -14978,13 +15313,13 @@ function isCLICreatedBiome(biomePath) {
14978
15313
  }
14979
15314
  function buildUninstallPlan(cwd) {
14980
15315
  const steps = [];
14981
- const hasSrc = fs42.existsSync(path46.join(cwd, "src"));
15316
+ const hasSrc = fs44.existsSync(path48.join(cwd, "src"));
14982
15317
  const appBase = hasSrc ? "src/app" : "app";
14983
15318
  const dirs = [];
14984
- const cmsDir = path46.join(cwd, "cms");
14985
- const cmsRouteGroup = path46.join(cwd, appBase, "(cms)");
14986
- if (fs42.existsSync(cmsDir)) dirs.push("cms/");
14987
- if (fs42.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
15319
+ const cmsDir = path48.join(cwd, "cms");
15320
+ const cmsRouteGroup = path48.join(cwd, appBase, "(cms)");
15321
+ if (fs44.existsSync(cmsDir)) dirs.push("cms/");
15322
+ if (fs44.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
14988
15323
  if (dirs.length > 0) {
14989
15324
  steps.push({
14990
15325
  label: "CMS directories",
@@ -14992,25 +15327,25 @@ function buildUninstallPlan(cwd) {
14992
15327
  count: dirs.length,
14993
15328
  unit: dirs.length === 1 ? "directory" : "directories",
14994
15329
  execute() {
14995
- if (fs42.existsSync(cmsDir)) fs42.rmSync(cmsDir, { recursive: true, force: true });
14996
- if (fs42.existsSync(cmsRouteGroup)) fs42.rmSync(cmsRouteGroup, { recursive: true, force: true });
15330
+ if (fs44.existsSync(cmsDir)) fs44.rmSync(cmsDir, { recursive: true, force: true });
15331
+ if (fs44.existsSync(cmsRouteGroup)) fs44.rmSync(cmsRouteGroup, { recursive: true, force: true });
14997
15332
  }
14998
15333
  });
14999
15334
  }
15000
15335
  const configFiles = [];
15001
15336
  const configPaths = [];
15002
15337
  const candidates = [
15003
- ["cms.config.ts", path46.join(cwd, "cms.config.ts")],
15004
- ["drizzle.config.ts", path46.join(cwd, "drizzle.config.ts")],
15005
- ["CMS.md", path46.join(cwd, "CMS.md")]
15338
+ ["cms.config.ts", path48.join(cwd, "cms.config.ts")],
15339
+ ["drizzle.config.ts", path48.join(cwd, "drizzle.config.ts")],
15340
+ ["CMS.md", path48.join(cwd, "CMS.md")]
15006
15341
  ];
15007
15342
  for (const [label, fullPath] of candidates) {
15008
- if (fs42.existsSync(fullPath)) {
15343
+ if (fs44.existsSync(fullPath)) {
15009
15344
  configFiles.push(label);
15010
15345
  configPaths.push(fullPath);
15011
15346
  }
15012
15347
  }
15013
- const biomePath = path46.join(cwd, "biome.json");
15348
+ const biomePath = path48.join(cwd, "biome.json");
15014
15349
  if (isCLICreatedBiome(biomePath)) {
15015
15350
  configFiles.push("biome.json (CLI-created)");
15016
15351
  configPaths.push(biomePath);
@@ -15023,14 +15358,14 @@ function buildUninstallPlan(cwd) {
15023
15358
  unit: configFiles.length === 1 ? "file" : "files",
15024
15359
  execute() {
15025
15360
  for (const p7 of configPaths) {
15026
- if (fs42.existsSync(p7)) fs42.unlinkSync(p7);
15361
+ if (fs44.existsSync(p7)) fs44.unlinkSync(p7);
15027
15362
  }
15028
15363
  }
15029
15364
  });
15030
15365
  }
15031
- const tsconfigPath = path46.join(cwd, "tsconfig.json");
15032
- if (fs42.existsSync(tsconfigPath)) {
15033
- const content = fs42.readFileSync(tsconfigPath, "utf-8");
15366
+ const tsconfigPath = path48.join(cwd, "tsconfig.json");
15367
+ if (fs44.existsSync(tsconfigPath)) {
15368
+ const content = fs44.readFileSync(tsconfigPath, "utf-8");
15034
15369
  const aliasMatches = content.match(/"@cms\//g);
15035
15370
  if (aliasMatches && aliasMatches.length > 0) {
15036
15371
  const aliasCount = aliasMatches.length;
@@ -15047,10 +15382,10 @@ function buildUninstallPlan(cwd) {
15047
15382
  }
15048
15383
  const cssFile = findMainCss2(cwd);
15049
15384
  if (cssFile) {
15050
- const cssContent = fs42.readFileSync(cssFile, "utf-8");
15385
+ const cssContent = fs44.readFileSync(cssFile, "utf-8");
15051
15386
  const sourceLines = cssContent.split("\n").filter((l) => /^@source\s+"[^"]*cms[^"]*";\s*$/.test(l));
15052
15387
  if (sourceLines.length > 0) {
15053
- const relCss = path46.relative(cwd, cssFile);
15388
+ const relCss = path48.relative(cwd, cssFile);
15054
15389
  steps.push({
15055
15390
  label: `CSS @source lines (${relCss})`,
15056
15391
  items: [`@source lines in ${relCss}`],
@@ -15062,9 +15397,9 @@ function buildUninstallPlan(cwd) {
15062
15397
  });
15063
15398
  }
15064
15399
  }
15065
- const envPath = path46.join(cwd, ".env.local");
15066
- if (fs42.existsSync(envPath)) {
15067
- const envContent = fs42.readFileSync(envPath, "utf-8");
15400
+ const envPath = path48.join(cwd, ".env.local");
15401
+ if (fs44.existsSync(envPath)) {
15402
+ const envContent = fs44.readFileSync(envPath, "utf-8");
15068
15403
  const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
15069
15404
  if (bsVars.length > 0) {
15070
15405
  steps.push({
@@ -15081,7 +15416,7 @@ function buildUninstallPlan(cwd) {
15081
15416
  return steps;
15082
15417
  }
15083
15418
  var uninstallCommand = new Command6("uninstall").description("Remove all CMS files and undo modifications made by betterstart init").option("-f, --force", "Skip all confirmation prompts", false).option("--cwd <path>", "Project root path").action(async (options) => {
15084
- const cwd = options.cwd ? path46.resolve(options.cwd) : process.cwd();
15419
+ const cwd = options.cwd ? path48.resolve(options.cwd) : process.cwd();
15085
15420
  p6.intro(pc4.bgRed(pc4.white(" BetterStart Uninstall ")));
15086
15421
  const steps = buildUninstallPlan(cwd);
15087
15422
  if (steps.length === 0) {
@@ -15118,11 +15453,11 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
15118
15453
  });
15119
15454
 
15120
15455
  // src/commands/update-deps.ts
15121
- import path47 from "path";
15456
+ import path49 from "path";
15122
15457
  import * as clack2 from "@clack/prompts";
15123
15458
  import { Command as Command7 } from "commander";
15124
15459
  var updateDepsCommand = new Command7("update-deps").description("Install or update all CMS dependencies").option("--cwd <path>", "Project root path").action(async (options) => {
15125
- const cwd = options.cwd ? path47.resolve(options.cwd) : process.cwd();
15460
+ const cwd = options.cwd ? path49.resolve(options.cwd) : process.cwd();
15126
15461
  clack2.intro("BetterStart Update Dependencies");
15127
15462
  const pm = detectPackageManager(cwd);
15128
15463
  clack2.log.info(`Package manager: ${pm}`);
@@ -15147,22 +15482,22 @@ var updateDepsCommand = new Command7("update-deps").description("Install or upda
15147
15482
  });
15148
15483
 
15149
15484
  // src/commands/update-styles.ts
15150
- import fs43 from "fs";
15151
- import path48 from "path";
15485
+ import fs45 from "fs";
15486
+ import path50 from "path";
15152
15487
  import * as clack3 from "@clack/prompts";
15153
15488
  import { Command as Command8 } from "commander";
15154
15489
  var updateStylesCommand = new Command8("update-styles").description("Replace cms-globals.css with the latest version from the CLI").option("--cwd <path>", "Project root path").action(async (options) => {
15155
- const cwd = options.cwd ? path48.resolve(options.cwd) : process.cwd();
15490
+ const cwd = options.cwd ? path50.resolve(options.cwd) : process.cwd();
15156
15491
  clack3.intro("BetterStart Update Styles");
15157
15492
  const config = await resolveConfig(cwd);
15158
15493
  const cmsDir = config.paths?.cms ?? "./cms";
15159
- const targetPath = path48.join(cwd, cmsDir, "cms-globals.css");
15160
- if (!fs43.existsSync(targetPath)) {
15161
- clack3.cancel(`cms-globals.css not found at ${path48.relative(cwd, targetPath)}`);
15494
+ const targetPath = path50.join(cwd, cmsDir, "cms-globals.css");
15495
+ if (!fs45.existsSync(targetPath)) {
15496
+ clack3.cancel(`cms-globals.css not found at ${path50.relative(cwd, targetPath)}`);
15162
15497
  process.exit(1);
15163
15498
  }
15164
- fs43.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15165
- clack3.log.success(`Updated ${path48.relative(cwd, targetPath)}`);
15499
+ fs45.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15500
+ clack3.log.success(`Updated ${path50.relative(cwd, targetPath)}`);
15166
15501
  clack3.outro("Styles updated");
15167
15502
  });
15168
15503