@betterstart/cli 0.1.40 → 0.1.42

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,23 +2248,31 @@ 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
2252
+ function resolveUiImport(cwd, componentName) {
2253
+ const locations = ["components/ui", "src/components/ui"];
2254
+ for (const loc of locations) {
2255
+ if (fs7.existsSync(path7.join(cwd, loc, `${componentName}.tsx`)) || fs7.existsSync(path7.join(cwd, loc, `${componentName}.ts`))) {
2256
+ return `@/components/ui/${componentName}`;
2257
+ }
2258
+ }
2259
+ return `@cms/components/ui/${componentName}`;
2260
+ }
2229
2261
  function escapeJsx(str) {
2230
2262
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2231
2263
  }
2232
- function generateFormComponent(schema, cwd, cmsDir, options) {
2233
- const formName = schema.name;
2234
- const pascal = toPascalCase(formName);
2235
- const fields = getAllFormSchemaFields(schema);
2236
- const kebab = toKebabCase(formName);
2237
- const filePath = path7.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2238
- const dir = path7.dirname(filePath);
2239
- if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
2240
- if (fs7.existsSync(filePath) && !options.force) {
2241
- return { files: [path7.relative(cwd, filePath)] };
2242
- }
2243
- const zodFields = fields.filter((f) => f.name).map((f) => ` ${f.name}: ${formFieldToZodType(f)}`).join(",\n");
2244
- 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) => {
2245
2276
  if (f.type === "checkbox") return ` ${f.name}: false`;
2246
2277
  if (f.type === "number") return ` ${f.name}: undefined`;
2247
2278
  if (f.type === "multiselect" || f.type === "list") return ` ${f.name}: []`;
@@ -2249,108 +2280,43 @@ function generateFormComponent(schema, cwd, cmsDir, options) {
2249
2280
  if (f.defaultValue !== void 0) return ` ${f.name}: '${f.defaultValue}'`;
2250
2281
  return ` ${f.name}: ''`;
2251
2282
  }).join(",\n");
2252
- const listFields = fields.filter(
2253
- (f) => f.name && f.type === "list" && f.fields && f.fields.length > 0
2254
- );
2255
- const hasListFields = listFields.length > 0;
2256
- const fieldArrayDecls = listFields.map(
2283
+ }
2284
+ function buildFieldArrayDecls(listFields) {
2285
+ return listFields.map(
2257
2286
  (f) => ` const ${f.name}FieldArray = useFieldArray({ control: form.control, name: '${f.name}' })`
2258
2287
  ).join("\n");
2259
- const fieldJSX = fields.filter((f) => f.name && !f.hidden).map((f) => generateFieldJSX(f)).join("\n\n");
2260
- const submitText = schema.submitButtonText || "Submit";
2261
- const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2262
- const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2263
- const fieldArraySetup = hasListFields ? `
2264
- ${fieldArrayDecls}
2265
- ` : "";
2266
- const content = `'use client'
2267
-
2268
- import { zodResolver } from '@hookform/resolvers/zod'
2269
- import { useState } from 'react'
2270
- ${rhfImport}
2271
- import { z } from 'zod/v3'
2272
- import { create${pascal}Submission } from '@cms/actions/${kebab}-form'
2273
- import { Button } from '@cms/components/ui/button'
2274
- import {
2275
- Form,
2276
- FormControl,
2277
- FormDescription,
2278
- FormField,
2279
- FormItem,
2280
- FormLabel,
2281
- FormMessage,
2282
- } from '@cms/components/ui/form'
2283
- import { Input } from '@cms/components/ui/input'
2284
- import { Textarea } from '@cms/components/ui/textarea'
2285
- import {
2286
- Select,
2287
- SelectContent,
2288
- SelectItem,
2289
- SelectTrigger,
2290
- SelectValue,
2291
- } from '@cms/components/ui/select'
2292
-
2293
- const formSchema = z.object({
2294
- ${zodFields}
2295
- })
2296
-
2297
- type FormValues = z.infer<typeof formSchema>
2298
-
2299
- export function ${pascal}Form() {
2300
- const [submitted, setSubmitted] = useState(false)
2301
- const [submitting, setSubmitting] = useState(false)
2302
-
2303
- const form = useForm<FormValues>({
2304
- resolver: zodResolver(formSchema),
2305
- defaultValues: {
2306
- ${defaults}
2307
- },
2308
- })
2309
- ${fieldArraySetup}
2310
- async function onSubmit(values: FormValues) {
2311
- setSubmitting(true)
2312
- try {
2313
- const result = await create${pascal}Submission(values)
2314
- if (result.success) {
2315
- setSubmitted(true)
2316
- } else {
2317
- form.setError('root', { message: result.error || 'Something went wrong' })
2318
- }
2319
- } catch {
2320
- form.setError('root', { message: 'Something went wrong. Please try again.' })
2321
- } finally {
2322
- setSubmitting(false)
2288
+ }
2289
+ function buildWatchDecls(fields) {
2290
+ const watchFields = /* @__PURE__ */ new Set();
2291
+ for (const f of fields) {
2292
+ if (f.showWhen) {
2293
+ watchFields.add(f.showWhen.field);
2323
2294
  }
2324
2295
  }
2325
-
2326
- if (submitted) {
2327
- return (
2328
- <div className="rounded-lg border p-6 text-center">
2329
- <h3 className="text-lg font-semibold">Thank you!</h3>
2330
- <p className="mt-2 text-muted-foreground">${successMessage}</p>
2331
- </div>
2332
- )
2333
- }
2334
-
2335
- return (
2336
- <Form {...form}>
2337
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
2338
- ${fieldJSX}
2339
-
2340
- {form.formState.errors.root && (
2341
- <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2342
- )}
2343
-
2344
- <Button type="submit" disabled={submitting}>
2345
- {submitting ? 'Submitting...' : '${submitText}'}
2346
- </Button>
2347
- </form>
2348
- </Form>
2349
- )
2296
+ if (watchFields.size === 0) return { setup: "", hasWatch: false };
2297
+ const decls = Array.from(watchFields).map((wf) => ` const ${wf}Value = form.watch('${wf}')`).join("\n");
2298
+ return { setup: `
2299
+ ${decls}
2300
+ `, hasWatch: true };
2350
2301
  }
2351
- `;
2352
- fs7.writeFileSync(filePath, content, "utf-8");
2353
- return { files: [path7.relative(cwd, filePath)] };
2302
+ function getListFields(fields) {
2303
+ return fields.filter(
2304
+ (f) => f.name && f.type === "list" && f.fields && f.fields.length > 0
2305
+ );
2306
+ }
2307
+ function wrapShowWhen(field, jsx) {
2308
+ if (!field.showWhen) return jsx;
2309
+ const watchVar = `${field.showWhen.field}Value`;
2310
+ const { value } = field.showWhen;
2311
+ if (Array.isArray(value)) {
2312
+ const vals = value.map((v) => `'${v}'`).join(", ");
2313
+ return ` {[${vals}].includes(${watchVar} as string) && (
2314
+ ${jsx}
2315
+ )}`;
2316
+ }
2317
+ return ` {${watchVar} === '${value}' && (
2318
+ ${jsx}
2319
+ )}`;
2354
2320
  }
2355
2321
  function generateFieldJSX(field) {
2356
2322
  const name = field.name || "";
@@ -2427,36 +2393,15 @@ ${optionItems}
2427
2393
  )}
2428
2394
  />`;
2429
2395
  case "email":
2430
- return generateTextFieldJSX(
2431
- name,
2432
- label,
2433
- placeholder || "email@example.com",
2434
- hintJSX,
2435
- requiredStar,
2436
- "email"
2437
- );
2396
+ return generateTextFieldJSX(name, label, placeholder || "email@example.com", hintJSX, requiredStar, "email");
2438
2397
  case "number":
2439
2398
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "number");
2440
2399
  case "date":
2441
2400
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "date");
2442
2401
  case "url":
2443
- return generateTextFieldJSX(
2444
- name,
2445
- label,
2446
- placeholder || "https://",
2447
- hintJSX,
2448
- requiredStar,
2449
- "url"
2450
- );
2402
+ return generateTextFieldJSX(name, label, placeholder || "https://", hintJSX, requiredStar, "url");
2451
2403
  case "phone":
2452
- return generateTextFieldJSX(
2453
- name,
2454
- label,
2455
- placeholder || "+1 (555) 000-0000",
2456
- hintJSX,
2457
- requiredStar,
2458
- "tel"
2459
- );
2404
+ return generateTextFieldJSX(name, label, placeholder || "+1 (555) 000-0000", hintJSX, requiredStar, "tel");
2460
2405
  case "file":
2461
2406
  case "upload":
2462
2407
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "file");
@@ -2557,9 +2502,402 @@ ${nestedFieldsJSX}
2557
2502
  </div>`;
2558
2503
  }
2559
2504
 
