@invect/cli 0.0.1

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.
@@ -0,0 +1,569 @@
1
+ import {
2
+ generateAllDrizzleSchemas,
3
+ generateAppendSchema,
4
+ generatePrismaSchema
5
+ } from "./chunk-K4RRNATQ.js";
6
+ import {
7
+ findConfigPath,
8
+ loadConfig
9
+ } from "./chunk-Q6JKV7VX.js";
10
+
11
+ // src/commands/generate.ts
12
+ import { Command } from "commander";
13
+ import path from "path";
14
+ import fs from "fs";
15
+ import pc from "picocolors";
16
+ import prompts from "prompts";
17
+ import { execSync } from "child_process";
18
+ var generateCommand = new Command("generate").description("Generate Drizzle or Prisma schema files from core + plugin schemas").option(
19
+ "--config <path>",
20
+ "Path to your Invect config file. Defaults to the first config found."
21
+ ).option(
22
+ "--output <path>",
23
+ "Output directory for generated schema files (used when --schema is not set)",
24
+ "./src/database"
25
+ ).option(
26
+ "--schema <path>",
27
+ "Path to your existing Drizzle schema file. Invect tables will be appended to this file. If not provided, auto-detected from drizzle.config.ts."
28
+ ).option(
29
+ "--adapter <adapter>",
30
+ 'Schema adapter to use: "drizzle" (default) or "prisma"'
31
+ ).option(
32
+ "--dialect <dialect>",
33
+ "Database dialect (sqlite, postgresql, mysql). Required when using --schema. Auto-detected from drizzle.config.ts when possible."
34
+ ).option("-y, --yes", "Skip confirmation prompt and generate directly", false).action(generateAction);
35
+ async function generateAction(options) {
36
+ console.log(pc.bold("\n\u{1F527} Invect Schema Generator\n"));
37
+ const adapter = (options.adapter || "drizzle").toLowerCase();
38
+ if (adapter !== "drizzle" && adapter !== "prisma") {
39
+ console.error(
40
+ pc.red(`\u2717 Unknown adapter "${options.adapter}".`) + "\n" + pc.dim(" Supported adapters: drizzle (default), prisma\n")
41
+ );
42
+ process.exit(1);
43
+ }
44
+ const configPath = findConfigPath(options.config);
45
+ if (!configPath) {
46
+ console.error(
47
+ pc.red("\u2717 Could not find Invect config file.") + "\n\n" + pc.dim(" Searched for: invect.config.ts in ./, src/, lib/, config/") + "\n" + pc.dim(" Use --config <path> to specify the config file explicitly.") + "\n\n" + pc.dim(" You can create one with: " + pc.cyan("npx invect init")) + "\n"
48
+ );
49
+ process.exit(1);
50
+ }
51
+ console.log(pc.dim(` Config: ${path.relative(process.cwd(), configPath)}`));
52
+ let config;
53
+ try {
54
+ config = await loadConfig(configPath);
55
+ } catch (error) {
56
+ console.error(
57
+ pc.red(`
58
+ \u2717 Failed to load config.`) + "\n" + pc.dim(` ${error instanceof Error ? error.message : String(error)}`) + "\n\n" + pc.dim(" If your config uses import aliases (e.g., @/ or ~/),") + "\n" + pc.dim(" try using relative paths instead, then run the CLI again.\n")
59
+ );
60
+ process.exit(1);
61
+ }
62
+ if (adapter === "prisma") {
63
+ await runPrismaMode(config, options);
64
+ process.exit(0);
65
+ }
66
+ let schemaFile = options.schema ? path.resolve(process.cwd(), options.schema) : void 0;
67
+ let dialect = normalizeDialect(options.dialect);
68
+ if (!schemaFile) {
69
+ const detected = detectDrizzleSchema();
70
+ if (detected) {
71
+ schemaFile = detected.schemaPath;
72
+ dialect = dialect || detected.dialect;
73
+ console.log(
74
+ pc.dim(` Schema: ${path.relative(process.cwd(), schemaFile)}`) + pc.dim(` (auto-detected from ${detected.configFile})`)
75
+ );
76
+ }
77
+ } else {
78
+ console.log(pc.dim(` Schema: ${path.relative(process.cwd(), schemaFile)}`));
79
+ }
80
+ const useAppendMode = !!schemaFile;
81
+ if (useAppendMode && !dialect) {
82
+ console.error(
83
+ pc.red("\u2717 Cannot determine database dialect.") + "\n\n" + pc.dim(" When using --schema, provide --dialect (sqlite, postgresql, or mysql).") + "\n" + pc.dim(" Or ensure your drizzle.config.ts specifies a dialect.\n")
84
+ );
85
+ process.exit(1);
86
+ }
87
+ if (useAppendMode) {
88
+ await runAppendMode(config, schemaFile, dialect, options);
89
+ } else {
90
+ await runSeparateFilesMode(config, options);
91
+ }
92
+ process.exit(0);
93
+ }
94
+ async function runPrismaMode(config, options) {
95
+ const provider = normalizePrismaProvider(options.dialect) || "postgresql";
96
+ const schemaFile = options.schema ? path.resolve(process.cwd(), options.schema) : path.resolve(process.cwd(), "prisma/schema.prisma");
97
+ console.log(pc.dim(` Adapter: ${pc.cyan("Prisma")}`));
98
+ console.log(pc.dim(` Provider: ${pc.white(provider)}`));
99
+ console.log(pc.dim(` Schema: ${path.relative(process.cwd(), schemaFile)}`));
100
+ let result;
101
+ try {
102
+ result = await generatePrismaSchema({
103
+ plugins: config.plugins,
104
+ file: schemaFile,
105
+ provider
106
+ });
107
+ } catch (error) {
108
+ console.error(pc.red(`
109
+ \u2717 Prisma schema generation failed:`));
110
+ console.error(pc.dim(` ${error instanceof Error ? error.message : String(error)}
111
+ `));
112
+ process.exit(1);
113
+ }
114
+ if (result.code === void 0) {
115
+ console.log(pc.bold(pc.green("\n\u2713 Prisma schema is already up to date.\n")));
116
+ process.exit(0);
117
+ }
118
+ const rel = path.relative(process.cwd(), result.fileName);
119
+ console.log("");
120
+ console.log(pc.bold(" Files:"));
121
+ if (result.overwrite) {
122
+ console.log(pc.yellow(` ~ ${rel}`) + pc.dim(" (will update)"));
123
+ } else {
124
+ console.log(pc.green(` + ${rel}`) + pc.dim(" (will create)"));
125
+ }
126
+ if (!options.yes) {
127
+ console.log("");
128
+ const response = await prompts({
129
+ type: "confirm",
130
+ name: "proceed",
131
+ message: result.overwrite ? `Update ${pc.cyan(rel)}?` : `Create ${pc.cyan(rel)}?`,
132
+ initial: true
133
+ });
134
+ if (!response.proceed) {
135
+ console.log(pc.dim("\n Cancelled.\n"));
136
+ process.exit(0);
137
+ }
138
+ }
139
+ const dir = path.dirname(result.fileName);
140
+ fs.mkdirSync(dir, { recursive: true });
141
+ fs.writeFileSync(result.fileName, result.code, "utf-8");
142
+ console.log(
143
+ pc.bold(pc.green(`
144
+ \u2713 Prisma schema ${result.overwrite ? "updated" : "created"}: ${rel}
145
+ `))
146
+ );
147
+ console.log(pc.dim(" Next steps:"));
148
+ console.log(
149
+ pc.dim(" 1. Run ") + pc.cyan("npx prisma db push") + pc.dim(" to apply schema changes")
150
+ );
151
+ console.log(
152
+ pc.dim(" 2. Run ") + pc.cyan("npx prisma generate") + pc.dim(" to regenerate the Prisma client")
153
+ );
154
+ console.log("");
155
+ }
156
+ function normalizePrismaProvider(dialect) {
157
+ if (!dialect) return void 0;
158
+ const d = dialect.toLowerCase();
159
+ if (d === "sqlite") return "sqlite";
160
+ if (d === "postgresql" || d === "pg" || d === "postgres") return "postgresql";
161
+ if (d === "mysql") return "mysql";
162
+ return void 0;
163
+ }
164
+ async function runAppendMode(config, schemaFile, dialect, options) {
165
+ let appendResult;
166
+ try {
167
+ appendResult = await generateAppendSchema({
168
+ plugins: config.plugins,
169
+ dialect
170
+ });
171
+ } catch (error) {
172
+ console.error(pc.red(`
173
+ \u2717 Schema generation failed:`));
174
+ console.error(pc.dim(` ${error instanceof Error ? error.message : String(error)}
175
+ `));
176
+ process.exit(1);
177
+ }
178
+ const { result, stats } = appendResult;
179
+ await printSummary(config, stats);
180
+ const fileExists = fs.existsSync(schemaFile);
181
+ const currentFileContent = fileExists ? fs.readFileSync(schemaFile, "utf-8") : "";
182
+ let existingContent = currentFileContent;
183
+ const marker = "// Invect tables \u2014 AUTO-GENERATED by @invect/cli";
184
+ const markerIndex = existingContent.indexOf(marker);
185
+ if (markerIndex !== -1) {
186
+ const sectionDivider = "// =============================================================================";
187
+ const dividerIndex = existingContent.lastIndexOf(sectionDivider, markerIndex);
188
+ const stripFrom = dividerIndex !== -1 ? dividerIndex : markerIndex;
189
+ existingContent = existingContent.substring(0, stripFrom).trimEnd();
190
+ }
191
+ const pendingImports = [];
192
+ let mergedContent = existingContent;
193
+ for (const imp of result.imports) {
194
+ const fromMatch = imp.match(/from\s+['"]([^'"]+)['"]/);
195
+ if (!fromMatch) {
196
+ pendingImports.push(imp);
197
+ continue;
198
+ }
199
+ const modulePath = fromMatch[1];
200
+ const moduleImportRegex = new RegExp(
201
+ `import\\s*\\{([\\s\\S]*?)\\}\\s*from\\s*['"]${modulePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}['"];?`,
202
+ "m"
203
+ );
204
+ const existingModuleImport = mergedContent.match(moduleImportRegex);
205
+ if (!existingModuleImport) {
206
+ pendingImports.push(imp);
207
+ continue;
208
+ }
209
+ const newSpecifiersMatch = imp.match(/import\s*\{([\s\S]*?)\}\s*from/);
210
+ if (!newSpecifiersMatch) {
211
+ continue;
212
+ }
213
+ const existingSpecifiers = existingModuleImport[1].split(",").map((specifier) => specifier.trim()).filter(Boolean);
214
+ const nextSpecifiers = newSpecifiersMatch[1].split(",").map((specifier) => specifier.trim()).filter(Boolean);
215
+ const mergedSpecifiers = Array.from(/* @__PURE__ */ new Set([...existingSpecifiers, ...nextSpecifiers]));
216
+ const replacement = `import { ${mergedSpecifiers.join(", ")} } from '${modulePath}';`;
217
+ mergedContent = mergedContent.replace(moduleImportRegex, replacement);
218
+ }
219
+ let finalContent = mergedContent;
220
+ if (pendingImports.length > 0) {
221
+ const importRegex = /^import\s.*$/gm;
222
+ let lastImportEnd = 0;
223
+ let match;
224
+ while ((match = importRegex.exec(finalContent)) !== null) {
225
+ lastImportEnd = match.index + match[0].length;
226
+ }
227
+ if (lastImportEnd > 0) {
228
+ finalContent = finalContent.substring(0, lastImportEnd) + "\n" + pendingImports.join("\n") + finalContent.substring(lastImportEnd);
229
+ } else {
230
+ finalContent = pendingImports.join("\n") + "\n" + finalContent;
231
+ }
232
+ }
233
+ finalContent = finalContent.trimEnd() + "\n" + result.code + "\n";
234
+ if (currentFileContent === finalContent) {
235
+ printSummaryAlreadyUpToDate();
236
+ process.exit(0);
237
+ }
238
+ const rel = path.relative(process.cwd(), schemaFile);
239
+ console.log("");
240
+ console.log(pc.bold(" Files:"));
241
+ if (fileExists) {
242
+ if (markerIndex !== -1) {
243
+ console.log(pc.yellow(` ~ ${rel}`) + pc.dim(" (Invect tables will be regenerated)"));
244
+ } else {
245
+ console.log(pc.green(` ~ ${rel}`) + pc.dim(" (Invect tables will be appended)"));
246
+ }
247
+ } else {
248
+ console.log(pc.green(` + ${rel}`) + pc.dim(" (will create)"));
249
+ }
250
+ if (!options.yes) {
251
+ console.log("");
252
+ const response = await prompts({
253
+ type: "confirm",
254
+ name: "proceed",
255
+ message: fileExists ? `Append Invect tables to ${pc.cyan(rel)}?` : `Create ${pc.cyan(rel)} with Invect tables?`,
256
+ initial: true
257
+ });
258
+ if (!response.proceed) {
259
+ console.log(pc.dim("\n Cancelled.\n"));
260
+ process.exit(0);
261
+ }
262
+ }
263
+ const dir = path.dirname(schemaFile);
264
+ fs.mkdirSync(dir, { recursive: true });
265
+ fs.writeFileSync(schemaFile, finalContent, "utf-8");
266
+ const schemaFileChanged = currentFileContent !== finalContent;
267
+ console.log(
268
+ pc.bold(
269
+ pc.green(
270
+ `
271
+ \u2713 Invect tables ${markerIndex !== -1 ? "updated" : "appended"} in ${rel}
272
+ `
273
+ )
274
+ )
275
+ );
276
+ if (!schemaFileChanged) {
277
+ console.log(
278
+ pc.dim(" Schema file unchanged after regeneration \u2014 skipping drizzle-kit push.\n") + pc.dim(" The database is already up to date.\n")
279
+ );
280
+ } else if (!options.yes) {
281
+ const { runPush } = await prompts({
282
+ type: "confirm",
283
+ name: "runPush",
284
+ message: `Run ${pc.cyan("drizzle-kit push")} to apply schema changes?`,
285
+ initial: true
286
+ });
287
+ if (runPush) {
288
+ await runDrizzleKitPush();
289
+ } else {
290
+ console.log(
291
+ pc.dim("\n Next: run ") + pc.cyan("npx drizzle-kit push") + pc.dim(" to apply schema changes.\n")
292
+ );
293
+ }
294
+ } else {
295
+ await runDrizzleKitPush();
296
+ }
297
+ }
298
+ async function runSeparateFilesMode(config, options) {
299
+ const outputDir = path.resolve(process.cwd(), options.output);
300
+ let generated;
301
+ try {
302
+ generated = await generateAllDrizzleSchemas({
303
+ plugins: config.plugins,
304
+ outputDir
305
+ });
306
+ } catch (error) {
307
+ console.error(pc.red(`
308
+ \u2717 Schema generation failed:`));
309
+ console.error(pc.dim(` ${error instanceof Error ? error.message : String(error)}
310
+ `));
311
+ process.exit(1);
312
+ }
313
+ const { results, stats } = generated;
314
+ await printSummary(config, stats);
315
+ const filteredResults = options.dialect ? results.filter((r) => {
316
+ const d = options.dialect.toLowerCase();
317
+ if (d === "sqlite") return r.fileName.includes("sqlite");
318
+ if (d === "postgresql" || d === "pg" || d === "postgres")
319
+ return r.fileName.includes("postgres");
320
+ if (d === "mysql") return r.fileName.includes("mysql");
321
+ return true;
322
+ }) : results;
323
+ const hasChanges = filteredResults.some((r) => r.code !== void 0);
324
+ if (!hasChanges) {
325
+ console.log(pc.bold(pc.green("\n\u2713 Schema files are already up to date.\n")));
326
+ process.exit(0);
327
+ }
328
+ console.log("");
329
+ console.log(pc.bold(" Files:"));
330
+ for (const result of filteredResults) {
331
+ const rel = path.relative(process.cwd(), result.fileName);
332
+ if (result.code === void 0) {
333
+ console.log(pc.dim(` \xB7 ${rel} (unchanged)`));
334
+ } else if (result.overwrite) {
335
+ console.log(pc.yellow(` ~ ${rel}`) + pc.dim(" (will update)"));
336
+ } else {
337
+ console.log(pc.green(` + ${rel}`) + pc.dim(" (will create)"));
338
+ }
339
+ }
340
+ if (!options.yes) {
341
+ console.log("");
342
+ const response = await prompts({
343
+ type: "confirm",
344
+ name: "proceed",
345
+ message: "Generate schema files?",
346
+ initial: true
347
+ });
348
+ if (!response.proceed) {
349
+ console.log(pc.dim("\n Cancelled.\n"));
350
+ process.exit(0);
351
+ }
352
+ }
353
+ let writtenCount = 0;
354
+ for (const result of filteredResults) {
355
+ if (result.code === void 0) continue;
356
+ const dir = path.dirname(result.fileName);
357
+ fs.mkdirSync(dir, { recursive: true });
358
+ fs.writeFileSync(result.fileName, result.code, "utf-8");
359
+ writtenCount++;
360
+ }
361
+ console.log(
362
+ pc.bold(
363
+ pc.green(`
364
+ \u2713 Generated ${writtenCount} schema file${writtenCount !== 1 ? "s" : ""}.
365
+ `)
366
+ )
367
+ );
368
+ if (!options.yes) {
369
+ const { runDrizzleKit } = await prompts({
370
+ type: "confirm",
371
+ name: "runDrizzleKit",
372
+ message: `Run ${pc.cyan("drizzle-kit generate")} to create SQL migrations?`,
373
+ initial: true
374
+ });
375
+ if (runDrizzleKit) {
376
+ await runDrizzleKitGenerate();
377
+ } else {
378
+ printNextSteps();
379
+ }
380
+ } else {
381
+ await runDrizzleKitGenerate();
382
+ }
383
+ }
384
+ function printSummaryAlreadyUpToDate() {
385
+ console.log(pc.bold(pc.green("\n\u2713 Schema is already up to date. Nothing to do.\n")));
386
+ }
387
+ async function printSummary(config, stats) {
388
+ const pluginsWithSchema = config.plugins.filter((p) => p.schema);
389
+ const pluginsWithRequiredTablesOnly = config.plugins.filter(
390
+ (p) => !p.schema && Array.isArray(p.requiredTables) && p.requiredTables.length > 0
391
+ );
392
+ console.log(
393
+ pc.dim(
394
+ ` Plugins: ${pc.white(String(config.plugins.length))} loaded` + (pluginsWithSchema.length > 0 ? `, ${pc.cyan(String(pluginsWithSchema.length))} with schema` : "")
395
+ )
396
+ );
397
+ console.log(
398
+ pc.dim(
399
+ ` Tables: ${pc.white(String(stats.totalTables))} total (${stats.coreTableCount} core` + (stats.pluginTableCount > 0 ? ` + ${pc.cyan(String(stats.pluginTableCount))} plugin` : "") + ")"
400
+ )
401
+ );
402
+ if (pluginsWithSchema.length > 0) {
403
+ let coreSchema;
404
+ try {
405
+ const core = await import("@invect/core");
406
+ coreSchema = core.CORE_SCHEMA;
407
+ } catch {
408
+ coreSchema = {};
409
+ }
410
+ console.log("");
411
+ for (const plugin of pluginsWithSchema) {
412
+ const tableNames = Object.keys(plugin.schema);
413
+ const newTables = tableNames.filter((t) => !(t in coreSchema));
414
+ const extendedTables = tableNames.filter((t) => t in coreSchema);
415
+ console.log(pc.dim(` Plugin ${pc.cyan(plugin.id)}:`));
416
+ for (const t of newTables) {
417
+ const fields = Object.keys(
418
+ plugin.schema[t]?.fields || {}
419
+ );
420
+ console.log(
421
+ pc.green(` + ${t}`) + pc.dim(` (new table, ${fields.length} field${fields.length !== 1 ? "s" : ""})`)
422
+ );
423
+ }
424
+ for (const t of extendedTables) {
425
+ const fields = Object.keys(
426
+ plugin.schema[t]?.fields || {}
427
+ );
428
+ console.log(
429
+ pc.yellow(` ~ ${t}`) + pc.dim(` (${fields.length} field${fields.length !== 1 ? "s" : ""} added)`)
430
+ );
431
+ }
432
+ }
433
+ }
434
+ if (pluginsWithRequiredTablesOnly.length > 0) {
435
+ console.log("");
436
+ console.log(
437
+ pc.yellow(" \u26A0 Some plugins require tables but do not provide schema definitions:")
438
+ );
439
+ for (const plugin of pluginsWithRequiredTablesOnly) {
440
+ const tables = plugin.requiredTables.join(", ");
441
+ console.log(
442
+ pc.dim(` ${pc.yellow(plugin.id)}: requires `) + pc.white(tables)
443
+ );
444
+ if (plugin.setupInstructions) {
445
+ console.log(pc.dim(` \u2192 ${plugin.setupInstructions}`));
446
+ }
447
+ }
448
+ console.log(
449
+ pc.dim(
450
+ "\n These tables must be added to your schema manually (or via the plugin's own tooling).\n The generated schema files will NOT include them automatically.\n"
451
+ )
452
+ );
453
+ }
454
+ }
455
+ function detectDrizzleSchema() {
456
+ const configFile = findDrizzleConfig();
457
+ if (!configFile) return null;
458
+ const configPath = path.resolve(process.cwd(), configFile);
459
+ let content;
460
+ try {
461
+ content = fs.readFileSync(configPath, "utf-8");
462
+ } catch {
463
+ return null;
464
+ }
465
+ const schemaMatch = content.match(/schema\s*:\s*['"]([^'"]+)['"]/);
466
+ if (!schemaMatch) return null;
467
+ let schemaPath = schemaMatch[1];
468
+ if (!schemaPath.endsWith(".ts") && !schemaPath.endsWith(".js")) {
469
+ schemaPath += ".ts";
470
+ }
471
+ schemaPath = path.resolve(process.cwd(), schemaPath);
472
+ let dialect;
473
+ const dialectMatch = content.match(/dialect\s*:\s*['"]([^'"]+)['"]/);
474
+ if (dialectMatch) {
475
+ const d = dialectMatch[1].toLowerCase();
476
+ if (d === "sqlite") dialect = "sqlite";
477
+ else if (d === "postgresql" || d === "pg" || d === "postgres") dialect = "postgresql";
478
+ else if (d === "mysql") dialect = "mysql";
479
+ }
480
+ return { schemaPath, dialect, configFile };
481
+ }
482
+ function normalizeDialect(dialect) {
483
+ if (!dialect) return void 0;
484
+ const d = dialect.toLowerCase();
485
+ if (d === "sqlite") return "sqlite";
486
+ if (d === "postgresql" || d === "pg" || d === "postgres") return "postgresql";
487
+ if (d === "mysql") return "mysql";
488
+ return void 0;
489
+ }
490
+ async function runDrizzleKitGenerate() {
491
+ console.log(pc.dim("\n Running drizzle-kit generate...\n"));
492
+ try {
493
+ const configFile = findDrizzleConfig();
494
+ const cmd = configFile ? `npx drizzle-kit generate --config ${configFile}` : "npx drizzle-kit generate";
495
+ execSync(cmd, { stdio: "inherit", cwd: process.cwd() });
496
+ console.log(
497
+ pc.bold(pc.green("\n\u2713 SQL migrations generated.\n")) + pc.dim(" Run ") + pc.cyan("npx invect migrate") + pc.dim(" to apply them.\n")
498
+ );
499
+ } catch {
500
+ console.error(
501
+ pc.yellow("\n\u26A0 drizzle-kit generate failed.") + "\n" + pc.dim(" Make sure drizzle-kit is installed and drizzle.config.ts exists.") + "\n" + pc.dim(" You can run it manually: ") + pc.cyan("npx drizzle-kit generate") + "\n"
502
+ );
503
+ }
504
+ }
505
+ async function runDrizzleKitPush() {
506
+ console.log(pc.dim("\n Running drizzle-kit push...\n"));
507
+ try {
508
+ const configFile = findDrizzleConfig();
509
+ const cmd = configFile ? `npx drizzle-kit push --config ${configFile}` : "npx drizzle-kit push";
510
+ const output = execSync(cmd, {
511
+ cwd: process.cwd(),
512
+ encoding: "utf-8",
513
+ stdio: ["inherit", "pipe", "pipe"]
514
+ });
515
+ if (output) process.stdout.write(output);
516
+ console.log(
517
+ pc.bold(pc.green("\n\u2713 Schema pushed to database.\n"))
518
+ );
519
+ } catch (error) {
520
+ const execError = error;
521
+ const combinedOutput = [
522
+ execError.stdout || "",
523
+ execError.stderr || "",
524
+ execError.message || ""
525
+ ].join("\n");
526
+ if (/already exists/i.test(combinedOutput)) {
527
+ console.log(
528
+ pc.bold(pc.green("\n\u2713 Schema is already applied to the database.\n"))
529
+ );
530
+ } else {
531
+ if (execError.stderr) process.stderr.write(execError.stderr);
532
+ if (execError.stdout) process.stdout.write(execError.stdout);
533
+ console.error(
534
+ pc.yellow("\n\u26A0 drizzle-kit push failed.") + "\n" + pc.dim(" Make sure drizzle-kit is installed and drizzle.config.ts exists.") + "\n" + pc.dim(" You can run it manually: ") + pc.cyan("npx drizzle-kit push") + "\n"
535
+ );
536
+ }
537
+ }
538
+ }
539
+ function findDrizzleConfig() {
540
+ const candidates = [
541
+ "drizzle.config.ts",
542
+ "drizzle.config.js",
543
+ "drizzle.config.sqlite.ts",
544
+ "drizzle.config.postgres.ts",
545
+ "drizzle.config.mysql.ts"
546
+ ];
547
+ for (const file of candidates) {
548
+ if (fs.existsSync(path.resolve(process.cwd(), file))) {
549
+ return file;
550
+ }
551
+ }
552
+ return null;
553
+ }
554
+ function printNextSteps() {
555
+ console.log(pc.dim("\n Next steps:"));
556
+ console.log(pc.dim(" 1. Review the generated schema files"));
557
+ console.log(
558
+ pc.dim(" 2. Run ") + pc.cyan("npx drizzle-kit generate") + pc.dim(" to create SQL migrations")
559
+ );
560
+ console.log(
561
+ pc.dim(" 3. Run ") + pc.cyan("npx invect migrate") + pc.dim(" to apply them")
562
+ );
563
+ console.log("");
564
+ }
565
+
566
+ export {
567
+ generateCommand,
568
+ generateAction
569
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ generateAction,
3
+ generateCommand
4
+ } from "./chunk-T4KEEHFJ.js";
5
+ import "./chunk-K4RRNATQ.js";
6
+ import "./chunk-Q6JKV7VX.js";
7
+ export {
8
+ generateAction,
9
+ generateCommand
10
+ };