@betterstart/cli 0.1.41 → 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,7 +2248,7 @@ function toTypeScriptType(field, mode = "output") {
2225
2248
  }
2226
2249
  }
2227
2250
 
2228
- // src/generators/form-pipeline/form-component.ts
2251
+ // src/generators/form-pipeline/form-component-shared.ts
2229
2252
  function resolveUiImport(cwd, componentName) {
2230
2253
  const locations = ["components/ui", "src/components/ui"];
2231
2254
  for (const loc of locations) {
@@ -2238,19 +2261,18 @@ function resolveUiImport(cwd, componentName) {
2238
2261
  function escapeJsx(str) {
2239
2262
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2240
2263
  }
2241
- function generateFormComponent(schema, cwd, cmsDir, options) {
2242
- const formName = schema.name;
2243
- const pascal = toPascalCase(formName);
2244
- const fields = getAllFormSchemaFields(schema);
2245
- const kebab = toKebabCase(formName);
2246
- const filePath = path7.join(cwd, cmsDir, "components", "forms", `${kebab}-form.tsx`);
2247
- const dir = path7.dirname(filePath);
2248
- if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
2249
- if (fs7.existsSync(filePath) && !options.force) {
2250
- return { files: [path7.relative(cwd, filePath)] };
2251
- }
2252
- const zodFields = fields.filter((f) => f.name).map((f) => ` ${f.name}: ${formFieldToZodType(f)}`).join(",\n");
2253
- const defaults = fields.filter((f) => f.name).map((f) => {
2264
+ function flattenFormFields(fields) {
2265
+ return fields.flatMap((field) => {
2266
+ if (field.type === "dynamicFields") return [];
2267
+ if (field.type === "group" && field.fields) return flattenFormFields(field.fields);
2268
+ return field.type === "group" ? [] : [field];
2269
+ });
2270
+ }
2271
+ function buildZodFields(fields) {
2272
+ return fields.filter((f) => f.name).map((f) => ` ${f.name}: ${formFieldToZodType(f)}`).join(",\n");
2273
+ }
2274
+ function buildDefaultValues(fields) {
2275
+ return fields.filter((f) => f.name).map((f) => {
2254
2276
  if (f.type === "checkbox") return ` ${f.name}: false`;
2255
2277
  if (f.type === "number") return ` ${f.name}: undefined`;
2256
2278
  if (f.type === "multiselect" || f.type === "list") return ` ${f.name}: []`;
@@ -2258,140 +2280,43 @@ function generateFormComponent(schema, cwd, cmsDir, options) {
2258
2280
  if (f.defaultValue !== void 0) return ` ${f.name}: '${f.defaultValue}'`;
2259
2281
  return ` ${f.name}: ''`;
2260
2282
  }).join(",\n");
2261
- const listFields = fields.filter(
2262
- (f) => f.name && f.type === "list" && f.fields && f.fields.length > 0
2263
- );
2264
- const hasListFields = listFields.length > 0;
2265
- const fieldArrayDecls = listFields.map(
2283
+ }
2284
+ function buildFieldArrayDecls(listFields) {
2285
+ return listFields.map(
2266
2286
  (f) => ` const ${f.name}FieldArray = useFieldArray({ control: form.control, name: '${f.name}' })`
2267
2287
  ).join("\n");
2288
+ }
2289
+ function buildWatchDecls(fields) {
2268
2290
  const watchFields = /* @__PURE__ */ new Set();
2269
2291
  for (const f of fields) {
2270
2292
  if (f.showWhen) {
2271
2293
  watchFields.add(f.showWhen.field);
2272
2294
  }
2273
2295
  }
2274
- const watchDecls = Array.from(watchFields).map((wf) => ` const ${wf}Value = form.watch('${wf}')`).join("\n");
2275
- const watchSetup = watchFields.size > 0 ? `
2276
- ${watchDecls}
2277
- ` : "";
2278
- const fieldJSX = fields.filter((f) => f.name && !f.hidden).map((f) => {
2279
- let jsx = generateFieldJSX(f);
2280
- if (f.showWhen) {
2281
- const watchVar = `${f.showWhen.field}Value`;
2282
- const { value } = f.showWhen;
2283
- if (Array.isArray(value)) {
2284
- const vals = value.map((v) => `'${v}'`).join(", ");
2285
- jsx = ` {[${vals}].includes(${watchVar} as string) && (
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 };
2301
+ }
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) && (
2286
2314
  ${jsx}
2287
2315
  )}`;
2288
- } else {
2289
- jsx = ` {${watchVar} === '${value}' && (
2316
+ }
2317
+ return ` {${watchVar} === '${value}' && (
2290
2318
  ${jsx}
2291
2319
  )}`;
2292
- }
2293
- }
2294
- return jsx;
2295
- }).join("\n\n");
2296
- const submitText = schema.submitButtonText || "Submit";
2297
- const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2298
- const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2299
- const fieldArraySetup = hasListFields ? `
2300
- ${fieldArrayDecls}
2301
- ` : "";
2302
- const buttonImport = resolveUiImport(cwd, "button");
2303
- const formImport = resolveUiImport(cwd, "form");
2304
- const inputImport = resolveUiImport(cwd, "input");
2305
- const textareaImport = resolveUiImport(cwd, "textarea");
2306
- const selectImport = resolveUiImport(cwd, "select");
2307
- const content = `'use client'
2308
-
2309
- import { zodResolver } from '@hookform/resolvers/zod'
2310
- import { useState } from 'react'
2311
- ${rhfImport}
2312
- import { z } from 'zod/v3'
2313
- import { create${pascal}Submission } from '@cms/actions/${kebab}-form'
2314
- import { Button } from '${buttonImport}'
2315
- import {
2316
- Form,
2317
- FormControl,
2318
- FormDescription,
2319
- FormField,
2320
- FormItem,
2321
- FormLabel,
2322
- FormMessage,
2323
- } from '${formImport}'
2324
- import { Input } from '${inputImport}'
2325
- import { Textarea } from '${textareaImport}'
2326
- import {
2327
- Select,
2328
- SelectContent,
2329
- SelectItem,
2330
- SelectTrigger,
2331
- SelectValue,
2332
- } from '${selectImport}'
2333
-
2334
- const formSchema = z.object({
2335
- ${zodFields}
2336
- })
2337
-
2338
- type FormValues = z.infer<typeof formSchema>
2339
-
2340
- export function ${pascal}Form() {
2341
- const [submitted, setSubmitted] = useState(false)
2342
- const [submitting, setSubmitting] = useState(false)
2343
-
2344
- const form = useForm<FormValues>({
2345
- resolver: zodResolver(formSchema),
2346
- defaultValues: {
2347
- ${defaults}
2348
- },
2349
- })
2350
- ${fieldArraySetup}${watchSetup}
2351
- async function onSubmit(values: FormValues) {
2352
- setSubmitting(true)
2353
- try {
2354
- const result = await create${pascal}Submission(values)
2355
- if (result.success) {
2356
- setSubmitted(true)
2357
- } else {
2358
- form.setError('root', { message: result.error || 'Something went wrong' })
2359
- }
2360
- } catch {
2361
- form.setError('root', { message: 'Something went wrong. Please try again.' })
2362
- } finally {
2363
- setSubmitting(false)
2364
- }
2365
- }
2366
-
2367
- if (submitted) {
2368
- return (
2369
- <div className="rounded-lg border p-6 text-center">
2370
- <h3 className="text-lg font-semibold">Thank you!</h3>
2371
- <p className="mt-2 text-muted-foreground">${successMessage}</p>
2372
- </div>
2373
- )
2374
- }
2375
-
2376
- return (
2377
- <Form {...form}>
2378
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
2379
- ${fieldJSX}
2380
-
2381
- {form.formState.errors.root && (
2382
- <p className="text-sm text-destructive">{form.formState.errors.root.message}</p>
2383
- )}
2384
-
2385
- <Button type="submit" disabled={submitting}>
2386
- {submitting ? 'Submitting...' : '${submitText}'}
2387
- </Button>
2388
- </form>
2389
- </Form>
2390
- )
2391
- }
2392
- `;
2393
- fs7.writeFileSync(filePath, content, "utf-8");
2394
- return { files: [path7.relative(cwd, filePath)] };
2395
2320
  }
2396
2321
  function generateFieldJSX(field) {
2397
2322
  const name = field.name || "";
@@ -2468,36 +2393,15 @@ ${optionItems}
2468
2393
  )}
2469
2394
  />`;
2470
2395
  case "email":
2471
- return generateTextFieldJSX(
2472
- name,
2473
- label,
2474
- placeholder || "email@example.com",
2475
- hintJSX,
2476
- requiredStar,
2477
- "email"
2478
- );
2396
+ return generateTextFieldJSX(name, label, placeholder || "email@example.com", hintJSX, requiredStar, "email");
2479
2397
  case "number":
2480
2398
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "number");
2481
2399
  case "date":
2482
2400
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "date");
2483
2401
  case "url":
2484
- return generateTextFieldJSX(
2485
- name,
2486
- label,
2487
- placeholder || "https://",
2488
- hintJSX,
2489
- requiredStar,
2490
- "url"
2491
- );
2402
+ return generateTextFieldJSX(name, label, placeholder || "https://", hintJSX, requiredStar, "url");
2492
2403
  case "phone":
2493
- return generateTextFieldJSX(
2494
- name,
2495
- label,
2496
- placeholder || "+1 (555) 000-0000",
2497
- hintJSX,
2498
- requiredStar,
2499
- "tel"
2500
- );
2404
+ return generateTextFieldJSX(name, label, placeholder || "+1 (555) 000-0000", hintJSX, requiredStar, "tel");
2501
2405
  case "file":
2502
2406
  case "upload":
2503
2407
  return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, "file");
@@ -2598,9 +2502,402 @@ ${nestedFieldsJSX}
2598
2502
  </div>`;
2599
2503
  }
2600
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
+
2601
2898
  // src/generators/form-pipeline/form-database.ts
2602
- import fs8 from "fs";
2603
- import path8 from "path";
2899
+ import fs10 from "fs";
2900
+ import path10 from "path";
2604
2901
  function findTableEnd(content, startIndex) {
2605
2902
  let depth = 0;
2606
2903
  let inString = false;
@@ -2655,8 +2952,8 @@ ${fieldDefs}${customFieldsCol}
2655
2952
  updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\`CURRENT_TIMESTAMP\`).notNull()
2656
2953
  })
2657
2954
  `;
2658
- const filePath = path8.join(cwd, dbSchemaPath);
2659
- let content = fs8.readFileSync(filePath, "utf-8");
2955
+ const filePath = path10.join(cwd, dbSchemaPath);
2956
+ let content = fs10.readFileSync(filePath, "utf-8");
2660
2957
  const pgCoreMatch = content.match(/import\s+\{([^}]+)\}\s+from\s+['"]drizzle-orm\/pg-core['"]/);
2661
2958
  if (pgCoreMatch) {
2662
2959
  const existing = new Set(
@@ -2692,23 +2989,23 @@ ${match}`
2692
2989
  }
2693
2990
  content += `
2694
2991
  ${tableSchema}`;
2695
- fs8.writeFileSync(filePath, content, "utf-8");
2992
+ fs10.writeFileSync(filePath, content, "utf-8");
2696
2993
  return { files: [dbSchemaPath] };
2697
2994
  }
2698
2995
 
2699
2996
  // src/generators/form-pipeline/form-hook.ts
2700
- import fs9 from "fs";
2701
- import path9 from "path";
2997
+ import fs11 from "fs";
2998
+ import path11 from "path";
2702
2999
  function generateFormHook(schema, cwd, hooksDir, options) {
2703
3000
  const formName = schema.name;
2704
3001
  const pascal = toPascalCase(formName);
2705
3002
  const camel = toCamelCase(formName);
2706
3003
  const kebab = toKebabCase(formName);
2707
- const filePath = path9.join(cwd, hooksDir, `use-${kebab}-form.ts`);
2708
- const dir = path9.dirname(filePath);
2709
- if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
2710
- if (fs9.existsSync(filePath) && !options.force) {
2711
- return { files: [path9.relative(cwd, filePath)] };
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)] };
2712
3009
  }
2713
3010
  const successMsg = (schema.successMessage || "Form submitted successfully").replace(/'/g, "\\'");
2714
3011
  const content = `import {
@@ -2814,8 +3111,8 @@ export function useExport${pascal}SubmissionsJSON() {
2814
3111
  })
2815
3112
  }
2816
3113
  `;
2817
- fs9.writeFileSync(filePath, content, "utf-8");
2818
- return { files: [path9.relative(cwd, filePath)] };
3114
+ fs11.writeFileSync(filePath, content, "utf-8");
3115
+ return { files: [path11.relative(cwd, filePath)] };
2819
3116
  }
2820
3117
 
2821
3118
  // src/generators/form-pipeline/pipeline.ts
@@ -2881,8 +3178,8 @@ function runFormPipeline(schema, cwd, config, options = {}) {
2881
3178
  }
2882
3179
 
2883
3180
  // src/generators/actions/entity-actions.ts
2884
- import fs10 from "fs";
2885
- import path10 from "path";
3181
+ import fs12 from "fs";
3182
+ import path12 from "path";
2886
3183
 
2887
3184
  // src/generators/actions/action-helpers.ts
2888
3185
  function generateFieldMapping(field, source = "input") {
@@ -3021,9 +3318,9 @@ ${blocks.join("\n\n")}
3021
3318
 
3022
3319
  // src/generators/actions/entity-actions.ts
3023
3320
  function generateActions(schema, cwd, actionsDir, options = {}) {
3024
- const absActionsDir = path10.join(cwd, actionsDir);
3025
- const filePath = path10.join(absActionsDir, `${schema.name}.ts`);
3026
- if (fs10.existsSync(filePath) && !options.force) {
3321
+ const absActionsDir = path12.join(cwd, actionsDir);
3322
+ const filePath = path12.join(absActionsDir, `${schema.name}.ts`);
3323
+ if (fs12.existsSync(filePath) && !options.force) {
3027
3324
  return { files: [] };
3028
3325
  }
3029
3326
  const singular = singularize(schema.name);
@@ -3509,20 +3806,20 @@ export async function bulkUpdate${Plural}SortOrder(
3509
3806
  }
3510
3807
  }${m2mHelpers}
3511
3808
  `;
3512
- if (!fs10.existsSync(absActionsDir)) {
3513
- fs10.mkdirSync(absActionsDir, { recursive: true });
3809
+ if (!fs12.existsSync(absActionsDir)) {
3810
+ fs12.mkdirSync(absActionsDir, { recursive: true });
3514
3811
  }
3515
- fs10.writeFileSync(filePath, content, "utf-8");
3516
- return { files: [path10.join(actionsDir, `${schema.name}.ts`)] };
3812
+ fs12.writeFileSync(filePath, content, "utf-8");
3813
+ return { files: [path12.join(actionsDir, `${schema.name}.ts`)] };
3517
3814
  }
3518
3815
 
3519
3816
  // src/generators/actions/single-actions.ts
3520
- import fs11 from "fs";
3521
- import path11 from "path";
3817
+ import fs13 from "fs";
3818
+ import path13 from "path";
3522
3819
  function generateSingleActions(schema, cwd, actionsDir, options = {}) {
3523
- const absActionsDir = path11.join(cwd, actionsDir);
3524
- const filePath = path11.join(absActionsDir, `${schema.name}.ts`);
3525
- if (fs11.existsSync(filePath) && !options.force) {
3820
+ const absActionsDir = path13.join(cwd, actionsDir);
3821
+ const filePath = path13.join(absActionsDir, `${schema.name}.ts`);
3822
+ if (fs13.existsSync(filePath) && !options.force) {
3526
3823
  return { files: [] };
3527
3824
  }
3528
3825
  const singular = singularize(schema.name);
@@ -3645,24 +3942,24 @@ ${upsertMappings},${singleHasHtmlOutput ? "\n" + singleHtmlOutputFields.map((f)
3645
3942
  }
3646
3943
  }
3647
3944
  `;
3648
- if (!fs11.existsSync(absActionsDir)) {
3649
- fs11.mkdirSync(absActionsDir, { recursive: true });
3945
+ if (!fs13.existsSync(absActionsDir)) {
3946
+ fs13.mkdirSync(absActionsDir, { recursive: true });
3650
3947
  }
3651
- fs11.writeFileSync(filePath, content, "utf-8");
3652
- return { files: [path11.join(actionsDir, `${schema.name}.ts`)] };
3948
+ fs13.writeFileSync(filePath, content, "utf-8");
3949
+ return { files: [path13.join(actionsDir, `${schema.name}.ts`)] };
3653
3950
  }
3654
3951
 
3655
3952
  // src/generators/cache.ts
3656
- import fs12 from "fs";
3657
- import path12 from "path";
3953
+ import fs14 from "fs";
3954
+ import path14 from "path";
3658
3955
  function loadAllSchemas(cwd, schemasDir) {
3659
- const dir = path12.join(cwd, schemasDir);
3660
- if (!fs12.existsSync(dir)) return [];
3661
- const files = fs12.readdirSync(dir).filter((f) => f.endsWith(".json"));
3956
+ const dir = path14.join(cwd, schemasDir);
3957
+ if (!fs14.existsSync(dir)) return [];
3958
+ const files = fs14.readdirSync(dir).filter((f) => f.endsWith(".json"));
3662
3959
  const seen = /* @__PURE__ */ new Map();
3663
3960
  for (const file of files) {
3664
3961
  if (file === "schema.json") continue;
3665
- const content = fs12.readFileSync(path12.join(dir, file), "utf-8");
3962
+ const content = fs14.readFileSync(path14.join(dir, file), "utf-8");
3666
3963
  const schema = JSON.parse(content);
3667
3964
  if (!schema.name) continue;
3668
3965
  seen.set(schema.name, schema);
@@ -3852,27 +4149,27 @@ export * from './revalidate'
3852
4149
  `;
3853
4150
  }
3854
4151
  function generateCache(_schema, cwd, cmsDir, _options = {}) {
3855
- const cacheDir = path12.join(cwd, cmsDir, "lib", "cache");
3856
- const schemasDir = path12.join(cmsDir, "schemas");
4152
+ const cacheDir = path14.join(cwd, cmsDir, "lib", "cache");
4153
+ const schemasDir = path14.join(cmsDir, "schemas");
3857
4154
  const schemas = loadAllSchemas(cwd, schemasDir);
3858
4155
  const configs = schemas.map(buildCacheConfig).sort((a, b) => a.name.localeCompare(b.name));
3859
- if (!fs12.existsSync(cacheDir)) {
3860
- fs12.mkdirSync(cacheDir, { recursive: true });
4156
+ if (!fs14.existsSync(cacheDir)) {
4157
+ fs14.mkdirSync(cacheDir, { recursive: true });
3861
4158
  }
3862
4159
  const files = [];
3863
- fs12.writeFileSync(path12.join(cacheDir, "tags.ts"), generateTags(configs), "utf-8");
3864
- files.push(path12.join(cmsDir, "lib", "cache", "tags.ts"));
3865
- fs12.writeFileSync(
3866
- path12.join(cacheDir, "cached-queries.ts"),
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"),
3867
4164
  generateCachedQueries(configs),
3868
4165
  "utf-8"
3869
4166
  );
3870
- files.push(path12.join(cmsDir, "lib", "cache", "cached-queries.ts"));
3871
- fs12.writeFileSync(path12.join(cacheDir, "revalidate.ts"), generateRevalidate(configs), "utf-8");
3872
- files.push(path12.join(cmsDir, "lib", "cache", "revalidate.ts"));
3873
- const customQueriesPath = path12.join(cacheDir, "cached-queries-custom.ts");
3874
- if (!fs12.existsSync(customQueriesPath)) {
3875
- fs12.writeFileSync(
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(
3876
4173
  customQueriesPath,
3877
4174
  `/**
3878
4175
  * Custom cached query functions (not auto-generated)
@@ -3883,16 +4180,16 @@ export {}
3883
4180
  `,
3884
4181
  "utf-8"
3885
4182
  );
3886
- files.push(path12.join(cmsDir, "lib", "cache", "cached-queries-custom.ts"));
4183
+ files.push(path14.join(cmsDir, "lib", "cache", "cached-queries-custom.ts"));
3887
4184
  }
3888
- fs12.writeFileSync(path12.join(cacheDir, "index.ts"), generateIndex(), "utf-8");
3889
- 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"));
3890
4187
  return { files };
3891
4188
  }
3892
4189
 
3893
4190
  // src/generators/columns/generate-columns.ts
3894
- import fs14 from "fs";
3895
- import path14 from "path";
4191
+ import fs16 from "fs";
4192
+ import path16 from "path";
3896
4193
 
3897
4194
  // src/generators/columns/column-defs.ts
3898
4195
  function isSortableColumn(column) {
@@ -4510,12 +4807,12 @@ function truncateStr(str: string, maxLength: number): string {
4510
4807
  }
4511
4808
 
4512
4809
  // src/generators/columns/custom-cell.ts
4513
- import fs13 from "fs";
4514
- import path13 from "path";
4810
+ import fs15 from "fs";
4811
+ import path15 from "path";
4515
4812
  function createCustomCellComponent(schema, componentName, cwd, pagesDir, options) {
4516
- const cellsDir = path13.join(cwd, pagesDir, schema.name, "cells");
4517
- const componentFilePath = path13.join(cellsDir, `${componentName}.tsx`);
4518
- if (fs13.existsSync(componentFilePath) && !options.force) return;
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;
4519
4816
  const singular = singularize(schema.name);
4520
4817
  const Singular = toPascalCase(singular);
4521
4818
  const content = `import type { ${Singular}Data } from '@cms/actions/${schema.name}'
@@ -4532,17 +4829,17 @@ export function ${componentName}({ data }: ${componentName}Props) {
4532
4829
  )
4533
4830
  }
4534
4831
  `;
4535
- if (!fs13.existsSync(cellsDir)) {
4536
- fs13.mkdirSync(cellsDir, { recursive: true });
4832
+ if (!fs15.existsSync(cellsDir)) {
4833
+ fs15.mkdirSync(cellsDir, { recursive: true });
4537
4834
  }
4538
- fs13.writeFileSync(componentFilePath, content, "utf-8");
4835
+ fs15.writeFileSync(componentFilePath, content, "utf-8");
4539
4836
  }
4540
4837
 
4541
4838
  // src/generators/columns/generate-columns.ts
4542
4839
  function generateColumns2(schema, cwd, pagesDir, options = {}) {
4543
- const entityDir = path14.join(cwd, pagesDir, schema.name);
4544
- const columnsFilePath = path14.join(entityDir, "columns.tsx");
4545
- if (fs14.existsSync(columnsFilePath) && !options.force) {
4840
+ const entityDir = path16.join(cwd, pagesDir, schema.name);
4841
+ const columnsFilePath = path16.join(entityDir, "columns.tsx");
4842
+ if (fs16.existsSync(columnsFilePath) && !options.force) {
4546
4843
  return { files: [] };
4547
4844
  }
4548
4845
  const singular = singularize(schema.name);
@@ -4684,22 +4981,22 @@ ${restColDefs}` : ""},
4684
4981
  ${actionsColumn}
4685
4982
  ]
4686
4983
  `;
4687
- if (!fs14.existsSync(entityDir)) {
4688
- fs14.mkdirSync(entityDir, { recursive: true });
4984
+ if (!fs16.existsSync(entityDir)) {
4985
+ fs16.mkdirSync(entityDir, { recursive: true });
4689
4986
  }
4690
- fs14.writeFileSync(columnsFilePath, content, "utf-8");
4987
+ fs16.writeFileSync(columnsFilePath, content, "utf-8");
4691
4988
  return {
4692
- files: [path14.join(pagesDir, schema.name, "columns.tsx")]
4989
+ files: [path16.join(pagesDir, schema.name, "columns.tsx")]
4693
4990
  };
4694
4991
  }
4695
4992
 
4696
4993
  // src/generators/create-page.ts
4697
- import fs15 from "fs";
4698
- import path15 from "path";
4994
+ import fs17 from "fs";
4995
+ import path17 from "path";
4699
4996
  function generateCreatePage(schema, cwd, pagesDir, options = {}) {
4700
- const newDir = path15.join(cwd, pagesDir, schema.name, "new");
4701
- const pageFilePath = path15.join(newDir, "page.tsx");
4702
- if (fs15.existsSync(pageFilePath) && !options.force) {
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) {
4703
5000
  return { files: [] };
4704
5001
  }
4705
5002
  const singular = singularize(schema.name);
@@ -4726,18 +5023,18 @@ export default async function Create${Singular}Page() {
4726
5023
  )
4727
5024
  }
4728
5025
  `;
4729
- if (!fs15.existsSync(newDir)) {
4730
- fs15.mkdirSync(newDir, { recursive: true });
5026
+ if (!fs17.existsSync(newDir)) {
5027
+ fs17.mkdirSync(newDir, { recursive: true });
4731
5028
  }
4732
- fs15.writeFileSync(pageFilePath, content, "utf-8");
5029
+ fs17.writeFileSync(pageFilePath, content, "utf-8");
4733
5030
  return {
4734
- files: [path15.join(pagesDir, schema.name, "new", "page.tsx")]
5031
+ files: [path17.join(pagesDir, schema.name, "new", "page.tsx")]
4735
5032
  };
4736
5033
  }
4737
5034
 
4738
5035
  // src/generators/database.ts
4739
- import fs16 from "fs";
4740
- import path16 from "path";
5036
+ import fs18 from "fs";
5037
+ import path18 from "path";
4741
5038
  function getFieldModifiers(field, needsSql) {
4742
5039
  const modifiers = [];
4743
5040
  if (field.primaryKey) {
@@ -4918,11 +5215,11 @@ function findTableEnd2(content, startIndex) {
4918
5215
  return content.length;
4919
5216
  }
4920
5217
  function generateDatabase(schema, cwd, schemaDir, options = {}) {
4921
- const schemaFilePath = path16.join(cwd, schemaDir);
5218
+ const schemaFilePath = path18.join(cwd, schemaDir);
4922
5219
  const files = [];
4923
5220
  let content = "";
4924
- if (fs16.existsSync(schemaFilePath)) {
4925
- content = fs16.readFileSync(schemaFilePath, "utf-8");
5221
+ if (fs18.existsSync(schemaFilePath)) {
5222
+ content = fs18.readFileSync(schemaFilePath, "utf-8");
4926
5223
  }
4927
5224
  const variableName = toCamelCase(schema.name);
4928
5225
  if (content.includes(`export const ${variableName} =`) && !options.force) {
@@ -4962,11 +5259,11 @@ ${junctionDefs[i]}`;
4962
5259
  }
4963
5260
  }
4964
5261
  updated = mergeImports(updated, requiredImports, needsSql.value);
4965
- const dir = path16.dirname(schemaFilePath);
4966
- if (!fs16.existsSync(dir)) {
4967
- fs16.mkdirSync(dir, { recursive: true });
5262
+ const dir = path18.dirname(schemaFilePath);
5263
+ if (!fs18.existsSync(dir)) {
5264
+ fs18.mkdirSync(dir, { recursive: true });
4968
5265
  }
4969
- fs16.writeFileSync(schemaFilePath, updated, "utf-8");
5266
+ fs18.writeFileSync(schemaFilePath, updated, "utf-8");
4970
5267
  files.push(schemaDir);
4971
5268
  return {
4972
5269
  files,
@@ -4976,12 +5273,12 @@ ${junctionDefs[i]}`;
4976
5273
  }
4977
5274
 
4978
5275
  // src/generators/edit-page.ts
4979
- import fs17 from "fs";
4980
- import path17 from "path";
5276
+ import fs19 from "fs";
5277
+ import path19 from "path";
4981
5278
  function generateEditPage(schema, cwd, pagesDir, options = {}) {
4982
- const editDir = path17.join(cwd, pagesDir, schema.name, "[id]", "edit");
4983
- const pageFilePath = path17.join(editDir, "page.tsx");
4984
- if (fs17.existsSync(pageFilePath) && !options.force) {
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) {
4985
5282
  return { files: [] };
4986
5283
  }
4987
5284
  const singular = singularize(schema.name);
@@ -5020,18 +5317,18 @@ export default async function Edit${Singular}Page({ params }: PageProps) {
5020
5317
  )
5021
5318
  }
5022
5319
  `;
5023
- if (!fs17.existsSync(editDir)) {
5024
- fs17.mkdirSync(editDir, { recursive: true });
5320
+ if (!fs19.existsSync(editDir)) {
5321
+ fs19.mkdirSync(editDir, { recursive: true });
5025
5322
  }
5026
- fs17.writeFileSync(pageFilePath, content, "utf-8");
5323
+ fs19.writeFileSync(pageFilePath, content, "utf-8");
5027
5324
  return {
5028
- files: [path17.join(pagesDir, schema.name, "[id]", "edit", "page.tsx")]
5325
+ files: [path19.join(pagesDir, schema.name, "[id]", "edit", "page.tsx")]
5029
5326
  };
5030
5327
  }
5031
5328
 
5032
5329
  // src/generators/form/form-entity.ts
5033
- import fs18 from "fs";
5034
- import path18 from "path";
5330
+ import fs20 from "fs";
5331
+ import path20 from "path";
5035
5332
 
5036
5333
  // src/generators/form/zod-schema.ts
5037
5334
  function getFormFieldType(field) {
@@ -5829,7 +6126,7 @@ function generateDefaultValue(f) {
5829
6126
  }
5830
6127
  return ` ${f.name}: initialData?.${f.name} ?? ''`;
5831
6128
  }
5832
- function buildZodFields(flatFields) {
6129
+ function buildZodFields2(flatFields) {
5833
6130
  return flatFields.filter((f) => f.type !== "tabs").flatMap((f) => {
5834
6131
  const defs = [];
5835
6132
  const zodType = getZodType(f);
@@ -5841,7 +6138,7 @@ function buildZodFields(flatFields) {
5841
6138
  return defs;
5842
6139
  }).join(",\n");
5843
6140
  }
5844
- function buildDefaultValues(flatFields) {
6141
+ function buildDefaultValues2(flatFields) {
5845
6142
  return flatFields.filter((f) => f.type !== "tabs").flatMap((f) => {
5846
6143
  const defs = [generateDefaultValue(f)];
5847
6144
  if (f.hasIcon) defs.push(` ${f.name}Icon: initialData?.${f.name}Icon ?? ''`);
@@ -5928,9 +6225,9 @@ function buildUiImports(ctx) {
5928
6225
 
5929
6226
  // src/generators/form/form-entity.ts
5930
6227
  function generateForm(schema, cwd, pagesDir, options = {}) {
5931
- const entityDir = path18.join(cwd, pagesDir, schema.name);
5932
- const formFilePath = path18.join(entityDir, `${schema.name}-form.tsx`);
5933
- if (fs18.existsSync(formFilePath) && !options.force) {
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) {
5934
6231
  return { files: [] };
5935
6232
  }
5936
6233
  const singular = singularize(schema.name);
@@ -5984,8 +6281,8 @@ function generateForm(schema, cwd, pagesDir, options = {}) {
5984
6281
  const hasList = hasFieldType(schema.fields, "list");
5985
6282
  const hasNestedList = listFieldsWithNested.length > 0;
5986
6283
  const hasSimpleList = hasList && flatFields.some((f) => f.type === "list" && (!f.fields || f.fields.length === 0));
5987
- const zodFields = buildZodFields(flatFields);
5988
- const defaultValues = buildDefaultValues(flatFields);
6284
+ const zodFields = buildZodFields2(flatFields);
6285
+ const defaultValues = buildDefaultValues2(flatFields);
5989
6286
  const formFieldsJSX = allFormFields.filter((f) => !(hasDraft && f.name === "published")).map((f) => {
5990
6287
  if (f.type === "tabs" && f.tabs) {
5991
6288
  const tabsList = f.tabs.map((t) => ` <TabsTrigger value="${t.name}">${t.label}</TabsTrigger>`).join("\n");
@@ -6186,22 +6483,22 @@ ${hasDraft ? ` <Button
6186
6483
  )
6187
6484
  }
6188
6485
  `;
6189
- if (!fs18.existsSync(entityDir)) {
6190
- fs18.mkdirSync(entityDir, { recursive: true });
6486
+ if (!fs20.existsSync(entityDir)) {
6487
+ fs20.mkdirSync(entityDir, { recursive: true });
6191
6488
  }
6192
- fs18.writeFileSync(formFilePath, content, "utf-8");
6489
+ fs20.writeFileSync(formFilePath, content, "utf-8");
6193
6490
  return {
6194
- files: [path18.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6491
+ files: [path20.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6195
6492
  };
6196
6493
  }
6197
6494
 
6198
6495
  // src/generators/form/form-single.ts
6199
- import fs19 from "fs";
6200
- import path19 from "path";
6496
+ import fs21 from "fs";
6497
+ import path21 from "path";
6201
6498
  function generateSingleForm(schema, cwd, pagesDir, options = {}) {
6202
- const entityDir = path19.join(cwd, pagesDir, schema.name);
6203
- const formFilePath = path19.join(entityDir, `${schema.name}-form.tsx`);
6204
- if (fs19.existsSync(formFilePath) && !options.force) {
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) {
6205
6502
  return { files: [] };
6206
6503
  }
6207
6504
  const singular = singularize(schema.name);
@@ -6253,8 +6550,8 @@ function generateSingleForm(schema, cwd, pagesDir, options = {}) {
6253
6550
  const hasList = hasFieldType(schema.fields, "list");
6254
6551
  const hasNestedList = listFieldsWithNested.length > 0;
6255
6552
  const hasSimpleList = hasList && flatFields.some((f) => f.type === "list" && (!f.fields || f.fields.length === 0));
6256
- const zodFields = buildZodFields(flatFields);
6257
- const defaultValues = buildDefaultValues(flatFields);
6553
+ const zodFields = buildZodFields2(flatFields);
6554
+ const defaultValues = buildDefaultValues2(flatFields);
6258
6555
  const formFieldsJSX = allFormFields.map((f) => {
6259
6556
  if (f.type === "tabs" && f.tabs) {
6260
6557
  const tabsList = f.tabs.map((t) => ` <TabsTrigger value="${t.name}">${t.label}</TabsTrigger>`).join("\n");
@@ -6404,21 +6701,21 @@ ${formFieldsJSX}
6404
6701
  )
6405
6702
  }
6406
6703
  `;
6407
- if (!fs19.existsSync(entityDir)) {
6408
- fs19.mkdirSync(entityDir, { recursive: true });
6704
+ if (!fs21.existsSync(entityDir)) {
6705
+ fs21.mkdirSync(entityDir, { recursive: true });
6409
6706
  }
6410
- fs19.writeFileSync(formFilePath, content, "utf-8");
6707
+ fs21.writeFileSync(formFilePath, content, "utf-8");
6411
6708
  return {
6412
- files: [path19.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6709
+ files: [path21.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]
6413
6710
  };
6414
6711
  }
6415
6712
 
6416
6713
  // src/generators/hook.ts
6417
- import fs20 from "fs";
6418
- import path20 from "path";
6714
+ import fs22 from "fs";
6715
+ import path22 from "path";
6419
6716
  function generateHook(schema, cwd, hooksDir, options = {}) {
6420
6717
  const hookFileName = `use-${schema.name}.ts`;
6421
- const hookFilePath = path20.join(cwd, hooksDir, hookFileName);
6718
+ const hookFilePath = path22.join(cwd, hooksDir, hookFileName);
6422
6719
  const singular = singularize(schema.name);
6423
6720
  const plural = pluralize(schema.name);
6424
6721
  const Singular = toPascalCase(singular);
@@ -6428,7 +6725,7 @@ function generateHook(schema, cwd, hooksDir, options = {}) {
6428
6725
  const hasHtmlOutput = dbFields.some(
6429
6726
  (f) => (f.type === "richtext" || f.type === "markdown") && f.output === "html"
6430
6727
  );
6431
- if (fs20.existsSync(hookFilePath) && !options.force) {
6728
+ if (fs22.existsSync(hookFilePath) && !options.force) {
6432
6729
  return { files: [], hookName: `use${Plural}` };
6433
6730
  }
6434
6731
  const hasFilters = schema.filters && schema.filters.length > 0;
@@ -6503,22 +6800,22 @@ export function use${Plural}(
6503
6800
  }
6504
6801
  ${singularHook}${slugHook}${distinctHooks}
6505
6802
  `;
6506
- const dir = path20.dirname(hookFilePath);
6507
- if (!fs20.existsSync(dir)) {
6508
- fs20.mkdirSync(dir, { recursive: true });
6803
+ const dir = path22.dirname(hookFilePath);
6804
+ if (!fs22.existsSync(dir)) {
6805
+ fs22.mkdirSync(dir, { recursive: true });
6509
6806
  }
6510
- fs20.writeFileSync(hookFilePath, content, "utf-8");
6807
+ fs22.writeFileSync(hookFilePath, content, "utf-8");
6511
6808
  return {
6512
- files: [path20.join(hooksDir, hookFileName)],
6809
+ files: [path22.join(hooksDir, hookFileName)],
6513
6810
  hookName: `use${Plural}`
6514
6811
  };
6515
6812
  }
6516
6813
  function generateSingleHook(schema, cwd, hooksDir, options = {}) {
6517
6814
  const hookFileName = `use-${schema.name}.ts`;
6518
- const hookFilePath = path20.join(cwd, hooksDir, hookFileName);
6815
+ const hookFilePath = path22.join(cwd, hooksDir, hookFileName);
6519
6816
  const singular = singularize(schema.name);
6520
6817
  const Singular = toPascalCase(singular);
6521
- if (fs20.existsSync(hookFilePath) && !options.force) {
6818
+ if (fs22.existsSync(hookFilePath) && !options.force) {
6522
6819
  return { files: [], hookName: `use${Singular}` };
6523
6820
  }
6524
6821
  const content = `import {
@@ -6535,20 +6832,20 @@ export function use${Singular}(): UseQueryResult<${Singular}Data | null, Error>
6535
6832
  })
6536
6833
  }
6537
6834
  `;
6538
- const dir = path20.dirname(hookFilePath);
6539
- if (!fs20.existsSync(dir)) {
6540
- fs20.mkdirSync(dir, { recursive: true });
6835
+ const dir = path22.dirname(hookFilePath);
6836
+ if (!fs22.existsSync(dir)) {
6837
+ fs22.mkdirSync(dir, { recursive: true });
6541
6838
  }
6542
- fs20.writeFileSync(hookFilePath, content, "utf-8");
6839
+ fs22.writeFileSync(hookFilePath, content, "utf-8");
6543
6840
  return {
6544
- files: [path20.join(hooksDir, hookFileName)],
6841
+ files: [path22.join(hooksDir, hookFileName)],
6545
6842
  hookName: `use${Singular}`
6546
6843
  };
6547
6844
  }
6548
6845
 
6549
6846
  // src/generators/navigation.ts
6550
- import fs21 from "fs";
6551
- import path21 from "path";
6847
+ import fs23 from "fs";
6848
+ import path23 from "path";
6552
6849
  function parseNavigationFile2(content) {
6553
6850
  const iconImportMatch = content.match(/import\s*\{([^}]+)\}\s*from\s*['"]lucide-react['"]/);
6554
6851
  const iconImports = iconImportMatch ? iconImportMatch[1].split(",").map((s) => s.trim()).filter((s) => s && s !== "LucideIcon") : [];
@@ -6651,14 +6948,14 @@ function appendItem2(lines, item, isLast) {
6651
6948
  lines.push(` }${isLast ? "" : ","}`);
6652
6949
  }
6653
6950
  function updateNavigation(schema, cwd, cmsDir, options = {}) {
6654
- const navFilePath = path21.join(cwd, cmsDir, "data", "navigation.ts");
6951
+ const navFilePath = path23.join(cwd, cmsDir, "data", "navigation.ts");
6655
6952
  if (schema.name === "settings") {
6656
6953
  return { files: [] };
6657
6954
  }
6658
6955
  let items = [];
6659
6956
  let iconImports = [];
6660
- if (fs21.existsSync(navFilePath)) {
6661
- const content = fs21.readFileSync(navFilePath, "utf-8");
6957
+ if (fs23.existsSync(navFilePath)) {
6958
+ const content = fs23.readFileSync(navFilePath, "utf-8");
6662
6959
  const parsed = parseNavigationFile2(content);
6663
6960
  items = parsed.items;
6664
6961
  iconImports = parsed.iconImports;
@@ -6695,24 +6992,24 @@ function updateNavigation(schema, cwd, cmsDir, options = {}) {
6695
6992
  iconImports.push(schema.icon);
6696
6993
  }
6697
6994
  iconImports.sort();
6698
- const dir = path21.dirname(navFilePath);
6699
- if (!fs21.existsSync(dir)) {
6700
- fs21.mkdirSync(dir, { recursive: true });
6995
+ const dir = path23.dirname(navFilePath);
6996
+ if (!fs23.existsSync(dir)) {
6997
+ fs23.mkdirSync(dir, { recursive: true });
6701
6998
  }
6702
6999
  const code = generateNavigationCode2(items, iconImports);
6703
- fs21.writeFileSync(navFilePath, code, "utf-8");
7000
+ fs23.writeFileSync(navFilePath, code, "utf-8");
6704
7001
  return {
6705
- files: [path21.join(cmsDir, "data", "navigation.ts")]
7002
+ files: [path23.join(cmsDir, "data", "navigation.ts")]
6706
7003
  };
6707
7004
  }
6708
7005
 
6709
7006
  // src/generators/page.ts
6710
- import fs22 from "fs";
6711
- import path22 from "path";
7007
+ import fs24 from "fs";
7008
+ import path24 from "path";
6712
7009
  function generatePage2(schema, cwd, pagesDir, options = {}) {
6713
- const entityDir = path22.join(cwd, pagesDir, schema.name);
6714
- const pageFilePath = path22.join(entityDir, "page.tsx");
6715
- if (fs22.existsSync(pageFilePath) && !options.force) {
7010
+ const entityDir = path24.join(cwd, pagesDir, schema.name);
7011
+ const pageFilePath = path24.join(entityDir, "page.tsx");
7012
+ if (fs24.existsSync(pageFilePath) && !options.force) {
6716
7013
  return { files: [] };
6717
7014
  }
6718
7015
  const plural = pluralize(schema.name);
@@ -6738,27 +7035,27 @@ export default function ${Plural}Page() {
6738
7035
  )
6739
7036
  }
6740
7037
  `;
6741
- if (!fs22.existsSync(entityDir)) {
6742
- fs22.mkdirSync(entityDir, { recursive: true });
7038
+ if (!fs24.existsSync(entityDir)) {
7039
+ fs24.mkdirSync(entityDir, { recursive: true });
6743
7040
  }
6744
- fs22.writeFileSync(pageFilePath, content, "utf-8");
7041
+ fs24.writeFileSync(pageFilePath, content, "utf-8");
6745
7042
  return {
6746
- files: [path22.join(pagesDir, schema.name, "page.tsx")]
7043
+ files: [path24.join(pagesDir, schema.name, "page.tsx")]
6747
7044
  };
6748
7045
  }
6749
7046
 
6750
7047
  // src/generators/page-content.ts
6751
- import fs23 from "fs";
6752
- import path23 from "path";
7048
+ import fs25 from "fs";
7049
+ import path25 from "path";
6753
7050
  function generatePageContent2(schema, cwd, pagesDir, options = {}) {
6754
- const entityDir = path23.join(cwd, pagesDir, schema.name);
7051
+ const entityDir = path25.join(cwd, pagesDir, schema.name);
6755
7052
  const singular = singularize(schema.name);
6756
7053
  const plural = pluralize(schema.name);
6757
7054
  const Singular = toPascalCase(singular);
6758
7055
  const Plural = toPascalCase(plural);
6759
7056
  const fileName = `${toKebabCase(plural)}-page-content.tsx`;
6760
- const filePath = path23.join(entityDir, fileName);
6761
- if (fs23.existsSync(filePath) && !options.force) {
7057
+ const filePath = path25.join(entityDir, fileName);
7058
+ if (fs25.existsSync(filePath) && !options.force) {
6762
7059
  return { files: [] };
6763
7060
  }
6764
7061
  const hasCreate = schema.actions?.create ?? false;
@@ -7011,22 +7308,22 @@ ${searchLogic}${deleteLogic}
7011
7308
  )
7012
7309
  }
7013
7310
  `;
7014
- if (!fs23.existsSync(entityDir)) {
7015
- fs23.mkdirSync(entityDir, { recursive: true });
7311
+ if (!fs25.existsSync(entityDir)) {
7312
+ fs25.mkdirSync(entityDir, { recursive: true });
7016
7313
  }
7017
- fs23.writeFileSync(filePath, content, "utf-8");
7314
+ fs25.writeFileSync(filePath, content, "utf-8");
7018
7315
  return {
7019
- files: [path23.join(pagesDir, schema.name, fileName)]
7316
+ files: [path25.join(pagesDir, schema.name, fileName)]
7020
7317
  };
7021
7318
  }
7022
7319
 
7023
7320
  // src/generators/single-page.ts
7024
- import fs24 from "fs";
7025
- import path24 from "path";
7321
+ import fs26 from "fs";
7322
+ import path26 from "path";
7026
7323
  function generateSinglePage(schema, cwd, pagesDir, options = {}) {
7027
- const entityDir = path24.join(cwd, pagesDir, schema.name);
7028
- const pageFilePath = path24.join(entityDir, "page.tsx");
7029
- if (fs24.existsSync(pageFilePath) && !options.force) {
7324
+ const entityDir = path26.join(cwd, pagesDir, schema.name);
7325
+ const pageFilePath = path26.join(entityDir, "page.tsx");
7326
+ if (fs26.existsSync(pageFilePath) && !options.force) {
7030
7327
  return { files: [] };
7031
7328
  }
7032
7329
  const singular = singularize(schema.name);
@@ -7049,20 +7346,20 @@ export default async function ${PageName}Page() {
7049
7346
  )
7050
7347
  }
7051
7348
  `;
7052
- if (!fs24.existsSync(entityDir)) {
7053
- fs24.mkdirSync(entityDir, { recursive: true });
7349
+ if (!fs26.existsSync(entityDir)) {
7350
+ fs26.mkdirSync(entityDir, { recursive: true });
7054
7351
  }
7055
- fs24.writeFileSync(pageFilePath, content, "utf-8");
7352
+ fs26.writeFileSync(pageFilePath, content, "utf-8");
7056
7353
  return {
7057
- files: [path24.join(pagesDir, schema.name, "page.tsx")]
7354
+ files: [path26.join(pagesDir, schema.name, "page.tsx")]
7058
7355
  };
7059
7356
  }
7060
7357
 
7061
7358
  // src/generators/table.ts
7062
- import fs25 from "fs";
7063
- import path25 from "path";
7359
+ import fs27 from "fs";
7360
+ import path27 from "path";
7064
7361
  function generateTable2(schema, cwd, pagesDir, options = {}) {
7065
- const entityDir = path25.join(cwd, pagesDir, schema.name);
7362
+ const entityDir = path27.join(cwd, pagesDir, schema.name);
7066
7363
  const singular = singularize(schema.name);
7067
7364
  const plural = pluralize(schema.name);
7068
7365
  const Singular = toPascalCase(singular);
@@ -7070,8 +7367,8 @@ function generateTable2(schema, cwd, pagesDir, options = {}) {
7070
7367
  const camelPlural = toCamelCase(plural);
7071
7368
  const camelSingular = toCamelCase(singular);
7072
7369
  const tableFileName = `${toKebabCase(plural)}-table.tsx`;
7073
- const tableFilePath = path25.join(entityDir, tableFileName);
7074
- if (fs25.existsSync(tableFilePath) && !options.force) {
7370
+ const tableFilePath = path27.join(entityDir, tableFileName);
7371
+ if (fs27.existsSync(tableFilePath) && !options.force) {
7075
7372
  return { files: [] };
7076
7373
  }
7077
7374
  const hasFilters = schema.filters && schema.filters.length > 0;
@@ -7435,12 +7732,12 @@ export function ${Plural}Table<TValue>({ columns, selectedIds, setSelectedIds, $
7435
7732
  )
7436
7733
  }
7437
7734
  `;
7438
- if (!fs25.existsSync(entityDir)) {
7439
- fs25.mkdirSync(entityDir, { recursive: true });
7735
+ if (!fs27.existsSync(entityDir)) {
7736
+ fs27.mkdirSync(entityDir, { recursive: true });
7440
7737
  }
7441
- fs25.writeFileSync(tableFilePath, content, "utf-8");
7738
+ fs27.writeFileSync(tableFilePath, content, "utf-8");
7442
7739
  return {
7443
- files: [path25.join(pagesDir, schema.name, tableFileName)]
7740
+ files: [path27.join(pagesDir, schema.name, tableFileName)]
7444
7741
  };
7445
7742
  }
7446
7743
 
@@ -7598,13 +7895,13 @@ function runSinglePipeline(schema, cwd, config, options = {}) {
7598
7895
 
7599
7896
  // src/generators/post-generate.ts
7600
7897
  import { execFileSync as execFileSync2 } from "child_process";
7601
- import fs27 from "fs";
7602
- import path27 from "path";
7898
+ import fs29 from "fs";
7899
+ import path29 from "path";
7603
7900
 
7604
7901
  // src/utils/package-manager.ts
7605
7902
  import { execFileSync } from "child_process";
7606
- import fs26 from "fs";
7607
- import path26 from "path";
7903
+ import fs28 from "fs";
7904
+ import path28 from "path";
7608
7905
  var LOCKFILE_MAP = {
7609
7906
  "pnpm-lock.yaml": "pnpm",
7610
7907
  "package-lock.json": "npm",
@@ -7613,18 +7910,18 @@ var LOCKFILE_MAP = {
7613
7910
  "bun.lock": "bun"
7614
7911
  };
7615
7912
  function detectPackageManager(cwd) {
7616
- let dir = path26.resolve(cwd);
7617
- const root = path26.parse(dir).root;
7913
+ let dir = path28.resolve(cwd);
7914
+ const root = path28.parse(dir).root;
7618
7915
  while (dir !== root) {
7619
7916
  for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {
7620
- if (fs26.existsSync(path26.join(dir, lockfile))) {
7917
+ if (fs28.existsSync(path28.join(dir, lockfile))) {
7621
7918
  return pm;
7622
7919
  }
7623
7920
  }
7624
- const pkgPath = path26.join(dir, "package.json");
7625
- if (fs26.existsSync(pkgPath)) {
7921
+ const pkgPath = path28.join(dir, "package.json");
7922
+ if (fs28.existsSync(pkgPath)) {
7626
7923
  try {
7627
- const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
7924
+ const pkg = JSON.parse(fs28.readFileSync(pkgPath, "utf-8"));
7628
7925
  if (typeof pkg.packageManager === "string") {
7629
7926
  const name = pkg.packageManager.split("@")[0];
7630
7927
  if (name === "pnpm" || name === "npm" || name === "yarn" || name === "bun") {
@@ -7634,7 +7931,7 @@ function detectPackageManager(cwd) {
7634
7931
  } catch {
7635
7932
  }
7636
7933
  }
7637
- dir = path26.dirname(dir);
7934
+ dir = path28.dirname(dir);
7638
7935
  }
7639
7936
  return "npm";
7640
7937
  }
@@ -7665,9 +7962,9 @@ function createNextAppCommand(pm) {
7665
7962
 
7666
7963
  // src/generators/post-generate.ts
7667
7964
  function loadEnvFile(cwd) {
7668
- const envPath = path27.join(cwd, ".env.local");
7669
- if (!fs27.existsSync(envPath)) return;
7670
- const content = fs27.readFileSync(envPath, "utf-8");
7965
+ const envPath = path29.join(cwd, ".env.local");
7966
+ if (!fs29.existsSync(envPath)) return;
7967
+ const content = fs29.readFileSync(envPath, "utf-8");
7671
7968
  for (const line of content.split("\n")) {
7672
7969
  const trimmed = line.trim();
7673
7970
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -7697,10 +7994,10 @@ function runPmScript(pm, script, cwd) {
7697
7994
  }
7698
7995
  }
7699
7996
  function hasPkgScript(cwd, script) {
7700
- const pkgPath = path27.join(cwd, "package.json");
7701
- if (!fs27.existsSync(pkgPath)) return false;
7997
+ const pkgPath = path29.join(cwd, "package.json");
7998
+ if (!fs29.existsSync(pkgPath)) return false;
7702
7999
  try {
7703
- const pkg = JSON.parse(fs27.readFileSync(pkgPath, "utf-8"));
8000
+ const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf-8"));
7704
8001
  const scripts = pkg.scripts;
7705
8002
  return !!scripts?.[script];
7706
8003
  } catch {
@@ -7727,7 +8024,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7727
8024
  console.log(ok ? " Database schema synced" : " Database push failed (run db:push manually)");
7728
8025
  } else {
7729
8026
  console.log("\n Running drizzle-kit push...");
7730
- const drizzleBin = path27.join(cwd, "node_modules", ".bin", "drizzle-kit");
8027
+ const drizzleBin = path29.join(cwd, "node_modules", ".bin", "drizzle-kit");
7731
8028
  try {
7732
8029
  execFileSync2(drizzleBin, ["push", "--force"], { cwd, stdio: "inherit" });
7733
8030
  result.dbPush = "success";
@@ -7746,7 +8043,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7746
8043
  result.lintFix = ok ? "success" : "failed";
7747
8044
  console.log(ok ? " Code formatted" : " Lint fix had issues (run lint:fix manually)");
7748
8045
  } else {
7749
- const biomeBin = path27.join(cwd, "node_modules", ".bin", "biome");
8046
+ const biomeBin = path29.join(cwd, "node_modules", ".bin", "biome");
7750
8047
  try {
7751
8048
  execFileSync2(biomeBin, ["check", "--write", "."], { cwd, stdio: "pipe" });
7752
8049
  result.lintFix = "success";
@@ -7769,7 +8066,7 @@ function runPostGenerate(cwd, schemaName, options = {}) {
7769
8066
  // src/commands/generate.ts
7770
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(
7771
8068
  async (schemaName, options) => {
7772
- const cwd = options.cwd ? path28.resolve(options.cwd) : process.cwd();
8069
+ const cwd = options.cwd ? path30.resolve(options.cwd) : process.cwd();
7773
8070
  console.log("\n BetterStart Generator\n");
7774
8071
  let config;
7775
8072
  try {
@@ -7778,7 +8075,7 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7778
8075
  console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`);
7779
8076
  process.exit(1);
7780
8077
  }
7781
- const schemasDir = path28.join(cwd, config.paths?.schemas ?? "./cms/schemas");
8078
+ const schemasDir = path30.join(cwd, config.paths?.schemas ?? "./cms/schemas");
7782
8079
  console.log(` Project root: ${cwd}`);
7783
8080
  console.log(` Loading schema: ${schemaName}.json
7784
8081
  `);
@@ -7790,7 +8087,7 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7790
8087
  console.error(` ${err.message}`);
7791
8088
  console.error(
7792
8089
  `
7793
- Create a schema file at: ${path28.join(schemasDir, `${schemaName}.json`)}`
8090
+ Create a schema file at: ${path30.join(schemasDir, `${schemaName}.json`)}`
7794
8091
  );
7795
8092
  } else {
7796
8093
  console.error(
@@ -7883,8 +8180,8 @@ var generateCommand = new Command("generate").alias("g").description("Generate e
7883
8180
 
7884
8181
  // src/commands/init.ts
7885
8182
  import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
7886
- import fs38 from "fs";
7887
- import path43 from "path";
8183
+ import fs40 from "fs";
8184
+ import path45 from "path";
7888
8185
  import * as p4 from "@clack/prompts";
7889
8186
  import { Command as Command3 } from "commander";
7890
8187
  import pc2 from "picocolors";
@@ -8027,21 +8324,21 @@ async function promptProject(defaultName) {
8027
8324
  }
8028
8325
 
8029
8326
  // src/init/scaffolders/api-routes.ts
8030
- import path30 from "path";
8327
+ import path32 from "path";
8031
8328
 
8032
8329
  // src/utils/fs.ts
8033
- import fs28 from "fs";
8034
- import path29 from "path";
8330
+ import fs30 from "fs";
8331
+ import path31 from "path";
8035
8332
  import fse from "fs-extra";
8036
8333
  function ensureDir(dirPath) {
8037
8334
  fse.ensureDirSync(dirPath);
8038
8335
  }
8039
8336
  function safeWriteFile(filePath, content, force = false) {
8040
- if (!force && fs28.existsSync(filePath)) {
8337
+ if (!force && fs30.existsSync(filePath)) {
8041
8338
  return false;
8042
8339
  }
8043
- ensureDir(path29.dirname(filePath));
8044
- fs28.writeFileSync(filePath, content, "utf-8");
8340
+ ensureDir(path31.dirname(filePath));
8341
+ fs30.writeFileSync(filePath, content, "utf-8");
8045
8342
  return true;
8046
8343
  }
8047
8344
 
@@ -8135,21 +8432,21 @@ export async function POST(request: NextRequest) {
8135
8432
  // src/init/scaffolders/api-routes.ts
8136
8433
  function scaffoldApiRoutes({ cwd, config }) {
8137
8434
  const created = [];
8138
- const apiDir = path30.resolve(cwd, config.paths.api);
8435
+ const apiDir = path32.resolve(cwd, config.paths.api);
8139
8436
  function write(relPath, content) {
8140
- const fullPath = path30.join(apiDir, relPath);
8141
- ensureDir(path30.dirname(fullPath));
8437
+ const fullPath = path32.join(apiDir, relPath);
8438
+ ensureDir(path32.dirname(fullPath));
8142
8439
  if (safeWriteFile(fullPath, content)) {
8143
- created.push(path30.join(config.paths.api, relPath));
8440
+ created.push(path32.join(config.paths.api, relPath));
8144
8441
  }
8145
8442
  }
8146
- write(path30.join("auth", "[...all]", "route.ts"), authRouteTemplate());
8147
- write(path30.join("upload", "route.ts"), uploadRouteTemplate());
8443
+ write(path32.join("auth", "[...all]", "route.ts"), authRouteTemplate());
8444
+ write(path32.join("upload", "route.ts"), uploadRouteTemplate());
8148
8445
  return created;
8149
8446
  }
8150
8447
 
8151
8448
  // src/init/scaffolders/auth.ts
8152
- import path31 from "path";
8449
+ import path33 from "path";
8153
8450
 
8154
8451
  // src/init/templates/lib/auth/auth.ts
8155
8452
  function authTemplate() {
@@ -8268,11 +8565,11 @@ export async function requireRole(allowedRoles: UserRole[]): Promise<User> {
8268
8565
  // src/init/scaffolders/auth.ts
8269
8566
  function scaffoldAuth({ cwd, config }) {
8270
8567
  const created = [];
8271
- const authDir = path31.resolve(cwd, config.paths.cms, "lib", "auth");
8568
+ const authDir = path33.resolve(cwd, config.paths.cms, "lib", "auth");
8272
8569
  function write(filename, content) {
8273
- const fullPath = path31.join(authDir, filename);
8570
+ const fullPath = path33.join(authDir, filename);
8274
8571
  if (safeWriteFile(fullPath, content)) {
8275
- created.push(path31.join(config.paths.cms, "lib", "auth", filename));
8572
+ created.push(path33.join(config.paths.cms, "lib", "auth", filename));
8276
8573
  }
8277
8574
  }
8278
8575
  write("auth.ts", authTemplate());
@@ -8282,51 +8579,51 @@ function scaffoldAuth({ cwd, config }) {
8282
8579
  }
8283
8580
 
8284
8581
  // src/init/scaffolders/base.ts
8285
- import fs29 from "fs";
8286
- import path32 from "path";
8582
+ import fs31 from "fs";
8583
+ import path34 from "path";
8287
8584
  function scaffoldBase({ cwd, config }) {
8288
8585
  const created = [];
8289
8586
  const cmsDirs = [
8290
8587
  config.paths.cms,
8291
8588
  config.paths.schemas,
8292
- path32.join(config.paths.cms, "db"),
8293
- path32.join(config.paths.cms, "db", "migrations"),
8294
- path32.join(config.paths.cms, "lib", "auth"),
8295
- path32.join(config.paths.cms, "lib", "actions"),
8296
- path32.join(config.paths.cms, "lib", "cache"),
8297
- path32.join(config.paths.cms, "lib", "markdown"),
8298
- path32.join(config.paths.cms, "lib", "emails"),
8299
- path32.join(config.paths.cms, "lib"),
8300
- path32.join(config.paths.cms, "hooks"),
8301
- path32.join(config.paths.cms, "components", "ui"),
8302
- path32.join(config.paths.cms, "components", "form"),
8303
- path32.join(config.paths.cms, "components", "data-table"),
8304
- path32.join(config.paths.cms, "components", "layout"),
8305
- path32.join(config.paths.cms, "components", "shared"),
8306
- path32.join(config.paths.cms, "types"),
8307
- path32.join(config.paths.cms, "utils"),
8308
- path32.join(config.paths.cms, "data")
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")
8309
8606
  ];
8310
8607
  for (const dir of cmsDirs) {
8311
- ensureDir(path32.resolve(cwd, dir));
8608
+ ensureDir(path34.resolve(cwd, dir));
8312
8609
  }
8313
8610
  const appDirs = [config.paths.pages, config.paths.login, config.paths.api];
8314
8611
  for (const dir of appDirs) {
8315
- ensureDir(path32.resolve(cwd, dir));
8612
+ ensureDir(path34.resolve(cwd, dir));
8316
8613
  }
8317
8614
  const configContent = generateConfigFile(config);
8318
- if (safeWriteFile(path32.resolve(cwd, "cms.config.ts"), configContent)) {
8615
+ if (safeWriteFile(path34.resolve(cwd, "cms.config.ts"), configContent)) {
8319
8616
  created.push("cms.config.ts");
8320
8617
  }
8321
8618
  const cmsDoc = generateCmsDoc(config, {});
8322
- if (safeWriteFile(path32.resolve(cwd, "CMS.md"), cmsDoc)) {
8619
+ if (safeWriteFile(path34.resolve(cwd, "CMS.md"), cmsDoc)) {
8323
8620
  created.push("CMS.md");
8324
8621
  }
8325
8622
  return created;
8326
8623
  }
8327
8624
  function regenerateCmsDoc(cwd, config, options) {
8328
8625
  const content = generateCmsDoc(config, options);
8329
- fs29.writeFileSync(path32.resolve(cwd, "CMS.md"), content, "utf-8");
8626
+ fs31.writeFileSync(path34.resolve(cwd, "CMS.md"), content, "utf-8");
8330
8627
  }
8331
8628
  function generateConfigFile(config) {
8332
8629
  return `import { defineConfig } from '@betterstart/cli'
@@ -8480,8 +8777,8 @@ Edit \`cms.config.ts\` to customize paths, database provider, and features.`);
8480
8777
  }
8481
8778
 
8482
8779
  // src/init/scaffolders/biome.ts
8483
- import fs30 from "fs";
8484
- import path33 from "path";
8780
+ import fs32 from "fs";
8781
+ import path35 from "path";
8485
8782
  function scaffoldBiome(cwd, linter) {
8486
8783
  if (linter.type !== "none") {
8487
8784
  return {
@@ -8489,8 +8786,8 @@ function scaffoldBiome(cwd, linter) {
8489
8786
  skippedReason: `${linter.type} already configured (${linter.configFile})`
8490
8787
  };
8491
8788
  }
8492
- const configPath = path33.join(cwd, "biome.json");
8493
- if (fs30.existsSync(configPath)) {
8789
+ const configPath = path35.join(cwd, "biome.json");
8790
+ if (fs32.existsSync(configPath)) {
8494
8791
  return { installed: false, skippedReason: "biome.json already exists" };
8495
8792
  }
8496
8793
  const config = {
@@ -8541,52 +8838,52 @@ function scaffoldBiome(cwd, linter) {
8541
8838
  ]
8542
8839
  }
8543
8840
  };
8544
- fs30.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
8841
+ fs32.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
8545
8842
  `, "utf-8");
8546
8843
  return { installed: true, skippedReason: null };
8547
8844
  }
8548
8845
 
8549
8846
  // src/init/scaffolders/components.ts
8550
- import path35 from "path";
8551
- import fs32 from "fs-extra";
8847
+ import path37 from "path";
8848
+ import fs34 from "fs-extra";
8552
8849
 
8553
8850
  // src/utils/detect.ts
8554
- import fs31 from "fs";
8555
- import path34 from "path";
8851
+ import fs33 from "fs";
8852
+ import path36 from "path";
8556
8853
  var NEXT_CONFIG_FILES = ["next.config.ts", "next.config.js", "next.config.mjs"];
8557
8854
  function detectProjectName(cwd) {
8558
- const pkgPath = path34.join(cwd, "package.json");
8559
- if (fs31.existsSync(pkgPath)) {
8855
+ const pkgPath = path36.join(cwd, "package.json");
8856
+ if (fs33.existsSync(pkgPath)) {
8560
8857
  try {
8561
- const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
8858
+ const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
8562
8859
  if (typeof pkg.name === "string" && pkg.name.length > 0) {
8563
8860
  return formatProjectName(pkg.name);
8564
8861
  }
8565
8862
  } catch {
8566
8863
  }
8567
8864
  }
8568
- return formatProjectName(path34.basename(cwd));
8865
+ return formatProjectName(path36.basename(cwd));
8569
8866
  }
8570
8867
  function formatProjectName(name) {
8571
8868
  const base = name.includes("/") ? name.split("/").pop() : name;
8572
8869
  return base.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
8573
8870
  }
8574
8871
  function detectProject(cwd) {
8575
- const isExisting = NEXT_CONFIG_FILES.some((f) => fs31.existsSync(path34.join(cwd, f)));
8576
- const hasSrcDir = fs31.existsSync(path34.join(cwd, "src"));
8577
- const hasTypeScript = fs31.existsSync(path34.join(cwd, "tsconfig.json")) || fs31.existsSync(path34.join(cwd, "tsconfig.app.json"));
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"));
8578
8875
  const hasTailwind = detectTailwind(cwd);
8579
8876
  const linter = detectLinter(cwd);
8580
8877
  const conflicts = [];
8581
8878
  if (isExisting) {
8582
- if (fs31.existsSync(path34.join(cwd, "cms"))) {
8879
+ if (fs33.existsSync(path36.join(cwd, "cms"))) {
8583
8880
  conflicts.push("cms/ directory already exists");
8584
8881
  }
8585
- if (fs31.existsSync(path34.join(cwd, "cms.config.ts"))) {
8882
+ if (fs33.existsSync(path36.join(cwd, "cms.config.ts"))) {
8586
8883
  conflicts.push("cms.config.ts already exists");
8587
8884
  }
8588
8885
  const appBase = hasSrcDir ? "src/app" : "app";
8589
- if (fs31.existsSync(path34.join(cwd, appBase, "(cms)"))) {
8886
+ if (fs33.existsSync(path36.join(cwd, appBase, "(cms)"))) {
8590
8887
  conflicts.push(`${appBase}/(cms)/ route group already exists`);
8591
8888
  }
8592
8889
  if (hasTsconfigCmsAliases(cwd)) {
@@ -8613,19 +8910,19 @@ var ESLINT_CONFIG_FILES = [
8613
8910
  ];
8614
8911
  function detectLinter(cwd) {
8615
8912
  for (const f of BIOME_CONFIG_FILES) {
8616
- if (fs31.existsSync(path34.join(cwd, f))) {
8913
+ if (fs33.existsSync(path36.join(cwd, f))) {
8617
8914
  return { type: "biome", configFile: f };
8618
8915
  }
8619
8916
  }
8620
8917
  for (const f of ESLINT_CONFIG_FILES) {
8621
- if (fs31.existsSync(path34.join(cwd, f))) {
8918
+ if (fs33.existsSync(path36.join(cwd, f))) {
8622
8919
  return { type: "eslint", configFile: f };
8623
8920
  }
8624
8921
  }
8625
- const pkgPath = path34.join(cwd, "package.json");
8626
- if (fs31.existsSync(pkgPath)) {
8922
+ const pkgPath = path36.join(cwd, "package.json");
8923
+ if (fs33.existsSync(pkgPath)) {
8627
8924
  try {
8628
- const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
8925
+ const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf-8"));
8629
8926
  if (pkg.eslintConfig) {
8630
8927
  return { type: "eslint", configFile: "package.json (eslintConfig)" };
8631
8928
  }
@@ -8636,14 +8933,14 @@ function detectLinter(cwd) {
8636
8933
  }
8637
8934
  function detectTailwind(cwd) {
8638
8935
  const cssFiles = ["globals.css", "app.css", "index.css"].flatMap((f) => [
8639
- path34.join(cwd, "src", "app", f),
8640
- path34.join(cwd, "app", f),
8641
- path34.join(cwd, "src", f),
8642
- path34.join(cwd, f)
8936
+ path36.join(cwd, "src", "app", f),
8937
+ path36.join(cwd, "app", f),
8938
+ path36.join(cwd, "src", f),
8939
+ path36.join(cwd, f)
8643
8940
  ]);
8644
8941
  for (const cssFile of cssFiles) {
8645
- if (fs31.existsSync(cssFile)) {
8646
- const content = fs31.readFileSync(cssFile, "utf-8");
8942
+ if (fs33.existsSync(cssFile)) {
8943
+ const content = fs33.readFileSync(cssFile, "utf-8");
8647
8944
  if (content.includes('@import "tailwindcss"') || content.includes("@import 'tailwindcss'") || content.includes("@theme")) {
8648
8945
  return true;
8649
8946
  }
@@ -8651,8 +8948,8 @@ function detectTailwind(cwd) {
8651
8948
  }
8652
8949
  const postcssFiles = ["postcss.config.js", "postcss.config.mjs", "postcss.config.cjs"];
8653
8950
  for (const f of postcssFiles) {
8654
- if (fs31.existsSync(path34.join(cwd, f))) {
8655
- 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");
8656
8953
  if (content.includes("tailwindcss") || content.includes("@tailwindcss")) {
8657
8954
  return true;
8658
8955
  }
@@ -8661,20 +8958,20 @@ function detectTailwind(cwd) {
8661
8958
  return false;
8662
8959
  }
8663
8960
  function hasTsconfigCmsAliases(cwd) {
8664
- const tsconfigPath = path34.join(cwd, "tsconfig.json");
8665
- if (!fs31.existsSync(tsconfigPath)) return false;
8961
+ const tsconfigPath = path36.join(cwd, "tsconfig.json");
8962
+ if (!fs33.existsSync(tsconfigPath)) return false;
8666
8963
  try {
8667
- const content = fs31.readFileSync(tsconfigPath, "utf-8");
8964
+ const content = fs33.readFileSync(tsconfigPath, "utf-8");
8668
8965
  return content.includes("@cms/");
8669
8966
  } catch {
8670
8967
  return false;
8671
8968
  }
8672
8969
  }
8673
8970
  function hasEnvBetterstartVars(cwd) {
8674
- const envPath = path34.join(cwd, ".env.local");
8675
- if (!fs31.existsSync(envPath)) return false;
8971
+ const envPath = path36.join(cwd, ".env.local");
8972
+ if (!fs33.existsSync(envPath)) return false;
8676
8973
  try {
8677
- const content = fs31.readFileSync(envPath, "utf-8");
8974
+ const content = fs33.readFileSync(envPath, "utf-8");
8678
8975
  return content.includes("BETTERSTART_");
8679
8976
  } catch {
8680
8977
  return false;
@@ -11373,12 +11670,12 @@ export function addToMailchimpAudience(email: string): void {
11373
11670
 
11374
11671
  // src/init/scaffolders/components.ts
11375
11672
  function scaffoldComponents({ cwd, config }) {
11376
- const cms = path35.resolve(cwd, config.paths.cms);
11673
+ const cms = path37.resolve(cwd, config.paths.cms);
11377
11674
  const created = [];
11378
11675
  function write(relPath, content) {
11379
- const fullPath = path35.join(cms, relPath);
11676
+ const fullPath = path37.join(cms, relPath);
11380
11677
  if (safeWriteFile(fullPath, content)) {
11381
- created.push(path35.join(config.paths.cms, relPath));
11678
+ created.push(path37.join(config.paths.cms, relPath));
11382
11679
  }
11383
11680
  }
11384
11681
  write("cms-globals.css", cmsGlobalsCssTemplate());
@@ -11427,18 +11724,18 @@ function scaffoldComponents({ cwd, config }) {
11427
11724
  }
11428
11725
  function copyUiTemplates(cwd, config) {
11429
11726
  const created = [];
11430
- const destDir = path35.resolve(cwd, config.paths.cms, "components", "ui");
11727
+ const destDir = path37.resolve(cwd, config.paths.cms, "components", "ui");
11431
11728
  const cliRoot = findCliRoot();
11432
- const srcDir = path35.join(cliRoot, "templates", "ui");
11433
- if (!fs32.existsSync(srcDir)) {
11729
+ const srcDir = path37.join(cliRoot, "templates", "ui");
11730
+ if (!fs34.existsSync(srcDir)) {
11434
11731
  return created;
11435
11732
  }
11436
- 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"));
11437
11734
  for (const file of files) {
11438
- const destPath = path35.join(destDir, file);
11439
- if (!fs32.existsSync(destPath)) {
11440
- fs32.copyFileSync(path35.join(srcDir, file), destPath);
11441
- created.push(path35.join(config.paths.cms, "components", "ui", file));
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));
11442
11739
  }
11443
11740
  }
11444
11741
  return created;
@@ -11446,25 +11743,25 @@ function copyUiTemplates(cwd, config) {
11446
11743
  function copyTiptapTemplates(cwd, config) {
11447
11744
  const created = [];
11448
11745
  const cliRoot = findCliRoot();
11449
- const srcDir = path35.join(cliRoot, "templates", "tiptap");
11450
- const destDir = path35.resolve(cwd, config.paths.cms, "components", "ui", "tiptap");
11451
- if (!fs32.existsSync(srcDir)) {
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)) {
11452
11749
  return created;
11453
11750
  }
11454
11751
  copyDirRecursive(srcDir, destDir, config.paths.cms, created);
11455
11752
  return created;
11456
11753
  }
11457
11754
  function copyDirRecursive(src, dest, cmsPrefix, created) {
11458
- fs32.ensureDirSync(dest);
11459
- const entries = fs32.readdirSync(src, { withFileTypes: true });
11755
+ fs34.ensureDirSync(dest);
11756
+ const entries = fs34.readdirSync(src, { withFileTypes: true });
11460
11757
  for (const entry of entries) {
11461
- const srcPath = path35.join(src, entry.name);
11462
- const destPath = path35.join(dest, entry.name);
11758
+ const srcPath = path37.join(src, entry.name);
11759
+ const destPath = path37.join(dest, entry.name);
11463
11760
  if (entry.isDirectory()) {
11464
11761
  copyDirRecursive(srcPath, destPath, cmsPrefix, created);
11465
- } else if (!fs32.existsSync(destPath)) {
11466
- fs32.copyFileSync(srcPath, destPath);
11467
- const relFromCms = path35.relative(path35.resolve(dest, "..", "..", "..", ".."), destPath);
11762
+ } else if (!fs34.existsSync(destPath)) {
11763
+ fs34.copyFileSync(srcPath, destPath);
11764
+ const relFromCms = path37.relative(path37.resolve(dest, "..", "..", "..", ".."), destPath);
11468
11765
  created.push(relFromCms);
11469
11766
  }
11470
11767
  }
@@ -11472,35 +11769,35 @@ function copyDirRecursive(src, dest, cmsPrefix, created) {
11472
11769
  function copySchemaMetaschema(cwd, config) {
11473
11770
  const created = [];
11474
11771
  const cliRoot = findCliRoot();
11475
- const srcPath = path35.join(cliRoot, "templates", "schema.json");
11476
- const destPath = path35.resolve(cwd, config.paths.schemas, "schema.json");
11477
- if (fs32.existsSync(srcPath) && !fs32.existsSync(destPath)) {
11478
- fs32.ensureDirSync(path35.dirname(destPath));
11479
- fs32.copyFileSync(srcPath, destPath);
11480
- created.push(path35.join(config.paths.schemas, "schema.json"));
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"));
11481
11778
  }
11482
11779
  return created;
11483
11780
  }
11484
11781
  function findCliRoot() {
11485
11782
  let dir = new URL(".", import.meta.url).pathname;
11486
11783
  for (let i = 0; i < 5; i++) {
11487
- const pkgPath = path35.join(dir, "package.json");
11488
- if (fs32.existsSync(pkgPath)) {
11784
+ const pkgPath = path37.join(dir, "package.json");
11785
+ if (fs34.existsSync(pkgPath)) {
11489
11786
  try {
11490
- const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
11787
+ const pkg = JSON.parse(fs34.readFileSync(pkgPath, "utf-8"));
11491
11788
  if (pkg.name === "@betterstart/cli") {
11492
11789
  return dir;
11493
11790
  }
11494
11791
  } catch {
11495
11792
  }
11496
11793
  }
11497
- dir = path35.dirname(dir);
11794
+ dir = path37.dirname(dir);
11498
11795
  }
11499
- return path35.resolve(new URL(".", import.meta.url).pathname, "..", "..");
11796
+ return path37.resolve(new URL(".", import.meta.url).pathname, "..", "..");
11500
11797
  }
11501
11798
 
11502
11799
  // src/init/scaffolders/database.ts
11503
- import path36 from "path";
11800
+ import path38 from "path";
11504
11801
 
11505
11802
  // src/init/templates/db/client.ts
11506
11803
  function dbClientTemplate() {
@@ -11611,16 +11908,16 @@ export const formSettings = pgTable(
11611
11908
  // src/init/scaffolders/database.ts
11612
11909
  function scaffoldDatabase({ cwd, config }) {
11613
11910
  const created = [];
11614
- const dbDir = path36.resolve(cwd, config.paths.cms, "db");
11911
+ const dbDir = path38.resolve(cwd, config.paths.cms, "db");
11615
11912
  function write(filename, content) {
11616
- const fullPath = path36.join(dbDir, filename);
11913
+ const fullPath = path38.join(dbDir, filename);
11617
11914
  if (safeWriteFile(fullPath, content)) {
11618
- created.push(path36.join(config.paths.cms, "db", filename));
11915
+ created.push(path38.join(config.paths.cms, "db", filename));
11619
11916
  }
11620
11917
  }
11621
11918
  write("client.ts", dbClientTemplate());
11622
11919
  write("schema.ts", dbSchemaTemplate());
11623
- const drizzleConfigPath = path36.resolve(cwd, "drizzle.config.ts");
11920
+ const drizzleConfigPath = path38.resolve(cwd, "drizzle.config.ts");
11624
11921
  if (safeWriteFile(drizzleConfigPath, drizzleConfigTemplate())) {
11625
11922
  created.push("drizzle.config.ts");
11626
11923
  }
@@ -11792,11 +12089,11 @@ import { existsSync, readFileSync } from "fs";
11792
12089
  import { join } from "path";
11793
12090
 
11794
12091
  // src/utils/env.ts
11795
- import fs33 from "fs";
11796
- import path37 from "path";
12092
+ import fs35 from "fs";
12093
+ import path39 from "path";
11797
12094
  function appendEnvVars(cwd, sections, overwrite) {
11798
- const envPath = path37.join(cwd, ".env.local");
11799
- 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") : "";
11800
12097
  const existingKeys = new Set(
11801
12098
  existing.split("\n").filter((line) => line.trim() && !line.trim().startsWith("#")).map((line) => line.split("=")[0]?.trim()).filter(Boolean)
11802
12099
  );
@@ -11840,7 +12137,7 @@ function appendEnvVars(cwd, sections, overwrite) {
11840
12137
  const header = existing.trim() ? "" : "# ============================================\n# BetterStart CMS\n# ============================================\n";
11841
12138
  const content = existing.trim() ? `${existing.trimEnd()}
11842
12139
  ${lines.join("\n")}` : header + lines.join("\n");
11843
- fs33.writeFileSync(envPath, content);
12140
+ fs35.writeFileSync(envPath, content);
11844
12141
  }
11845
12142
  return { added, skipped, updated };
11846
12143
  }
@@ -11919,7 +12216,7 @@ function scaffoldEnv(cwd, options) {
11919
12216
  }
11920
12217
 
11921
12218
  // src/init/scaffolders/layout.ts
11922
- import path38 from "path";
12219
+ import path40 from "path";
11923
12220
 
11924
12221
  // src/init/templates/pages/authenticated-layout.ts
11925
12222
  function authenticatedLayoutTemplate() {
@@ -12806,30 +13103,30 @@ export function UsersTable<TValue>({ columns }: UsersTableProps<TValue>) {
12806
13103
  function scaffoldLayout({ cwd, config }) {
12807
13104
  const created = [];
12808
13105
  function write(relPath, content) {
12809
- const fullPath = path38.resolve(cwd, relPath);
12810
- ensureDir(path38.dirname(fullPath));
13106
+ const fullPath = path40.resolve(cwd, relPath);
13107
+ ensureDir(path40.dirname(fullPath));
12811
13108
  if (safeWriteFile(fullPath, content)) {
12812
13109
  created.push(relPath);
12813
13110
  }
12814
13111
  }
12815
- const cmsDir = path38.dirname(config.paths.pages);
12816
- write(path38.join(cmsDir, "layout.tsx"), cmsLayoutTemplate());
12817
- write(path38.join(config.paths.pages, "layout.tsx"), authenticatedLayoutTemplate());
12818
- write(path38.join(config.paths.login, "page.tsx"), loginPageTemplate());
12819
- write(path38.join(config.paths.login, "login-form.tsx"), loginFormTemplate());
12820
- write(path38.join(config.paths.pages, "page.tsx"), dashboardPageTemplate());
12821
- const usersDir = path38.join(config.paths.pages, "users");
12822
- write(path38.join(usersDir, "page.tsx"), usersPageTemplate());
12823
- write(path38.join(usersDir, "users-table.tsx"), usersTableTemplate());
12824
- write(path38.join(usersDir, "columns.tsx"), usersColumnsTemplate());
12825
- write(path38.join(usersDir, "create-user-dialog.tsx"), createUserDialogTemplate());
12826
- write(path38.join(usersDir, "edit-role-dialog.tsx"), editRoleDialogTemplate());
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());
12827
13124
  return created;
12828
13125
  }
12829
13126
 
12830
13127
  // src/init/scaffolders/preset.ts
12831
- import fs34 from "fs";
12832
- import path39 from "path";
13128
+ import fs36 from "fs";
13129
+ import path41 from "path";
12833
13130
 
12834
13131
  // src/init/templates/presets/blog-categories.ts
12835
13132
  function blogCategoriesSchema() {
@@ -13234,15 +13531,15 @@ function scaffoldPreset({
13234
13531
  generatedFiles: [],
13235
13532
  errors: []
13236
13533
  };
13237
- const schemasDir = path39.join(cwd, config.paths?.schemas ?? "./cms/schemas");
13534
+ const schemasDir = path41.join(cwd, config.paths?.schemas ?? "./cms/schemas");
13238
13535
  const presetSchemas = getPresetSchemas(preset);
13239
13536
  for (const ps of presetSchemas) {
13240
- const filePath = path39.join(schemasDir, ps.filename);
13241
- const dir = path39.dirname(filePath);
13242
- if (!fs34.existsSync(dir)) {
13243
- fs34.mkdirSync(dir, { recursive: true });
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 });
13244
13541
  }
13245
- fs34.writeFileSync(filePath, ps.content, "utf-8");
13542
+ fs36.writeFileSync(filePath, ps.content, "utf-8");
13246
13543
  result.schemas.push(ps.filename);
13247
13544
  }
13248
13545
  for (const ps of presetSchemas) {
@@ -13283,8 +13580,8 @@ function scaffoldPreset({
13283
13580
  }
13284
13581
 
13285
13582
  // src/init/scaffolders/tailwind.ts
13286
- import fs35 from "fs";
13287
- import path40 from "path";
13583
+ import fs37 from "fs";
13584
+ import path42 from "path";
13288
13585
  var SOURCE_LINES = ['@source "../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
13289
13586
  var SOURCE_LINES_SRC = ['@source "../../cms/**/*.{ts,tsx}";', '@source "./(cms)/**/*.{ts,tsx}";'];
13290
13587
  var CMS_THEME_BLOCK = `
@@ -13339,8 +13636,8 @@ function findMainCss(cwd) {
13339
13636
  "globals.css"
13340
13637
  ];
13341
13638
  for (const candidate of candidates) {
13342
- const filePath = path40.join(cwd, candidate);
13343
- if (fs35.existsSync(filePath)) {
13639
+ const filePath = path42.join(cwd, candidate);
13640
+ if (fs37.existsSync(filePath)) {
13344
13641
  return filePath;
13345
13642
  }
13346
13643
  }
@@ -13351,7 +13648,7 @@ function scaffoldTailwind(cwd, hasSrcDir) {
13351
13648
  if (!cssFile) {
13352
13649
  return { file: null, appended: false };
13353
13650
  }
13354
- let content = fs35.readFileSync(cssFile, "utf-8");
13651
+ let content = fs37.readFileSync(cssFile, "utf-8");
13355
13652
  let changed = false;
13356
13653
  const sourceLines = hasSrcDir ? SOURCE_LINES_SRC : SOURCE_LINES;
13357
13654
  const missingLines = sourceLines.filter((sl) => !content.includes(sl));
@@ -13403,14 +13700,14 @@ ${CMS_THEME_BLOCK}
13403
13700
  }
13404
13701
  }
13405
13702
  if (changed) {
13406
- fs35.writeFileSync(cssFile, content, "utf-8");
13703
+ fs37.writeFileSync(cssFile, content, "utf-8");
13407
13704
  }
13408
13705
  return { file: cssFile, appended: changed };
13409
13706
  }
13410
13707
 
13411
13708
  // src/init/scaffolders/tsconfig.ts
13412
- import fs36 from "fs";
13413
- import path41 from "path";
13709
+ import fs38 from "fs";
13710
+ import path43 from "path";
13414
13711
  function stripJsonComments(input) {
13415
13712
  let result = "";
13416
13713
  let i = 0;
@@ -13460,14 +13757,14 @@ var CMS_PATH_ALIASES = {
13460
13757
  "@cms/cache/*": ["./cms/lib/cache/*"]
13461
13758
  };
13462
13759
  function scaffoldTsconfig(cwd) {
13463
- const tsconfigPath = path41.join(cwd, "tsconfig.json");
13760
+ const tsconfigPath = path43.join(cwd, "tsconfig.json");
13464
13761
  const added = [];
13465
13762
  const skipped = [];
13466
- if (!fs36.existsSync(tsconfigPath)) {
13763
+ if (!fs38.existsSync(tsconfigPath)) {
13467
13764
  skipped.push("tsconfig.json not found");
13468
13765
  return { added, skipped };
13469
13766
  }
13470
- const raw = fs36.readFileSync(tsconfigPath, "utf-8");
13767
+ const raw = fs38.readFileSync(tsconfigPath, "utf-8");
13471
13768
  const stripped = stripJsonComments(raw).replace(/,\s*([\]}])/g, "$1");
13472
13769
  let tsconfig;
13473
13770
  try {
@@ -13488,14 +13785,14 @@ function scaffoldTsconfig(cwd) {
13488
13785
  }
13489
13786
  compilerOptions.paths = paths;
13490
13787
  tsconfig.compilerOptions = compilerOptions;
13491
- fs36.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
13788
+ fs38.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
13492
13789
  `, "utf-8");
13493
13790
  return { added, skipped };
13494
13791
  }
13495
13792
 
13496
13793
  // src/commands/seed.ts
13497
- import fs37 from "fs";
13498
- import path42 from "path";
13794
+ import fs39 from "fs";
13795
+ import path44 from "path";
13499
13796
  import * as clack from "@clack/prompts";
13500
13797
  import { Command as Command2 } from "commander";
13501
13798
  function buildSeedScript() {
@@ -13614,7 +13911,7 @@ main().catch((err) => {
13614
13911
  `;
13615
13912
  }
13616
13913
  var seedCommand = new Command2("seed").description("Create the initial admin user").option("--cwd <path>", "Project root path").action(async (options) => {
13617
- const cwd = options.cwd ? path42.resolve(options.cwd) : process.cwd();
13914
+ const cwd = options.cwd ? path44.resolve(options.cwd) : process.cwd();
13618
13915
  clack.intro("BetterStart Seed");
13619
13916
  let config;
13620
13917
  try {
@@ -13654,14 +13951,14 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13654
13951
  clack.cancel("Cancelled.");
13655
13952
  process.exit(0);
13656
13953
  }
13657
- const scriptsDir = path42.join(cwd, cmsDir, "scripts");
13658
- const seedPath = path42.join(scriptsDir, "seed.ts");
13659
- if (!fs37.existsSync(scriptsDir)) {
13660
- fs37.mkdirSync(scriptsDir, { recursive: true });
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 });
13661
13958
  }
13662
- fs37.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13959
+ fs39.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13663
13960
  const { execFile } = await import("child_process");
13664
- const tsxBin = path42.join(cwd, "node_modules", ".bin", "tsx");
13961
+ const tsxBin = path44.join(cwd, "node_modules", ".bin", "tsx");
13665
13962
  const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
13666
13963
  execFile(
13667
13964
  tsxBin,
@@ -13700,7 +13997,7 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13700
13997
  if (clack.isCancel(overwrite) || !overwrite) {
13701
13998
  clack.cancel("Seed cancelled.");
13702
13999
  try {
13703
- fs37.unlinkSync(seedPath);
14000
+ fs39.unlinkSync(seedPath);
13704
14001
  } catch {
13705
14002
  }
13706
14003
  process.exit(0);
@@ -13717,15 +14014,15 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13717
14014
  clack.log.error(errMsg);
13718
14015
  clack.log.info("You can run the seed script manually:");
13719
14016
  clack.log.info(
13720
- ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path42.relative(cwd, seedPath)}`
14017
+ ` SEED_EMAIL="${email}" SEED_PASSWORD="..." npx tsx ${path44.relative(cwd, seedPath)}`
13721
14018
  );
13722
14019
  clack.outro("");
13723
14020
  process.exit(1);
13724
14021
  }
13725
14022
  try {
13726
- fs37.unlinkSync(seedPath);
13727
- if (fs37.existsSync(scriptsDir) && fs37.readdirSync(scriptsDir).length === 0) {
13728
- fs37.rmdirSync(scriptsDir);
14023
+ fs39.unlinkSync(seedPath);
14024
+ if (fs39.existsSync(scriptsDir) && fs39.readdirSync(scriptsDir).length === 0) {
14025
+ fs39.rmdirSync(scriptsDir);
13729
14026
  }
13730
14027
  } catch {
13731
14028
  }
@@ -13756,16 +14053,16 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13756
14053
  const nukeFiles = ["cms.config.ts", "CMS.md", "drizzle.config.ts"];
13757
14054
  let nuked = 0;
13758
14055
  for (const dir of nukeDirs) {
13759
- const fullPath = path43.resolve(cwd, dir);
13760
- if (fs38.existsSync(fullPath)) {
13761
- fs38.rmSync(fullPath, { recursive: true, force: true });
14056
+ const fullPath = path45.resolve(cwd, dir);
14057
+ if (fs40.existsSync(fullPath)) {
14058
+ fs40.rmSync(fullPath, { recursive: true, force: true });
13762
14059
  nuked++;
13763
14060
  }
13764
14061
  }
13765
14062
  for (const file of nukeFiles) {
13766
- const fullPath = path43.resolve(cwd, file);
13767
- if (fs38.existsSync(fullPath)) {
13768
- fs38.unlinkSync(fullPath);
14063
+ const fullPath = path45.resolve(cwd, file);
14064
+ if (fs40.existsSync(fullPath)) {
14065
+ fs40.unlinkSync(fullPath);
13769
14066
  nuked++;
13770
14067
  }
13771
14068
  }
@@ -13812,7 +14109,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13812
14109
  }
13813
14110
  pm = pmChoice;
13814
14111
  }
13815
- const displayName = projectPrompt.projectName === "." ? path43.basename(cwd) : projectPrompt.projectName;
14112
+ const displayName = projectPrompt.projectName === "." ? path45.basename(cwd) : projectPrompt.projectName;
13816
14113
  const { bin, prefix } = createNextAppCommand(pm);
13817
14114
  const cnaArgs = [
13818
14115
  ...prefix,
@@ -13844,10 +14141,10 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13844
14141
  );
13845
14142
  process.exit(1);
13846
14143
  }
13847
- cwd = path43.resolve(cwd, projectPrompt.projectName);
13848
- 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"));
13849
14146
  const hasNextConfig = ["next.config.ts", "next.config.js", "next.config.mjs"].some(
13850
- (f) => fs38.existsSync(path43.join(cwd, f))
14147
+ (f) => fs40.existsSync(path45.join(cwd, f))
13851
14148
  );
13852
14149
  if (!hasPackageJson || !hasNextConfig) {
13853
14150
  p4.log.error(
@@ -13948,11 +14245,11 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13948
14245
  s.stop("");
13949
14246
  process.stdout.write("\x1B[2A\x1B[J");
13950
14247
  p4.note(noteLines.join("\n"), "Scaffolded CMS");
13951
- const drizzleConfigPath = path43.join(cwd, "drizzle.config.ts");
13952
- if (!dbFiles.includes("drizzle.config.ts") && fs38.existsSync(drizzleConfigPath)) {
14248
+ const drizzleConfigPath = path45.join(cwd, "drizzle.config.ts");
14249
+ if (!dbFiles.includes("drizzle.config.ts") && fs40.existsSync(drizzleConfigPath)) {
13953
14250
  if (options.force) {
13954
14251
  const { drizzleConfigTemplate: drizzleConfigTemplate2 } = await import("./drizzle-config-EDKOEZ6G.js");
13955
- fs38.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
14252
+ fs40.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
13956
14253
  p4.log.success("Updated drizzle.config.ts");
13957
14254
  } else if (!options.yes) {
13958
14255
  const overwrite = await p4.confirm({
@@ -13961,7 +14258,7 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13961
14258
  });
13962
14259
  if (!p4.isCancel(overwrite) && overwrite) {
13963
14260
  const { drizzleConfigTemplate: drizzleConfigTemplate2 } = await import("./drizzle-config-EDKOEZ6G.js");
13964
- fs38.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
14261
+ fs40.writeFileSync(drizzleConfigPath, drizzleConfigTemplate2(), "utf-8");
13965
14262
  p4.log.success("Updated drizzle.config.ts");
13966
14263
  }
13967
14264
  }
@@ -13994,15 +14291,15 @@ var initCommand = new Command3("init").description("Scaffold CMS into a new or e
13994
14291
  {
13995
14292
  const entityNames = [];
13996
14293
  const formNames = [];
13997
- const schemasDir = path43.join(cwd, config.paths.schemas);
13998
- const formsDir = path43.join(schemasDir, "forms");
13999
- if (fs38.existsSync(schemasDir)) {
14000
- for (const f of fs38.readdirSync(schemasDir)) {
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)) {
14001
14298
  if (f.endsWith(".json")) entityNames.push(f.replace(".json", ""));
14002
14299
  }
14003
14300
  }
14004
- if (fs38.existsSync(formsDir)) {
14005
- for (const f of fs38.readdirSync(formsDir)) {
14301
+ if (fs40.existsSync(formsDir)) {
14302
+ for (const f of fs40.readdirSync(formsDir)) {
14006
14303
  if (f.endsWith(".json")) formNames.push(f.replace(".json", ""));
14007
14304
  }
14008
14305
  }
@@ -14181,9 +14478,9 @@ function isValidDbUrl(url) {
14181
14478
  return url.startsWith("postgres://") || url.startsWith("postgresql://");
14182
14479
  }
14183
14480
  function readExistingDbUrl(cwd) {
14184
- const envPath = path43.join(cwd, ".env.local");
14185
- if (!fs38.existsSync(envPath)) return void 0;
14186
- const content = fs38.readFileSync(envPath, "utf-8");
14481
+ const envPath = path45.join(cwd, ".env.local");
14482
+ if (!fs40.existsSync(envPath)) return void 0;
14483
+ const content = fs40.readFileSync(envPath, "utf-8");
14187
14484
  for (const line of content.split("\n")) {
14188
14485
  const trimmed = line.trim();
14189
14486
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -14206,9 +14503,9 @@ function maskDbUrl(url) {
14206
14503
  }
14207
14504
  }
14208
14505
  function hasDbUrl(cwd) {
14209
- const envPath = path43.join(cwd, ".env.local");
14210
- if (!fs38.existsSync(envPath)) return false;
14211
- const content = fs38.readFileSync(envPath, "utf-8");
14506
+ const envPath = path45.join(cwd, ".env.local");
14507
+ if (!fs40.existsSync(envPath)) return false;
14508
+ const content = fs40.readFileSync(envPath, "utf-8");
14212
14509
  for (const line of content.split("\n")) {
14213
14510
  const trimmed = line.trim();
14214
14511
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -14222,23 +14519,23 @@ function hasDbUrl(cwd) {
14222
14519
  return false;
14223
14520
  }
14224
14521
  function runSeed(cwd, cmsDir, email, password4, overwrite = false) {
14225
- const scriptsDir = path43.join(cwd, cmsDir, "scripts");
14226
- const seedPath = path43.join(scriptsDir, "seed.ts");
14227
- if (!fs38.existsSync(scriptsDir)) {
14228
- fs38.mkdirSync(scriptsDir, { recursive: true });
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 });
14229
14526
  }
14230
- fs38.writeFileSync(seedPath, buildSeedScript(), "utf-8");
14527
+ fs40.writeFileSync(seedPath, buildSeedScript(), "utf-8");
14231
14528
  const cleanup = () => {
14232
14529
  try {
14233
- fs38.unlinkSync(seedPath);
14234
- if (fs38.existsSync(scriptsDir) && fs38.readdirSync(scriptsDir).length === 0) {
14235
- fs38.rmdirSync(scriptsDir);
14530
+ fs40.unlinkSync(seedPath);
14531
+ if (fs40.existsSync(scriptsDir) && fs40.readdirSync(scriptsDir).length === 0) {
14532
+ fs40.rmdirSync(scriptsDir);
14236
14533
  }
14237
14534
  } catch {
14238
14535
  }
14239
14536
  };
14240
14537
  return new Promise((resolve) => {
14241
- const tsxBin = path43.join(cwd, "node_modules", ".bin", "tsx");
14538
+ const tsxBin = path45.join(cwd, "node_modules", ".bin", "tsx");
14242
14539
  const child = spawn2(tsxBin, [seedPath], {
14243
14540
  cwd,
14244
14541
  stdio: "pipe",
@@ -14303,7 +14600,7 @@ ${stderr}`;
14303
14600
  }
14304
14601
  function runDrizzlePush(cwd) {
14305
14602
  return new Promise((resolve) => {
14306
- const drizzleBin = path43.join(cwd, "node_modules", ".bin", "drizzle-kit");
14603
+ const drizzleBin = path45.join(cwd, "node_modules", ".bin", "drizzle-kit");
14307
14604
  const child = spawn2(drizzleBin, ["push", "--force"], {
14308
14605
  cwd,
14309
14606
  stdio: "pipe",
@@ -14324,8 +14621,8 @@ function runDrizzlePush(cwd) {
14324
14621
  }
14325
14622
 
14326
14623
  // src/commands/remove.ts
14327
- import fs39 from "fs";
14328
- import path44 from "path";
14624
+ import fs41 from "fs";
14625
+ import path46 from "path";
14329
14626
  import readline from "readline";
14330
14627
  import { Command as Command4 } from "commander";
14331
14628
  function findTableEnd3(content, startIndex) {
@@ -14356,8 +14653,8 @@ function findTableEnd3(content, startIndex) {
14356
14653
  return content.length;
14357
14654
  }
14358
14655
  function removeTableFromSchema(schemaFilePath, name) {
14359
- if (!fs39.existsSync(schemaFilePath)) return false;
14360
- let content = fs39.readFileSync(schemaFilePath, "utf-8");
14656
+ if (!fs41.existsSync(schemaFilePath)) return false;
14657
+ let content = fs41.readFileSync(schemaFilePath, "utf-8");
14361
14658
  const variableName = toCamelCase(name);
14362
14659
  let changed = false;
14363
14660
  if (content.includes(`export const ${variableName} =`)) {
@@ -14385,13 +14682,13 @@ function removeTableFromSchema(schemaFilePath, name) {
14385
14682
  }
14386
14683
  if (changed) {
14387
14684
  content = content.replace(/\n{3,}/g, "\n\n");
14388
- fs39.writeFileSync(schemaFilePath, content, "utf-8");
14685
+ fs41.writeFileSync(schemaFilePath, content, "utf-8");
14389
14686
  }
14390
14687
  return changed;
14391
14688
  }
14392
14689
  function removeFromNavigation(navFilePath, name) {
14393
- if (!fs39.existsSync(navFilePath)) return false;
14394
- const content = fs39.readFileSync(navFilePath, "utf-8");
14690
+ if (!fs41.existsSync(navFilePath)) return false;
14691
+ const content = fs41.readFileSync(navFilePath, "utf-8");
14395
14692
  const href = `/cms/${name}`;
14396
14693
  if (!content.includes(`'${href}'`)) return false;
14397
14694
  const lines = content.split("\n");
@@ -14422,7 +14719,7 @@ function removeFromNavigation(navFilePath, name) {
14422
14719
  if (startLine === -1 || endLine === -1) return false;
14423
14720
  lines.splice(startLine, endLine - startLine + 1);
14424
14721
  const updated = lines.join("\n").replace(/,\s*,/g, ",").replace(/\[\s*,/, "[");
14425
- fs39.writeFileSync(navFilePath, updated, "utf-8");
14722
+ fs41.writeFileSync(navFilePath, updated, "utf-8");
14426
14723
  return true;
14427
14724
  }
14428
14725
  async function promptConfirm(message) {
@@ -14438,7 +14735,7 @@ async function promptConfirm(message) {
14438
14735
  });
14439
14736
  }
14440
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) => {
14441
- const cwd = options.cwd ? path44.resolve(options.cwd) : process.cwd();
14738
+ const cwd = options.cwd ? path46.resolve(options.cwd) : process.cwd();
14442
14739
  console.log("\n BetterStart Remove\n");
14443
14740
  let config;
14444
14741
  try {
@@ -14451,34 +14748,34 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14451
14748
  const pagesDir = config.paths?.pages ?? "./src/app/(cms)/cms/(authenticated)";
14452
14749
  const kebabName = toKebabCase(schemaName);
14453
14750
  const targets = [];
14454
- const entityPagesDir = path44.join(cwd, pagesDir, schemaName);
14455
- if (fs39.existsSync(entityPagesDir)) {
14751
+ const entityPagesDir = path46.join(cwd, pagesDir, schemaName);
14752
+ if (fs41.existsSync(entityPagesDir)) {
14456
14753
  targets.push({
14457
14754
  path: entityPagesDir,
14458
- label: `${path44.join(pagesDir, schemaName)}/`,
14755
+ label: `${path46.join(pagesDir, schemaName)}/`,
14459
14756
  isDir: true
14460
14757
  });
14461
14758
  }
14462
- const actionsFile = path44.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
14463
- if (fs39.existsSync(actionsFile)) {
14759
+ const actionsFile = path46.join(cwd, cmsDir, "lib", "actions", `${kebabName}.ts`);
14760
+ if (fs41.existsSync(actionsFile)) {
14464
14761
  targets.push({
14465
14762
  path: actionsFile,
14466
- label: path44.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
14763
+ label: path46.join(cmsDir, "lib", "actions", `${kebabName}.ts`),
14467
14764
  isDir: false
14468
14765
  });
14469
14766
  }
14470
- const hookFile = path44.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
14471
- if (fs39.existsSync(hookFile)) {
14767
+ const hookFile = path46.join(cwd, cmsDir, "hooks", `use-${kebabName}.ts`);
14768
+ if (fs41.existsSync(hookFile)) {
14472
14769
  targets.push({
14473
14770
  path: hookFile,
14474
- label: path44.join(cmsDir, "hooks", `use-${kebabName}.ts`),
14771
+ label: path46.join(cmsDir, "hooks", `use-${kebabName}.ts`),
14475
14772
  isDir: false
14476
14773
  });
14477
14774
  }
14478
- const schemaFilePath = path44.join(cwd, cmsDir, "db", "schema.ts");
14479
- const hasTable = fs39.existsSync(schemaFilePath) && fs39.readFileSync(schemaFilePath, "utf-8").includes(`export const ${toCamelCase(schemaName)} =`);
14480
- const navFilePath = path44.join(cwd, cmsDir, "data", "navigation.ts");
14481
- const hasNavEntry = fs39.existsSync(navFilePath) && fs39.readFileSync(navFilePath, "utf-8").includes(`'/cms/${schemaName}'`);
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}'`);
14482
14779
  if (targets.length === 0 && !hasTable && !hasNavEntry) {
14483
14780
  console.log(` No generated files found for: ${schemaName}`);
14484
14781
  return;
@@ -14488,10 +14785,10 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14488
14785
  console.log(` ${t.isDir ? "[dir]" : " "} ${t.label}`);
14489
14786
  }
14490
14787
  if (hasTable) {
14491
- console.log(` [edit] ${path44.join(cmsDir, "db", "schema.ts")} (remove table)`);
14788
+ console.log(` [edit] ${path46.join(cmsDir, "db", "schema.ts")} (remove table)`);
14492
14789
  }
14493
14790
  if (hasNavEntry) {
14494
- console.log(` [edit] ${path44.join(cmsDir, "data", "navigation.ts")} (remove entry)`);
14791
+ console.log(` [edit] ${path46.join(cmsDir, "data", "navigation.ts")} (remove entry)`);
14495
14792
  }
14496
14793
  if (!options.force) {
14497
14794
  console.log("");
@@ -14504,19 +14801,19 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14504
14801
  console.log("");
14505
14802
  for (const t of targets) {
14506
14803
  if (t.isDir) {
14507
- fs39.rmSync(t.path, { recursive: true, force: true });
14804
+ fs41.rmSync(t.path, { recursive: true, force: true });
14508
14805
  } else {
14509
- fs39.unlinkSync(t.path);
14806
+ fs41.unlinkSync(t.path);
14510
14807
  }
14511
14808
  console.log(` Removed: ${t.label}`);
14512
14809
  }
14513
14810
  if (hasTable) {
14514
14811
  removeTableFromSchema(schemaFilePath, schemaName);
14515
- console.log(` Cleaned: ${path44.join(cmsDir, "db", "schema.ts")}`);
14812
+ console.log(` Cleaned: ${path46.join(cmsDir, "db", "schema.ts")}`);
14516
14813
  }
14517
14814
  if (hasNavEntry) {
14518
14815
  removeFromNavigation(navFilePath, schemaName);
14519
- console.log(` Cleaned: ${path44.join(cmsDir, "data", "navigation.ts")}`);
14816
+ console.log(` Cleaned: ${path46.join(cmsDir, "data", "navigation.ts")}`);
14520
14817
  }
14521
14818
  console.log("\n Removal complete!");
14522
14819
  console.log("\n Note: You may need to manually:");
@@ -14528,14 +14825,14 @@ var removeCommand = new Command4("remove").alias("rm").description("Remove all g
14528
14825
 
14529
14826
  // src/commands/setup-r2.ts
14530
14827
  import { execFileSync as execFileSync5, spawnSync } from "child_process";
14531
- import fs40 from "fs";
14828
+ import fs42 from "fs";
14532
14829
  import os from "os";
14533
- import path45 from "path";
14830
+ import path47 from "path";
14534
14831
  import * as p5 from "@clack/prompts";
14535
14832
  import { Command as Command5 } from "commander";
14536
14833
  import pc3 from "picocolors";
14537
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) => {
14538
- const cwd = options.cwd ? path45.resolve(options.cwd) : process.cwd();
14835
+ const cwd = options.cwd ? path47.resolve(options.cwd) : process.cwd();
14539
14836
  p5.intro(pc3.bgCyan(pc3.black(" BetterStart \u2014 R2 Storage Setup ")));
14540
14837
  const s = p5.spinner();
14541
14838
  s.start("Looking for wrangler CLI");
@@ -14727,8 +15024,8 @@ var setupR2Command = new Command5("setup-r2").description("Create a Cloudflare R
14727
15024
  p5.outro("Done! Your CMS can now upload files to R2.");
14728
15025
  });
14729
15026
  function findWrangler(cwd) {
14730
- const localBin = path45.join(cwd, "node_modules", ".bin", "wrangler");
14731
- 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: [] };
14732
15029
  const result = spawnSync("which", ["wrangler"], { stdio: "pipe", timeout: 5e3 });
14733
15030
  if (result.status === 0) {
14734
15031
  const found = result.stdout?.toString().trim();
@@ -14760,11 +15057,11 @@ function extractAccountId(ref, cwd) {
14760
15057
  }
14761
15058
  function readWranglerToken() {
14762
15059
  const candidates = [
14763
- path45.join(os.homedir(), "Library", "Preferences", ".wrangler", "config", "default.toml"),
15060
+ path47.join(os.homedir(), "Library", "Preferences", ".wrangler", "config", "default.toml"),
14764
15061
  // macOS
14765
- path45.join(os.homedir(), ".config", ".wrangler", "config", "default.toml"),
15062
+ path47.join(os.homedir(), ".config", ".wrangler", "config", "default.toml"),
14766
15063
  // Linux
14767
- path45.join(os.homedir(), ".wrangler", "config", "default.toml")
15064
+ path47.join(os.homedir(), ".wrangler", "config", "default.toml")
14768
15065
  // fallback
14769
15066
  ];
14770
15067
  if (process.env.WRANGLER_CONFIG_PATH) {
@@ -14772,13 +15069,13 @@ function readWranglerToken() {
14772
15069
  }
14773
15070
  if (process.env.XDG_CONFIG_HOME) {
14774
15071
  candidates.unshift(
14775
- path45.join(process.env.XDG_CONFIG_HOME, ".wrangler", "config", "default.toml")
15072
+ path47.join(process.env.XDG_CONFIG_HOME, ".wrangler", "config", "default.toml")
14776
15073
  );
14777
15074
  }
14778
15075
  for (const configPath of candidates) {
14779
- if (!fs40.existsSync(configPath)) continue;
15076
+ if (!fs42.existsSync(configPath)) continue;
14780
15077
  try {
14781
- const content = fs40.readFileSync(configPath, "utf-8");
15078
+ const content = fs42.readFileSync(configPath, "utf-8");
14782
15079
  const match = content.match(/^oauth_token\s*=\s*"([^"]+)"/m);
14783
15080
  if (match) return match[1];
14784
15081
  } catch {
@@ -14810,14 +15107,14 @@ async function enablePublicDomain(accountId, bucketName, token) {
14810
15107
  }
14811
15108
 
14812
15109
  // src/commands/uninstall.ts
14813
- import fs42 from "fs";
14814
- import path46 from "path";
15110
+ import fs44 from "fs";
15111
+ import path48 from "path";
14815
15112
  import * as p6 from "@clack/prompts";
14816
15113
  import { Command as Command6 } from "commander";
14817
15114
  import pc4 from "picocolors";
14818
15115
 
14819
15116
  // src/commands/uninstall-cleaners.ts
14820
- import fs41 from "fs";
15117
+ import fs43 from "fs";
14821
15118
  function stripJsonComments2(input) {
14822
15119
  let result = "";
14823
15120
  let i = 0;
@@ -14851,8 +15148,8 @@ function stripJsonComments2(input) {
14851
15148
  return result;
14852
15149
  }
14853
15150
  function cleanTsconfig(tsconfigPath) {
14854
- if (!fs41.existsSync(tsconfigPath)) return [];
14855
- const raw = fs41.readFileSync(tsconfigPath, "utf-8");
15151
+ if (!fs43.existsSync(tsconfigPath)) return [];
15152
+ const raw = fs43.readFileSync(tsconfigPath, "utf-8");
14856
15153
  const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
14857
15154
  let tsconfig;
14858
15155
  try {
@@ -14876,13 +15173,13 @@ function cleanTsconfig(tsconfigPath) {
14876
15173
  compilerOptions.paths = paths;
14877
15174
  }
14878
15175
  tsconfig.compilerOptions = compilerOptions;
14879
- fs41.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
15176
+ fs43.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
14880
15177
  `, "utf-8");
14881
15178
  return removed;
14882
15179
  }
14883
15180
  function cleanCss(cssPath) {
14884
- if (!fs41.existsSync(cssPath)) return [];
14885
- const content = fs41.readFileSync(cssPath, "utf-8");
15181
+ if (!fs43.existsSync(cssPath)) return [];
15182
+ const content = fs43.readFileSync(cssPath, "utf-8");
14886
15183
  const lines = content.split("\n");
14887
15184
  const sourcePattern = /^@source\s+"[^"]*cms[^"]*";\s*$/;
14888
15185
  const removed = [];
@@ -14896,12 +15193,12 @@ function cleanCss(cssPath) {
14896
15193
  }
14897
15194
  if (removed.length === 0) return [];
14898
15195
  const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
14899
- fs41.writeFileSync(cssPath, cleaned, "utf-8");
15196
+ fs43.writeFileSync(cssPath, cleaned, "utf-8");
14900
15197
  return removed;
14901
15198
  }
14902
15199
  function cleanEnvFile(envPath) {
14903
- if (!fs41.existsSync(envPath)) return [];
14904
- const content = fs41.readFileSync(envPath, "utf-8");
15200
+ if (!fs43.existsSync(envPath)) return [];
15201
+ const content = fs43.readFileSync(envPath, "utf-8");
14905
15202
  const lines = content.split("\n");
14906
15203
  const removed = [];
14907
15204
  const kept = [];
@@ -14934,9 +15231,9 @@ function cleanEnvFile(envPath) {
14934
15231
  if (removed.length === 0) return [];
14935
15232
  const result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
14936
15233
  if (result === "") {
14937
- fs41.unlinkSync(envPath);
15234
+ fs43.unlinkSync(envPath);
14938
15235
  } else {
14939
- fs41.writeFileSync(envPath, `${result}
15236
+ fs43.writeFileSync(envPath, `${result}
14940
15237
  `, "utf-8");
14941
15238
  }
14942
15239
  return removed;
@@ -14962,15 +15259,15 @@ function findMainCss2(cwd) {
14962
15259
  "globals.css"
14963
15260
  ];
14964
15261
  for (const candidate of candidates) {
14965
- const filePath = path46.join(cwd, candidate);
14966
- if (fs42.existsSync(filePath)) return filePath;
15262
+ const filePath = path48.join(cwd, candidate);
15263
+ if (fs44.existsSync(filePath)) return filePath;
14967
15264
  }
14968
15265
  return void 0;
14969
15266
  }
14970
15267
  function isCLICreatedBiome(biomePath) {
14971
- if (!fs42.existsSync(biomePath)) return false;
15268
+ if (!fs44.existsSync(biomePath)) return false;
14972
15269
  try {
14973
- const content = JSON.parse(fs42.readFileSync(biomePath, "utf-8"));
15270
+ const content = JSON.parse(fs44.readFileSync(biomePath, "utf-8"));
14974
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");
14975
15272
  } catch {
14976
15273
  return false;
@@ -14978,13 +15275,13 @@ function isCLICreatedBiome(biomePath) {
14978
15275
  }
14979
15276
  function buildUninstallPlan(cwd) {
14980
15277
  const steps = [];
14981
- const hasSrc = fs42.existsSync(path46.join(cwd, "src"));
15278
+ const hasSrc = fs44.existsSync(path48.join(cwd, "src"));
14982
15279
  const appBase = hasSrc ? "src/app" : "app";
14983
15280
  const dirs = [];
14984
- const cmsDir = path46.join(cwd, "cms");
14985
- const cmsRouteGroup = path46.join(cwd, appBase, "(cms)");
14986
- if (fs42.existsSync(cmsDir)) dirs.push("cms/");
14987
- if (fs42.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
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)/`);
14988
15285
  if (dirs.length > 0) {
14989
15286
  steps.push({
14990
15287
  label: "CMS directories",
@@ -14992,25 +15289,25 @@ function buildUninstallPlan(cwd) {
14992
15289
  count: dirs.length,
14993
15290
  unit: dirs.length === 1 ? "directory" : "directories",
14994
15291
  execute() {
14995
- if (fs42.existsSync(cmsDir)) fs42.rmSync(cmsDir, { recursive: true, force: true });
14996
- if (fs42.existsSync(cmsRouteGroup)) fs42.rmSync(cmsRouteGroup, { recursive: true, force: true });
15292
+ if (fs44.existsSync(cmsDir)) fs44.rmSync(cmsDir, { recursive: true, force: true });
15293
+ if (fs44.existsSync(cmsRouteGroup)) fs44.rmSync(cmsRouteGroup, { recursive: true, force: true });
14997
15294
  }
14998
15295
  });
14999
15296
  }
15000
15297
  const configFiles = [];
15001
15298
  const configPaths = [];
15002
15299
  const candidates = [
15003
- ["cms.config.ts", path46.join(cwd, "cms.config.ts")],
15004
- ["drizzle.config.ts", path46.join(cwd, "drizzle.config.ts")],
15005
- ["CMS.md", path46.join(cwd, "CMS.md")]
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")]
15006
15303
  ];
15007
15304
  for (const [label, fullPath] of candidates) {
15008
- if (fs42.existsSync(fullPath)) {
15305
+ if (fs44.existsSync(fullPath)) {
15009
15306
  configFiles.push(label);
15010
15307
  configPaths.push(fullPath);
15011
15308
  }
15012
15309
  }
15013
- const biomePath = path46.join(cwd, "biome.json");
15310
+ const biomePath = path48.join(cwd, "biome.json");
15014
15311
  if (isCLICreatedBiome(biomePath)) {
15015
15312
  configFiles.push("biome.json (CLI-created)");
15016
15313
  configPaths.push(biomePath);
@@ -15023,14 +15320,14 @@ function buildUninstallPlan(cwd) {
15023
15320
  unit: configFiles.length === 1 ? "file" : "files",
15024
15321
  execute() {
15025
15322
  for (const p7 of configPaths) {
15026
- if (fs42.existsSync(p7)) fs42.unlinkSync(p7);
15323
+ if (fs44.existsSync(p7)) fs44.unlinkSync(p7);
15027
15324
  }
15028
15325
  }
15029
15326
  });
15030
15327
  }
15031
- const tsconfigPath = path46.join(cwd, "tsconfig.json");
15032
- if (fs42.existsSync(tsconfigPath)) {
15033
- 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");
15034
15331
  const aliasMatches = content.match(/"@cms\//g);
15035
15332
  if (aliasMatches && aliasMatches.length > 0) {
15036
15333
  const aliasCount = aliasMatches.length;
@@ -15047,10 +15344,10 @@ function buildUninstallPlan(cwd) {
15047
15344
  }
15048
15345
  const cssFile = findMainCss2(cwd);
15049
15346
  if (cssFile) {
15050
- const cssContent = fs42.readFileSync(cssFile, "utf-8");
15347
+ const cssContent = fs44.readFileSync(cssFile, "utf-8");
15051
15348
  const sourceLines = cssContent.split("\n").filter((l) => /^@source\s+"[^"]*cms[^"]*";\s*$/.test(l));
15052
15349
  if (sourceLines.length > 0) {
15053
- const relCss = path46.relative(cwd, cssFile);
15350
+ const relCss = path48.relative(cwd, cssFile);
15054
15351
  steps.push({
15055
15352
  label: `CSS @source lines (${relCss})`,
15056
15353
  items: [`@source lines in ${relCss}`],
@@ -15062,9 +15359,9 @@ function buildUninstallPlan(cwd) {
15062
15359
  });
15063
15360
  }
15064
15361
  }
15065
- const envPath = path46.join(cwd, ".env.local");
15066
- if (fs42.existsSync(envPath)) {
15067
- 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");
15068
15365
  const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
15069
15366
  if (bsVars.length > 0) {
15070
15367
  steps.push({
@@ -15081,7 +15378,7 @@ function buildUninstallPlan(cwd) {
15081
15378
  return steps;
15082
15379
  }
15083
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) => {
15084
- const cwd = options.cwd ? path46.resolve(options.cwd) : process.cwd();
15381
+ const cwd = options.cwd ? path48.resolve(options.cwd) : process.cwd();
15085
15382
  p6.intro(pc4.bgRed(pc4.white(" BetterStart Uninstall ")));
15086
15383
  const steps = buildUninstallPlan(cwd);
15087
15384
  if (steps.length === 0) {
@@ -15118,11 +15415,11 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
15118
15415
  });
15119
15416
 
15120
15417
  // src/commands/update-deps.ts
15121
- import path47 from "path";
15418
+ import path49 from "path";
15122
15419
  import * as clack2 from "@clack/prompts";
15123
15420
  import { Command as Command7 } from "commander";
15124
15421
  var updateDepsCommand = new Command7("update-deps").description("Install or update all CMS dependencies").option("--cwd <path>", "Project root path").action(async (options) => {
15125
- const cwd = options.cwd ? path47.resolve(options.cwd) : process.cwd();
15422
+ const cwd = options.cwd ? path49.resolve(options.cwd) : process.cwd();
15126
15423
  clack2.intro("BetterStart Update Dependencies");
15127
15424
  const pm = detectPackageManager(cwd);
15128
15425
  clack2.log.info(`Package manager: ${pm}`);
@@ -15147,22 +15444,22 @@ var updateDepsCommand = new Command7("update-deps").description("Install or upda
15147
15444
  });
15148
15445
 
15149
15446
  // src/commands/update-styles.ts
15150
- import fs43 from "fs";
15151
- import path48 from "path";
15447
+ import fs45 from "fs";
15448
+ import path50 from "path";
15152
15449
  import * as clack3 from "@clack/prompts";
15153
15450
  import { Command as Command8 } from "commander";
15154
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) => {
15155
- const cwd = options.cwd ? path48.resolve(options.cwd) : process.cwd();
15452
+ const cwd = options.cwd ? path50.resolve(options.cwd) : process.cwd();
15156
15453
  clack3.intro("BetterStart Update Styles");
15157
15454
  const config = await resolveConfig(cwd);
15158
15455
  const cmsDir = config.paths?.cms ?? "./cms";
15159
- const targetPath = path48.join(cwd, cmsDir, "cms-globals.css");
15160
- if (!fs43.existsSync(targetPath)) {
15161
- clack3.cancel(`cms-globals.css not found at ${path48.relative(cwd, targetPath)}`);
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)}`);
15162
15459
  process.exit(1);
15163
15460
  }
15164
- fs43.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15165
- clack3.log.success(`Updated ${path48.relative(cwd, targetPath)}`);
15461
+ fs45.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15462
+ clack3.log.success(`Updated ${path50.relative(cwd, targetPath)}`);
15166
15463
  clack3.outro("Styles updated");
15167
15464
  });
15168
15465