@betterstart/cli 0.1.0

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.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entry point for @betterstart/cli
4
+ */
5
+ /**
6
+ * Run the CLI
7
+ */
8
+ declare function run(args?: string[]): Promise<void>;
9
+
10
+ export { run };
package/dist/cli.js ADDED
@@ -0,0 +1,472 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ findProjectRoot,
4
+ loadConfig,
5
+ resolveConfig
6
+ } from "./chunk-46UVIUJF.js";
7
+ import {
8
+ toKebabCase,
9
+ toPascalCase
10
+ } from "./chunk-GEH43BA4.js";
11
+ import {
12
+ detectPreset,
13
+ getPresetNames,
14
+ presets
15
+ } from "./chunk-PWRI4LKM.js";
16
+ import {
17
+ SchemaValidationError,
18
+ createConsoleLogger,
19
+ getLogger,
20
+ setLogger
21
+ } from "./chunk-WY6BC55D.js";
22
+
23
+ // src/cli/index.ts
24
+ import fs4 from "fs";
25
+ import path4 from "path";
26
+ import { fileURLToPath } from "url";
27
+ import { Command as Command4 } from "commander";
28
+
29
+ // src/cli/commands/generate.ts
30
+ import fs from "fs";
31
+ import path from "path";
32
+ import { Command } from "commander";
33
+ function generateCommand() {
34
+ const command = new Command("generate").alias("g").description("Generate code from a schema").argument("<name>", "Schema name to generate").option("--skip-migration", "Skip database migration").option("-f, --force", "Overwrite existing files").option("--cwd <path>", "Project root path").option("--generators <generators>", "Comma-separated list of generators to run").action(async (name, options) => {
35
+ const logger = getLogger();
36
+ const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
37
+ logger.info("\n\u{1F680} Betterstart Generator\n");
38
+ try {
39
+ const projectRoot = findProjectRoot(cwd);
40
+ logger.info(`\u{1F4C1} Project root: ${projectRoot}`);
41
+ const config = await loadConfig(projectRoot);
42
+ const resolvedConfig = resolveConfig(config, projectRoot);
43
+ logger.info(`\u{1F4C4} Loading schema: ${name}.json`);
44
+ const schemaPath = path.join(resolvedConfig.paths.schemas, `${name}.json`);
45
+ if (!fs.existsSync(schemaPath)) {
46
+ logger.error(`Schema file not found: ${schemaPath}`);
47
+ logger.info(`
48
+ Make sure the schema file exists at: ${schemaPath}`);
49
+ logger.info("You can create a schema using:");
50
+ logger.info(` echo '{}' > ${schemaPath}`);
51
+ process.exit(1);
52
+ }
53
+ let schema;
54
+ try {
55
+ const schemaContent = fs.readFileSync(schemaPath, "utf-8");
56
+ schema = JSON.parse(schemaContent);
57
+ } catch (error) {
58
+ logger.error(
59
+ `Failed to parse schema: ${error instanceof Error ? error.message : String(error)}`
60
+ );
61
+ process.exit(1);
62
+ }
63
+ const validationErrors = validateSchema(schema);
64
+ if (validationErrors.length > 0) {
65
+ throw new SchemaValidationError("Schema validation failed", validationErrors, {
66
+ schemaPath
67
+ });
68
+ }
69
+ logger.success("Schema validated");
70
+ logger.info("\n\u{1F4E6} Generating files...\n");
71
+ const { generate } = await import("./index.js");
72
+ await generate(name, {
73
+ skipMigration: options.skipMigration,
74
+ force: options.force
75
+ });
76
+ } catch (error) {
77
+ if (error instanceof SchemaValidationError) {
78
+ logger.error("\nSchema validation failed:\n");
79
+ for (const validationError of error.validationErrors) {
80
+ logger.error(` - ${validationError}`);
81
+ }
82
+ } else if (error instanceof Error) {
83
+ logger.error(`
84
+ ${error.message}`);
85
+ }
86
+ process.exit(1);
87
+ }
88
+ });
89
+ return command;
90
+ }
91
+ function validateSchema(schema) {
92
+ const errors = [];
93
+ if (!schema.name || typeof schema.name !== "string") {
94
+ errors.push('Schema must have a valid "name" field');
95
+ }
96
+ if (!schema.label || typeof schema.label !== "string") {
97
+ errors.push('Schema must have a valid "label" field');
98
+ }
99
+ if (!schema.description || typeof schema.description !== "string") {
100
+ errors.push('Schema must have a valid "description" field');
101
+ }
102
+ if (!schema.icon || typeof schema.icon !== "string") {
103
+ errors.push('Schema must have a valid "icon" field');
104
+ }
105
+ if (!Array.isArray(schema.fields) || schema.fields.length === 0) {
106
+ errors.push("Schema must have at least one field");
107
+ }
108
+ if (!Array.isArray(schema.columns) || schema.columns.length === 0) {
109
+ errors.push("Schema must have at least one column");
110
+ }
111
+ for (const field of schema.fields || []) {
112
+ if (field.type === "separator") {
113
+ continue;
114
+ }
115
+ if (!field.name || !field.type) {
116
+ errors.push(`Field is missing required properties: ${JSON.stringify(field)}`);
117
+ }
118
+ }
119
+ return errors;
120
+ }
121
+
122
+ // src/cli/commands/init.ts
123
+ import fs2 from "fs";
124
+ import path2 from "path";
125
+ import { Command as Command2 } from "commander";
126
+ function initCommand() {
127
+ const command = new Command2("init").description("Initialize betterstart in your project").option("-p, --preset <preset>", "Use a preset configuration").option("-y, --yes", "Skip interactive prompts and use defaults").option("--cwd <path>", "Project root path").action(async (options) => {
128
+ const logger = getLogger();
129
+ const cwd = options.cwd ? path2.resolve(options.cwd) : process.cwd();
130
+ logger.info("\n\u{1F680} Initializing betterstart...\n");
131
+ const projectRoot = findProjectRoot(cwd);
132
+ logger.info(`\u{1F4C1} Project root: ${projectRoot}`);
133
+ const configPath = path2.join(projectRoot, "betterstart.config.ts");
134
+ if (fs2.existsSync(configPath)) {
135
+ logger.warn("Configuration file already exists: betterstart.config.ts");
136
+ if (!options.yes) {
137
+ logger.info("Use --yes to overwrite");
138
+ return;
139
+ }
140
+ }
141
+ let presetName = options.preset;
142
+ if (!presetName) {
143
+ const detected = detectPreset(projectRoot);
144
+ presetName = detected.name;
145
+ logger.info(`\u{1F50D} Detected project type: ${presetName}`);
146
+ } else {
147
+ if (!getPresetNames().includes(presetName)) {
148
+ logger.error(`Unknown preset: ${presetName}`);
149
+ logger.info(`Available presets: ${getPresetNames().join(", ")}`);
150
+ process.exit(1);
151
+ }
152
+ logger.info(`\u{1F4CB} Using preset: ${presetName}`);
153
+ }
154
+ const preset = presets[presetName];
155
+ const configContent = generateConfigFile(presetName, preset.config);
156
+ fs2.writeFileSync(configPath, configContent);
157
+ logger.success(`Created: betterstart.config.ts`);
158
+ const schemasDir = path2.join(projectRoot, preset.config.paths?.schemas || "schemas");
159
+ if (!fs2.existsSync(schemasDir)) {
160
+ fs2.mkdirSync(schemasDir, { recursive: true });
161
+ logger.success(`Created: ${preset.config.paths?.schemas || "schemas"}/`);
162
+ }
163
+ const exampleSchemaPath = path2.join(schemasDir, "example.json");
164
+ if (!fs2.existsSync(exampleSchemaPath)) {
165
+ fs2.writeFileSync(exampleSchemaPath, generateExampleSchema());
166
+ logger.success("Created: example.json (sample schema)");
167
+ }
168
+ logger.info("\n\u2705 Initialization complete!\n");
169
+ logger.info("Next steps:");
170
+ logger.info(" 1. Review betterstart.config.ts and adjust paths if needed");
171
+ logger.info(" 2. Create your schema in the schemas directory");
172
+ logger.info(" 3. Run: npx betterstart generate <schema-name>");
173
+ logger.info("");
174
+ });
175
+ return command;
176
+ }
177
+ function generateConfigFile(presetName, _config) {
178
+ if (presetName === "nextjs-monorepo") {
179
+ return `import { defineConfig } from '@betterstart/cli'
180
+
181
+ export default defineConfig({
182
+ // Using nextjs-monorepo preset defaults
183
+ // Customize paths if your project structure differs:
184
+ // paths: {
185
+ // app: 'apps/web',
186
+ // database: 'packages/database',
187
+ // lib: 'packages/lib',
188
+ // hooks: 'packages/hooks',
189
+ // schemas: 'schemas',
190
+ // }
191
+ })
192
+ `;
193
+ }
194
+ if (presetName === "nextjs-standalone") {
195
+ return `import { defineConfig } from '@betterstart/cli'
196
+
197
+ export default defineConfig({
198
+ // Import paths for generated code
199
+ // Customize these to match your project structure:
200
+ imports: {
201
+ database: '@/lib/db',
202
+ adminUi: '@/components/ui',
203
+ webUi: '@/components/ui',
204
+ hooks: '@/hooks',
205
+ utils: '@/lib/utils',
206
+ types: '@/types',
207
+ lib: '@/lib',
208
+ actions: '@/lib/actions/{name}',
209
+ libMarkdown: '@/lib/markdown'
210
+ },
211
+ // Customize paths if your project structure differs:
212
+ // paths: {
213
+ // app: '.',
214
+ // database: '.',
215
+ // lib: '.',
216
+ // hooks: '.',
217
+ // schemas: 'schemas',
218
+ // output: {
219
+ // actions: 'src/actions',
220
+ // hooks: 'src/hooks',
221
+ // components: 'src/components/admin',
222
+ // pages: 'src/app/(admin)/admin',
223
+ // emails: 'src/emails'
224
+ // }
225
+ // }
226
+ })
227
+ `;
228
+ }
229
+ return `import { defineConfig } from '@betterstart/cli'
230
+
231
+ export default defineConfig({
232
+ // Import paths for generated code
233
+ imports: {
234
+ database: '@/lib/db',
235
+ adminUi: '@/components/ui',
236
+ webUi: '@/components/ui',
237
+ hooks: '@/hooks',
238
+ utils: '@/lib/utils',
239
+ types: '@/types',
240
+ lib: '@/lib',
241
+ actions: '@/lib/actions/{name}',
242
+ libMarkdown: '@/lib/markdown'
243
+ },
244
+ paths: {
245
+ app: '.',
246
+ database: '.',
247
+ lib: '.',
248
+ hooks: '.',
249
+ schemas: 'schemas',
250
+ output: {
251
+ actions: 'src/actions',
252
+ hooks: 'src/hooks',
253
+ components: 'src/components/admin',
254
+ pages: 'src/app/(admin)/admin',
255
+ emails: 'src/emails'
256
+ }
257
+ },
258
+ database: {
259
+ provider: 'drizzle',
260
+ schemaFile: 'src/db/schema.ts',
261
+ migrationsDir: 'src/db/migrations',
262
+ autoMigrate: true
263
+ },
264
+ ui: {
265
+ framework: 'shadcn',
266
+ components: {
267
+ path: '@/components/ui',
268
+ adminPath: '@/components/admin'
269
+ }
270
+ }
271
+ })
272
+ `;
273
+ }
274
+ function generateExampleSchema() {
275
+ return JSON.stringify(
276
+ {
277
+ $schema: "./schema.json",
278
+ name: "posts",
279
+ label: "Posts",
280
+ description: "Blog posts and articles",
281
+ icon: "FileText",
282
+ fields: [
283
+ {
284
+ name: "title",
285
+ type: "string",
286
+ label: "Title",
287
+ required: true,
288
+ length: 255
289
+ },
290
+ {
291
+ name: "slug",
292
+ type: "string",
293
+ label: "Slug",
294
+ required: true,
295
+ length: 255
296
+ },
297
+ {
298
+ name: "content",
299
+ type: "markdown",
300
+ label: "Content",
301
+ required: true
302
+ },
303
+ {
304
+ name: "published",
305
+ type: "boolean",
306
+ label: "Published",
307
+ default: false
308
+ }
309
+ ],
310
+ columns: [
311
+ {
312
+ accessorKey: "title",
313
+ header: "Title",
314
+ type: "text",
315
+ sortable: true
316
+ },
317
+ {
318
+ accessorKey: "slug",
319
+ header: "Slug",
320
+ type: "text"
321
+ },
322
+ {
323
+ accessorKey: "published",
324
+ header: "Status",
325
+ type: "badge"
326
+ },
327
+ {
328
+ accessorKey: "createdAt",
329
+ header: "Created",
330
+ type: "date",
331
+ sortable: true
332
+ }
333
+ ],
334
+ actions: {
335
+ create: true,
336
+ edit: true,
337
+ delete: true
338
+ }
339
+ },
340
+ null,
341
+ 2
342
+ );
343
+ }
344
+
345
+ // src/cli/commands/remove.ts
346
+ import fs3 from "fs";
347
+ import path3 from "path";
348
+ import readline from "readline";
349
+ import { Command as Command3 } from "commander";
350
+ function removeCommand() {
351
+ const command = new Command3("remove").alias("rm").description("Remove generated files for a schema").argument("<name>", "Schema name to remove").option("-f, --force", "Skip confirmation prompt").option("--cwd <path>", "Project root path").action(async (name, options) => {
352
+ const logger = getLogger();
353
+ const cwd = options.cwd ? path3.resolve(options.cwd) : process.cwd();
354
+ logger.info("\n\u{1F5D1}\uFE0F Betterstart Remove\n");
355
+ try {
356
+ const projectRoot = findProjectRoot(cwd);
357
+ const config = await loadConfig(projectRoot);
358
+ const resolvedConfig = resolveConfig(config, projectRoot);
359
+ const kebabName = toKebabCase(name);
360
+ const _pascalName = toPascalCase(name);
361
+ const filesToRemove = [];
362
+ const adminPagesDir = path3.join(resolvedConfig.paths.output.pages, kebabName);
363
+ if (fs3.existsSync(adminPagesDir)) {
364
+ filesToRemove.push(adminPagesDir);
365
+ }
366
+ const actionsFile = path3.join(resolvedConfig.paths.output.actions, `${kebabName}.ts`);
367
+ if (fs3.existsSync(actionsFile)) {
368
+ filesToRemove.push(actionsFile);
369
+ }
370
+ const hookFile = path3.join(resolvedConfig.paths.output.hooks, `use-${kebabName}.ts`);
371
+ if (fs3.existsSync(hookFile)) {
372
+ filesToRemove.push(hookFile);
373
+ }
374
+ if (filesToRemove.length === 0) {
375
+ logger.warn(`No generated files found for schema: ${name}`);
376
+ return;
377
+ }
378
+ logger.info("The following files will be removed:\n");
379
+ for (const file of filesToRemove) {
380
+ const relativePath = path3.relative(projectRoot, file);
381
+ const isDir = fs3.statSync(file).isDirectory();
382
+ logger.info(` ${isDir ? "\u{1F4C1}" : "\u{1F4C4}"} ${relativePath}${isDir ? "/" : ""}`);
383
+ }
384
+ if (!options.force) {
385
+ const confirmed = await confirm("\nAre you sure you want to remove these files?");
386
+ if (!confirmed) {
387
+ logger.info("\nRemoval cancelled.");
388
+ return;
389
+ }
390
+ }
391
+ logger.info("");
392
+ for (const file of filesToRemove) {
393
+ const relativePath = path3.relative(projectRoot, file);
394
+ const isDir = fs3.statSync(file).isDirectory();
395
+ if (isDir) {
396
+ fs3.rmSync(file, { recursive: true, force: true });
397
+ } else {
398
+ fs3.unlinkSync(file);
399
+ }
400
+ logger.success(`Removed: ${relativePath}`);
401
+ }
402
+ logger.info("\n\u2705 Removal complete!");
403
+ logger.info("\nNote: The following may need manual cleanup:");
404
+ logger.info(" - Database table (run a migration to drop it)");
405
+ logger.info(" - Navigation entries in navigation.json");
406
+ logger.info(" - Any imports referencing removed files");
407
+ } catch (error) {
408
+ if (error instanceof Error) {
409
+ logger.error(`
410
+ ${error.message}`);
411
+ }
412
+ process.exit(1);
413
+ }
414
+ });
415
+ return command;
416
+ }
417
+ async function confirm(message) {
418
+ const rl = readline.createInterface({
419
+ input: process.stdin,
420
+ output: process.stdout
421
+ });
422
+ return new Promise((resolve) => {
423
+ rl.question(`${message} (y/N) `, (answer) => {
424
+ rl.close();
425
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
426
+ });
427
+ });
428
+ }
429
+
430
+ // src/cli/index.ts
431
+ function getVersion() {
432
+ try {
433
+ const __dirname = path4.dirname(fileURLToPath(import.meta.url));
434
+ for (const rel of ["../../package.json", "../package.json"]) {
435
+ const pkgPath = path4.resolve(__dirname, rel);
436
+ if (fs4.existsSync(pkgPath)) {
437
+ const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
438
+ return pkg.version ?? "0.0.0";
439
+ }
440
+ }
441
+ } catch {
442
+ }
443
+ return "0.0.0";
444
+ }
445
+ setLogger(createConsoleLogger());
446
+ function createProgram() {
447
+ const program = new Command4();
448
+ program.name("betterstart").description("Generate admin CRUD interfaces for your Next.js project").version(getVersion());
449
+ program.addCommand(initCommand());
450
+ program.addCommand(generateCommand());
451
+ program.addCommand(removeCommand());
452
+ return program;
453
+ }
454
+ async function run(args) {
455
+ const program = createProgram();
456
+ try {
457
+ await program.parseAsync(args || process.argv);
458
+ } catch (error) {
459
+ if (error instanceof Error) {
460
+ console.error(`
461
+ Error: ${error.message}`);
462
+ } else {
463
+ console.error("\nAn unexpected error occurred");
464
+ }
465
+ process.exit(1);
466
+ }
467
+ }
468
+ run();
469
+ export {
470
+ run
471
+ };
472
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/index.ts","../src/cli/commands/generate.ts","../src/cli/commands/init.ts","../src/cli/commands/remove.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * CLI entry point for @betterstart/cli\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { Command } from 'commander'\nimport { createConsoleLogger, setLogger } from '../core/logger'\nimport { generateCommand } from './commands/generate'\nimport { initCommand } from './commands/init'\nimport { removeCommand } from './commands/remove'\n\n// Read version from package.json\nfunction getVersion(): string {\n try {\n const __dirname = path.dirname(fileURLToPath(import.meta.url))\n // Try dist layout first (built), then source layout\n for (const rel of ['../../package.json', '../package.json']) {\n const pkgPath = path.resolve(__dirname, rel)\n if (fs.existsSync(pkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n return pkg.version ?? '0.0.0'\n }\n }\n } catch {\n // Fallback\n }\n return '0.0.0'\n}\n\n// Set up console logger\nsetLogger(createConsoleLogger())\n\n/**\n * Create the CLI program\n */\nfunction createProgram(): Command {\n const program = new Command()\n\n program\n .name('betterstart')\n .description('Generate admin CRUD interfaces for your Next.js project')\n .version(getVersion())\n\n // Add commands\n program.addCommand(initCommand())\n program.addCommand(generateCommand())\n program.addCommand(removeCommand())\n\n return program\n}\n\n/**\n * Run the CLI\n */\nexport async function run(args?: string[]): Promise<void> {\n const program = createProgram()\n\n try {\n await program.parseAsync(args || process.argv)\n } catch (error) {\n if (error instanceof Error) {\n console.error(`\\nError: ${error.message}`)\n } else {\n console.error('\\nAn unexpected error occurred')\n }\n process.exit(1)\n }\n}\n\n// Always run when this file is executed\nrun()\n","/**\n * CLI generate command\n * Generates code from a schema\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { Command } from 'commander'\nimport { findProjectRoot, loadConfig, resolveConfig } from '../../config'\nimport { SchemaValidationError } from '../../core/errors'\nimport { getLogger } from '../../core/logger'\nimport type { Schema } from '../../types'\n\n/**\n * Create the generate command\n */\nexport function generateCommand(): Command {\n const command = new Command('generate')\n .alias('g')\n .description('Generate code from a schema')\n .argument('<name>', 'Schema name to generate')\n .option('--skip-migration', 'Skip database migration')\n .option('-f, --force', 'Overwrite existing files')\n .option('--cwd <path>', 'Project root path')\n .option('--generators <generators>', 'Comma-separated list of generators to run')\n .action(async (name, options) => {\n const logger = getLogger()\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n logger.info('\\nšŸš€ Betterstart Generator\\n')\n\n try {\n // Find project root and load config\n const projectRoot = findProjectRoot(cwd)\n logger.info(`šŸ“ Project root: ${projectRoot}`)\n\n const config = await loadConfig(projectRoot)\n const resolvedConfig = resolveConfig(config, projectRoot)\n logger.info(`šŸ“„ Loading schema: ${name}.json`)\n\n // Find schema file\n const schemaPath = path.join(resolvedConfig.paths.schemas, `${name}.json`)\n\n if (!fs.existsSync(schemaPath)) {\n logger.error(`Schema file not found: ${schemaPath}`)\n logger.info(`\\nMake sure the schema file exists at: ${schemaPath}`)\n logger.info('You can create a schema using:')\n logger.info(` echo '{}' > ${schemaPath}`)\n process.exit(1)\n }\n\n // Load and parse schema\n let schema: Schema\n try {\n const schemaContent = fs.readFileSync(schemaPath, 'utf-8')\n schema = JSON.parse(schemaContent)\n } catch (error) {\n logger.error(\n `Failed to parse schema: ${error instanceof Error ? error.message : String(error)}`\n )\n process.exit(1)\n }\n\n // Validate schema\n const validationErrors = validateSchema(schema)\n if (validationErrors.length > 0) {\n throw new SchemaValidationError('Schema validation failed', validationErrors, {\n schemaPath\n })\n }\n\n logger.success('Schema validated')\n logger.info('\\nšŸ“¦ Generating files...\\n')\n\n // For now, we'll import the existing generate function\n // In the full refactoring, this would use the new generator system\n const { generate } = await import('../../index')\n\n await generate(name, {\n skipMigration: options.skipMigration,\n force: options.force\n })\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n logger.error('\\nSchema validation failed:\\n')\n for (const validationError of error.validationErrors) {\n logger.error(` - ${validationError}`)\n }\n } else if (error instanceof Error) {\n logger.error(`\\n${error.message}`)\n }\n process.exit(1)\n }\n })\n\n return command\n}\n\n/**\n * Validate schema structure\n */\nfunction validateSchema(schema: Schema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Schema must have a valid \"name\" field')\n }\n\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Schema must have a valid \"label\" field')\n }\n\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Schema must have a valid \"description\" field')\n }\n\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Schema must have a valid \"icon\" field')\n }\n\n if (!Array.isArray(schema.fields) || schema.fields.length === 0) {\n errors.push('Schema must have at least one field')\n }\n\n if (!Array.isArray(schema.columns) || schema.columns.length === 0) {\n errors.push('Schema must have at least one column')\n }\n\n // Validate fields\n for (const field of schema.fields || []) {\n if (field.type === 'separator') {\n continue\n }\n if (!field.name || !field.type) {\n errors.push(`Field is missing required properties: ${JSON.stringify(field)}`)\n }\n }\n\n return errors\n}\n","/**\n * CLI init command\n * Initializes betterstart in a project\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { Command } from 'commander'\nimport { findProjectRoot } from '../../config'\nimport { detectPreset, getPresetNames, presets } from '../../config/presets'\nimport { getLogger } from '../../core/logger'\n\n/**\n * Create the init command\n */\nexport function initCommand(): Command {\n const command = new Command('init')\n .description('Initialize betterstart in your project')\n .option('-p, --preset <preset>', 'Use a preset configuration')\n .option('-y, --yes', 'Skip interactive prompts and use defaults')\n .option('--cwd <path>', 'Project root path')\n .action(async (options) => {\n const logger = getLogger()\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n logger.info('\\nšŸš€ Initializing betterstart...\\n')\n\n // Find project root\n const projectRoot = findProjectRoot(cwd)\n logger.info(`šŸ“ Project root: ${projectRoot}`)\n\n // Check if config already exists\n const configPath = path.join(projectRoot, 'betterstart.config.ts')\n if (fs.existsSync(configPath)) {\n logger.warn('Configuration file already exists: betterstart.config.ts')\n\n if (!options.yes) {\n logger.info('Use --yes to overwrite')\n return\n }\n }\n\n // Detect or use specified preset\n let presetName = options.preset\n if (!presetName) {\n const detected = detectPreset(projectRoot)\n presetName = detected.name\n logger.info(`šŸ” Detected project type: ${presetName}`)\n } else {\n if (!getPresetNames().includes(presetName)) {\n logger.error(`Unknown preset: ${presetName}`)\n logger.info(`Available presets: ${getPresetNames().join(', ')}`)\n process.exit(1)\n }\n logger.info(`šŸ“‹ Using preset: ${presetName}`)\n }\n\n const preset = presets[presetName]\n\n // Generate config file content\n const configContent = generateConfigFile(presetName, preset.config)\n\n // Write config file\n fs.writeFileSync(configPath, configContent)\n logger.success(`Created: betterstart.config.ts`)\n\n // Create schemas directory if it doesn't exist\n const schemasDir = path.join(projectRoot, preset.config.paths?.schemas || 'schemas')\n if (!fs.existsSync(schemasDir)) {\n fs.mkdirSync(schemasDir, { recursive: true })\n logger.success(`Created: ${preset.config.paths?.schemas || 'schemas'}/`)\n }\n\n // Create example schema\n const exampleSchemaPath = path.join(schemasDir, 'example.json')\n if (!fs.existsSync(exampleSchemaPath)) {\n fs.writeFileSync(exampleSchemaPath, generateExampleSchema())\n logger.success('Created: example.json (sample schema)')\n }\n\n logger.info('\\nāœ… Initialization complete!\\n')\n logger.info('Next steps:')\n logger.info(' 1. Review betterstart.config.ts and adjust paths if needed')\n logger.info(' 2. Create your schema in the schemas directory')\n logger.info(' 3. Run: npx betterstart generate <schema-name>')\n logger.info('')\n })\n\n return command\n}\n\n/**\n * Generate the config file content\n */\nfunction generateConfigFile(presetName: string, _config: unknown): string {\n // For monorepo preset, use a simpler config since most paths are defaults\n if (presetName === 'nextjs-monorepo') {\n return `import { defineConfig } from '@betterstart/cli'\n\nexport default defineConfig({\n // Using nextjs-monorepo preset defaults\n // Customize paths if your project structure differs:\n // paths: {\n // app: 'apps/web',\n // database: 'packages/database',\n // lib: 'packages/lib',\n // hooks: 'packages/hooks',\n // schemas: 'schemas',\n // }\n})\n`\n }\n\n // For standalone preset\n if (presetName === 'nextjs-standalone') {\n return `import { defineConfig } from '@betterstart/cli'\n\nexport default defineConfig({\n // Import paths for generated code\n // Customize these to match your project structure:\n imports: {\n database: '@/lib/db',\n adminUi: '@/components/ui',\n webUi: '@/components/ui',\n hooks: '@/hooks',\n utils: '@/lib/utils',\n types: '@/types',\n lib: '@/lib',\n actions: '@/lib/actions/{name}',\n libMarkdown: '@/lib/markdown'\n },\n // Customize paths if your project structure differs:\n // paths: {\n // app: '.',\n // database: '.',\n // lib: '.',\n // hooks: '.',\n // schemas: 'schemas',\n // output: {\n // actions: 'src/actions',\n // hooks: 'src/hooks',\n // components: 'src/components/admin',\n // pages: 'src/app/(admin)/admin',\n // emails: 'src/emails'\n // }\n // }\n})\n`\n }\n\n // For custom preset, include all paths\n return `import { defineConfig } from '@betterstart/cli'\n\nexport default defineConfig({\n // Import paths for generated code\n imports: {\n database: '@/lib/db',\n adminUi: '@/components/ui',\n webUi: '@/components/ui',\n hooks: '@/hooks',\n utils: '@/lib/utils',\n types: '@/types',\n lib: '@/lib',\n actions: '@/lib/actions/{name}',\n libMarkdown: '@/lib/markdown'\n },\n paths: {\n app: '.',\n database: '.',\n lib: '.',\n hooks: '.',\n schemas: 'schemas',\n output: {\n actions: 'src/actions',\n hooks: 'src/hooks',\n components: 'src/components/admin',\n pages: 'src/app/(admin)/admin',\n emails: 'src/emails'\n }\n },\n database: {\n provider: 'drizzle',\n schemaFile: 'src/db/schema.ts',\n migrationsDir: 'src/db/migrations',\n autoMigrate: true\n },\n ui: {\n framework: 'shadcn',\n components: {\n path: '@/components/ui',\n adminPath: '@/components/admin'\n }\n }\n})\n`\n}\n\n/**\n * Generate an example schema\n */\nfunction generateExampleSchema(): string {\n return JSON.stringify(\n {\n $schema: './schema.json',\n name: 'posts',\n label: 'Posts',\n description: 'Blog posts and articles',\n icon: 'FileText',\n fields: [\n {\n name: 'title',\n type: 'string',\n label: 'Title',\n required: true,\n length: 255\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n required: true,\n length: 255\n },\n {\n name: 'content',\n type: 'markdown',\n label: 'Content',\n required: true\n },\n {\n name: 'published',\n type: 'boolean',\n label: 'Published',\n default: false\n }\n ],\n columns: [\n {\n accessorKey: 'title',\n header: 'Title',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'slug',\n header: 'Slug',\n type: 'text'\n },\n {\n accessorKey: 'published',\n header: 'Status',\n type: 'badge'\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true\n }\n },\n null,\n 2\n )\n}\n","/**\n * CLI remove command\n * Removes generated files for a schema\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport readline from 'node:readline'\nimport { Command } from 'commander'\nimport { findProjectRoot, loadConfig, resolveConfig } from '../../config'\nimport { getLogger } from '../../core/logger'\nimport { toKebabCase, toPascalCase } from '../../utils'\n\n/**\n * Create the remove command\n */\nexport function removeCommand(): Command {\n const command = new Command('remove')\n .alias('rm')\n .description('Remove generated files for a schema')\n .argument('<name>', 'Schema name to remove')\n .option('-f, --force', 'Skip confirmation prompt')\n .option('--cwd <path>', 'Project root path')\n .action(async (name, options) => {\n const logger = getLogger()\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n logger.info('\\nšŸ—‘ļø Betterstart Remove\\n')\n\n try {\n // Find project root and load config\n const projectRoot = findProjectRoot(cwd)\n const config = await loadConfig(projectRoot)\n const resolvedConfig = resolveConfig(config, projectRoot)\n\n const kebabName = toKebabCase(name)\n const _pascalName = toPascalCase(name)\n\n // Collect files to remove\n const filesToRemove: string[] = []\n\n // Admin pages directory\n const adminPagesDir = path.join(resolvedConfig.paths.output.pages, kebabName)\n if (fs.existsSync(adminPagesDir)) {\n filesToRemove.push(adminPagesDir)\n }\n\n // Server actions file\n const actionsFile = path.join(resolvedConfig.paths.output.actions, `${kebabName}.ts`)\n if (fs.existsSync(actionsFile)) {\n filesToRemove.push(actionsFile)\n }\n\n // Hook file\n const hookFile = path.join(resolvedConfig.paths.output.hooks, `use-${kebabName}.ts`)\n if (fs.existsSync(hookFile)) {\n filesToRemove.push(hookFile)\n }\n\n if (filesToRemove.length === 0) {\n logger.warn(`No generated files found for schema: ${name}`)\n return\n }\n\n // Show files to remove\n logger.info('The following files will be removed:\\n')\n for (const file of filesToRemove) {\n const relativePath = path.relative(projectRoot, file)\n const isDir = fs.statSync(file).isDirectory()\n logger.info(` ${isDir ? 'šŸ“' : 'šŸ“„'} ${relativePath}${isDir ? '/' : ''}`)\n }\n\n // Confirm removal\n if (!options.force) {\n const confirmed = await confirm('\\nAre you sure you want to remove these files?')\n if (!confirmed) {\n logger.info('\\nRemoval cancelled.')\n return\n }\n }\n\n // Remove files\n logger.info('')\n for (const file of filesToRemove) {\n const relativePath = path.relative(projectRoot, file)\n const isDir = fs.statSync(file).isDirectory()\n\n if (isDir) {\n fs.rmSync(file, { recursive: true, force: true })\n } else {\n fs.unlinkSync(file)\n }\n\n logger.success(`Removed: ${relativePath}`)\n }\n\n logger.info('\\nāœ… Removal complete!')\n logger.info('\\nNote: The following may need manual cleanup:')\n logger.info(' - Database table (run a migration to drop it)')\n logger.info(' - Navigation entries in navigation.json')\n logger.info(' - Any imports referencing removed files')\n } catch (error) {\n if (error instanceof Error) {\n logger.error(`\\n${error.message}`)\n }\n process.exit(1)\n }\n })\n\n return command\n}\n\n/**\n * Prompt for confirmation\n */\nasync function confirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout\n })\n\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close()\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')\n })\n })\n}\n"],"mappings":"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","names":["fs","path","Command","fs","path","Command","Command","path","fs","fs","path","Command","Command","path","fs","path","fs","Command"]}