2505
+ // src/generators/form-pipeline/form-component-multistep.ts
2506
+ function generateMultiStepForm(schema, cwd, cmsDir, options) {
2507
+ const formName = schema.name;
2508
+ const pascal = toPascalCase(formName);
2509
+ const kebab = toKebabCase(formName);
2510
+ const steps = schema.steps;
2511
+ const filePath = path8.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2512
+ const dir = path8.dirname(filePath);
2513
+ if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
2514
+ if (fs8.existsSync(filePath) && !options.force) {
2515
+ return { files: [path8.relative(cwd, filePath)] };
2516
+ }
2517
+ const allFields = getAllFormSchemaFields(schema);
2518
+ const zodFields = buildZodFields(allFields);
2519
+ const defaults = buildDefaultValues(allFields);
2520
+ const listFields = getListFields(allFields);
2521
+ const hasListFields = listFields.length > 0;
2522
+ const { setup: watchSetup } = buildWatchDecls(allFields);
2523
+ const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2524
+ const fieldArraySetup = hasListFields ? `
2525
+ ${buildFieldArrayDecls(listFields)}
2526
+ ` : "";
2527
+ const stepsConst = buildStepsConstant(steps, schema);
2528
+ const stepContentBlocks = steps.map((step, index) => {
2529
+ const stepFields = flattenFormFields(step.fields);
2530
+ const fieldsJSX = stepFields.filter((f) => f.name && !f.hidden).map((f) => wrapShowWhen(f, generateFieldJSX(f))).join("\n\n");
2531
+ return ` {currentStep === ${index} && (
2532
+ <>
2533
+ ${fieldsJSX}
2534
+ </>
2535
+ )}`;
2536
+ }).join("\n");
2537
+ const submitText = schema.submitButtonText || "Submit";
2538
+ const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2539
+ const buttonImport = resolveUiImport(cwd, "button");
2540
+ const formImport = resolveUiImport(cwd, "form");
2541
+ const inputImport = resolveUiImport(cwd, "input");
2542
+ const textareaImport = resolveUiImport(cwd, "textarea");
2543
+ const selectImport = resolveUiImport(cwd, "select");
2544
+ const progressImport = resolveUiImport(cwd, "progress");
2545
+ const content = buildComponentSource({
2546
+ pascal,
2547
+ kebab,
2548
+ rhfImport,
2549
+ buttonImport,
2550
+ formImport,
2551
+ inputImport,
2552
+ textareaImport,
2553
+ selectImport,
2554
+ progressImport,
2555
+ zodFields,
2556
+ defaults,
2557
+ stepsConst,
2558
+ fieldArraySetup,
2559
+ watchSetup,
2560
+ stepContentBlocks,
2561
+ submitText,
2562
+ successMessage
2563
+ });
2564
+ fs8.writeFileSync(filePath, content, "utf-8");
2565
+ return { files: [path8.relative(cwd, filePath)] };
2566
+ }
2567
+ function buildStepsConstant(steps, schema) {
2568
+ const entries = steps.map((step) => {
2569
+ const fieldNames = getStepFieldNames(step);
2570
+ const fieldsStr = fieldNames.map((n) => `'${n}'`).join(", ");
2571
+ const desc = step.description ? `, description: '${escapeQuotes(step.description)}'` : "";
2572
+ return ` { name: '${step.name}', label: '${escapeQuotes(step.label)}'${desc}, fields: [${fieldsStr}] }`;
2573
+ });
2574
+ return `const STEPS = [
2575
+ ${entries.join(",\n")}
2576
+ ]`;
2577
+ }
2578
+ function escapeQuotes(str) {
2579
+ return str.replace(/'/g, "\\'");
2580
+ }
2581
+ function buildComponentSource(p7) {
2582
+ return `'use client'
2583
+
2584
+ import { zodResolver } from '@hookform/resolvers/zod'
2585
+ import { Check, ChevronLeft, ChevronRight } from 'lucide-react'
2586
+ import { useState } from 'react'
2587
+ ${p7.rhfImport}
2588
+ import { z } from 'zod/v3'
2589
+ import { create${p7.pascal}Submission } from '@cms/actions/${p7.kebab}-form'
2590
+ import { Button } from '${p7.buttonImport}'
2591
+ import {
2592
+ Form,
2593
+ FormControl,
2594
+ FormDescription,
2595
+ FormField,
2596
+ FormItem,
2597
+ FormLabel,
2598
+ FormMessage,
2599
+ } from '${p7.formImport}'
2600
+ import { Input } from '${p7.inputImport}'
2601
+ import { Progress } from '${p7.progressImport}'
2602
+ import { Textarea } from '${p7.textareaImport}'
2603
+ import {
2604
+ Select,
2605
+ SelectContent,
2606
+ SelectItem,
2607
+ SelectTrigger,
2608
+ SelectValue,
2609
+ } from '${p7.selectImport}'
2610
+
2611
+ const formSchema = z.object({
2612
+ ${p7.zodFields}
2613
+ })
2614
+
2615
+ type FormValues = z.infer<typeof formSchema>
2616
+
2617
+ ${p7.stepsConst}
2618
+
2619
+ export function ${p7.pascal}Form() {
2620
+ const [currentStep, setCurrentStep] = useState(0)
2621
+ const [completedSteps, setCompletedSteps] = useState<Set<number>>(new Set())
2622
+ const [submitted, setSubmitted] = useState(false)
2623
+ const [submitting, setSubmitting] = useState(false)
2624
+
2625
+ const form = useForm<FormValues>({
2626
+ resolver: zodResolver(formSchema),
2627
+ mode: 'onTouched',
2628
+ defaultValues: {
2629
+ ${p7.defaults}
2630
+ },
2631
+ })
2632
+ ${p7.fieldArraySetup}${p7.watchSetup}
2633
+ async function handleNext() {
2634
+ const isValid = await form.trigger(
2635
+ STEPS[currentStep].fields as (keyof FormValues)[]
2636
+ )
2637
+ if (isValid) {
2638
+ setCompletedSteps((prev) => new Set(prev).add(currentStep))
2639
+ setCurrentStep((prev) => prev + 1)
2640
+ }
2641
+ }
2642
+
2643
+ function handleBack() {
2644
+ setCurrentStep((prev) => prev - 1)
2645
+ }
2646
+
2647
+ function handleStepClick(index: number) {
2648
+ if (index < currentStep || completedSteps.has(index)) {
2649
+ setCurrentStep(index)
2650
+ }
2651
+ }
2652
+
2653
+ async function onSubmit(values: FormValues) {
2654
+ setSubmitting(true)
2655
+ try {
2656
+ const result = await create${p7.pascal}Submission(values)
2657
+ if (result.success) {
2658
+ setSubmitted(true)
2659
+ } else {
2660
+ form.setError('root', { message: result.error || 'Something went wrong' })
2661
+ }
2662
+ } catch {
2663
+ form.setError('root', { message: 'Something went wrong. Please try again.' })
2664
+ } finally {
2665
+ setSubmitting(false)
2666
+ }
2667
+ }
2668
+
2669
+ if (submitted) {
2670
+ return (
2671
+ <div className="rounded-lg border p-6 text-center">
2672
+ <h3 className="text-lg font-semibold">Thank you!</h3>
2673
+ <p className="mt-2 text-muted-foreground">${p7.successMessage}</p>
2674
+ </div>
2675
+ )
2676
+ }
2677
+
2678
+ return (
2679
+ <Form {...form}>
2680
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
2681
+ {/* Mobile step indicator */}
2682
+ <div className="md:hidden space-y-2">
2683
+ <p className="text-sm text-muted-foreground">
2684
+ Step {currentStep + 1} of {STEPS.length} &mdash; {STEPS[currentStep].label}
2685
+ </p>
2686
+ <Progress value={((currentStep + 1) / STEPS.length) * 100} />
2687
+ </div>
2688
+
2689
+ {/* Desktop step indicator */}
2690
+ <nav className="hidden md:flex items-center justify-center" aria-label="Form progress">
2691
+ {STEPS.map((step, index) => (
2692
+ <div key={step.name} className="flex items-center">
2693
+ <button
2694
+ type="button"
2695
+ onClick={() => handleStepClick(index)}
2696
+ disabled={index > currentStep && !completedSteps.has(index)}
2697
+ aria-current={index === currentStep ? 'step' : undefined}
2698
+ className={\`flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium transition-colors \${
2699
+ completedSteps.has(index)
2700
+ ? 'bg-primary text-primary-foreground cursor-pointer'
2701
+ : index === currentStep
2702
+ ? 'border-2 border-primary text-primary'
2703
+ : 'border-2 border-muted text-muted-foreground'
2704
+ }\`}
2705
+ >
2706
+ {completedSteps.has(index) ? (
2707
+ <Check className="h-4 w-4" />
2708
+ ) : (
2709
+ index + 1
2710
+ )}
2711
+ </button>
2712
+ {index < STEPS.length - 1 && (
2713
+ <div
2714
+ className={\`h-0.5 w-8 mx-1 \${
2715
+ completedSteps.has(index) ? 'bg-primary' : 'bg-muted'
2716
+ }\`}
2717
+ />
2718
+ )}
2719
+ </div>
2720
+ ))}
2721
+ </nav>
2722
+
2723
+ {/* Step header */}
2724
+ <div>
2725
+ <h3 className="text-lg font-semibold">{STEPS[currentStep].label}</h3>
2726
+ {'description' in STEPS[currentStep] && STEPS[currentStep].description && (
2727
+ <p className="text-sm text-muted-foreground mt-1">{STEPS[currentStep].description}</p>
2728
+ )}
2729
+ </div>
2730
+
2731
+ {/* Step content */}
2732
+ <div key={currentStep} className="animate-in fade-in duration-300 space-y-6">
2733
+ ${p7.stepContentBlocks}
2734
+ </div>
2735
+
2736
+ {form.formState.errors.root && (
2737
+ <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2738
+ )}
2739
+
2740
+ {/* Navigation */}
2741
+ <div className="flex justify-between">
2742
+ <Button
2743
+ type="button"
2744
+ variant="outline"
2745
+ onClick={handleBack}
2746
+ disabled={currentStep === 0}
2747
+ >
2748
+ <ChevronLeft className="mr-2 h-4 w-4" />
2749
+ Back
2750
+ </Button>
2751
+ {currentStep < STEPS.length - 1 ? (
2752
+ <Button type="button" onClick={handleNext}>
2753
+ Next
2754
+ <ChevronRight className="ml-2 h-4 w-4" />
2755
+ </Button>
2756
+ ) : (
2757
+ <Button type="submit" disabled={submitting}>
2758
+ {submitting ? 'Submitting...' : '${p7.submitText}'}
2759
+ </Button>
2760
+ )}
2761
+ </div>
2762
+ </form>
2763
+ </Form>
2764
+ )
2765
+ }
2766
+ `;
2767
+ }
2768
+
2769
+ // src/generators/form-pipeline/form-component-single.ts
2770
+ import fs9 from "fs";
2771
+ import path9 from "path";
2772
+ function generateSingleStepForm(schema, cwd, cmsDir, options) {
2773
+ const formName = schema.name;
2774
+ const pascal = toPascalCase(formName);
2775
+ const fields = getAllFormSchemaFields(schema);
2776
+ const kebab = toKebabCase(formName);
2777
+ const filePath = path9.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2778
+ const dir = path9.dirname(filePath);
2779
+ if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
2780
+ if (fs9.existsSync(filePath) && !options.force) {
2781
+ return { files: [path9.relative(cwd, filePath)] };
2782
+ }
2783
+ const zodFields = buildZodFields(fields);
2784
+ const defaults = buildDefaultValues(fields);
2785
+ const listFields = getListFields(fields);
2786
+ const hasListFields = listFields.length > 0;
2787
+ const { setup: watchSetup } = buildWatchDecls(fields);
2788
+ const fieldJSX = fields.filter((f) => f.name && !f.hidden).map((f) => wrapShowWhen(f, generateFieldJSX(f))).join("\n\n");
2789
+ const submitText = schema.submitButtonText || "Submit";
2790
+ const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2791
+ const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2792
+ const fieldArraySetup = hasListFields ? `
2793
+ ${buildFieldArrayDecls(listFields)}
2794
+ ` : "";
2795
+ const buttonImport = resolveUiImport(cwd, "button");
2796
+ const formImport = resolveUiImport(cwd, "form");
2797
+ const inputImport = resolveUiImport(cwd, "input");
2798
+ const textareaImport = resolveUiImport(cwd, "textarea");
2799
+ const selectImport = resolveUiImport(cwd, "select");
2800
+ const content = `'use client'
2801
+
2802
+ import { zodResolver } from '@hookform/resolvers/zod'
2803
+ import { useState } from 'react'
2804
+ ${rhfImport}
2805
+ import { z } from 'zod/v3'
2806
+ import { create${pascal}Submission } from '@cms/actions/${kebab}-form'
2807
+ import { Button } from '${buttonImport}'
2808
+ import {
2809
+ Form,
2810
+ FormControl,
2811
+ FormDescription,
2812
+ FormField,
2813
+ FormItem,
2814
+ FormLabel,
2815
+ FormMessage,
2816
+ } from '${formImport}'
2817
+ import { Input } from '${inputImport}'
2818
+ import { Textarea } from '${textareaImport}'
2819
+ import {
2820
+ Select,
2821
+ SelectContent,
2822
+ SelectItem,
2823
+ SelectTrigger,
2824
+ SelectValue,
2825
+ } from '${selectImport}'
2826
+
2827
+ const formSchema = z.object({
2828
+ ${zodFields}
2829
+ })
2830
+
2831
+ type FormValues = z.infer<typeof formSchema>
2832
+
2833
+ export function ${pascal}Form() {
2834
+ const [submitted, setSubmitted] = useState(false)
2835
+ const [submitting, setSubmitting] = useState(false)
2836
+
2837
+ const form = useForm<FormValues>({
2838
+ resolver: zodResolver(formSchema),
2839
+ defaultValues: {
2840
+ ${defaults}
2841
+ },
2842
+ })
2843
+ ${fieldArraySetup}${watchSetup}
2844
+ async function onSubmit(values: FormValues) {
2845
+ setSubmitting(true)
2846
+ try {
2847
+ const result = await create${pascal}Submission(values)
2848
+ if (result.success) {
2849
+ setSubmitted(true)
2850
+ } else {
2851
+ form.setError('root', { message: result.error || 'Something went wrong' })
2852
+ }
2853
+ } catch {
2854
+ form.setError('root', { message: 'Something went wrong. Please try again.' })
2855
+ } finally {
2856
+ setSubmitting(false)
2857
+ }
2858
+ }
2859
+
2860
+ if (submitted) {
2861
+ return (
2862
+ <div className="rounded-lg border p-6 text-center">
2863
+ <h3 className="text-lg font-semibold">Thank you!</h3>
2864
+ <p className="mt-2 text-muted-foreground">${successMessage}</p>
2865
+ </div>
2866
+ )
2867
+ }
2868
+
2869
+ return (
2870
+ <Form {...form}>
2871
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
2872
+ ${fieldJSX}
2873
+
2874
+ {form.formState.errors.root && (
2875
+ <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2876
+ )}
2877
+
2878
+ <Button type="submit" disabled={submitting}>
2879
+ {submitting ? 'Submitting...' : '${submitText}'}
2880
+ </Button>
2881
+ </form>
2882
+ </Form>
2883
+ )
2884
+ }
2885
+ `;
2886
+ fs9.writeFileSync(filePath, content, "utf-8");
2887
+ return { files: [path9.relative(cwd, filePath)] };
2888
+ }
2889
+
2890
+ // src/generators/form-pipeline/form-component.ts
2891
+ function generateFormComponent(schema, cwd, cmsDir, options) {
2892
+ if (isMultiStepForm(schema) && schema.steps.length > 1) {
2893
+ return generateMultiStepForm(schema, cwd, cmsDir, options);
2894
+ }
2895
+ return generateSingleStepForm(schema, cwd, cmsDir, options);
2896
+ }
2897
+
2560
2898
  // src/generators/form-pipeline/form-database.ts
2561
- import fs8 from "fs";
2562
- import path8 from "path";
2899
+ import fs10 from "fs";
2900
+ import path10 from "path";
2563
2901
  function findTableEnd(content, startIndex) {
2564
2902
  let depth = 0;
2565
2903
  let inString = false;
@@ -2614,8 +2952,8 @@ ${fieldDefs}${customFieldsCol}
2614
2952
  updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\`CURRENT_TIMESTAMP\`).notNull()
2615
2953
  })
2616
2954
  `;
2617
- const filePath = path8.join(cwd, dbSchemaPath);
2618
- let content = fs8.readFileSync(filePath, "utf-8");
2955
+ const filePath = path10.join(cwd, dbSchemaPath);
2956
+ let content = fs10.readFileSync(filePath, "utf-8");
2619
2957
  const pgCoreMatch = content.match(/import\s+\{([^}]+)\}\s+from\s+['"]drizzle-orm\/pg-core['"]/);
2620
2958
  if (pgCoreMatch) {
2621
2959
  const existing = new Set(
@@ -2651,23 +2989,23 @@ ${match}`
2651
2989
  }
2652
2990
  content += `
2653
2991
  ${tableSchema}`;
2654
- fs8.writeFileSync(filePath, content, "utf-8");
2992
+ fs10.writeFileSync(filePath, content, "utf-8");
2655
2993
  return { files: [dbSchemaPath] };
2656
2994
  }
2657
2995
 
2658
2996
  // src/generators/form-pipeline/form-hook.ts
2659
- import fs9 from "fs";
2660
- import path9 from "path";
2997
+ import fs11 from "fs";
2998
+ import path11 from "path";
2661
2999
  function generateFormHook(schema, cwd, hooksDir, options) {
2662
3000
  const formName = schema.name;
2663
3001
  const pascal = toPascalCase(formName);
2664
3002
  const camel = toCamelCase(formName);
2665
3003
  const kebab = toKebabCase(formName);
2666
- const filePath = path9.join(cwd, hooksDir, `use-${kebab}-form.ts`);
2667
- const dir = path9.dirname(filePath);
2668
- if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
2669
- if (fs9.existsSync(filePath) && !options.force) {
2670
- return { files: [path9.relative(cwd, filePath)] };
3004
+ const filePath = path11.join(cwd, hooksDir, `use-${kebab}-form.ts`);
3005
+ const dir = path11.dirname(filePath);
3006
+ if (!fs11.existsSync(dir)) fs11.mkdirSync(dir, { recursive: true });
3007
+ if (fs11.existsSync(filePath) && !options.force) {
3008
+ return { files: [path11.relative(cwd, filePath)] };
2671
3009
  }
2672
3010
  const successMsg = (schema.successMessage || "Form submitted successfully").replace(/'/g, "\\'");
2673
3011
  const content = `import {
@@ -2773,8 +3111,8 @@ export function useExport${pascal}SubmissionsJSON() {
2773
3111
  })
2774
3112
  }
2775
3113
  `;
2776
- fs9.writeFileSync(filePath, content, "utf-8");
2777
- return { files: [path9.relative(cwd, filePath)] };
3114
+ fs11.writeFileSync(filePath, content, "utf-8");
3115
+ return { files: [path11.relative(cwd, filePath)] };
2778
3116
  }
2779
3117
 
2780
3118
  // src/generators/form-pipeline/pipeline.ts
@@ -2840,8 +3178,8 @@ function runFormPipeline(schema, cwd, config, options = {}) {
2840
3178
  }
2841
3179
 
2842
3180
  // src/generators/actions/entity-actions.ts
2843
- import fs10 from "fs";
2844
- import path10 from "path";
3181
+ import fs12 from "fs";
3182
+ import path12 from "path";
2845
3183
 
2846
3184
  // src/generators/actions/action-helpers.ts
2847
3185
  function generateFieldMapping(field, source = "input") {
@@ -2980,9 +3318,9 @@ ${blocks.join("\n\n")}
2980
3318
 
2981
3319
  // src/generators/actions/entity-actions.ts
2982
3320
  function generateActions(schema, cwd, actionsDir, options = {}) {
2983
- const absActionsDir = path10.join(cwd, actionsDir);
2984
- const filePath = path10.join(absActionsDir, `${schema.name}.ts`);
2985
- if (fs10.existsSync(filePath) && !options.force) {
3321
+ const absActionsDir = path12.join(cwd, actionsDir);
3322
+ const filePath = path12.join(absActionsDir, `${schema.name}.ts`);
3323
+ if (fs12.existsSync(filePath) && !options.force) {
2986
3324
  return { files: [] };
2987
3325
  }
2988
3326
  const singular = singularize(schema.name);
@@ -3468,20 +3806,20 @@ export async function bulkUpdate${Plural}SortOrder(
3468
3806
  }
3469
3807
  }${m2mHelpers}
3470
3808
  `;
3471
- if (!fs10.existsSync(absActionsDir)) {
3472
- fs10.mkdirSync(absActionsDir, { recursive: true });
3809
+ if (!fs12.existsSync(absActionsDir)) {
3810
+ fs12.mkdirSync(absActionsDir, { recursive: true });
3473
3811
  }
3474
- fs10.writeFileSync(filePath, content, "utf-8");
3475
- return { files: [path10.join(actionsDir, `${schema.name}.ts`)] };
3812
+ fs12.writeFileSync(filePath, content, "utf-8");
3813
+ return { files: [path12.join(actionsDir, `${schema.name}.ts`)] };
3476
3814
  }
3477
3815
 
3478
3816
  // src/generators/actions/single-actions.ts
3479
- import fs11 from "fs";
3480
- import path11 from "path";
3817
+ import fs13 from "fs";
3818
+ import path13 from "path";
3481
3819
  function generateSingleActions(schema, cwd, actionsDir, options = {}) {
3482
- const absActionsDir = path11.join(cwd, actionsDir);
3483
- const filePath = path11.join(absActionsDir, `${schema.name}.ts`);
3484
- if (fs11.existsSync(filePath) && !options.force) {
3820
+ const absActionsDir = path13.join(cwd, actionsDir);
3821
+ const filePath = path13.join(absActionsDir, `${schema.name}.ts`);
3822
+ if (fs13.existsSync(filePath) && !options.force) {
3485
3823
  return { files: [] };
3486
3824
  }
3487
3825
  const singular = singularize(schema.name);
@@ -3604,24 +3942,24 @@ ${upsertMappings},${singleHasHtmlOutput ? "\n" + singleHtmlOutputFields.map((f)
3604
3942
  }
3605
3943
  }
3606
3944
  `;
3607
- if (!fs11.existsSync(absActionsDir)) {
3608
- fs11.mkdirSync(absActionsDir, { recursive: true });
3945
+ if (!fs13.existsSync(absActionsDir)) {
3946
+ fs13.mkdirSync(absActionsDir, { recursive: true });
3609
3947
  }
3610
- fs11.writeFileSync(filePath, content, "utf-8");
3611
- return { files: [path11.join(actionsDir, `${schema.name}.ts`)] };
3948
+ fs13.writeFileSync(filePath, content, "utf-8");
3949
+ return { files: [path13.join(actionsDir, `${schema.name}.ts`)] };
3612
3950
  }
3613
3951
 
3614
3952
  // src/generators/cache.ts
3615
- import fs12 from "fs";
3616
- import path12 from "path";
3953
+ import fs14 from "fs";
3954
+ import path14 from "path";
3617
3955
  function loadAllSchemas(cwd, schemasDir) {
3618
- const dir = path12.join(cwd, schemasDir);
3619
- if (!fs12.existsSync(dir)) return [];
3620
- const files = fs12.readdirSync(dir).filter((f) => f.endsWith(".json"));
3956
+ const dir = path14.join(cwd, schemasDir);
3957
+ if (!fs14.existsSync(dir)) return [];
3958
+ const files = fs14.readdirSync(dir).filter((f) => f.endsWith(".json"));
3621
3959
  const seen = /* @__PURE__ */ new Map();
3622
3960
  for (const file of files) {
3623
3961
  if (file === "schema.json") continue;
3624
- const content = fs12.readFileSync(path12.join(dir, file), "utf-8");
3962
+ const content = fs14.readFileSync(path14.join(dir, file), "utf-8");
3625
3963
  const schema = JSON.parse(content);
3626
3964
  if (!schema.name) continue;
3627
3965
  seen.set(schema.name, schema);
@@ -3811,27 +4149,27 @@ export * from './revalidate'
3811
4149
  `;
3812
4150
  }
3813
4151
  function generateCache(_schema, cwd, cmsDir, _options = {}) {
3814
- const cacheDir = path12.join(cwd, cmsDir, "lib", "cache");
3815
- const schemasDir = path12.join(cmsDir, "schemas");
4152
+ const cacheDir = path14.join(cwd, cmsDir, "lib", "cache");
4153
+ const schemasDir = path14.join(cmsDir, "schemas");
3816
4154
  const schemas = loadAllSchemas(cwd, schemasDir);
3817
4155
  const configs = schemas.map(buildCacheConfig).sort((a, b) => a.name.localeCompare(b.name));
3818
- if (!fs12.existsSync(cacheDir)) {
3819
- fs12.mkdirSync(cacheDir, { recursive: true });
4156
+ if (!fs14.existsSync(cacheDir)) {
4157
+ fs14.mkdirSync(cacheDir, { recursive: true });
3820
4158
  }
3821
4159
  const files = [];
3822
- fs12.writeFileSync(path12.join(cacheDir, "tags.ts"), generateTags(configs), "utf-8");
3823
- files.push(path12.join(cmsDir, "lib", "cache", "tags.ts"));
3824
- fs12.writeFileSync(
3825
- path12.join(cacheDir, "cached-queries.ts"),
4160
+ fs14.writeFileSync(path14.join(cacheDir, "tags.ts"), generateTags(configs), "utf-8");
4161
+ files.push(path14.join(cmsDir, "lib", "cache", "tags.ts"));
4162
+ fs14.writeFileSync(
4163
+ path14.join(cacheDir, "cached-queries.ts"),
3826
4164
  generateCachedQueries(configs),
3827
4165
  "utf-8"
3828
4166
  );
3829
- files.push(path12.join(cmsDir, "lib", "cache", "cached-queries.ts"));
3830
- fs12.writeFileSync(path12.join(cacheDir, "revalidate.ts"), generateRevalidate(configs), "utf-8");
3831
- files.push(path12.join(cmsDir, "lib", "cache", "revalidate.ts"));
3832
- const customQueriesPath = path12.join(cacheDir, "cached-queries-custom.ts");
3833
- if (!fs12.existsSync(customQueriesPath)) {
3834
- fs12.writeFileSync(
4167
+ files.push(path14.join(cmsDir, "lib", "cache", "cached-queries.ts"));
4168
+ fs14.writeFileSync(path14.join(cacheDir, "revalidate.ts"), generateRevalidate(configs), "utf-8");
4169
+ files.push(path14.join(cmsDir, "lib", "cache", "revalidate.ts"));
4170
+ const customQueriesPath = path14.join(cacheDir, "cached-queries-custom.ts");
4171
+ if (!fs14.existsSync(customQueriesPath)) {
4172
+ fs14.writeFileSync(
3835
4173
  customQueriesPath,
3836
4174
  `/**
3837
4175
  * Custom cached query functions (not auto-generated)
@@ -3842,16 +4180,16 @@ export {}
3842
4180
  `,
3843
4181
  "utf-8"
3844
4182
  );
3845
- files.push(path12.join(cmsDir, "lib", "cache", "cached-queries-custom.ts"));
4183
+ files.push(path14.join(cmsDir, "lib", "cache", "cached-queries-custom.ts"));
3846
4184
  }
3847
- fs12.writeFileSync(path12.join(cacheDir, "index.ts"), generateIndex(), "utf-8");
3848
- files.push(path12.join(cmsDir, "lib", "cache", "index.ts"));
4185
+ fs14.writeFileSync(path14.join(cacheDir, "index.ts"), generateIndex(), "utf-8");
4186
+ files.push(path14.join(cmsDir, "lib", "cache", "index.ts"));
3849
4187
  return { files };
3850
4188
  }
3851
4189
 
3852
4190
  // src/generators/columns/generate-columns.ts
3853
- import fs14 from "fs";
3854
- import path14 from "path";
4191
+ import fs16 from "fs";
4192
+ import path16 from "path";
3855
4193
 
3856
4194
  // src/generators/columns/column-defs.ts
3857
4195
  function isSortableColumn(column) {
@@ -4469,12 +4807,12 @@ function truncateStr(str: string, maxLength: number): string {
4469
4807
  }
4470
4808
 
4471
4809
  // src/generators/columns/custom-cell.ts
4472
- import fs13 from "fs";
4473
- import path13 from "path";
4810
+ import fs15 from "fs";
4811
+ import path15 from "path";
4474
4812
  function createCustomCellComponent(schema, componentName, cwd, pagesDir, options) {
4475
- const cellsDir = path13.join(cwd, pagesDir, schema.name, "cells");
4476
- const componentFilePath = path13.join(cellsDir, `${componentName}.tsx`);
4477
- if (fs13.existsSync(componentFilePath) && !options.force) return;
4813
+ const cellsDir = path15.join(cwd, pagesDir, schema.name, "cells");
4814
+ const componentFilePath = path15.join(cellsDir, `${componentName}.tsx`);
4815
+ if (fs15.existsSync(componentFilePath) && !options.force) return;
4478
4816
  const singular = singularize(schema.name);
4479
4817
  const Singular = toPascalCase(singular);
4480
4818
  const content = `import type { ${Singular}Data } from '@cms/actions/${schema.name}'
@@ -4491,17 +4829,17 @@ export function ${componentName}({ data }: ${componentName}Props) {
4491
4829
  )
4492
4830
  }
4493
4831
  `;
4494
- if (!fs13.existsSync(cellsDir)) {
4495
- fs13.mkdirSync(cellsDir, { recursive: true });
4832
+ if (!fs15.existsSync(cellsDir)) {
4833
+ fs15.mkdirSync(cellsDir, { recursive: true });
4496
4834
  }
4497
- fs13.writeFileSync(componentFilePath, content, "utf-8");
4835
+ fs15.writeFileSync(componentFilePath, content, "utf-8");
4498
4836
  }
4499
4837
 
4500
4838
  // src/generators/columns/generate-columns.ts
4501
4839
  function generateColumns2(schema, cwd, pagesDir, options = {}) {
4502
- const entityDir = path14.join(cwd, pagesDir, schema.name);
4503
- const columnsFilePath = path14.join(entityDir, "columns.tsx");
4504
- if (fs14.existsSync(columnsFilePath) && !options.force) {
4840
+ const entityDir = path16.join(cwd, pagesDir, schema.name);
4841
+ const columnsFilePath = path16.join(entityDir, "columns.tsx");
4842
+ if (fs16.existsSync(columnsFilePath) && !options.force) {
4505
4843
  return { files: [] };
4506
4844
  }
4507
4845
  const singular = singularize(schema.name);
@@ -4643,22 +4981,22 @@ ${restColDefs}` : ""},
4643
4981
  ${actionsColumn}
4644
4982
  ]
4645
4983
  `;
4646
- if (!fs14.existsSync(entityDir)) {
4647
- fs14.mkdirSync(entityDir, { recursive: true });
4984
+ if (!fs16.existsSync(entityDir)) {
4985
+ fs16.mkdirSync(entityDir, { recursive: true });
4648
4986
  }
4649
- fs14.writeFileSync(columnsFilePath, content, "utf-8");
4987
+ fs16.writeFileSync(columnsFilePath, content, "utf-8");
4650
4988
  return {
4651
- files: [path14.join(pagesDir, schema.name, "columns.tsx")]
4989
+ files: [path16.join(pagesDir, schema.name, "columns.tsx")]
4652
4990
  };
4653
4991
  }
4654
4992
 
4655
4993
  // src/generators/create-page.ts
4656
- import fs15 from "fs";
4657
- import path15 from "path";
4994
+ import fs17 from "fs";
4995
+ import path17 from "path";
4658
4996
  function generateCreatePage(schema, cwd, pagesDir, options = {}) {
4659
- const newDir = path15.join(cwd, pagesDir, schema.name, "new");
4660
- const pageFilePath = path15.join(newDir, "page.tsx");
4661
- if (fs15.existsSync(pageFilePath) && !options.force) {
4997
+ const newDir = path17.join(cwd, pagesDir, schema.name, "new");
4998
+ const pageFilePath = path17.join(newDir, "page.tsx");
4999
+ if (fs17.existsSync(pageFilePath) && !options.force) {
4662
5000
  return { files: [] };
4663
5001
  }
4664
5002
  const singular = singularize(schema.name);
@@ -4685,18 +5023,18 @@ export default async function Create${Singular}Page() {
4685
5023
  )
4686
5024
  }
4687
5025
  `;
4688
- if (!fs15.existsSync(newDir)) {
4689
- fs15.mkdirSync(newDir, { recursive: true });
5026
+ if (!fs17.existsSync(newDir)) {
5027
+ fs17.mkdirSync(newDir, { recursive: true });
4690
5028
  }
4691
- fs15.writeFileSync(pageFilePath, content, "utf-8");
5029
+ fs17.writeFileSync(pageFilePath, content, "utf-8");
4692
5030
  return {
4693
- files: [path15.join(pagesDir, schema.name, "new", "page.tsx")]
5031
+ files: [path17.join(pagesDir, schema.name, "new", "page.tsx")]
4694
5032
  };
4695
5033
  }
4696
5034
 
4697
5035
  // src/generators/database.ts
4698
- import fs16 from "fs";
4699
- import path16 from "path";
5036
+ import fs18 from "fs";
5037
+ import path18 from "path";
4700
5038
  function getFieldModifiers(field, needsSql) {
4701
5039
  const modifiers = [];
4702
5040
  if (field.primaryKey) {
@@ -4877,11 +5215,11 @@ function findTableEnd2(content, startIndex) {
4877
5215
  return content.length;
4878
5216
  }
4879
5217
  function generateDatabase(schema, cwd, schemaDir, options = {}) {
4880
- const schemaFilePath = path16.join(cwd, schemaDir);
5218
+ const schemaFilePath = path18.join(cwd, schemaDir);
4881
5219
  const files = [];
4882
5220
  let content = "";
4883
- if (fs16.existsSync(schemaFilePath)) {
4884
- content = fs16.readFileSync(schemaFilePath, "utf-8");
5221
+ if (fs18.existsSync(schemaFilePath)) {
5222
+ content = fs18.readFileSync(schemaFilePath, "utf-8");
4885
5223
  }
4886
5224
  const variableName = toCamelCase(schema.name);
4887
5225
  if (content.includes(`export const ${variableName} =`) && !options.force) {
@@ -4921,11 +5259,11 @@ ${junctionDefs[i]}`;
4921
5259
  }
4922
5260
  }
4923
5261
  updated = mergeImports(updated, requiredImports, needsSql.value);
4924
- const dir = path16.dirname(schemaFilePath);
4925
- if (!fs16.existsSync(dir)) {
4926
- fs16.mkdirSync(dir, { recursive: true });
5262
+ const dir = path18.dirname(schemaFilePath);
5263
+ if (!fs18.existsSync(dir)) {
5264
+ fs18.mkdirSync(dir, { recursive: true });
4927
5265
  }
4928
- fs16.writeFileSync(schemaFilePath, updated, "utf-8");
5266
+ fs18.writeFileSync(schemaFilePath, updated, "utf-8");
4929
5267
  files.push(schemaDir);
4930
5268
  return {
4931
5269
  files,
@@ -4935,12 +5273,12 @@ ${junctionDefs[i]}`;
4935
5273
  }
4936
5274
 
4937
5275
  // src/generators/edit-page.ts
4938
- import fs17 from "fs";
4939
- import path17 from "path";
5276
+ import fs19 from "fs";
5277
+ import path19 from "path";
4940
5278
  function generateEditPage(schema, cwd, pagesDir, options = {}) {
4941
- const editDir = path17.join(cwd, pagesDir, schema.name, "[id]", "edit");
4942
- const pageFilePath = path17.join(editDir, "page.tsx");
4943
- if (fs17.existsSync(pageFilePath) && !options.force) {
5279
+ const editDir = path19.join(cwd, pagesDir, schema.name, "[id]", "edit");
5280
+ const pageFilePath = path19.join(editDir, "page.tsx");
5281
+ if (fs19.existsSync(pageFilePath) && !options.force) {
4944
5282
  return { files: [] };
4945
5283
  }
4946
5284
  const singular = singularize(schema.name);
@@ -4979,18 +5317,18 @@ export default async function Edit${Singular}Page({ params }: PageProps) {
4979
5317
  )
4980
5318
  }
4981
5319
  `;
4982
- if (!fs17.existsSync(editDir)) {
4983
- fs17.mkdirSync(editDir, { recursive: true });
5320
+ if (!fs19.existsSync(editDir)) {
5321
+ fs19.mkdirSync(editDir, { recursive: true });
4984
5322
  }
4985
- fs17.writeFileSync(pageFilePath, content, "utf-8");
5323
+ fs19.writeFileSync(pageFilePath, content, "utf-8");
4986
5324
  return {
4987
- files: [path17.join(pagesDir, schema.name, "[id]", "edit", "page.tsx")]
5325
+ files: [path19.join(pagesDir, schema.name, "[id]", "edit", "page.tsx")]
4988
5326
  };
4989
5327
  }
4990
5328
 
4991
5329
  // src/generators/form/form-entity.ts
4992
- import fs18 from "fs";
4993
- import path18 from "path";
5330
+ import fs20 from "fs";
5331
+ import path20 from "path";
4994
5332
 
4995
5333
  // src/generators/form/zod-schema.ts
4996
5334
  function getFormFieldType(field) {
@@ -5788,7 +6126,7 @@ function generateDefaultValue(f) {
5788
6126
  }
5789
6127
  return ` ${f.name}: initialData?.${f.name} ?? ''`;
5790
6128
  }
5791
- function buildZodFields(flatFields) {
6129
+ function buildZodFields2(flatFields) {
5792
6130
  return flatFields.filter((f) => f.type !== "tabs").flatMap((f) => {
5793
6131
  const defs = [];
5794
6132
  const zodType = getZodType(f);
@@ -5800,7 +6138,7 @@ function buildZodFields(flatFields) {
5800
6138
  return defs;
5801
6139
  }).join(",\n");
5802
6140
  }
5803
- function buildDefaultValues(flatFields) {
6141
+ function buildDefaultValues2(flatFields) {
5804
6142
  return flatFields.filter((f) => f.type !== "tabs").flatMap((f) => {
5805
6143
  const defs = [generateDefaultValue(f)];
5806
6144
  if (f.hasIcon) defs.push(` ${f.name}Icon: initialData?.${f.name}Icon ?? ''`);
@@ -5887,9 +6225,9 @@ function buildUiImports(ctx) {
5887
6225
 
5888
6226
  // src/generators/form/form-entity.ts
5889
6227
  function generateForm(schema, cwd, pagesDir, options = {}) {
5890
- const entityDir = path18.join(cwd, pagesDir, schema.name);
5891
- const formFilePath = path18.join(entityDir, `${schema.name}-form.tsx`);
5892
- if (fs18.existsSync(formFilePath) && !options.force) {
6228
+ const entityDir = path20.join(cwd, pagesDir, schema.name);
6229
+ const formFilePath = path20.join(entityDir, `${schema.name}-form.tsx`);
6230
+ if (fs20.existsSync(formFilePath) && !options.force) {
5893
6231
  return { files: [] };
5894
6232
  }
5895
6233
  const singular = singularize(schema.name);
@@ -5943,8 +6281,8 @@ function generateForm(schema, cwd, pagesDir, options = {}) {
5943
6281
  const hasList = hasFieldType(schema.fields, "list");
5944
6282
  const hasNestedList = listFieldsWithNested.length > 0;
5945
6283
  const hasSimpleList = hasList && flatFields.some((f) => f.type === "list" && (!f.fields || f.fields.length === 0));
5946
- const zodFields = buildZodFields(flatFields);
5947
- const defaultValues = buildDefaultValues(flatFields);
6284
+ const zodFields = buildZodFields2(flatFields);
6285
+ const defaultValues = buildDefaultValues2(flatFields);
5948
6286
  const formFieldsJSX = allFormFields.filter((f) => !(hasDraft && f.name === "published")).map((f) => {
5949
6287
  if (f.type === "tabs" && f.tabs) {
5950
6288
  const tabsList = f.tabs.map((t) => ` <TabsTrigger value="${t.name}">${t.label}</TabsTrigger>`).join("\n");
@@ -6145,22 +6483,22 @@ ${hasDraft ? ` <Button
6145
6483
  )
6146
6484
  }
6147
6485
  `;
6148
- if (!fs18.existsSync(entityDir)) {
6149
- fs18.mkdirSync(entityDir, { recursive: true });
6486
+ if (!fs20.existsSync(entityDir)) {
6487
+ fs20.mkdirSync(entityDir, { recursive: true });
6150
6488
  }
6151
- fs18.writeFileSync(formFilePath, content, "utf-8");
6489
+ fs20.writeFileSync(formFilePath, content, "utf-8");
6152
6490
  return {
6153
- files: [path18.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6491
+ files: [path20.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6154
6492
  };
6155
6493
  }
6156
6494
 
6157
6495
  // src/generators/form/form-single.ts
6158
- import fs19 from "fs";
6159
- import path19 from "path";
6496
+ import fs21 from "fs";
6497
+ import path21 from "path";
6160
6498
  function generateSingleForm(schema, cwd, pagesDir, options = {}) {
6161
- const entityDir = path19.join(cwd, pagesDir, schema.name);
6162
- const formFilePath = path19.join(entityDir, `${schema.name}-form.tsx`);
6163
- if (fs19.existsSync(formFilePath) && !options.force) {
6499
+ const entityDir = path21.join(cwd, pagesDir, schema.name);
6500
+ const formFilePath = path21.join(entityDir, `${schema.name}-form.tsx`);
6501
+ if (fs21.existsSync(formFilePath) && !options.force) {
6164
6502
  return { files: [] };
6165
6503
  }
6166
6504
  const singular = singularize(schema.name);
@@ -6212,8 +6550,8 @@ function generateSingleForm(schema, cwd, pagesDir, options = {}) {
6212
6550
  const hasList = hasFieldType(schema.fields, "list");
6213
6551
  const hasNestedList = listFieldsWithNested.length > 0;
6214
6552
  const hasSimpleList = hasList && flatFields.some((f) => f.type === "list" && (!f.fields || f.fields.length === 0));
6215
- const zodFields = buildZodFields(flatFields);
6216
- const defaultValues = buildDefaultValues(flatFields);
6553
+ const zodFields = buildZodFields2(flatFields);
6554
+ const defaultValues = buildDefaultValues2(flatFields);
6217
6555
  const formFieldsJSX = allFormFields.map((f) => {
6218
6556
  if (f.type === "tabs" && f.tabs) {
6219
6557
  const tabsList = f.tabs.map((t) => ` <TabsTrigger value="${t.name}">${t.label}</TabsTrigger>`).join("\n");
@@ -6363,21 +6701,21 @@ ${formFieldsJSX}
6363
6701
  )
6364
6702
  }
6365
6703
  `;
6366
- if (!fs19.existsSync(entityDir)) {
6367
- fs19.mkdirSync(entityDir, { recursive: true });
6704
+ if (!fs21.existsSync(entityDir)) {
6705
+ fs21.mkdirSync(entityDir, { recursive: true });
6368
6706
  }
6369
- fs19.writeFileSync(formFilePath, content, "utf-8");
6707
+ fs21.writeFileSync(formFilePath, content, "utf-8");
6370
6708
  return {
6371
- files: [path19.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6709
+ files: [path21.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6372
6710
  };
6373
6711
  }
6374
6712
 
6375
6713
  // src/generators/hook.ts
6376
- import fs20 from "fs";
6377
- import path20 from "path";
6714
+ import fs22 from "fs";
6715
+ import path22 from "path";
6378
6716
  function generateHook(schema, cwd, hooksDir, options = {}) {
6379
6717
  const hookFileName = `use-${schema.name}.ts`;
6380
- const hookFilePath = path20.join(cwd, hooksDir, hookFileName);
6718
+ const hookFilePath = path22.join(cwd, hooksDir, hookFileName);
6381
6719
  const singular = singularize(schema.name);
6382
6720
  const plural = pluralize(schema.name);
6383
6721
  const Singular = toPascalCase(singular);
@@ -6387,7 +6725,7 @@ function generateHook(schema, cwd, hooksDir, options = {}) {
6387
6725
  const hasHtmlOutput = dbFields.some(
6388
6726
  (f) => (f.type === "richtext" || f.type === "markdown") && f.output === "html"
6389
6727
  );
6390
- if (fs20.existsSync(hookFilePath) && !options.force) {
6728
+ if (fs22.existsSync(hookFilePath) && !options.force) {
6391
6729
  return { files: [], hookName: `use${Plural}` };
6392
6730
  }
6393
6731
  const hasFilters = schema.filters && schema.filters.length > 0;
@@ -6462,22 +6800,22 @@ export function use${Plural}(
6462
6800
  }
6463
6801
  ${singularHook}${slugHook}${distinctHooks}
6464
6802
  `;
6465
- const dir = path20.dirname(hookFilePath);
6466
- if (!fs20.existsSync(dir)) {
6467
- fs20.mkdirSync(dir, { recursive: true });
6803
+ const dir = path22.dirname(hookFilePath);
6804
+ if (!fs22.existsSync(dir)) {
6805
+ fs22.mkdirSync(dir, { recursive: true });
6468
6806
  }
6469
- fs20.writeFileSync(hookFilePath, content, "utf-8");
6807
+ fs22.writeFileSync(hookFilePath, content, "utf-8");
6470
6808
  return {
6471
- files: [path20.join(hooksDir, hookFileName)],
6809
+ files: [path22.join(hooksDir, hookFileName)],
6472
6810
  hookName: `use${Plural}`
6473
6811
  };
6474
6812
  }
6475
6813
  function generateSingleHook(schema, cwd, hooksDir, options = {}) {
6476
6814
  const hookFileName = `use-${schema.name}.ts`;
6477
- const hookFilePath = path20.join(cwd, hooksDir, hookFileName);
6815
+ const hookFilePath = path22.join(cwd, hooksDir, hookFileName);
6478
6816
  const singular = singularize(schema.name);
6479
6817
  const Singular = toPascalCase(singular);
6480
- if (fs20.existsSync(hookFilePath) && !options.force) {
6818
+ if (fs22.existsSync(hookFilePath) && !options.force) {
6481
6819
  return { files: [], hookName: `use${Singular}` };
6482
6820
  }
6483
6821
  const content = `import {
@@ -6494,20 +6832,20 @@ export function use${Singular}(): UseQueryResult<${Singular}Data | null, Error>
6494
6832
  })
6495
6833
  }
6496
6834
  `;
6497
- const dir = path20.dirname(hookFilePath);
6498
- if (!fs20.existsSync(dir)) {
6499
- fs20.mkdirSync(dir, { recursive: true });
6835
+ const dir = path22.dirname(hookFilePath);
6836
+ if (!fs22.existsSync(dir)) {
6837
+ fs22.mkdirSync(dir, { recursive: true });
6500
6838
  }
6501
- fs20.writeFileSync(hookFilePath, content, "utf-8");
6839
+ fs22.writeFileSync(hookFilePath, content, "utf-8");
6502
6840
  return {
6503
- files: [path20.join(hooksDir, hookFileName)],
6841
+ files: [path22.join(hooksDir, hookFileName)],
6504
6842
  hookName: `use${Singular}`
6505
6843
  };
6506
6844
  }
6507
6845
 
6508
6846
  // src/generators/navigation.ts
6509
- import fs21 from "fs";
6510
- import path21 from "path";
6847
+ import fs23 from "fs";
6848
+ import path23 from "path";
6511
6849
  function parseNavigationFile2(content) {
6512
6850
  const iconImportMatch = content.match(/import\s*\{([^}]+)\}\s*from\s*['"]lucide-react['"]/);
6513
6851
  const iconImports = iconImportMatch ? iconImportMatch[1].split(",").map((s) => s.trim()).filter((s) => s && s !== "LucideIcon") : [];
@@ -6610,14 +6948,14 @@ function appendItem2(lines, item, isLast) {
6610
6948
  lines.push(` }${isLast ? "" : ","}`);
6611
6949
  }
6612
6950
  function updateNavigation(schema, cwd, cmsDir, options = {}) {
6613
- const navFilePath = path21.join(cwd, cmsDir, "data", "navigation.ts");
6951
+ const navFilePath = path23.join(cwd, cmsDir, "data", "navigation.ts");
6614
6952
  if (schema.name === "settings") {
6615
6953
  return { files: [] };
6616
6954
  }
6617
6955
  let items = [];
6618
6956
  let iconImports = [];
6619
- if (fs21.existsSync(navFilePath)) {
6620
- const content = fs21.readFileSync(navFilePath, "utf-8");
6957
+ if (fs23.existsSync(navFilePath)) {
6958
+ const content = fs23.readFileSync(navFilePath, "utf-8");
6621
6959
  const parsed = parseNavigationFile2(content);
6622
6960
  items = parsed.items;
6623
6961
  iconImports = parsed.iconImports;
@@ -6654,24 +6992,24 @@ function updateNavigation(schema, cwd, cmsDir, options = {}) {
6654
6992
  iconImports.push(schema.icon);
6655
6993
  }
6656
6994
  iconImports.sort();
6657
- const dir = path21.dirname(navFilePath);
6658
- if (!fs21.existsSync(dir)) {
6659
- fs21.mkdirSync(dir, { recursive: true });
6995
+ const dir = path23.dirname(navFilePath);
6996
+ if (!fs23.existsSync(dir)) {
6997
+ fs23.mkdirSync(dir, { recursive: true });
6660
6998
  }
6661
6999
  const code = generateNavigationCode2(items, iconImports);
6662
- fs21.writeFileSync(navFilePath, code, "utf-8");
7000
+ fs23.writeFileSync(navFilePath, code, "utf-8");
6663
7001
  return {
6664
- files: [path21.join(cmsDir, "data", "navigation.ts")]
7002
+ files: [path23.join(cmsDir, "data", "navigation.ts")]
6665
7003
  };
6666
7004
  }
6667
7005
 
6668
7006
  // src/generators/page.ts
6669
- import fs22 from "fs";
6670
- import path22 from "path";
7007
+ import fs24 from "fs";
7008
+ import path24 from "path";
6671
7009
  function generatePage2(schema, cwd, pagesDir, options = {}) {
6672
- const entityDir = path22.join(cwd, pagesDir, schema.name);
6673
- const pageFilePath = path22.join(entityDir, "page.tsx");
6674
- if (fs22.existsSync(pageFilePath) && !options.force) {
7010
+ const entityDir = path24.join(cwd, pagesDir, schema.name);
7011
+ const pageFilePath = path24.join(entityDir, "page.tsx");
7012
+ if (fs24.existsSync(pageFilePath) && !options.force) {
6675
7013
  return { files: [] };
6676
7014
  }
6677
7015
  const plural = pluralize(schema.name);
@@ -6697,27 +7035,27 @@ export default function ${Plural}Page() {
6697
7035
  )
6698
7036
  }
6699
7037
  `;
6700
- if (!fs22.existsSync(entityDir)) {
6701
- fs22.mkdirSync(entityDir, { recursive: true });
7038
+ if (!fs24.existsSync(entityDir)) {
7039
+ fs24.mkdirSync(entityDir, { recursive: true });
6702
7040
  }
6703
- fs22.writeFileSync(pageFilePath, content, "utf-8");
7041
+ fs24.writeFileSync(pageFilePath, content, "utf-8");
6704
7042
  return {
6705
- files: [path22.join(pagesDir, schema.name, "page.tsx")]
7043
+ files: [path24.join(pagesDir, schema.name, "page.tsx")]
6706
7044
  };
6707
7045
  }
6708
7046
 
6709
7047
  // src/generators/page-content.ts
6710
- import fs23 from "fs";
6711
- import path23 from "path";
7048
+ import fs25 from "fs";
7049
+ import path25 from "path";
6712
7050
  function generatePageContent2(schema, cwd, pagesDir, options = {}) {
6713
- const entityDir = path23.join(cwd, pagesDir, schema.name);
7051
+ const entityDir = path25.join(cwd, pagesDir, schema.name);
6714
7052
  const singular = singularize(schema.name);
6715
7053
  const plural = pluralize(schema.name);
6716
7054
  const Singular = toPascalCase(singular);
6717
7055
  const Plural = toPascalCase(plural);
6718
7056
  const fileName = `${toKebabCase(plural)}-page-content.tsx`;
6719
- const filePath = path23.join(entityDir, fileName);
6720
- if (fs23.existsSync(filePath) && !options.force) {
7057
+ const filePath = path25.join(entityDir, fileName);
7058
+ if (fs25.existsSync(filePath) && !options.force) {
6721
7059
  return { files: [] };
6722
7060
  }
6723
7061
  const hasCreate = schema.actions?.create ?? false;
@@ -6970,22 +7308,22 @@ ${searchLogic}${deleteLogic}
6970
7308
  )
6971
7309
  }
6972
7310
  `;
6973
- if (!fs23.existsSync(entityDir)) {
6974
- fs23.mkdirSync(entityDir, { recursive: true });
7311
+ if (!fs25.existsSync(entityDir)) {
7312
+ fs25.mkdirSync(entityDir, { recursive: true });
6975
7313
  }
6976
- fs23.writeFileSync(filePath, content, "utf-8");
7314
+ fs25.writeFileSync(filePath, content, "utf-8");
6977
7315
  return {
6978
- files: [path23.join(pagesDir, schema.name, fileName)]
7316
+ files: [path25.join(pagesDir, schema.name, fileName)]
6979
7317
  };
6980
7318
  }
6981
7319
 
6982
7320
  // src/generators/single-page.ts
6983
- import fs24 from "fs";
6984
- import path24 from "path";
7321
+ import fs26 from "fs";
7322
+ import path26 from "path";
6985
7323
  function generateSinglePage(schema, cwd, pagesDir, options = {}) {
6986
- const entityDir = path24.join(cwd, pagesDir, schema.name);
6987
- const pageFilePath = path24.join(entityDir, "page.tsx");
6988
- if (fs24.existsSync(pageFilePath) && !options.force) {
7324
+ const entityDir = path26.join(cwd, pagesDir, schema.name);
7325
+ const pageFilePath = path26.join(entityDir, "page.tsx");
7326
+ if (fs26.existsSync(pageFilePath) && !options.force) {
6989
7327
  return { files: [] };
6990
7328
  }
6991
7329
  const singular = singularize(schema.name);
@@ -7008,20 +7346,20 @@ export default async function ${PageName}Page() {
7008
7346
  )
7009
7347
  }
7010
7348
  `;
7011
- if (!fs24.existsSync(entityDir)) {
7012
- fs24.mkdirSync(entityDir, { recursive: true });
7349
+ if (!fs26.existsSync(entityDir)) {
7350
+ fs26.mkdirSync(entityDir, { recursive: true });
7013
7351
  }
7014
- fs24.writeFileSync(pageFilePath, content, "utf-8");
7352
+ fs26.writeFileSync(pageFilePath, content, "utf-8");
7015
7353
  return {
7016
- files: [path24.join(pagesDir, schema.name, "page.tsx")]
7354
+ files: [path26.join(pagesDir, schema.name, "page.tsx")]
7017
7355
  };
7018
7356
  }
7019
7357
 
7020
7358
  // src/generators/table.ts
7021
- import fs25 from "fs";
7022
- import path25 from "path";
7359
+ import fs27 from "fs";
7360
+ import path27 from "path";
7023
7361
  function generateTable2(schema, cwd, pagesDir, options = {}) {
7024
- const entityDir = path25.join(cwd, pagesDir, schema.name);
7362
+ const entityDir = path27.join(cwd, pagesDir, schema.name);
7025
7363
  const singular = singularize(schema.name);
7026
7364
  const plural = pluralize(schema.name);
7027
7365
  const Singular = toPascalCase(singular);
@@ -7029,8 +7367,8 @@ function generateTable2(schema, cwd, pagesDir, options = {}) {
7029
7367
  const camelPlural = toCamelCase(plural);
7030
7368
  const camelSingular = toCamelCase(singular);
7031
7369
  const tableFileName = `${toKebabCase(plural)}-table.tsx`;
7032
- const tableFilePath = path25.join(entityDir, tableFileName);
7033
- if (fs25.existsSync(tableFilePath) && !options.force) {
7370
+ const tableFilePath = path27.join(entityDir, tableFileName);
7371
+ if (fs27.existsSync(tableFilePath) && !options.force) {
7034
7372
  return { files: [] };
7035
7373
  }
7036
7374
  const hasFilters = schema.filters && schema.filters.length > 0;
@@ -7394,12 +7732,12 @@ export function ${Plural}Table<TValue>({ columns, selectedIds, setSelectedIds, $
7394
7732
  )
7395
7733
  }
7396
7734
  `;
7397
- if (!fs25.existsSync(entityDir)) {
7398
- fs25.mkdirSync(entityDir, { recursive: true });
7735
+ if (!fs27.existsSync(entityDir)) {
7736
+ fs27.mkdirSync(entityDir, { recursive: true });
7399
7737
  }
7400
- fs25.writeFileSync(tableFilePath, content, "utf-8");
7738
+ fs27.writeFileSync(tableFilePath, content, "utf-8");
7401
7739
  return {
7402
- files: [path25.join(pagesDir, schema.name, tableFileName)]
7740
+ files: [path27.join(pagesDir, schema.name, tableFileName)]
7403
7741
  };
7404
7742
  }
7405
7743
 
@@ -7557,13 +7895,13 @@ function runSinglePipeline(schema, cwd, config, options = {}) {
7557
7895
 
7558
7896
  // src/generators/post-generate.ts
7559
7897
  import { execFileSync as execFileSync2 } from "child_process";
7560
- import fs27 from "fs";
7561
- import path27 from "path";
7898
+ import fs29 from "fs";
7899
+ import path29 from "path";
7562
7900
 
7563
7901
  // src/utils/package-manager.ts
7564
7902
  import { execFileSync } from "child_process";
7565
- import fs26 from "fs";
7566
- import path26 from "path";
7903
+ import fs28 from "fs";
7904
+ import path28 from "path";
7567
7905
  var LOCKFILE_MAP = {
7568
7906
  "pnpm-lock.yaml": "pnpm",
7569
7907
  "package-lock.json": "npm",
@@ -7572,18 +7910,18 @@ var LOCKFILE_MAP = {
7572
7910
  "bun.lock": "bun"
7573
7911
  };
7574
7912
  function detectPackageManager(cwd) {
7575
- let dir = path26.resolve(cwd);
7576
- const root = path26.parse(dir).root;
7913
+ let dir = path28.resolve(cwd);
7914
+ const root = path28.parse(dir).root;
7577
7915
  while (dir !== root) {
7578
7916
  for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {
7579
- if (fs26.existsSync(path26.join(dir, lockfile))) {
7917
+ if (fs28.existsSync(path28.join(dir, lockfile))) {
7580
7918
  return pm;
7581
7919
  }
7582
7920
  }
7583
- const pkgPath = path26.join(dir, "package.json");
7584
- if (fs26.existsSync(pkgPath)) {
7921
+ const pkgPath = path28.join(dir, "package.json");
7922
+ if (fs28.existsSync(pkgPath)) {
7585
7923
  try {
7586
- const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
7924
+ const pkg = JSON.parse(fs28.readFileSync(pkgPath, "utf-8"));
7587
7925
  if (typeof pkg.packageManager === "string") {
7588
7926
  const name = pkg.packageManager.split("@")[0];
7589
7927
  if (name === "pnpm" || name === "npm" || name === "yarn" || name === "bun") {
@@ -7593,7 +7931,7 @@ function detectPackageManager(cwd) {
7593
7931
  } catch {
7594
7932
  }
7595
7933
  }
7596
- dir = path26.dirname(dir);
7934
+ dir = path28.dirname(dir);
7597
7935
  }
7598
7936
  return "npm";
7599
7937
  }
@@ -7624,9 +7962,9 @@ function createNextAppCommand(pm) {
7624
7962
 
7625
7963
  // src/generators/post-generate.ts
7626
7964
  function loadEnvFile(cwd) {
7627
- const envPath = path27.join(cwd, ".env.local");
7628
- if (!fs27.existsSync(envPath)) return;
7629
- const content = fs27.readFileSync(envPath, "utf-8");
7965
+ const envPath = path29.join(cwd, ".env.local");
7966
+ if (!fs29.existsSync(envPath)) return;
7967
+ const content = fs29.readFileSync(envPath, "utf-8");
7630
7968
  for (const line of content.split("\n")) {
7631
7969
  const trimmed = line.trim();
7632
7970
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -7656,10 +7994,10 @@ function runPmScript(pm, script, cwd) {
7656
7994
  }
7657
7995
  }
7658
7996
  function hasPkgScript(cwd, script) {
7659
- const pkgPath = path27.join(cwd, "package.json");
7660
- if (!fs27.existsSync(pkgPath)) return false;
7997
+ const pkgPath = path29.join(cwd, "package.json");
7998
+ if (!fs29.existsSync(pkgPath)) return false;
7661
7999
  try {
7662
- const pkg = JSON.parse(fs27.readFileSync(pkgPath, "utf-8"));
8000
+ const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf-8"));
7663
8001
  const scripts = pkg.scripts;
7664
8002
  return !!scripts?.[script];
7665
8003
  } catch {
@@ -7686,7 +8024,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7686
8024
  console.log(ok ? " Database schema synced" : " Database push failed (run db:push manually)");
7687
8025
  } else {
7688
8026
  console.log("\n Running drizzle-kit push...");
7689
- const drizzleBin = path27.join(cwd, "node_modules", ".bin", "drizzle-kit");
8027
+ const drizzleBin = path29.join(cwd, "node_modules", ".bin", "drizzle-kit");
7690
8028
  try {
7691
8029
  execFileSync2(drizzleBin, ["push", "--force"], { cwd, stdio: "inherit" });
7692
8030
  result.dbPush = "success";
@@ -7705,7 +8043,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7705
8043
  result.lintFix = ok ? "success" : "failed";
7706
8044
  console.log(ok ? " Code formatted" : " Lint fix had issues (run lint:fix manually)");
7707
8045
  } else {
7708
- const biomeBin = path27.join(cwd, "node_modules", ".bin", "biome");
8046
+ const biomeBin = path29.join(cwd, "node_modules", ".bin", "biome");
7709
8047
  try {
7710
8048
  execFileSync2(biomeBin, ["check", "--write", "."], { cwd, stdio: "pipe" });
7711
8049
  result.lintFix = "success";
@@ -7728,7 +8066,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7728
8066
  // src/commands/generate.ts
7729
8067
  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(
7730
8068
  async (schemaName, options) => {
7731
- const cwd = options.cwd ? path28.resolve(options.cwd) : process.cwd();
8069
+ const cwd = options.cwd ? path30.resolve(options.cwd) : process.cwd();
7732
8070
  console.log("\n BetterStart Generator\n");
7733
8071
  let config;
7734
8072
  try {
@@ -7737,7 +8075,7 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7737
8075
  console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`);
7738
8076
  process.exit(1);
7739
8077
  }
7740
- const schemasDir = path28.join(cwd, config.paths?.schemas ?? "./cms/schemas");
8078
+ const schemasDir = path30.join(cwd, config.paths?.schemas ?? "./cms/schemas");
7741
8079
  console.log(` Project root: ${cwd}`);
7742
8080
  console.log(` Loading schema: ${schemaName}.json
7743
8081
  `);
@@ -7749,7 +8087,7 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7749
8087
  console.error(` ${err.message}`);
7750
8088
  console.error(
7751
8089
  `
7752
- Create a schema file at: ${path28.join(schemasDir, `${schemaName}.json`)}`
8090
+ Create a schema file at: ${path30.join(schemasDir, `${schemaName}.json`)}`
7753
8091
  );
7754
8092
  } else {
7755
8093
  console.error(
@@ -7842,8 +8180,8 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7842
8180
 
7843
8181
  // src/commands/init.ts
7844
8182
  import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
7845
- import fs38 from "fs";
7846
- import path43 from "path";
8183
+ import fs40 from "fs";
8184
+ import path45 from "path";
7847
8185
  import * as p4 from "@clack/prompts";
7848
8186
  import { Command as Command3 } from "commander";
7849
8187
  import pc2 from "picocolors";
@@ -7986,21 +8324,21 @@ async function promptProject(defaultName) {
7986
8324
  }
7987
8325
 
7988
8326
  // src/init/scaffolders/api-routes.ts
7989
- import path30 from "path";
8327
+ import path32 from "path";
7990
8328
 
7991
8329
  // src/utils/fs.ts
7992
- import fs28 from "fs";
7993
- import path29 from "path";
8330
+ import fs30 from "fs";
8331
+ import path31 from "path";
7994
8332
  import fse from "fs-extra";
7995
8333
  function ensureDir(dirPath) {
7996
8334
  fse.ensureDirSync(dirPath);
7997
8335
  }
7998
8336
  function safeWriteFile(filePath, content, force = false) {
7999
- if (!force && fs28.existsSync(filePath)) {
8337
+ if (!force && fs30.existsSync(filePath)) {
8000
8338
  return false;
8001
8339
  }
8002
- ensureDir(path29.dirname(filePath));
8003
- fs28.writeFileSync(filePath, content, "utf-8");
8340
+ ensureDir(path31.dirname(filePath));
8341
+ fs30.writeFileSync(filePath, content, "utf-8");
8004
8342
  return true;
8005
8343
  }
8006
8344
 
@@ -8094,21 +8432,21 @@ export async function POST(request: NextRequest) {
8094
8432
  // src/init/scaffolders/api-routes.ts
8095
8433
  function scaffoldApiRoutes({ cwd, config }) {
8096
8434
  const created = [];
8097
- const apiDir = path30.resolve(cwd, config.paths.api);
8435
+ const apiDir = path32.resolve(cwd, config.paths.api);
8098
8436
  function write(relPath, content) {
8099
- const fullPath = path30.join(apiDir, relPath);
8100
- ensureDir(path30.dirname(fullPath));
8437
+ const fullPath = path32.join(apiDir, relPath);
8438
+ ensureDir(path32.dirname(fullPath));
8101
8439
  if (safeWriteFile(fullPath, content)) {
8102
- created.push(path30.join(config.paths.api, relPath));
8440
+ created.push(path32.join(config.paths.api, relPath));
8103
8441
  }
8104
8442
  }
8105
- write(path30.join("auth", "[...all]", "route.ts"), authRouteTemplate());
8106
- write(path30.join("upload", "route.ts"), uploadRouteTemplate());
8443
+ write(path32.join("auth", "[...all]", "route.ts"), authRouteTemplate());
8444
+ write(path32.join("upload", "route.ts"), uploadRouteTemplate());
8107
8445
  return created;
8108
8446
  }
8109
8447
 
8110
8448
  // src/init/scaffolders/auth.ts
8111
- import path31 from "path";
8449
+ import path33 from "path";
8112
8450
 
8113
8451
  // src/init/templates/lib/auth/auth.ts
8114
8452
  function authTemplate() {
@@ -8227,11 +8565,11 @@ export async function requireRole(allowedRoles: UserRole[]): Promise<User> {
8227
8565
  // src/init/scaffolders/auth.ts
8228
8566
  function scaffoldAuth({ cwd, config }) {
8229
8567
  const created = [];
8230
- const authDir = path31.resolve(cwd, config.paths.cms, "lib", "auth");
8568
+ const authDir = path33.resolve(cwd, config.paths.cms, "lib", "auth");
8231
8569
  function write(filename, content) {
8232
- const fullPath = path31.join(authDir, filename);
8570
+ const fullPath = path33.join(authDir, filename);
8233
8571
  if (safeWriteFile(fullPath, content)) {
8234
- created.push(path31.join(config.paths.cms, "lib", "auth", filename));
8572
+ created.push(path33.join(config.paths.cms, "lib", "auth", filename));
8235
8573
  }
8236
8574
  }
8237
8575
  write("auth.ts", authTemplate());
@@ -8241,51 +8579,51 @@ function scaffoldAuth({ cwd, config }) {
8241
8579
  }
8242
8580
 
8243
8581
  // src/init/scaffolders/base.ts
8244
- import fs29 from "fs";
8245
- import path32 from "path";
8582
+ import fs31 from "fs";
8583
+ import path34 from "path";
8246
8584
  function scaffoldBase({ cwd, config }) {
8247
8585
  const created = [];
8248
8586
  const cmsDirs = [
8249
8587
  config.paths.cms,
8250
8588
  config.paths.schemas,
8251
- path32.join(config.paths.cms, "db"),
8252
- path32.join(config.paths.cms, "db", "migrations"),
8253
- path32.join(config.paths.cms, "lib", "auth"),
8254
- path32.join(config.paths.cms, "lib", "actions"),
8255
- path32.join(config.paths.cms, "lib", "cache"),
8256
- path32.join(config.paths.cms, "lib", "markdown"),
8257
- path32.join(config.paths.cms, "lib", "emails"),
8258
- path32.join(config.paths.cms, "lib"),
8259
- path32.join(config.paths.cms, "hooks"),
8260
- path32.join(config.paths.cms, "components", "ui"),
8261
- path32.join(config.paths.cms, "components", "form"),
8262
- path32.join(config.paths.cms, "components", "data-table"),
8263
- path32.join(config.paths.cms, "components", "layout"),
8264
- path32.join(config.paths.cms, "components", "shared"),
8265
- path32.join(config.paths.cms, "types"),
8266
- path32.join(config.paths.cms, "utils"),
8267
- path32.join(config.paths.cms, "data")
8589
+ path34.join(config.paths.cms, "db"),
8590
+ path34.join(config.paths.cms, "db", "migrations"),
8591
+ path34.join(config.paths.cms, "lib", "auth"),
8592
+ path34.join(config.paths.cms, "lib", "actions"),
8593
+ path34.join(config.paths.cms, "lib", "cache"),
8594
+ path34.join(config.paths.cms, "lib", "markdown"),
8595
+ path34.join(config.paths.cms, "lib", "emails"),
8596
+ path34.join(config.paths.cms, "lib"),
8597
+ path34.join(config.paths.cms, "hooks"),
8598
+ path34.join(config.paths.cms, "components", "ui"),
8599
+ path34.join(config.paths.cms, "components", "form"),
8600
+ path34.join(config.paths.cms, "components", "data-table"),
8601
+ path34.join(config.paths.cms, "components", "layout"),
8602
+ path34.join(config.paths.cms, "components", "shared"),
8603
+ path34.join(config.paths.cms, "types"),
8604
+ path34.join(config.paths.cms, "utils"),
8605
+ path34.join(config.paths.cms, "data")
8268
8606
  ];
8269
8607
  for (const dir of cmsDirs) {
8270
- ensureDir(path32.resolve(cwd, dir));
8608
+ ensureDir(path34.resolve(cwd, dir));
8271
8609
  }
8272
8610
  const appDirs = [config.paths.pages, config.paths.login, config.paths.api];
8273
8611
  for (const dir of appDirs) {
8274
- ensureDir(path32.resolve(cwd, dir));
8612
+ ensureDir(path34.resolve(cwd, dir));
8275
8613
  }
8276
8614
  const configContent = generateConfigFile(config);
8277
- if (safeWriteFile(path32.resolve(cwd, "cms.config.ts"), configContent)) {
8615
+ if (safeWriteFile(path34.resolve(cwd, "cms.config.ts"), configContent)) {
8278
8616
  created.push("cms.config.ts");
8279
8617
  }
8280
8618
  const cmsDoc = generateCmsDoc(config, {});
8281
- if (safeWriteFile(path32.resolve(cwd, "CMS.md"), cmsDoc)) {
8619
+ if (safeWriteFile(path34.resolve(cwd, "CMS.md"), cmsDoc)) {
8282
8620
  created.push("CMS.md");
8283
8621
  }
8284
8622
  return created;
8285
8623
  }
8286
8624
  function regenerateCmsDoc(cwd, config, options) {
8287
8625
  const content = generateCmsDoc(config, options);
8288
- fs29.writeFileSync(path32.resolve(cwd, "CMS.md"), content, "utf-8");
8626
+ fs31.writeFileSync(path34.resolve(cwd, "CMS.md"), content, "utf-8");
8289
8627
  }
8290
8628
  function generateConfigFile(config) {
8291
8629
  return `import { defineConfig } from '@betterstart/cli'
@@ -8439,8 +8777,8 @@ Edit \`cms.config.ts\` to customize paths, database provider, and features.`);
8439
8777
  }
8440
8778
 
8441
8779
  // src/init/scaffolders/biome.ts
8442
- import fs30 from "fs";
8443
- import path33 from "path";
8780
+ import fs32 from "fs";
8781
+ import path35 from "path";
8444
8782
  function scaffoldBiome(cwd, linter) {
8445
8783
  if (linter.type !== "none") {
8446
8784
  return {
@@ -8448,8 +8786,8 @@ function scaffoldBiome(cwd, linter) {
8448
8786
  skippedReason: `${linter.type} already configured (${linter.configFile})`
8449
8787
  };
8450
8788
  }
8451
- const configPath = path33.join(cwd, "biome.json");
8452
- if (fs30.existsSync(configPath)) {
8789
+ const configPath = path35.join(cwd, "biome.json");
8790
+ if (fs32.existsSync(configPath)) {
8453
8791
  return { installed: false, skippedReason: "biome.json already exists" };
8454
8792
  }
8455
8793
  const config = {
@@ -8500,52 +8838,52 @@ function scaffoldBiome(cwd, linter) {
8500
8838
  ]
8501
8839
  }
8502
8840
  };
8503
- fs30.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
8841
+ fs32.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
8504
8842
  `, "utf-8");
8505
8843
  return { installed: true, skippedReason: null };
8506
8844
  }
8507
8845
 
8508
8846
  // src/init/scaffolders/components.ts
8509
- import path35 from "path";
8510
- import fs32 from "fs-extra";
8847
+ import path37 from "path";
8848
+ import fs34 from "fs-extra";
8511
8849
 
8512
8850
  // src/utils/detect.ts
8513
- import fs31 from "fs";
8514
- import path34 from "path";
8851
+ import fs33 from "fs";
8852
+ import path36 from "path";
8515
8853
  var NEXT_CONFIG_FILES = ["next.config.ts", "next.config.js", "next.config.mjs"];
8516
8854
  function detectProjectName(cwd) {
8517
- const pkgPath = path34.join(cwd, "package.json");
8518
- if (fs31.existsSync(pkgPath)) {
8855
+ const pkgPath = path36.join(cwd, "package.json");
8856
+ if (fs33.existsSync(pkgPath)) {
8519
8857
  try {
8520
- const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
8858
+ const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
8521
8859
  if (typeof pkg.name === "string" && pkg.name.length > 0) {
8522
8860
  return formatProjectName(pkg.name);
8523
8861
  }
8524
8862
  } catch {
8525
8863
  }
8526
8864
  }
8527
- return formatProjectName(path34.basename(cwd));
8865
+ return formatProjectName(path36.basename(cwd));
8528
8866
  }
8529
8867
  function formatProjectName(name) {
8530
8868
  const base = name.includes("/") ? name.split("/").pop() : name;
8531
8869
  return base.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
8532
8870
  }
8533
8871
  function detectProject(cwd) {
8534
- const isExisting = NEXT_CONFIG_FILES.some((f) => fs31.existsSync(path34.join(cwd, f)));
8535
- const hasSrcDir = fs31.existsSync(path34.join(cwd, "src"));
8536
- const hasTypeScript = fs31.existsSync(path34.join(cwd, "tsconfig.json")) || fs31.existsSync(path34.join(cwd, "tsconfig.app.json"));
8872
+ const isExisting = NEXT_CONFIG_FILES.some((f) => fs33.existsSync(path36.join(cwd, f)));
8873
+ const hasSrcDir = fs33.existsSync(path36.join(cwd, "src"));
8874
+ const hasTypeScript = fs33.existsSync(path36.join(cwd, "tsconfig.json")) || fs33.existsSync(path36.join(cwd, "tsconfig.app.json"));
8537
8875
  const hasTailwind = detectTailwind(cwd);
8538
8876
  const linter = detectLinter(cwd);
8539
8877
  const conflicts = [];
8540
8878
  if (isExisting) {
8541
- if (fs31.existsSync(path34.join(cwd, "cms"))) {
8879
+ if (fs33.existsSync(path36.join(cwd, "cms"))) {
8542
8880
  conflicts.push("cms/ directory already exists");
8543
8881
  }
8544
- if (fs31.existsSync(path34.join(cwd, "cms.config.ts"))) {
8882
+ if (fs33.existsSync(path36.join(cwd, "cms.config.ts"))) {
8545
8883
  conflicts.push("cms.config.ts already exists");
8546
8884
  }
8547
8885
  const appBase = hasSrcDir ? "src/app" : "app";
8548
- if (fs31.existsSync(path34.join(cwd, appBase, "(cms)"))) {
8886
+ if (fs33.existsSync(path36.join(cwd, appBase, "(cms)"))) {
8549
8887
  conflicts.push(`${appBase}/(cms)/ route group already exists`);
8550
8888
  }
8551
8889
  if (hasTsconfigCmsAliases(cwd)) {
@@ -8572,19 +8910,19 @@ var ESLINT_CONFIG_FILES = [
8572
8910
  ];
8573
8911
  function detectLinter(cwd) {
8574
8912
  for (const f of BIOME_CONFIG_FILES) {
8575
- if (fs31.existsSync(path34.join(cwd, f))) {
8913
+ if (fs33.existsSync(path36.join(cwd, f))) {
8576
8914
  return { type: "biome", configFile: f };
8577
8915
  }
8578
8916
  }
8579
8917
  for (const f of ESLINT_CONFIG_FILES) {
8580
- if (fs31.existsSync(path34.join(cwd, f))) {
8918
+ if (fs33.existsSync(path36.join(cwd, f))) {
8581
8919
  return { type: "eslint", configFile: f };
8582
8920
  }
8583
8921
  }
8584
- const pkgPath = path34.join(cwd, "package.json");
8585
- if (fs31.existsSync(pkgPath)) {
8922
+ const pkgPath = path36.join(cwd, "package.json");
8923
+ if (fs33.existsSync(pkgPath)) {
8586
8924
  try {
8587
- const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
8925
+ const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
8588
8926
  if (pkg.eslintConfig) {
8589
8927
  return { type: "eslint", configFile: "package.json (eslintConfig)" };
8590
8928
  }
@@ -8595,14 +8933,14 @@ function detectLinter(cwd) {
8595
8933
  }
8596
8934
  function detectTailwind(cwd) {
8597
8935
  const cssFiles = ["globals.css", "app.css", "index.css"].flatMap((f) => [
8598
- path34.join(cwd, "src", "app", f),
8599
- path34.join(cwd, "app", f),
8600
- path34.join(cwd, "src", f),
8601
- path34.join(cwd, f)
8936
+ path36.join(cwd, "src", "app", f),
8937
+ path36.join(cwd, "app", f),
8938
+ path36.join(cwd, "src", f),
8939
+ path36.join(cwd, f)
8602
8940
  ]);
8603
8941
  for (const cssFile of cssFiles) {
8604
- if (fs31.existsSync(cssFile)) {
8605
- const content = fs31.readFileSync(cssFile, "utf-8");
8942
+ if (fs33.existsSync(cssFile)) {
8943
+ const content = fs33.readFileSync(cssFile, "utf-8");
8606
8944
  if (content.includes('@import "tailwindcss"') || content.includes("@import 'tailwindcss'") || content.includes("@theme")) {
8607
8945
  return true;
8608
8946
  }
@@ -8610,8 +8948,8 @@ function detectTailwind(cwd) {
8610
8948
  }
8611
8949
  const postcssFiles = ["postcss.config.js", "postcss.config.mjs", "postcss.config.cjs"];
8612
8950
  for (const f of postcssFiles) {
8613
- if (fs31.existsSync(path34.join(cwd, f))) {
8614
- const content = fs31.readFileSync(path34.join(cwd, f), "utf-8");
8951
+ if (fs33.existsSync(path36.join(cwd, f))) {
8952
+ const content = fs33.readFileSync(path36.join(cwd, f), "utf-8");
8615
8953
  if (content.includes("tailwindcss") || content.includes("@tailwindcss")) {
8616
8954
  return true;
8617
8955
  }
@@ -8620,20 +8958,20 @@ function detectTailwind(cwd) {
8620
8958
  return false;
8621
8959
  }
8622
8960
  function hasTsconfigCmsAliases(cwd) {
8623
- const tsconfigPath = path34.join(cwd, "tsconfig.json");
8624
- if (!fs31.existsSync(tsconfigPath)) return false;
8961
+ const tsconfigPath = path36.join(cwd, "tsconfig.json");
8962
+ if (!fs33.existsSync(tsconfigPath)) return false;
8625
8963
  try {
8626
- const content = fs31.readFileSync(tsconfigPath, "utf-8");
8964
+ const content = fs33.readFileSync(tsconfigPath, "utf-8");
8627
8965
  return content.includes("@cms/");
8628
8966
  } catch {
8629
8967
  return false;
8630
8968
  }
8631
8969
  }
8632
8970
  function hasEnvBetterstartVars(cwd) {
8633
- const envPath = path34.join(cwd, ".env.local");
8634
- if (!fs31.existsSync(envPath)) return false;
8971
+ const envPath = path36.join(cwd, ".env.local");
8972
+ if (!fs33.existsSync(envPath)) return false;
8635
8973
  try {
8636
- const content = fs31.readFileSync(envPath, "utf-8");
8974
+ const content = fs33.readFileSync(envPath, "utf-8");
8637
8975
  return content.includes("BETTERSTART_");
8638
8976
  } catch {
8639
8977
  return false;
@@ -11332,12 +11670,12 @@ export function addToMailchimpAudience(email: string): void {
11332
11670
 
11333
11671
  // src/init/scaffolders/components.ts
11334
11672
  function scaffoldComponents({ cwd, config }) {
11335
- const cms = path35.resolve(cwd, config.paths.cms);
11673
+ const cms = path37.resolve(cwd, config.paths.cms);
11336
11674
  const created = [];
11337
11675
  function write(relPath, content) {
11338
- const fullPath = path35.join(cms, relPath);
11676
+ const fullPath = path37.join(cms, relPath);
11339
11677
  if (safeWriteFile(fullPath, content)) {
11340
- created.push(path35.join(config.paths.cms, relPath));
11678
+ created.push(path37.join(config.paths.cms, relPath));
11341
11679
  }
11342
11680
  }
11343
11681
  write("cms-globals.css", cmsGlobalsCssTemplate());
@@ -11386,18 +11724,18 @@ function scaffoldComponents({ cwd, config }) {
11386
11724
  }
11387
11725
  function copyUiTemplates(cwd, config) {
11388
11726
  const created = [];
11389
- const destDir = path35.resolve(cwd, config.paths.cms, "components", "ui");
11727
+ const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui");
11390
11728
  const cliRoot = findCliRoot();
11391
- const srcDir = path35.join(cliRoot, "templates", "ui");
11392
- if (!fs32.existsSync(srcDir)) {
11729
+ const srcDir = path37.join(cliRoot, "templates", "ui");
11730
+ if (!fs34.existsSync(srcDir)) {
11393
11731
  return created;
11394
11732
  }
11395
- const files = fs32.readdirSync(srcDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
11733
+ const files = fs34.readdirSync(srcDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
11396
11734
  for (const file of files) {
11397
- const destPath = path35.join(destDir, file);
11398
- if (!fs32.existsSync(destPath)) {
11399
- fs32.copyFileSync(path35.join(srcDir, file), destPath);
11400
- created.push(path35.join(config.paths.cms, "components", "ui", file));
11735
+ const destPath = path37.join(destDir, file);
11736
+ if (!fs34.existsSync(destPath)) {
11737
+ fs34.copyFileSync(path37.join(srcDir, file), destPath);
11738
+ created.push(path37.join(config.paths.cms, "components", "ui", file));
11401
11739
  }
11402
11740
  }
11403
11741
  return created;
@@ -11405,25 +11743,25 @@ function copyUiTemplates(cwd, config) {
11405
11743
  function copyTiptapTemplates(cwd, config) {
11406
11744
  const created = [];
11407
11745
  const cliRoot = findCliRoot();
11408
- const srcDir = path35.join(cliRoot, "templates", "tiptap");
11409
- const destDir = path35.resolve(cwd, config.paths.cms, "components", "ui", "tiptap");
11410
- if (!fs32.existsSync(srcDir)) {
11746
+ const srcDir = path37.join(cliRoot, "templates", "tiptap");
11747
+ const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui", "tiptap");
11748
+ if (!fs34.existsSync(srcDir)) {
11411
11749
  return created;
11412
11750
  }
11413
11751
  copyDirRecursive(srcDir, destDir, config.paths.cms, created);
11414
11752
  return created;
11415
11753
  }
11416
11754
  function copyDirRecursive(src, dest, cmsPrefix, created) {
11417
- fs32.ensureDirSync(dest);
11418
- const entries = fs32.readdirSync(src, { withFileTypes: true });
11755
+ fs34.ensureDirSync(dest);
11756
+ const entries = fs34.readdirSync(src, { withFileTypes: true });
11419
11757
  for (const entry of entries) {
11420
- const srcPath = path35.join(src, entry.name);
11421
- const destPath = path35.join(dest, entry.name);
11758
+ const srcPath = path37.join(src, entry.name);
11759
+ const destPath = path37.join(dest, entry.name);
11422
11760
  if (entry.isDirectory()) {
11423
11761
  copyDirRecursive(srcPath, destPath, cmsPrefix, created);
11424
- } else if (!fs32.existsSync(destPath)) {
11425
- fs32.copyFileSync(srcPath, destPath);
11426
- const relFromCms = path35.relative(path35.resolve(dest, "..", "..", "..", ".."), destPath);
11762
+ } else if (!fs34.existsSync(destPath)) {
11763
+ fs34.copyFileSync(srcPath, destPath);
11764
+ const relFromCms = path37.relative(path37.resolve(dest, "..", "..", "..", ".."), destPath);
11427
11765
  created.push(relFromCms);
11428
11766
  }
11429
11767
  }
@@ -11431,35 +11769,35 @@ function copyDirRecursive(src, dest, cmsPrefix, created) {
11431
11769
  function copySchemaMetaschema(cwd, config) {
11432
11770
  const created = [];
11433
11771
  const cliRoot = findCliRoot();
11434
- const srcPath = path35.join(cliRoot, "templates", "schema.json");
11435
- const destPath = path35.resolve(cwd, config.paths.schemas, "schema.json");
11436
- if (fs32.existsSync(srcPath) && !fs32.existsSync(destPath)) {
11437
- fs32.ensureDirSync(path35.dirname(destPath));
11438
- fs32.copyFileSync(srcPath, destPath);
11439
- created.push(path35.join(config.paths.schemas, "schema.json"));
11772
+ const srcPath = path37.join(cliRoot, "templates", "schema.json");
11773
+ const destPath = path37.resolve(cwd, config.paths.schemas, "schema.json");
11774
+ if (fs34.existsSync(srcPath) && !fs34.existsSync(destPath)) {
11775
+ fs34.ensureDirSync(path37.dirname(destPath));
11776
+ fs34.copyFileSync(srcPath, destPath);
11777
+ created.push(path37.join(config.paths.schemas, "schema.json"));
11440
11778
  }
11441
11779
  return created;
11442
11780
  }
11443
11781
  function findCliRoot() {
11444
11782
  let dir = new URL(".", import.meta.url).pathname;
11445
11783
  for (let i = 0; i < 5; i++) {
11446
- const pkgPath = path35.join(dir, "package.json");
11447
- if (fs32.existsSync(pkgPath)) {
11784
+ const pkgPath = path37.join(dir, "package.json");
11785
+ if (fs34.existsSync(pkgPath)) {
11448
11786
  try {
11449
- const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
11787
+ const pkg = JSON.parse(fs34.readFileSync(pkgPath, "utf-8"));
11450
11788
  if (pkg.name === "@betterstart/cli") {
11451
11789
  return dir;
11452
11790
  }
11453
11791
  } catch {
11454
11792
  }
11455
11793
  }
11456
- dir = path35.dirname(dir);
11794
+ dir = path37.dirname(dir);
11457
11795
  }
11458
- return path35.resolve(new URL(".", import.meta.url).pathname, "..", "..");
11796
+ return path37.resolve(new URL(".", import.meta.url).pathname, "..", "..");
11459
11797
  }
11460
11798
 
11461
11799
  // src/init/scaffolders/database.ts
11462
- import path36 from "path";
11800
+ import path38 from "path";
11463
11801
 
11464
11802
  // src/init/templates/db/client.ts
11465
11803
  function dbClientTemplate() {
@@ -11570,16 +11908,16 @@ export const formSettings = pgTable(
11570
11908
  // src/init/scaffolders/database.ts
11571
11909
  function scaffoldDatabase({ cwd, config }) {
11572
11910
  const created = [];
11573
- const dbDir = path36.resolve(cwd, config.paths.cms, "db");
11911
+ const dbDir = path38.resolve(cwd, config.paths.cms, "db");
11574
11912
  function write(filename, content) {
11575
- const fullPath = path36.join(dbDir, filename);
11913
+ const fullPath = path38.join(dbDir, filename);
11576
11914
  if (safeWriteFile(fullPath, content)) {
11577
- created.push(path36.join(config.paths.cms, "db", filename));
11915
+ created.push(path38.join(config.paths.cms, "db", filename));
11578
11916
  }
11579
11917
  }
11580
11918
  write("client.ts", dbClientTemplate());
11581
11919
  write("schema.ts", dbSchemaTemplate());
11582
- const drizzleConfigPath = path36.resolve(cwd, "drizzle.config.ts");
11920
+ const drizzleConfigPath = path38.resolve(cwd, "drizzle.config.ts");
11583
11921
  if (safeWriteFile(drizzleConfigPath, drizzleConfigTemplate())) {
11584
11922
  created.push("drizzle.config.ts");
11585
11923
  }
@@ -11751,11 +12089,11 @@ import { existsSync, readFileSync } from "fs";
11751
12089
  import { join } from "path";
11752
12090
 
11753
12091
  // src/utils/env.ts
11754
- import fs33 from "fs";
11755
- import path37 from "path";
12092
+ import fs35 from "fs";
12093
+ import path39 from "path";
11756
12094
  function appendEnvVars(cwd, sections, overwrite) {
11757
- const envPath = path37.join(cwd, ".env.local");
11758
- let existing = fs33.existsSync(envPath) ? fs33.readFileSync(envPath, "utf-8") : "";
12095
+ const envPath = path39.join(cwd, ".env.local");
12096
+ let existing = fs35.existsSync(envPath) ? fs35.readFileSync(envPath, "utf-8") : "";
11759
12097
  const existingKeys = new Set(
11760
12098
  existing.split("\n").filter((line) => line.trim() && !line.trim().startsWith("#")).map((line) => line.split("=")[0]?.trim()).filter(Boolean)
11761
12099
  );
@@ -11799,7 +12137,7 @@ function appendEnvVars(cwd, sections, overwrite) {
11799
12137
  const header = existing.trim() ? "" : "# ============================================\n# BetterStart CMS\n# ============================================\n";
11800
12138
  const content = existing.trim() ? `${existing.trimEnd()}
11801
12139
  ${lines.join("\n")}` : header + lines.join("\n");
11802
- fs33.writeFileSync(envPath, content);
12140
+ fs35.writeFileSync(envPath, content);
11803
12141
  }
11804
12142
  return { added, skipped, updated };
11805
12143
  }
@@ -11878,7 +12216,7 @@ function scaffoldEnv(cwd, options) {
11878
12216
  }
11879
12217
 
11880
12218
  // src/init/scaffolders/layout.ts
11881
- import path38 from "path";
12219
+ import path40 from "path";
11882
12220
 
11883
12221
  // src/init/templates/pages/authenticated-layout.ts
11884
12222
  function authenticatedLayoutTemplate() {
@@ -12765,30 +13103,30 @@ export function UsersTable<TValue>({ columns }: UsersTableProps<TValue>) {
12765
13103
  function scaffoldLayout({ cwd, config }) {
12766
13104
  const created = [];
12767
13105
  function write(relPath, content) {
12768
- const fullPath = path38.resolve(cwd, relPath);
12769
- ensureDir(path38.dirname(fullPath));
13106
+ const fullPath = path40.resolve(cwd, relPath);
13107
+ ensureDir(path40.dirname(fullPath));
12770
13108
  if (safeWriteFile(fullPath, content)) {
12771
13109
  created.push(relPath);
12772
13110
  }
12773
13111
  }
12774
- const cmsDir = path38.dirname(config.paths.pages);
12775
- write(path38.join(cmsDir, "layout.tsx"), cmsLayoutTemplate());
12776
- write(path38.join(config.paths.pages, "layout.tsx"), authenticatedLayoutTemplate());
12777
- write(path38.join(config.paths.login, "page.tsx"), loginPageTemplate());
12778
- write(path38.join(config.paths.login, "login-form.tsx"), loginFormTemplate());
12779
- write(path38.join(config.paths.pages, "page.tsx"), dashboardPageTemplate());
12780
- const usersDir = path38.join(config.paths.pages, "users");
12781
- write(path38.join(usersDir, "page.tsx"), usersPageTemplate());
12782
- write(path38.join(usersDir, "users-table.tsx"), usersTableTemplate());
12783
- write(path38.join(usersDir, "columns.tsx"), usersColumnsTemplate());
12784
- write(path38.join(usersDir, "create-user-dialog.tsx"), createUserDialogTemplate());
12785
- write(path38.join(usersDir, "edit-role-dialog.tsx"), editRoleDialogTemplate());
13112
+ const cmsDir = path40.dirname(config.paths.pages);
13113
+ write(path40.join(cmsDir, "layout.tsx"), cmsLayoutTemplate());
13114
+ write(path40.join(config.paths.pages, "layout.tsx"), authenticatedLayoutTemplate());
13115
+ write(path40.join(config.paths.login, "page.tsx"), loginPageTemplate());
13116
+ write(path40.join(config.paths.login, "login-form.tsx"), loginFormTemplate());
13117
+ write(path40.join(config.paths.pages, "page.tsx"), dashboardPageTemplate());
13118
+ const usersDir = path40.join(config.paths.pages, "users");
13119
+ write(path40.join(usersDir, "page.tsx"), usersPageTemplate());
13120
+ write(path40.join(usersDir, "users-table.tsx"), usersTableTemplate());
13121
+ write(path40.join(usersDir, "columns.tsx"), usersColumnsTemplate());
13122
+ write(path40.join(usersDir, "create-user-dialog.tsx"), createUserDialogTemplate());
13123
+ write(path40.join(usersDir, "edit-role-dialog.tsx"), editRoleDialogTemplate());
12786
13124
  return created;
12787
13125
  }
12788
13126
 
12789
13127
  // src/init/scaffolders/preset.ts
12790
- import fs34 from "fs";
12791
- import path39 from "path";
13128
+ import fs36 from "fs";
13129
+ import path41 from "path";
12792
13130
 
12793
13131
  // src/init/templates/presets/blog-categories.ts
12794
13132
  function blogCategoriesSchema() {
@@ -13193,15 +13531,15 @@ function scaffoldPreset({
13193
13531
  generatedFiles: [],
13194
13532
  errors: []
13195
13533
  };
13196
- const schemasDir = path39.join(cwd, config.paths?.schemas ?? "./cms/schemas");
13534
+ const schemasDir = path41.join(cwd, config.paths?.schemas ?? "./cms/schemas");
13197
13535
  const presetSchemas = getPresetSchemas(preset);
13198
13536
  for (const ps of presetSchemas) {
13199
- const filePath = path39.join(schemasDir, ps.filename);
13200
- const dir = path39.dirname(filePath);
13201
- if (!fs34.existsSync(dir)) {
13202
- fs34.mkdirSync(dir, { recursive: true });
13537
+ const filePath = path41.join(schemasDir, ps.filename);
13538
+ const dir = path41.dirname(filePath);
13539
+ if (!fs36.existsSync(dir)) {
13540
+ fs36.mkdirSync(dir, { recursive: true });
13203
13541
  }
13204
- fs34.writeFileSync(filePath, ps.content, "utf-8");
13542
+ fs36.writeFileSync(filePath, ps.content, "utf-8");
13205
13543
  result.schemas.push(ps.filename);
13206
13544
  }
13207
13545
  for (const ps of presetSchemas) {
@@ -13242,8 +13580,8 @@ function scaffoldPreset({
13242
13580
  }
13243
13581
 
13244
13582
  // src/init/scaffolders/tailwind.ts
13245
- import fs35 from "fs";
13246
- import path40 from "path";
13583
+ import fs37 from "fs";
13584
+ import path42 from "path";
13247
13585
  var SOURCE_LINES = ['@source "../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
13248
13586
  var SOURCE_LINES_SRC = ['@source "../../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
13249
13587
  var CMS_THEME_BLOCK = `
@@ -13298,8 +13636,8 @@ function findMainCss(cwd) {
13298
13636
  "globals.css"
13299
13637
  ];
13300
13638
  for (const candidate of candidates) {
13301
- const filePath = path40.join(cwd, candidate);
13302
- if (fs35.existsSync(filePath)) {
13639
+ const filePath = path42.join(cwd, candidate);
13640
+ if (fs37.existsSync(filePath)) {
13303
13641
  return filePath;
13304
13642
  }
13305
13643
  }
@@ -13310,7 +13648,7 @@ function scaffoldTailwind(cwd, hasSrcDir) {
13310
13648
  if (!cssFile) {
13311
13649
  return { file: null, appended: false };
13312
13650
  }
13313
- let content = fs35.readFileSync(cssFile, "utf-8");
13651
+ let content = fs37.readFileSync(cssFile, "utf-8");
13314
13652
  let changed = false;
13315
13653
  const sourceLines = hasSrcDir ? SOURCE_LINES_SRC : SOURCE_LINES;
13316
13654
  const missingLines = sourceLines.filter((sl) => !content.includes(sl));
@@ -13362,14 +13700,14 @@ ${CMS_THEME_BLOCK}
13362
13700
  }
13363
13701
  }
13364
13702
  if (changed) {
13365
- fs35.writeFileSync(cssFile, content, "utf-8");
13703
+ fs37.writeFileSync(cssFile, content, "utf-8");
13366
13704
  }
13367
13705
  return { file: cssFile, appended: changed };
13368
13706
  }
13369
13707
 
13370
13708
  // src/init/scaffolders/tsconfig.ts
13371
- import fs36 from "fs";
13372
- import path41 from "path";
13709
+ import fs38 from "fs";
13710
+ import path43 from "path";
13373
13711
  function stripJsonComments(input) {
13374
13712
  let result = "";
13375
13713
  let i = 0;
@@ -13419,14 +13757,14 @@ var CMS_PATH_ALIASES = {
13419
13757
  "@cms/cache/*": ["./cms/lib/cache/*"]
13420
13758
  };
13421
13759
  function scaffoldTsconfig(cwd) {
13422
- const tsconfigPath = path41.join(cwd, "tsconfig.json");
13760
+ const tsconfigPath = path43.join(cwd, "tsconfig.json");
13423
13761
  const added = [];
13424
13762
  const skipped = [];
13425
- if (!fs36.existsSync(tsconfigPath)) {
13763
+ if (!fs38.existsSync(tsconfigPath)) {
13426
13764
  skipped.push("tsconfig.json not found");
13427
13765
  return { added, skipped };
13428
13766
  }
13429
- const raw = fs36.readFileSync(tsconfigPath, "utf-8");
13767
+ const raw = fs38.readFileSync(tsconfigPath, "utf-8");
13430
13768
  const stripped = stripJsonComments(raw).replace(/,\s*([\]}])/g, "$1");
13431
13769
  let tsconfig;
13432
13770
  try {
@@ -13447,14 +13785,14 @@ function scaffoldTsconfig(cwd) {
13447
13785
  }
13448
13786
  compilerOptions.paths = paths;
13449
13787
  tsconfig.compilerOptions = compilerOptions;
13450
- fs36.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
13788
+ fs38.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
13451
13789
  `, "utf-8");
13452
13790
  return { added, skipped };
13453
13791
  }
13454
13792
 
13455
13793
  // src/commands/seed.ts
13456
- import fs37 from "fs";
13457
- import path42 from "path";
13794
+ import fs39 from "fs";
13795
+ import path44 from "path";
13458
13796
  import * as clack from "@clack/prompts";
13459
13797
  import { Command as Command2 } from "commander";
13460
13798
  function buildSeedScript() {
@@ -13573,7 +13911,7 @@ main().catch((err) => {
13573
13911
  `;
13574
13912
  }
13575
13913
  var seedCommand = new Command2("seed").description("Create the initial admin user").option("--cwd <path>", "Project root path").action(async (options) => {
13576
- const cwd = options.cwd ? path42.resolve(options.cwd) : process.cwd();
13914
+ const cwd = options.cwd ? path44.resolve(options.cwd) : process.cwd();
13577
13915
  clack.intro("BetterStart Seed");
13578
13916
  let config;
13579
13917
  try {
@@ -13613,14 +13951,14 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13613
13951
  clack.cancel("Cancelled.");
13614
13952
  process.exit(0);
13615
13953
  }
13616
- const scriptsDir = path42.join(cwd, cmsDir, "scripts");
13617
- const seedPath = path42.join(scriptsDir, "seed.ts");
13618
- if (!fs37.existsSync(scriptsDir)) {
13619
- fs37.mkdirSync(scriptsDir, { recursive: true });
13954
+ const scriptsDir = path44.join(cwd, cmsDir, "scripts");
13955
+ const seedPath = path44.join(scriptsDir, "seed.ts");
13956
+ if (!fs39.existsSync(scriptsDir)) {
13957
+ fs39.mkdirSync(scriptsDir, { recursive: true });
13620
13958
  }
13621
- fs37.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13959
+ fs39.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13622
13960
  const { execFile } = await import("child_process");
13623
- const tsxBin = path42.join(cwd, "node_modules", ".bin", "tsx");
13961
+ const tsxBin = path44.join(cwd, "node_modules", ".bin", "tsx");
13624
13962
  const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
13625
13963
  execFile(
13626
13964
  tsxBin,
@@ -13659,7 +13997,7 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13659
13997
  if (clack.isCancel(overwrite) || !overwrite) {
13660
13998
  clack.cancel("Seed cancelled.");
13661
13999
  try {
13662
- fs37.unlinkSync(seedPath);
14000
+ fs39.unlinkSync(seedPath);
13663
14001
  } catch {
13664
14002
  }
13665
14003
  process.exit(0);
@@ -13676,15 +14014,15 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13676
14014
  clack.log.error(errMsg);
13677
14015
  clack.log.info("You can run the seed script manually:");
13678
14016
  clack.log.info(
13679
- ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path42.relative(cwd, seedPath)}`
14017
+ ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path44.relative(cwd, seedPath)}`
13680
14018
  );
13681
14019
  clack.outro("");
13682
14020
  process.exit(1);
13683
14021
  }
13684
14022
  try {
13685
- fs37.unlinkSync(seedPath);
13686
- if (fs37.existsSync(scriptsDir) && fs37.readdirSync(scriptsDir).length === 0) {
13687
- fs37.rmdirSync(scriptsDir);
14023
+ fs39.unlinkSync(seedPath);
14024
+ if (fs39.existsSync(scriptsDir) && fs39.readdirSync(scriptsDir).length === 0) {
14025
+ fs39.rmdirSync(scriptsDir);
13688
14026
  }
13689
14027
  } catch {
13690
14028
  }
@@ -13715,16 +14053,16 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13715
14053
  const nukeFiles = ["cms.config.ts", "CMS.md", "drizzle.config.ts"];
13716
14054
  let nuked = 0;
13717
14055
  for (const dir of nukeDirs) {
13718
- const fullPath = path43.resolve(cwd, dir);
13719
- if (fs38.existsSync(fullPath)) {
13720
- fs38.rmSync(fullPath, { recursive: true, force: true });
14056
+ const fullPath = path45.resolve(cwd, dir);
14057
+ if (fs40.existsSync(fullPath)) {
14058
+ fs40.rmSync(fullPath, { recursive: true, force: true });
13721
14059
  nuked++;
13722
14060
  }
13723
14061
  }
13724
14062
  for (const file of nukeFiles) {
13725
- const fullPath = path43.resolve(cwd, file);
13726
- if (fs38.existsSync(fullPath)) {
13727
- fs38.unlinkSync(fullPath);
14063
+ const fullPath = path45.resolve(cwd, file);
14064
+ if (fs40.existsSync(fullPath)) {
14065
+ fs40.unlinkSync(fullPath);
13728
14066
  nuked++;
13729
14067
  }
13730
14068
  }
@@ -13771,7 +14109,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13771
14109
  }
13772
14110
  pm = pmChoice;
13773
14111
  }
13774
- const displayName = projectPrompt.projectName === "." ? path43.basename(cwd) : projectPrompt.projectName;
14112
+ const displayName = projectPrompt.projectName === "." ? path45.basename(cwd) : projectPrompt.projectName;
13775
14113
  const { bin, prefix } = createNextAppCommand(pm);
13776
14114
  const cnaArgs = [
13777
14115
  ...prefix,
@@ -13803,10 +14141,10 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13803
14141
  );
13804
14142
  process.exit(1);
13805
14143
  }
13806
- cwd = path43.resolve(cwd, projectPrompt.projectName);
13807
- const hasPackageJson = fs38.existsSync(path43.join(cwd, "package.json"));
14144
+ cwd = path45.resolve(cwd, projectPrompt.projectName);
14145
+ const hasPackageJson = fs40.existsSync(path45.join(cwd, "package.json"));
13808
14146
  const hasNextConfig = ["next.config.ts", "next.config.js", "next.config.mjs"].some(
13809
- (f) => fs38.existsSync(path43.join(cwd, f))
14147
+ (f) => fs40.existsSync(path45.join(cwd, f))
13810
14148
  );
13811
14149
  if (!hasPackageJson || !hasNextConfig) {
13812
14150
  p4.log.error(
@@ -13907,11 +14245,11 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13907
14245
  s.stop("");
13908
14246
  process.stdout.write("\x1B[2A\x1B[J");
13909
14247
  p4.note(noteLines.join("\n"), "Scaffolded CMS");
13910
- const drizzleConfigPath = path43.join(cwd, "drizzle.config.ts");
13911
- if (!dbFiles.includes("drizzle.config.ts") && fs38.existsSync(drizzleConfigPath)) {
14248
+ const drizzleConfigPath = path45.join(cwd, "drizzle.config.ts");
14249
+ if (!dbFiles.includes("drizzle.config.ts") && fs40.existsSync(drizzleConfigPath)) {
13912
14250
  if (options.force) {
13913
14251
  const { drizzleConfigTemplate: drizzleConfigTemplate2 } = await import("./drizzle-config-EDKOEZ6G.js");
13914
- fs38.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
14252
+ fs40.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
13915
14253
  p4.log.success("Updated drizzle.config.ts");
13916
14254
  } else if (!options.yes) {
13917
14255
  const overwrite = await p4.confirm({
@@ -13920,7 +14258,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13920
14258
  });
13921
14259
  if (!p4.isCancel(overwrite) && overwrite) {
13922
14260
  const { drizzleConfigTemplate: drizzleConfigTemplate2 } = await import("./drizzle-config-EDKOEZ6G.js");
13923
- fs38.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
14261
+ fs40.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
13924
14262
  p4.log.success("Updated drizzle.config.ts");
13925
14263
  }
13926
14264
  }
@@ -13953,15 +14291,15 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13953
14291
  {
13954
14292
  const entityNames = [];
13955
14293
  const formNames = [];
13956
- const schemasDir = path43.join(cwd, config.paths.schemas);
13957
- const formsDir = path43.join(schemasDir, "forms");
13958
- if (fs38.existsSync(schemasDir)) {
13959
- for (const f of fs38.readdirSync(schemasDir)) {
14294
+ const schemasDir = path45.join(cwd, config.paths.schemas);
14295
+ const formsDir = path45.join(schemasDir, "forms");
14296
+ if (fs40.existsSync(schemasDir)) {
14297
+ for (const f of fs40.readdirSync(schemasDir)) {
13960
14298
  if (f.endsWith(".json")) entityNames.push(f.replace(".json", ""));
13961
14299
  }
13962
14300
  }
13963
- if (fs38.existsSync(formsDir)) {
13964
- for (const f of fs38.readdirSync(formsDir)) {
14301
+ if (fs40.existsSync(formsDir)) {
14302
+ for (const f of fs40.readdirSync(formsDir)) {
13965
14303
  if (f.endsWith(".json")) formNames.push(f.replace(".json", ""));
13966
14304
  }
13967
14305
  }
@@ -14140,9 +14478,9 @@ function isValidDbUrl(url) {
14140
14478
  return url.startsWith("postgres://") || url.startsWith("postgresql://");
14141
14479
  }
14142
14480
  function readExistingDbUrl(cwd) {
14143
- const envPath = path43.join(cwd, ".env.local");
14144
- if (!fs38.existsSync(envPath)) return void 0;
14145
- const content = fs38.readFileSync(envPath, "utf-8");
14481
+ const envPath = path45.join(cwd, ".env.local");
14482
+ if (!fs40.existsSync(envPath)) return void 0;
14483
+ const content = fs40.readFileSync(envPath, "utf-8");
14146
14484
  for (const line of content.split("\n")) {
14147
14485
  const trimmed = line.trim();
14148
14486
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -14165,9 +14503,9 @@ function maskDbUrl(url) {
14165
14503
  }
14166
14504
  }
14167
14505
  function hasDbUrl(cwd) {
14168
- const envPath = path43.join(cwd, ".env.local");
14169
- if (!fs38.existsSync(envPath)) return false;
14170
- const content = fs38.readFileSync(envPath, "utf-8");
14506
+ const envPath = path45.join(cwd, ".env.local");
14507
+ if (!fs40.existsSync(envPath)) return false;
14508
+ const content = fs40.readFileSync(envPath, "utf-8");
14171
14509
  for (const line of content.split("\n")) {
14172
14510
  const trimmed = line.trim();
14173
14511
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -14181,23 +14519,23 @@ function hasDbUrl(cwd) {
14181
14519
  return false;
14182
14520
  }
14183
14521
  function runSeed(cwd, cmsDir, email, password4, overwrite = false) {
14184
- const scriptsDir = path43.join(cwd, cmsDir, "scripts");
14185
- const seedPath = path43.join(scriptsDir, "seed.ts");
14186
- if (!fs38.existsSync(scriptsDir)) {
14187
- fs38.mkdirSync(scriptsDir, { recursive: true });
14522
+ const scriptsDir = path45.join(cwd, cmsDir, "scripts");
14523
+ const seedPath = path45.join(scriptsDir, "seed.ts");
14524
+ if (!fs40.existsSync(scriptsDir)) {
14525
+ fs40.mkdirSync(scriptsDir, { recursive: true });
14188
14526
  }
14189
- fs38.writeFileSync(seedPath, buildSeedScript(), "utf-8");
14527
+ fs40.writeFileSync(seedPath, buildSeedScript(), "utf-8");
14190
14528
  const cleanup = () => {
14191
14529
  try {
14192
- fs38.unlinkSync(seedPath);
14193
- if (fs38.existsSync(scriptsDir) && fs38.readdirSync(scriptsDir).length === 0) {
14194
- fs38.rmdirSync(scriptsDir);
14530
+ fs40.unlinkSync(seedPath);
14531
+ if (fs40.existsSync(scriptsDir) && fs40.readdirSync(scriptsDir).length === 0) {
14532
+ fs40.rmdirSync(scriptsDir);
14195
14533
  }
14196
14534
  } catch {
14197
14535
  }
14198
14536
  };
14199
14537
  return new Promise((resolve) => {
14200
- const tsxBin = path43.join(cwd, "node_modules", ".bin", "tsx");
14538
+ const tsxBin = path45.join(cwd, "node_modules", ".bin", "tsx");
14201
14539
  const child = spawn2(tsxBin, [seedPath], {
14202
14540
  cwd,
14203
14541
  stdio: "pipe",
@@ -14262,7 +14600,7 @@ ${stderr}`;
14262
14600
  }
14263
14601
  function runDrizzlePush(cwd) {
14264
14602
  return new Promise((resolve) => {
14265
- const drizzleBin = path43.join(cwd, "node_modules", ".bin", "drizzle-kit");
14603
+ const drizzleBin = path45.join(cwd, "node_modules", ".bin", "drizzle-kit");
14266
14604
  const child = spawn2(drizzleBin, ["push", "--force"], {
14267
14605
  cwd,
14268
14606
  stdio: "pipe",
@@ -14283,8 +14621,8 @@ function runDrizzlePush(cwd) {
14283
14621
  }
14284
14622
 
14285
14623
  // src/commands/remove.ts
14286
- import fs39 from "fs";
14287
- import path44 from "path";
14624
+ import fs41 from "fs";
14625
+ import path46 from "path";
14288
14626
  import readline from "readline";
14289
14627
  import { Command as Command4 } from "commander";
14290
14628
  function findTableEnd3(content, startIndex) {
@@ -14315,8 +14653,8 @@ function findTableEnd3(content, startIndex) {
14315
14653
  return content.length;
14316
14654
  }
14317
14655
  function removeTableFromSchema(schemaFilePath, name) {
14318
- if (!fs39.existsSync(schemaFilePath)) return false;
14319
- let content = fs39.readFileSync(schemaFilePath, "utf-8");
14656
+ if (!fs41.existsSync(schemaFilePath)) return false;
14657
+ let content = fs41.readFileSync(schemaFilePath, "utf-8");
14320
14658
  const variableName = toCamelCase(name);
14321
14659
  let changed = false;
14322
14660
  if (content.includes(`export const ${variableName} =`)) {
@@ -14344,13 +14682,13 @@ function removeTableFromSchema(schemaFilePath, name) {
14344
14682
  }
14345
14683
  if (changed) {
14346
14684
  content = content.replace(/\n{3,}/g, "\n\n");
14347
- fs39.writeFileSync(schemaFilePath, content, "utf-8");
14685
+ fs41.writeFileSync(schemaFilePath, content, "utf-8");
14348
14686
  }
14349
14687
  return changed;
14350
14688
  }
14351
14689
  function removeFromNavigation(navFilePath, name) {
14352
- if (!fs39.existsSync(navFilePath)) return false;
14353
- const content = fs39.readFileSync(navFilePath, "utf-8");
14690
+ if (!fs41.existsSync(navFilePath)) return false;
14691
+ const content = fs41.readFileSync(navFilePath, "utf-8");
14354
14692
  const href = `/cms/${name}`;
14355
14693
  if (!content.includes(`'${href}'`)) return false;
14356
14694
  const lines = content.split("\n");
@@ -14381,7 +14719,7 @@ function removeFromNavigation(navFilePath, name) {
14381
14719
  if (startLine === -1 || endLine === -1) return false;
14382
14720
  lines.splice(startLine, endLine - startLine + 1);
14383
14721
  const updated = lines.join("\n").replace(/,\s*,/g, ",").replace(/\[\s*,/, "[");
14384
- fs39.writeFileSync(navFilePath, updated, "utf-8");
14722
+ fs41.writeFileSync(navFilePath, updated, "utf-8");
14385
14723
  return true;
14386
14724
  }
14387
14725
  async function promptConfirm(message) {
@@ -14397,7 +14735,7 @@ async function promptConfirm(message) {
14397
14735
  });
14398
14736
  }
14399
14737
  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) => {
14400
- const cwd = options.cwd ? path44.resolve(options.cwd) : process.cwd();
14738
+ const cwd = options.cwd ? path46.resolve(options.cwd) : process.cwd();
14401
14739
  console.log("\n BetterStart Remove\n");
14402
14740
  let config;
14403
14741
  try {
@@ -14410,34 +14748,34 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14410
14748
  const pagesDir = config.paths?.pages ?? "./src/app/(cms)/cms/(authenticated)";
14411
14749
  const kebabName = toKebabCase(schemaName);
14412
14750
  const targets = [];
14413
- const entityPagesDir = path44.join(cwd, pagesDir, schemaName);
14414
- if (fs39.existsSync(entityPagesDir)) {
14751
+ const entityPagesDir = path46.join(cwd, pagesDir, schemaName);
14752
+ if (fs41.existsSync(entityPagesDir)) {
14415
14753
  targets.push({
14416
14754
  path: entityPagesDir,
14417
- label: `${path44.join(pagesDir, schemaName)}/`,
14755
+ label: `${path46.join(pagesDir, schemaName)}/`,
14418
14756
  isDir: true
14419
14757
  });
14420
14758
  }
14421
- const actionsFile = path44.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
14422
- if (fs39.existsSync(actionsFile)) {
14759
+ const actionsFile = path46.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
14760
+ if (fs41.existsSync(actionsFile)) {
14423
14761
  targets.push({
14424
14762
  path: actionsFile,
14425
- label: path44.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
14763
+ label: path46.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
14426
14764
  isDir: false
14427
14765
  });
14428
14766
  }
14429
- const hookFile = path44.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
14430
- if (fs39.existsSync(hookFile)) {
14767
+ const hookFile = path46.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
14768
+ if (fs41.existsSync(hookFile)) {
14431
14769
  targets.push({
14432
14770
  path: hookFile,
14433
- label: path44.join(cmsDir, "hooks", `use-${kebabName}.ts`),
14771
+ label: path46.join(cmsDir, "hooks", `use-${kebabName}.ts`),
14434
14772
  isDir: false
14435
14773
  });
14436
14774
  }
14437
- const schemaFilePath = path44.join(cwd, cmsDir, "db", "schema.ts");
14438
- const hasTable = fs39.existsSync(schemaFilePath) && fs39.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
14439
- const navFilePath = path44.join(cwd, cmsDir, "data", "navigation.ts");
14440
- const hasNavEntry = fs39.existsSync(navFilePath) && fs39.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
14775
+ const schemaFilePath = path46.join(cwd, cmsDir, "db", "schema.ts");
14776
+ const hasTable = fs41.existsSync(schemaFilePath) && fs41.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
14777
+ const navFilePath = path46.join(cwd, cmsDir, "data", "navigation.ts");
14778
+ const hasNavEntry = fs41.existsSync(navFilePath) && fs41.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
14441
14779
  if (targets.length === 0 && !hasTable && !hasNavEntry) {
14442
14780
  console.log(` No generated files found for: ${schemaName}`);
14443
14781
  return;
@@ -14447,10 +14785,10 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14447
14785
  console.log(` ${t.isDir ? "[dir]" : " "} ${t.label}`);
14448
14786
  }
14449
14787
  if (hasTable) {
14450
- console.log(` [edit] ${path44.join(cmsDir, "db", "schema.ts")} (remove table)`);
14788
+ console.log(` [edit] ${path46.join(cmsDir, "db", "schema.ts")} (remove table)`);
14451
14789
  }
14452
14790
  if (hasNavEntry) {
14453
- console.log(` [edit] ${path44.join(cmsDir, "data", "navigation.ts")} (remove entry)`);
14791
+ console.log(` [edit] ${path46.join(cmsDir, "data", "navigation.ts")} (remove entry)`);
14454
14792
  }
14455
14793
  if (!options.force) {
14456
14794
  console.log("");
@@ -14463,19 +14801,19 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14463
14801
  console.log("");
14464
14802
  for (const t of targets) {
14465
14803
  if (t.isDir) {
14466
- fs39.rmSync(t.path, { recursive: true, force: true });
14804
+ fs41.rmSync(t.path, { recursive: true, force: true });
14467
14805
  } else {
14468
- fs39.unlinkSync(t.path);
14806
+ fs41.unlinkSync(t.path);
14469
14807
  }
14470
14808
  console.log(` Removed: ${t.label}`);
14471
14809
  }
14472
14810
  if (hasTable) {
14473
14811
  removeTableFromSchema(schemaFilePath, schemaName);
14474
- console.log(` Cleaned: ${path44.join(cmsDir, "db", "schema.ts")}`);
14812
+ console.log(` Cleaned: ${path46.join(cmsDir, "db", "schema.ts")}`);
14475
14813
  }
14476
14814
  if (hasNavEntry) {
14477
14815
  removeFromNavigation(navFilePath, schemaName);
14478
- console.log(` Cleaned: ${path44.join(cmsDir, "data", "navigation.ts")}`);
14816
+ console.log(` Cleaned: ${path46.join(cmsDir, "data", "navigation.ts")}`);
14479
14817
  }
14480
14818
  console.log("\n Removal complete!");
14481
14819
  console.log("\n Note: You may need to manually:");
@@ -14487,14 +14825,14 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14487
14825
 
14488
14826
  // src/commands/setup-r2.ts
14489
14827
  import { execFileSync as execFileSync5, spawnSync } from "child_process";
14490
- import fs40 from "fs";
14828
+ import fs42 from "fs";
14491
14829
  import os from "os";
14492
- import path45 from "path";
14830
+ import path47 from "path";
14493
14831
  import * as p5 from "@clack/prompts";
14494
14832
  import { Command as Command5 } from "commander";
14495
14833
  import pc3 from "picocolors";
14496
14834
  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) => {
14497
- const cwd = options.cwd ? path45.resolve(options.cwd) : process.cwd();
14835
+ const cwd = options.cwd ? path47.resolve(options.cwd) : process.cwd();
14498
14836
  p5.intro(pc3.bgCyan(pc3.black(" BetterStart \u2014 R2 Storage Setup ")));
14499
14837
  const s = p5.spinner();
14500
14838
  s.start("Looking for wrangler CLI");
@@ -14686,8 +15024,8 @@ var setupR2Command = new Command5("setup-r2").description("Create a Cloudflare R
14686
15024
  p5.outro("Done! Your CMS can now upload files to R2.");
14687
15025
  });
14688
15026
  function findWrangler(cwd) {
14689
- const localBin = path45.join(cwd, "node_modules", ".bin", "wrangler");
14690
- if (fs40.existsSync(localBin)) return { bin: localBin, prefix: [] };
15027
+ const localBin = path47.join(cwd, "node_modules", ".bin", "wrangler");
15028
+ if (fs42.existsSync(localBin)) return { bin: localBin, prefix: [] };
14691
15029
  const result = spawnSync("which", ["wrangler"], { stdio: "pipe", timeout: 5e3 });
14692
15030
  if (result.status === 0) {
14693
15031
  const found = result.stdout?.toString().trim();
@@ -14719,11 +15057,11 @@ function extractAccountId(ref, cwd) {
14719
15057
  }
14720
15058
  function readWranglerToken() {
14721
15059
  const candidates = [
14722
- path45.join(os.homedir(), "Library", "Preferences", ".wrangler", "config", "default.toml"),
15060
+ path47.join(os.homedir(), "Library", "Preferences", ".wrangler", "config", "default.toml"),
14723
15061
  // macOS
14724
- path45.join(os.homedir(), ".config", ".wrangler", "config", "default.toml"),
15062
+ path47.join(os.homedir(), ".config", ".wrangler", "config", "default.toml"),
14725
15063
  // Linux
14726
- path45.join(os.homedir(), ".wrangler", "config", "default.toml")
15064
+ path47.join(os.homedir(), ".wrangler", "config", "default.toml")
14727
15065
  // fallback
14728
15066
  ];
14729
15067
  if (process.env.WRANGLER_CONFIG_PATH) {
@@ -14731,13 +15069,13 @@ function readWranglerToken() {
14731
15069
  }
14732
15070
  if (process.env.XDG_CONFIG_HOME) {
14733
15071
  candidates.unshift(
14734
- path45.join(process.env.XDG_CONFIG_HOME, ".wrangler", "config", "default.toml")
15072
+ path47.join(process.env.XDG_CONFIG_HOME, ".wrangler", "config", "default.toml")
14735
15073
  );
14736
15074
  }
14737
15075
  for (const configPath of candidates) {
14738
- if (!fs40.existsSync(configPath)) continue;
15076
+ if (!fs42.existsSync(configPath)) continue;
14739
15077
  try {
14740
- const content = fs40.readFileSync(configPath, "utf-8");
15078
+ const content = fs42.readFileSync(configPath, "utf-8");
14741
15079
  const match = content.match(/^oauth_token\s*=\s*"([^"]+)"/m);
14742
15080
  if (match) return match[1];
14743
15081
  } catch {
@@ -14769,14 +15107,14 @@ async function enablePublicDomain(accountId, bucketName, token) {
14769
15107
  }
14770
15108
 
14771
15109
  // src/commands/uninstall.ts
14772
- import fs42 from "fs";
14773
- import path46 from "path";
15110
+ import fs44 from "fs";
15111
+ import path48 from "path";
14774
15112
  import * as p6 from "@clack/prompts";
14775
15113
  import { Command as Command6 } from "commander";
14776
15114
  import pc4 from "picocolors";
14777
15115
 
14778
15116
  // src/commands/uninstall-cleaners.ts
14779
- import fs41 from "fs";
15117
+ import fs43 from "fs";
14780
15118
  function stripJsonComments2(input) {
14781
15119
  let result = "";
14782
15120
  let i = 0;
@@ -14810,8 +15148,8 @@ function stripJsonComments2(input) {
14810
15148
  return result;
14811
15149
  }
14812
15150
  function cleanTsconfig(tsconfigPath) {
14813
- if (!fs41.existsSync(tsconfigPath)) return [];
14814
- const raw = fs41.readFileSync(tsconfigPath, "utf-8");
15151
+ if (!fs43.existsSync(tsconfigPath)) return [];
15152
+ const raw = fs43.readFileSync(tsconfigPath, "utf-8");
14815
15153
  const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
14816
15154
  let tsconfig;
14817
15155
  try {
@@ -14835,13 +15173,13 @@ function cleanTsconfig(tsconfigPath) {
14835
15173
  compilerOptions.paths = paths;
14836
15174
  }
14837
15175
  tsconfig.compilerOptions = compilerOptions;
14838
- fs41.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
15176
+ fs43.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
14839
15177
  `, "utf-8");
14840
15178
  return removed;
14841
15179
  }
14842
15180
  function cleanCss(cssPath) {
14843
- if (!fs41.existsSync(cssPath)) return [];
14844
- const content = fs41.readFileSync(cssPath, "utf-8");
15181
+ if (!fs43.existsSync(cssPath)) return [];
15182
+ const content = fs43.readFileSync(cssPath, "utf-8");
14845
15183
  const lines = content.split("\n");
14846
15184
  const sourcePattern = /^@source\s+"[^"]*cms[^"]*";\s*$/;
14847
15185
  const removed = [];
@@ -14855,12 +15193,12 @@ function cleanCss(cssPath) {
14855
15193
  }
14856
15194
  if (removed.length === 0) return [];
14857
15195
  const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
14858
- fs41.writeFileSync(cssPath, cleaned, "utf-8");
15196
+ fs43.writeFileSync(cssPath, cleaned, "utf-8");
14859
15197
  return removed;
14860
15198
  }
14861
15199
  function cleanEnvFile(envPath) {
14862
- if (!fs41.existsSync(envPath)) return [];
14863
- const content = fs41.readFileSync(envPath, "utf-8");
15200
+ if (!fs43.existsSync(envPath)) return [];
15201
+ const content = fs43.readFileSync(envPath, "utf-8");
14864
15202
  const lines = content.split("\n");
14865
15203
  const removed = [];
14866
15204
  const kept = [];
@@ -14893,9 +15231,9 @@ function cleanEnvFile(envPath) {
14893
15231
  if (removed.length === 0) return [];
14894
15232
  const result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
14895
15233
  if (result === "") {
14896
- fs41.unlinkSync(envPath);
15234
+ fs43.unlinkSync(envPath);
14897
15235
  } else {
14898
- fs41.writeFileSync(envPath, `${result}
15236
+ fs43.writeFileSync(envPath, `${result}
14899
15237
  `, "utf-8");
14900
15238
  }
14901
15239
  return removed;
@@ -14921,15 +15259,15 @@ function findMainCss2(cwd) {
14921
15259
  "globals.css"
14922
15260
  ];
14923
15261
  for (const candidate of candidates) {
14924
- const filePath = path46.join(cwd, candidate);
14925
- if (fs42.existsSync(filePath)) return filePath;
15262
+ const filePath = path48.join(cwd, candidate);
15263
+ if (fs44.existsSync(filePath)) return filePath;
14926
15264
  }
14927
15265
  return void 0;
14928
15266
  }
14929
15267
  function isCLICreatedBiome(biomePath) {
14930
- if (!fs42.existsSync(biomePath)) return false;
15268
+ if (!fs44.existsSync(biomePath)) return false;
14931
15269
  try {
14932
- const content = JSON.parse(fs42.readFileSync(biomePath, "utf-8"));
15270
+ const content = JSON.parse(fs44.readFileSync(biomePath, "utf-8"));
14933
15271
  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");
14934
15272
  } catch {
14935
15273
  return false;
@@ -14937,13 +15275,13 @@ function isCLICreatedBiome(biomePath) {
14937
15275
  }
14938
15276
  function buildUninstallPlan(cwd) {
14939
15277
  const steps = [];
14940
- const hasSrc = fs42.existsSync(path46.join(cwd, "src"));
15278
+ const hasSrc = fs44.existsSync(path48.join(cwd, "src"));
14941
15279
  const appBase = hasSrc ? "src/app" : "app";
14942
15280
  const dirs = [];
14943
- const cmsDir = path46.join(cwd, "cms");
14944
- const cmsRouteGroup = path46.join(cwd, appBase, "(cms)");
14945
- if (fs42.existsSync(cmsDir)) dirs.push("cms/");
14946
- if (fs42.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
15281
+ const cmsDir = path48.join(cwd, "cms");
15282
+ const cmsRouteGroup = path48.join(cwd, appBase, "(cms)");
15283
+ if (fs44.existsSync(cmsDir)) dirs.push("cms/");
15284
+ if (fs44.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
14947
15285
  if (dirs.length > 0) {
14948
15286
  steps.push({
14949
15287
  label: "CMS directories",
@@ -14951,25 +15289,25 @@ function buildUninstallPlan(cwd) {
14951
15289
  count: dirs.length,
14952
15290
  unit: dirs.length === 1 ? "directory" : "directories",
14953
15291
  execute() {
14954
- if (fs42.existsSync(cmsDir)) fs42.rmSync(cmsDir, { recursive: true, force: true });
14955
- if (fs42.existsSync(cmsRouteGroup)) fs42.rmSync(cmsRouteGroup, { recursive: true, force: true });
15292
+ if (fs44.existsSync(cmsDir)) fs44.rmSync(cmsDir, { recursive: true, force: true });
15293
+ if (fs44.existsSync(cmsRouteGroup)) fs44.rmSync(cmsRouteGroup, { recursive: true, force: true });
14956
15294
  }
14957
15295
  });
14958
15296
  }
14959
15297
  const configFiles = [];
14960
15298
  const configPaths = [];
14961
15299
  const candidates = [
14962
- ["cms.config.ts", path46.join(cwd, "cms.config.ts")],
14963
- ["drizzle.config.ts", path46.join(cwd, "drizzle.config.ts")],
14964
- ["CMS.md", path46.join(cwd, "CMS.md")]
15300
+ ["cms.config.ts", path48.join(cwd, "cms.config.ts")],
15301
+ ["drizzle.config.ts", path48.join(cwd, "drizzle.config.ts")],
15302
+ ["CMS.md", path48.join(cwd, "CMS.md")]
14965
15303
  ];
14966
15304
  for (const [label, fullPath] of candidates) {
14967
- if (fs42.existsSync(fullPath)) {
15305
+ if (fs44.existsSync(fullPath)) {
14968
15306
  configFiles.push(label);
14969
15307
  configPaths.push(fullPath);
14970
15308
  }
14971
15309
  }
14972
- const biomePath = path46.join(cwd, "biome.json");
15310
+ const biomePath = path48.join(cwd, "biome.json");
14973
15311
  if (isCLICreatedBiome(biomePath)) {
14974
15312
  configFiles.push("biome.json (CLI-created)");
14975
15313
  configPaths.push(biomePath);
@@ -14982,14 +15320,14 @@ function buildUninstallPlan(cwd) {
14982
15320
  unit: configFiles.length === 1 ? "file" : "files",
14983
15321
  execute() {
14984
15322
  for (const p7 of configPaths) {
14985
- if (fs42.existsSync(p7)) fs42.unlinkSync(p7);
15323
+ if (fs44.existsSync(p7)) fs44.unlinkSync(p7);
14986
15324
  }
14987
15325
  }
14988
15326
  });
14989
15327
  }
14990
- const tsconfigPath = path46.join(cwd, "tsconfig.json");
14991
- if (fs42.existsSync(tsconfigPath)) {
14992
- const content = fs42.readFileSync(tsconfigPath, "utf-8");
15328
+ const tsconfigPath = path48.join(cwd, "tsconfig.json");
15329
+ if (fs44.existsSync(tsconfigPath)) {
15330
+ const content = fs44.readFileSync(tsconfigPath, "utf-8");
14993
15331
  const aliasMatches = content.match(/"@cms\//g);
14994
15332
  if (aliasMatches && aliasMatches.length > 0) {
14995
15333
  const aliasCount = aliasMatches.length;
@@ -15006,10 +15344,10 @@ function buildUninstallPlan(cwd) {
15006
15344
  }
15007
15345
  const cssFile = findMainCss2(cwd);
15008
15346
  if (cssFile) {
15009
- const cssContent = fs42.readFileSync(cssFile, "utf-8");
15347
+ const cssContent = fs44.readFileSync(cssFile, "utf-8");
15010
15348
  const sourceLines = cssContent.split("\n").filter((l) => /^@source\s+"[^"]*cms[^"]*";\s*$/.test(l));
15011
15349
  if (sourceLines.length > 0) {
15012
- const relCss = path46.relative(cwd, cssFile);
15350
+ const relCss = path48.relative(cwd, cssFile);
15013
15351
  steps.push({
15014
15352
  label: `CSS @source lines (${relCss})`,
15015
15353
  items: [`@source lines in ${relCss}`],
@@ -15021,9 +15359,9 @@ function buildUninstallPlan(cwd) {
15021
15359
  });
15022
15360
  }
15023
15361
  }
15024
- const envPath = path46.join(cwd, ".env.local");
15025
- if (fs42.existsSync(envPath)) {
15026
- const envContent = fs42.readFileSync(envPath, "utf-8");
15362
+ const envPath = path48.join(cwd, ".env.local");
15363
+ if (fs44.existsSync(envPath)) {
15364
+ const envContent = fs44.readFileSync(envPath, "utf-8");
15027
15365
  const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
15028
15366
  if (bsVars.length > 0) {
15029
15367
  steps.push({
@@ -15040,7 +15378,7 @@ function buildUninstallPlan(cwd) {
15040
15378
  return steps;
15041
15379
  }
15042
15380
  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) => {
15043
- const cwd = options.cwd ? path46.resolve(options.cwd) : process.cwd();
15381
+ const cwd = options.cwd ? path48.resolve(options.cwd) : process.cwd();
15044
15382
  p6.intro(pc4.bgRed(pc4.white(" BetterStart Uninstall ")));
15045
15383
  const steps = buildUninstallPlan(cwd);
15046
15384
  if (steps.length === 0) {
@@ -15077,11 +15415,11 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
15077
15415
  });
15078
15416
 
15079
15417
  // src/commands/update-deps.ts
15080
- import path47 from "path";
15418
+ import path49 from "path";
15081
15419
  import * as clack2 from "@clack/prompts";
15082
15420
  import { Command as Command7 } from "commander";
15083
15421
  var updateDepsCommand = new Command7("update-deps").description("Install or update all CMS dependencies").option("--cwd <path>", "Project root path").action(async (options) => {
15084
- const cwd = options.cwd ? path47.resolve(options.cwd) : process.cwd();
15422
+ const cwd = options.cwd ? path49.resolve(options.cwd) : process.cwd();
15085
15423
  clack2.intro("BetterStart Update Dependencies");
15086
15424
  const pm = detectPackageManager(cwd);
15087
15425
  clack2.log.info(`Package manager: ${pm}`);
@@ -15106,22 +15444,22 @@ var updateDepsCommand = new Command7("update-deps").description("Install or upda
15106
15444
  });
15107
15445
 
15108
15446
  // src/commands/update-styles.ts
15109
- import fs43 from "fs";
15110
- import path48 from "path";
15447
+ import fs45 from "fs";
15448
+ import path50 from "path";
15111
15449
  import * as clack3 from "@clack/prompts";
15112
15450
  import { Command as Command8 } from "commander";
15113
15451
  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) => {
15114
- const cwd = options.cwd ? path48.resolve(options.cwd) : process.cwd();
15452
+ const cwd = options.cwd ? path50.resolve(options.cwd) : process.cwd();
15115
15453
  clack3.intro("BetterStart Update Styles");
15116
15454
  const config = await resolveConfig(cwd);
15117
15455
  const cmsDir = config.paths?.cms ?? "./cms";
15118
- const targetPath = path48.join(cwd, cmsDir, "cms-globals.css");
15119
- if (!fs43.existsSync(targetPath)) {
15120
- clack3.cancel(`cms-globals.css not found at ${path48.relative(cwd, targetPath)}`);
15456
+ const targetPath = path50.join(cwd, cmsDir, "cms-globals.css");
15457
+ if (!fs45.existsSync(targetPath)) {
15458
+ clack3.cancel(`cms-globals.css not found at ${path50.relative(cwd, targetPath)}`);
15121
15459
  process.exit(1);
15122
15460
  }
15123
- fs43.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15124
- clack3.log.success(`Updated ${path48.relative(cwd, targetPath)}`);
15461
+ fs45.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15462
+ clack3.log.success(`Updated ${path50.relative(cwd, targetPath)}`);
15125
15463
  clack3.outro("Styles updated");
15126
15464
  });
15127
15465