drixio 1.1.9 → 1.1.10

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
@@ -28,27 +28,201 @@ var init_types = __esm({
28
28
  // src/logic/loader.ts
29
29
  import fs from "fs/promises";
30
30
  import path from "path";
31
+ function parseEnvContent(content) {
32
+ const env = {};
33
+ const lines = content.split(/\r?\n/);
34
+ for (let line of lines) {
35
+ line = line.trim();
36
+ if (!line || line.startsWith("#")) continue;
37
+ if (line.startsWith("export ")) {
38
+ line = line.slice(7).trim();
39
+ }
40
+ const eqIdx = line.indexOf("=");
41
+ if (eqIdx === -1) continue;
42
+ const key = line.slice(0, eqIdx).trim();
43
+ let val = line.slice(eqIdx + 1).trim();
44
+ if (val.startsWith('"')) {
45
+ const endQuote = val.indexOf('"', 1);
46
+ val = endQuote !== -1 ? val.slice(1, endQuote) : val.slice(1);
47
+ } else if (val.startsWith("'")) {
48
+ const endQuote = val.indexOf("'", 1);
49
+ val = endQuote !== -1 ? val.slice(1, endQuote) : val.slice(1);
50
+ } else {
51
+ const commentIdx = val.indexOf("#");
52
+ if (commentIdx !== -1) {
53
+ val = val.slice(0, commentIdx).trim();
54
+ }
55
+ }
56
+ if (key) {
57
+ env[key] = val;
58
+ }
59
+ }
60
+ return env;
61
+ }
62
+ async function loadCascadedEnv(cwd) {
63
+ const envFiles = [
64
+ ".env",
65
+ ".env.production",
66
+ ".env.development",
67
+ ".env.local",
68
+ ".env.development.local"
69
+ ];
70
+ const mergedEnv = {};
71
+ for (const file of envFiles) {
72
+ try {
73
+ const filePath = path.join(cwd, file);
74
+ const content = await fs.readFile(filePath, "utf-8");
75
+ const parsed = parseEnvContent(content);
76
+ Object.assign(mergedEnv, parsed);
77
+ } catch {
78
+ }
79
+ }
80
+ for (const [key, val] of Object.entries(process.env)) {
81
+ if (typeof val === "string" && val.trim() !== "") {
82
+ mergedEnv[key] = val.trim();
83
+ }
84
+ }
85
+ return mergedEnv;
86
+ }
87
+ function classifyDatabaseUrl(rawUrl, cwd) {
88
+ let trimmed = rawUrl.trim();
89
+ if (!trimmed) return null;
90
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
91
+ trimmed = trimmed.slice(1, -1).trim();
92
+ }
93
+ if (trimmed.startsWith("postgres://") || trimmed.startsWith("postgresql://")) {
94
+ return { type: "postgres", targetUrl: trimmed };
95
+ }
96
+ if (trimmed.startsWith("mysql://")) {
97
+ return { type: "mysql", targetUrl: trimmed };
98
+ }
99
+ const lower = trimmed.toLowerCase();
100
+ const isSqlitePrefix = lower.startsWith("file:") || lower.startsWith("sqlite://") || lower.startsWith("sqlite:");
101
+ const isSqliteExt = lower.endsWith(".db") || lower.endsWith(".sqlite") || lower.endsWith(".sqlite3") || lower.endsWith(".db3");
102
+ const isMemory = lower === ":memory:";
103
+ if (isSqlitePrefix || isSqliteExt || isMemory) {
104
+ let cleanPath = trimmed.replace(/^sqlite:\/\//i, "").replace(/^sqlite:/i, "").replace(/^file:/i, "");
105
+ if (cleanPath === ":memory:") {
106
+ return { type: "sqlite", targetUrl: ":memory:" };
107
+ }
108
+ if (!path.isAbsolute(cleanPath)) {
109
+ cleanPath = path.resolve(cwd, cleanPath);
110
+ }
111
+ return { type: "sqlite", targetUrl: cleanPath };
112
+ }
113
+ return null;
114
+ }
115
+ function buildUrlFromComponentEnv(env) {
116
+ const host = env.DB_HOST || env.DATABASE_HOST || env.MYSQL_HOST || env.POSTGRES_HOST || env.PGHOST;
117
+ const dbName = env.DB_NAME || env.DB_DATABASE || env.DATABASE_NAME || env.MYSQL_DATABASE || env.POSTGRES_DB || env.PGDATABASE;
118
+ if (!host || !dbName) return null;
119
+ const driver = (env.DB_CONNECTION || env.DB_TYPE || env.DB_DRIVER || "").toLowerCase();
120
+ const portStr = env.DB_PORT || env.MYSQL_PORT || env.POSTGRES_PORT || env.PGPORT;
121
+ let type = "mysql";
122
+ if (driver.includes("postgres") || driver.includes("pgsql") || driver.includes("pg") || env.POSTGRES_HOST || env.PGHOST || portStr === "5432") {
123
+ type = "postgres";
124
+ } else if (driver.includes("mysql") || driver.includes("mariadb") || env.MYSQL_HOST || portStr === "3306") {
125
+ type = "mysql";
126
+ }
127
+ const defaultPort = type === "postgres" ? 5432 : 3306;
128
+ const port = portStr ? parseInt(portStr, 10) || defaultPort : defaultPort;
129
+ const user = env.DB_USER || env.DB_USERNAME || env.MYSQL_USER || env.POSTGRES_USER || env.PGUSER || (type === "postgres" ? "postgres" : "root");
130
+ const pass = env.DB_PASSWORD || env.DB_PASS || env.MYSQL_PASSWORD || env.POSTGRES_PASSWORD || env.PGPASSWORD || "";
131
+ const auth = pass ? `${encodeURIComponent(user)}:${encodeURIComponent(pass)}` : encodeURIComponent(user);
132
+ const targetUrl = `${type}://${auth}@${host}:${port}/${dbName}`;
133
+ return { type, targetUrl };
134
+ }
31
135
  async function detectDatabase(databaseUrl) {
32
136
  const cwd = process.cwd();
33
137
  if (databaseUrl) {
34
- let type = "sqlite";
35
- if (databaseUrl.startsWith("postgres://") || databaseUrl.startsWith("postgresql://")) {
36
- type = "postgres";
37
- } else if (databaseUrl.startsWith("mysql://")) {
38
- type = "mysql";
39
- } else {
40
- type = "sqlite";
41
- }
42
- let targetUrl = databaseUrl.replace("file:", "");
43
- if (type === "sqlite" && !path.isAbsolute(targetUrl)) {
44
- targetUrl = path.resolve(cwd, targetUrl);
138
+ const classified = classifyDatabaseUrl(databaseUrl, cwd);
139
+ if (classified) {
140
+ return {
141
+ type: classified.type,
142
+ targetUrl: classified.targetUrl,
143
+ source: "manual"
144
+ };
45
145
  }
46
146
  return {
47
- type,
48
- targetUrl,
147
+ type: "unknown",
148
+ targetUrl: databaseUrl,
49
149
  source: "manual"
50
150
  };
51
151
  }
152
+ const allEnv = await loadCascadedEnv(cwd);
153
+ const prismaPaths = [
154
+ path.join(cwd, "prisma", "schema.prisma"),
155
+ path.join(cwd, "src", "prisma", "schema.prisma")
156
+ ];
157
+ for (const schemaPath of prismaPaths) {
158
+ try {
159
+ const schemaContent = await fs.readFile(schemaPath, "utf-8");
160
+ const providerMatch = schemaContent.match(
161
+ /provider\s*=\s*["']([^"']+)["']/
162
+ );
163
+ const urlMatch = schemaContent.match(
164
+ /url\s*=\s*(?:env\(["']([^"']+)["']\)|["']([^"']+)["'])/
165
+ );
166
+ if (providerMatch) {
167
+ let provider = providerMatch[1];
168
+ if (provider === "postgresql") provider = "postgres";
169
+ let rawUrl;
170
+ if (urlMatch) {
171
+ if (urlMatch[1]) {
172
+ rawUrl = allEnv[urlMatch[1]];
173
+ } else if (urlMatch[2]) {
174
+ rawUrl = urlMatch[2];
175
+ }
176
+ }
177
+ if (rawUrl) {
178
+ if (provider === "sqlite") {
179
+ let cleanPath = rawUrl.replace(/^file:/i, "");
180
+ if (!path.isAbsolute(cleanPath)) {
181
+ cleanPath = path.resolve(
182
+ path.dirname(schemaPath),
183
+ cleanPath
184
+ );
185
+ }
186
+ return {
187
+ type: "sqlite",
188
+ targetUrl: cleanPath,
189
+ source: ".env"
190
+ };
191
+ }
192
+ const classified = classifyDatabaseUrl(rawUrl, cwd);
193
+ if (classified) {
194
+ return {
195
+ type: classified.type,
196
+ targetUrl: classified.targetUrl,
197
+ source: ".env"
198
+ };
199
+ }
200
+ }
201
+ }
202
+ } catch {
203
+ }
204
+ }
205
+ for (const key of DB_ENV_KEYS) {
206
+ const candidate = allEnv[key];
207
+ if (candidate) {
208
+ const classified = classifyDatabaseUrl(candidate, cwd);
209
+ if (classified) {
210
+ return {
211
+ type: classified.type,
212
+ targetUrl: classified.targetUrl,
213
+ source: ".env"
214
+ };
215
+ }
216
+ }
217
+ }
218
+ const assembled = buildUrlFromComponentEnv(allEnv);
219
+ if (assembled) {
220
+ return {
221
+ type: assembled.type,
222
+ targetUrl: assembled.targetUrl,
223
+ source: ".env"
224
+ };
225
+ }
52
226
  const searchDirs = [
53
227
  ".",
54
228
  "prisma",
@@ -61,9 +235,10 @@ async function detectDatabase(databaseUrl) {
61
235
  try {
62
236
  const targetDir = path.join(cwd, dir);
63
237
  const files = await fs.readdir(targetDir);
64
- const sqliteFile = files.find(
65
- (file) => file.endsWith(".db") || file.endsWith(".sqlite") || file.endsWith(".sqlite3")
66
- );
238
+ const sqliteFile = files.find((file) => {
239
+ const lower = file.toLowerCase();
240
+ return lower.endsWith(".db") || lower.endsWith(".sqlite") || lower.endsWith(".sqlite3") || lower.endsWith(".db3");
241
+ });
67
242
  if (sqliteFile) {
68
243
  return {
69
244
  type: "sqlite",
@@ -74,81 +249,6 @@ async function detectDatabase(databaseUrl) {
74
249
  } catch {
75
250
  }
76
251
  }
77
- const prismaSchemaPath = path.join(cwd, "prisma", "schema.prisma");
78
- try {
79
- const schemaContent = await fs.readFile(prismaSchemaPath, "utf-8");
80
- const providerMatch = schemaContent.match(
81
- /provider\s*=\s*["']([^"']+)["']/
82
- );
83
- const urlMatch = schemaContent.match(
84
- /url\s*=\s*(?:env\(["']([^"']+)["']\)|["']([^"']+)["'])/
85
- );
86
- if (providerMatch) {
87
- let provider = providerMatch[1];
88
- if (provider === "postgresql") provider = "postgres";
89
- let targetUrl = "";
90
- if (urlMatch && urlMatch[2]) {
91
- targetUrl = urlMatch[2];
92
- if (targetUrl.startsWith("file:")) {
93
- targetUrl = path.join(
94
- cwd,
95
- "prisma",
96
- targetUrl.replace("file:", "")
97
- );
98
- }
99
- }
100
- if (targetUrl && (provider === "sqlite" || provider === "postgres" || provider === "mysql")) {
101
- return {
102
- type: provider,
103
- targetUrl,
104
- source: ".env"
105
- };
106
- }
107
- }
108
- } catch {
109
- }
110
- const envPath = path.join(cwd, ".env");
111
- try {
112
- const envContent = await fs.readFile(envPath, "utf-8");
113
- const dbKeys = [
114
- "DATABASE_URL",
115
- "DB_URL",
116
- "POSTGRES_URL",
117
- "POSTGRES_PRISMA_URL",
118
- "MYSQL_URL"
119
- ];
120
- for (const key of dbKeys) {
121
- const regex = new RegExp(`${key}\\s*=\\s*["']?([^"'\\r\\n]+)["']?`);
122
- const match = envContent.match(regex);
123
- if (match) {
124
- const url = match[1];
125
- if (url.startsWith("file:") || url.endsWith(".db") || url.includes(".sqlite")) {
126
- let targetUrl = url.replace("file:", "");
127
- if (!path.isAbsolute(targetUrl)) {
128
- targetUrl = path.resolve(cwd, targetUrl);
129
- }
130
- return {
131
- type: "sqlite",
132
- targetUrl,
133
- source: ".env"
134
- };
135
- } else if (url.startsWith("postgres://") || url.startsWith("postgresql://")) {
136
- return {
137
- type: "postgres",
138
- targetUrl: url,
139
- source: ".env"
140
- };
141
- } else if (url.startsWith("mysql://")) {
142
- return {
143
- type: "mysql",
144
- targetUrl: url,
145
- source: ".env"
146
- };
147
- }
148
- }
149
- }
150
- } catch (error) {
151
- }
152
252
  return {
153
253
  type: "unknown",
154
254
  targetUrl: "",
@@ -161,7 +261,7 @@ async function saveDatabaseUrl(url) {
161
261
  let envContent = "";
162
262
  try {
163
263
  envContent = await fs.readFile(envPath, "utf-8");
164
- } catch (e) {
264
+ } catch {
165
265
  }
166
266
  const regex = /DATABASE_URL\s*=\s*["']?([^"'\r\n]+)["']?/;
167
267
  if (regex.test(envContent)) {
@@ -183,10 +283,27 @@ async function saveDatabaseUrl(url) {
183
283
  );
184
284
  }
185
285
  }
286
+ var DB_ENV_KEYS;
186
287
  var init_loader = __esm({
187
288
  "src/logic/loader.ts"() {
188
289
  "use strict";
189
290
  init_types();
291
+ DB_ENV_KEYS = [
292
+ "DATABASE_URL",
293
+ "DB_URL",
294
+ "DATABASE_URI",
295
+ "DB_URI",
296
+ "DIRECT_URL",
297
+ "POSTGRES_URL",
298
+ "POSTGRESQL_URL",
299
+ "POSTGRES_PRISMA_URL",
300
+ "POSTGRES_URL_NON_POOLING",
301
+ "SUPABASE_DB_URL",
302
+ "MYSQL_URL",
303
+ "MYSQL_DATABASE_URL",
304
+ "JAWSDB_URL",
305
+ "CLEARDB_DATABASE_URL"
306
+ ];
190
307
  }
191
308
  });
192
309
 
@@ -203,10 +320,14 @@ var init_sqlite = __esm({
203
320
  }
204
321
  async getDb() {
205
322
  if (!this.db) {
206
- let modFs = "node:fs";
207
- const fs16 = await import(modFs);
208
- if (!fs16.existsSync(this.dbPath)) {
209
- throw new Error(`Failed to found database file at: ${this.dbPath}`);
323
+ if (this.dbPath !== ":memory:") {
324
+ let modFs = "node:fs";
325
+ const fs19 = await import(modFs);
326
+ if (!fs19.existsSync(this.dbPath)) {
327
+ throw new Error(
328
+ `Failed to found database file at: ${this.dbPath}`
329
+ );
330
+ }
210
331
  }
211
332
  let mod = "node:sqlite";
212
333
  const sqlite = await import(mod);
@@ -222,12 +343,17 @@ var init_sqlite = __esm({
222
343
  const db = await this.getDb();
223
344
  const vQuery = db.prepare("SELECT sqlite_version() as v");
224
345
  const vRow = vQuery.get();
225
- let modFs = "node:fs";
226
- const fs16 = await import(modFs);
227
- const stats = fs16.statSync(this.dbPath);
228
- let modPath = "node:path";
229
- const path17 = await import(modPath);
230
- const dbName = path17.basename(this.dbPath);
346
+ let sizeBytes = 0;
347
+ let dbName = ":memory:";
348
+ if (this.dbPath !== ":memory:") {
349
+ let modFs = "node:fs";
350
+ const fs19 = await import(modFs);
351
+ const stats = fs19.statSync(this.dbPath);
352
+ sizeBytes = stats.size;
353
+ let modPath = "node:path";
354
+ const path20 = await import(modPath);
355
+ dbName = path20.basename(this.dbPath);
356
+ }
231
357
  return {
232
358
  status: "connected",
233
359
  dbType: "sqlite",
@@ -235,7 +361,7 @@ var init_sqlite = __esm({
235
361
  version: vRow?.v,
236
362
  activeConnections: 1,
237
363
  // SQLite is single file, essentially 1 active connection for the app
238
- sizeBytes: stats.size,
364
+ sizeBytes,
239
365
  uptime: process.uptime()
240
366
  };
241
367
  } catch (e) {
@@ -549,6 +675,31 @@ var init_sqlite = __esm({
549
675
 
550
676
  // src/logic/adapters/postgres.ts
551
677
  import pg from "pg";
678
+ function buildPgPoolConfig(connectionString) {
679
+ const config = {
680
+ connectionString,
681
+ connectionTimeoutMillis: 1e4
682
+ // 10s timeout to prevent hanging on unreachable hosts
683
+ };
684
+ try {
685
+ const lower = connectionString.toLowerCase();
686
+ const isExplicitSslDisable = lower.includes("sslmode=disable");
687
+ const isExplicitSslRequire = lower.includes("sslmode=require") || lower.includes("sslmode=prefer") || lower.includes("ssl=true") || lower.includes("ssl=1");
688
+ let isCloudProvider = false;
689
+ const match = connectionString.match(/@([^/:?#]+)/);
690
+ if (match && match[1]) {
691
+ const host = match[1].toLowerCase();
692
+ isCloudProvider = host.includes("supabase.") || host.includes("neon.tech") || host.includes("railway.") || host.includes("render.com") || host.includes("cockroach") || host.includes("aiven") || host.includes("rds.amazonaws.com");
693
+ }
694
+ if (!isExplicitSslDisable && (isExplicitSslRequire || isCloudProvider)) {
695
+ config.ssl = {
696
+ rejectUnauthorized: false
697
+ };
698
+ }
699
+ } catch {
700
+ }
701
+ return config;
702
+ }
552
703
  var PostgresAdapter;
553
704
  var init_postgres = __esm({
554
705
  "src/logic/adapters/postgres.ts"() {
@@ -561,9 +712,7 @@ var init_postgres = __esm({
561
712
  }
562
713
  getPool() {
563
714
  if (!this.pool) {
564
- this.pool = new pg.Pool({
565
- connectionString: this.connectionString
566
- });
715
+ this.pool = new pg.Pool(buildPgPoolConfig(this.connectionString));
567
716
  this.pool.on("error", () => {
568
717
  });
569
718
  }
@@ -866,7 +1015,8 @@ var init_mysql = __esm({
866
1015
  if (!this.pool) {
867
1016
  this.pool = mysql.createPool({
868
1017
  uri: this.connection,
869
- multipleStatements: true
1018
+ multipleStatements: true,
1019
+ connectTimeout: 1e4
870
1020
  });
871
1021
  this.pool.on("connection", (connection) => {
872
1022
  connection.query("SET SESSION sql_mode = 'ANSI_QUOTES'").catch(() => {
@@ -1984,6 +2134,9 @@ function inferColumnStrategy(col) {
1984
2134
  if (name.includes("last_name")) {
1985
2135
  return { type: "last_name", label: "Last Name" };
1986
2136
  }
2137
+ if (name.includes("username") || name.includes("user_name") || name.includes("handle")) {
2138
+ return { type: "username", label: "Username" };
2139
+ }
1987
2140
  if (name.includes("name") || name.includes("author") || name.includes("user")) {
1988
2141
  return { type: "full_name", label: "Full Name" };
1989
2142
  }
@@ -2064,6 +2217,11 @@ function generateFieldValue(strategy, fkCache = {}) {
2064
2217
  return getRandomItem(FIRST_NAMES);
2065
2218
  case "last_name":
2066
2219
  return getRandomItem(LAST_NAMES);
2220
+ case "username": {
2221
+ const f = getRandomItem(FIRST_NAMES).toLowerCase();
2222
+ const l = getRandomItem(LAST_NAMES).toLowerCase();
2223
+ return `${f}_${l}${getRandomInt(100, 99999)}`;
2224
+ }
2067
2225
  case "full_name":
2068
2226
  return `${getRandomItem(FIRST_NAMES)} ${getRandomItem(LAST_NAMES)}`;
2069
2227
  case "avatar":
@@ -4116,6 +4274,72 @@ var init_snippets = __esm({
4116
4274
  }
4117
4275
  });
4118
4276
 
4277
+ // src/logic/version.ts
4278
+ import fs5 from "fs";
4279
+ import path5 from "path";
4280
+ import { fileURLToPath } from "url";
4281
+ function getDrixioVersion() {
4282
+ if (cachedVersion) {
4283
+ return cachedVersion;
4284
+ }
4285
+ if ("1.1.10") {
4286
+ cachedVersion = "1.1.10";
4287
+ return cachedVersion;
4288
+ }
4289
+ try {
4290
+ let currentDir = path5.dirname(fileURLToPath(import.meta.url));
4291
+ for (let i = 0; i < 5; i++) {
4292
+ const candidate = path5.join(currentDir, "package.json");
4293
+ if (fs5.existsSync(candidate)) {
4294
+ const pkg = JSON.parse(fs5.readFileSync(candidate, "utf-8"));
4295
+ if (pkg.name === "drixio" && typeof pkg.version === "string") {
4296
+ cachedVersion = pkg.version;
4297
+ return pkg.version;
4298
+ }
4299
+ }
4300
+ const parent = path5.dirname(currentDir);
4301
+ if (parent === currentDir) break;
4302
+ currentDir = parent;
4303
+ }
4304
+ } catch {
4305
+ }
4306
+ try {
4307
+ const cwdPkgPath = path5.resolve(process.cwd(), "package.json");
4308
+ if (fs5.existsSync(cwdPkgPath)) {
4309
+ const pkg = JSON.parse(fs5.readFileSync(cwdPkgPath, "utf-8"));
4310
+ if (pkg.name === "drixio" && typeof pkg.version === "string") {
4311
+ cachedVersion = pkg.version;
4312
+ return pkg.version;
4313
+ }
4314
+ }
4315
+ } catch {
4316
+ }
4317
+ if (typeof process.env.npm_package_version === "string") {
4318
+ cachedVersion = process.env.npm_package_version;
4319
+ return cachedVersion;
4320
+ }
4321
+ cachedVersion = "0.0.0";
4322
+ return cachedVersion;
4323
+ }
4324
+ var cachedVersion;
4325
+ var init_version = __esm({
4326
+ "src/logic/version.ts"() {
4327
+ "use strict";
4328
+ }
4329
+ });
4330
+
4331
+ // src/logic/serialization.ts
4332
+ var init_serialization = __esm({
4333
+ "src/logic/serialization.ts"() {
4334
+ "use strict";
4335
+ if (!("toJSON" in BigInt.prototype)) {
4336
+ BigInt.prototype.toJSON = function() {
4337
+ return this.toString();
4338
+ };
4339
+ }
4340
+ }
4341
+ });
4342
+
4119
4343
  // src/logic/index.ts
4120
4344
  var init_logic = __esm({
4121
4345
  "src/logic/index.ts"() {
@@ -4134,6 +4358,8 @@ var init_logic = __esm({
4134
4358
  init_safety();
4135
4359
  init_diff();
4136
4360
  init_snippets();
4361
+ init_version();
4362
+ init_serialization();
4137
4363
  }
4138
4364
  });
4139
4365
 
@@ -4177,7 +4403,7 @@ function printCustomDashboard(title, rows) {
4177
4403
  );
4178
4404
  }
4179
4405
  function printDashboard(dbConfig) {
4180
- const version = true ? "1.1.9" : process.env.npm_package_version || "unknown";
4406
+ const version = getDrixioVersion();
4181
4407
  const headerTitle = ` Lightweight Interactive TUI Database Client \u2022 v${version} `;
4182
4408
  let dbTypeVal = "None";
4183
4409
  let targetVal = "-";
@@ -4208,6 +4434,7 @@ var rgb, l1, l2, l3, l4, l5, l6;
4208
4434
  var init_logo = __esm({
4209
4435
  "src/tui/ui/logo.ts"() {
4210
4436
  "use strict";
4437
+ init_version();
4211
4438
  rgb = (r, g, b) => (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
4212
4439
  l1 = rgb(0, 255, 255);
4213
4440
  l2 = rgb(0, 230, 245);
@@ -4526,8 +4753,8 @@ x Error creating table: ${e.message}`));
4526
4753
  await waitForEnter2();
4527
4754
  }
4528
4755
  async function waitForEnter2() {
4529
- const { input: input8 } = await import("@inquirer/prompts");
4530
- await input8({
4756
+ const { input: input11 } = await import("@inquirer/prompts");
4757
+ await input11({
4531
4758
  message: "Press Enter to continue..."
4532
4759
  });
4533
4760
  }
@@ -4600,8 +4827,8 @@ var init_buildTable = __esm({
4600
4827
  });
4601
4828
 
4602
4829
  // src/tui/views/sqlRunner.ts
4603
- import fs14 from "fs/promises";
4604
- import path14 from "path";
4830
+ import fs15 from "fs/promises";
4831
+ import path15 from "path";
4605
4832
  import { input as input5 } from "@inquirer/prompts";
4606
4833
  import pc29 from "picocolors";
4607
4834
  async function runSqlRunner(dbConfig) {
@@ -4622,10 +4849,10 @@ No database connection found. Please setup first.`)
4622
4849
  message: "Enter the path to your .md or .sql file:"
4623
4850
  });
4624
4851
  if (filePath && filePath.trim()) {
4625
- const absolutePath = path14.resolve(process.cwd(), filePath.trim());
4852
+ const absolutePath = path15.resolve(process.cwd(), filePath.trim());
4626
4853
  let fileContent = "";
4627
4854
  try {
4628
- fileContent = await fs14.readFile(absolutePath, "utf-8");
4855
+ fileContent = await fs15.readFile(absolutePath, "utf-8");
4629
4856
  } catch (err2) {
4630
4857
  console.log(pc29.red(`
4631
4858
  x Failed to read file: ${err2.message}`));
@@ -5160,8 +5387,8 @@ async function handleModifyMenu(dbConfig) {
5160
5387
  await waitForEnter3();
5161
5388
  }
5162
5389
  async function waitForEnter3() {
5163
- const { input: input8 } = await import("@inquirer/prompts");
5164
- await input8({
5390
+ const { input: input11 } = await import("@inquirer/prompts");
5391
+ await input11({
5165
5392
  message: "Press Enter to continue..."
5166
5393
  });
5167
5394
  }
@@ -5179,11 +5406,465 @@ var init_tableManagerFlow = __esm({
5179
5406
  }
5180
5407
  });
5181
5408
 
5409
+ // src/tui/wizards/ormWizard.ts
5410
+ var ormWizard_exports = {};
5411
+ __export(ormWizard_exports, {
5412
+ runOrmWizard: () => runOrmWizard
5413
+ });
5414
+ import { select as select13, input as input8 } from "@inquirer/prompts";
5415
+ import fs16 from "fs/promises";
5416
+ import path16 from "path";
5417
+ import pc34 from "picocolors";
5418
+ async function runOrmWizard(dbConfig) {
5419
+ if (dbConfig.type === "unknown") {
5420
+ console.log(
5421
+ pc34.yellow(
5422
+ "\nNo database connection found. Please setup database first."
5423
+ )
5424
+ );
5425
+ return;
5426
+ }
5427
+ const adapter = createDBAdapter(dbConfig);
5428
+ try {
5429
+ const allSchemasRes = await getTableSchemas(adapter, void 0, true);
5430
+ if (!allSchemasRes.success) {
5431
+ console.log(
5432
+ pc34.red(`
5433
+ \u2718 Failed to inspect schema: ${allSchemasRes.error}`)
5434
+ );
5435
+ return;
5436
+ }
5437
+ const allTables = allSchemasRes.data;
5438
+ if (allTables.length === 0) {
5439
+ console.log(pc34.yellow("\nNo tables found in this database."));
5440
+ return;
5441
+ }
5442
+ console.log(pc34.cyan("\n--- Modern ORM & Type Definition Generator ---"));
5443
+ console.log(
5444
+ pc34.dim(
5445
+ "Generate production-ready Prisma, Drizzle, or TypeScript definitions.\n"
5446
+ )
5447
+ );
5448
+ const targetFormat = await select13({
5449
+ message: "Select target ORM or definition format:",
5450
+ choices: [
5451
+ {
5452
+ name: "Prisma Schema (schema.prisma)",
5453
+ value: "prisma",
5454
+ description: "Standard Prisma models with data source and generator"
5455
+ },
5456
+ {
5457
+ name: "Drizzle ORM (schema.ts)",
5458
+ value: "drizzle",
5459
+ description: "Type-safe Drizzle table definitions with core packages"
5460
+ },
5461
+ {
5462
+ name: "TypeScript Interfaces (drixio-types.d.ts)",
5463
+ value: "types",
5464
+ description: "Pure TypeScript interface definitions for database records"
5465
+ }
5466
+ ]
5467
+ });
5468
+ const scope = await select13({
5469
+ message: "Select generation scope:",
5470
+ choices: [
5471
+ {
5472
+ name: `All Tables (${allTables.length} tables)`,
5473
+ value: "all"
5474
+ },
5475
+ {
5476
+ name: "Single Table",
5477
+ value: "single"
5478
+ }
5479
+ ]
5480
+ });
5481
+ let selectedTables = allTables;
5482
+ if (scope === "single") {
5483
+ const chosenTableName = await select13({
5484
+ message: "Select table to generate code for:",
5485
+ choices: allTables.map((t) => ({
5486
+ name: t.tableName,
5487
+ value: t.tableName
5488
+ }))
5489
+ });
5490
+ selectedTables = allTables.filter((t) => t.tableName === chosenTableName);
5491
+ }
5492
+ let generatedCode = "";
5493
+ let defaultFileName = "schema.ts";
5494
+ if (targetFormat === "prisma") {
5495
+ generatedCode = generatePrismaSchema(selectedTables, dbConfig.type);
5496
+ defaultFileName = "schema.prisma";
5497
+ } else if (targetFormat === "drizzle") {
5498
+ generatedCode = generateDrizzleSchema(selectedTables, dbConfig.type);
5499
+ defaultFileName = "schema.ts";
5500
+ } else {
5501
+ generatedCode = generateTypeScriptDefinitions(selectedTables, dbConfig.type);
5502
+ defaultFileName = "drixio-types.d.ts";
5503
+ }
5504
+ const outputAction = await select13({
5505
+ message: "What would you like to do with the generated code?",
5506
+ choices: [
5507
+ {
5508
+ name: `Save to file (${defaultFileName})`,
5509
+ value: "save"
5510
+ },
5511
+ {
5512
+ name: "Print directly to terminal",
5513
+ value: "print"
5514
+ }
5515
+ ]
5516
+ });
5517
+ if (outputAction === "print") {
5518
+ console.log(pc34.bold(pc34.cyan(`
5519
+ --- Generated Code ---`)));
5520
+ console.log(generatedCode);
5521
+ console.log(pc34.bold(pc34.cyan(`----------------------
5522
+ `)));
5523
+ } else {
5524
+ const outPath = await input8({
5525
+ message: "Enter destination file path:",
5526
+ default: defaultFileName
5527
+ });
5528
+ const resolvedPath = path16.resolve(process.cwd(), outPath);
5529
+ await fs16.mkdir(path16.dirname(resolvedPath), { recursive: true });
5530
+ await fs16.writeFile(resolvedPath, generatedCode, "utf-8");
5531
+ console.log(
5532
+ pc34.green(
5533
+ `
5534
+ \u2714 Successfully generated and saved to: ${pc34.bold(resolvedPath)}`
5535
+ )
5536
+ );
5537
+ }
5538
+ } catch (e) {
5539
+ console.log(pc34.red(`
5540
+ \u2718 Code generation failed: ${e.message}`));
5541
+ } finally {
5542
+ await adapter.close();
5543
+ }
5544
+ }
5545
+ var init_ormWizard = __esm({
5546
+ "src/tui/wizards/ormWizard.ts"() {
5547
+ "use strict";
5548
+ init_logic();
5549
+ }
5550
+ });
5551
+
5552
+ // src/tui/wizards/snippetsWizard.ts
5553
+ var snippetsWizard_exports = {};
5554
+ __export(snippetsWizard_exports, {
5555
+ runSnippetsWizard: () => runSnippetsWizard
5556
+ });
5557
+ import { select as select14, input as input9 } from "@inquirer/prompts";
5558
+ import pc35 from "picocolors";
5559
+ async function runSnippetsWizard(dbConfig) {
5560
+ if (dbConfig.type === "unknown") {
5561
+ console.log(
5562
+ pc35.yellow(
5563
+ "\nNo database connection found. Please setup database first."
5564
+ )
5565
+ );
5566
+ return;
5567
+ }
5568
+ const snippets = await loadSnippets();
5569
+ if (snippets.length === 0) {
5570
+ console.log(pc35.yellow("\nNo SQL snippets found in workspace."));
5571
+ return;
5572
+ }
5573
+ console.log(pc35.cyan("\n--- SQL Snippets & Operational Templates ---"));
5574
+ console.log(
5575
+ pc35.dim(
5576
+ "Run parameterized diagnostic queries and high-frequency templates.\n"
5577
+ )
5578
+ );
5579
+ const snippetChoices = snippets.map((s) => ({
5580
+ name: `${s.title} ${pc35.dim(`(${s.tags?.join(", ") || "general"})`)}`,
5581
+ value: s.id,
5582
+ description: s.description || s.sql
5583
+ }));
5584
+ const chosenId = await select14({
5585
+ message: "Select a snippet to execute:",
5586
+ choices: snippetChoices
5587
+ });
5588
+ const snippet = snippets.find((s) => s.id === chosenId);
5589
+ if (!snippet) return;
5590
+ console.log(pc35.bold(pc35.cyan(`
5591
+ Template SQL:`)));
5592
+ console.log(pc35.dim(snippet.sql));
5593
+ const params = extractSnippetParams(snippet.sql);
5594
+ const paramValues = {};
5595
+ if (params.length > 0) {
5596
+ console.log(pc35.yellow(`
5597
+ This query requires ${params.length} parameter(s):`));
5598
+ for (const param of params) {
5599
+ let defaultVal = "";
5600
+ if (param === "limit") defaultVal = "20";
5601
+ if (param === "table") defaultVal = "users";
5602
+ const val = await input9({
5603
+ message: `Enter value for :${pc35.bold(param)}:`,
5604
+ default: defaultVal
5605
+ });
5606
+ paramValues[param] = val;
5607
+ }
5608
+ }
5609
+ const finalSql = substituteSnippetParams(
5610
+ snippet.sql,
5611
+ paramValues,
5612
+ dbConfig.type
5613
+ );
5614
+ console.log(pc35.bold(pc35.cyan(`
5615
+ Executing Query:`)));
5616
+ console.log(pc35.white(finalSql));
5617
+ const adapter = createDBAdapter(dbConfig);
5618
+ try {
5619
+ const startTime = performance.now();
5620
+ const result = await adapter.query(finalSql);
5621
+ const elapsed = Math.round(performance.now() - startTime);
5622
+ console.log(
5623
+ pc35.green(
5624
+ `
5625
+ \u2714 Query executed successfully in ${elapsed}ms (${result.rows.length} row(s) returned):
5626
+ `
5627
+ )
5628
+ );
5629
+ if (result.rows.length > 0) {
5630
+ console.table(result.rows.slice(0, 50));
5631
+ if (result.rows.length > 50) {
5632
+ console.log(
5633
+ pc35.dim(`... and ${result.rows.length - 50} more row(s) hidden.`)
5634
+ );
5635
+ }
5636
+ } else {
5637
+ console.log(pc35.dim("(No rows returned)"));
5638
+ }
5639
+ } catch (e) {
5640
+ console.log(pc35.red(`
5641
+ \u2718 Query execution failed: ${e.message}`));
5642
+ } finally {
5643
+ await adapter.close();
5644
+ }
5645
+ }
5646
+ var init_snippetsWizard = __esm({
5647
+ "src/tui/wizards/snippetsWizard.ts"() {
5648
+ "use strict";
5649
+ init_logic();
5650
+ }
5651
+ });
5652
+
5653
+ // src/tui/wizards/diffWizard.ts
5654
+ var diffWizard_exports = {};
5655
+ __export(diffWizard_exports, {
5656
+ runDiffWizard: () => runDiffWizard
5657
+ });
5658
+ import { select as select15, input as input10 } from "@inquirer/prompts";
5659
+ import fs17 from "fs/promises";
5660
+ import { existsSync as existsSync3 } from "fs";
5661
+ import path17 from "path";
5662
+ import pc36 from "picocolors";
5663
+ async function runDiffWizard(dbConfig) {
5664
+ if (dbConfig.type === "unknown") {
5665
+ console.log(
5666
+ pc36.yellow(
5667
+ "\nNo database connection found. Please setup database first."
5668
+ )
5669
+ );
5670
+ return;
5671
+ }
5672
+ console.log(pc36.cyan("\n--- Schema Diff & Migration Wizard ---"));
5673
+ console.log(
5674
+ pc36.dim(
5675
+ "Compare schemas against snapshots or external databases, and generate Up/Down migration SQL.\n"
5676
+ )
5677
+ );
5678
+ const action = await select15({
5679
+ message: "Select diff action:",
5680
+ choices: [
5681
+ {
5682
+ name: "Capture Schema Snapshot (JSON)",
5683
+ value: "snapshot",
5684
+ description: "Save current database structure to a versioned JSON snapshot"
5685
+ },
5686
+ {
5687
+ name: "Compare with Snapshot File (.json)",
5688
+ value: "compare-file",
5689
+ description: "Compare current database with a saved schema snapshot file"
5690
+ },
5691
+ {
5692
+ name: "Compare with Another Database URL",
5693
+ value: "compare-url",
5694
+ description: "Compare current database directly with a remote/local database"
5695
+ }
5696
+ ]
5697
+ });
5698
+ const adapter = createDBAdapter(dbConfig);
5699
+ try {
5700
+ if (action === "snapshot") {
5701
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5702
+ const defaultFileName = `.drixio/snapshot_${timestamp}.json`;
5703
+ const outPath = await input10({
5704
+ message: "Enter output file path for snapshot:",
5705
+ default: defaultFileName
5706
+ });
5707
+ const resolvedPath = path17.resolve(process.cwd(), outPath);
5708
+ await fs17.mkdir(path17.dirname(resolvedPath), { recursive: true });
5709
+ console.log(pc36.dim("\nCapturing schema snapshot..."));
5710
+ const snapshotRes = await createSchemaSnapshot(
5711
+ adapter,
5712
+ dbConfig.type,
5713
+ path17.basename(outPath, ".json")
5714
+ );
5715
+ if (!snapshotRes.success) {
5716
+ console.log(pc36.red(`
5717
+ \u2718 Failed to create snapshot: ${snapshotRes.error}`));
5718
+ return;
5719
+ }
5720
+ await fs17.writeFile(
5721
+ resolvedPath,
5722
+ JSON.stringify(snapshotRes.data, null, 2),
5723
+ "utf-8"
5724
+ );
5725
+ console.log(
5726
+ pc36.green(
5727
+ `
5728
+ \u2714 Successfully saved snapshot with ${snapshotRes.data.tables.length} table(s) to: ${pc36.bold(resolvedPath)}`
5729
+ )
5730
+ );
5731
+ return;
5732
+ }
5733
+ let diffResult;
5734
+ if (action === "compare-file") {
5735
+ const defaultPath = existsSync3(path17.resolve(process.cwd(), ".drixio/schema.json")) ? ".drixio/schema.json" : "schema.json";
5736
+ const snapshotPath = await input10({
5737
+ message: "Enter path to snapshot JSON file:",
5738
+ default: defaultPath
5739
+ });
5740
+ const resolvedSnapshot = path17.resolve(process.cwd(), snapshotPath);
5741
+ if (!existsSync3(resolvedSnapshot)) {
5742
+ console.log(pc36.red(`
5743
+ \u2718 Snapshot file not found: ${resolvedSnapshot}`));
5744
+ return;
5745
+ }
5746
+ console.log(pc36.dim("\nComparing current database with snapshot..."));
5747
+ const content = await fs17.readFile(resolvedSnapshot, "utf-8");
5748
+ let snapshot;
5749
+ try {
5750
+ snapshot = JSON.parse(content);
5751
+ } catch {
5752
+ console.log(pc36.red(`
5753
+ \u2718 Invalid JSON content in snapshot file: ${resolvedSnapshot}`));
5754
+ return;
5755
+ }
5756
+ const res = await diffDatabaseWithSnapshot(
5757
+ adapter,
5758
+ snapshot,
5759
+ dbConfig.type,
5760
+ "Current Database",
5761
+ `Snapshot (${path17.basename(resolvedSnapshot)})`
5762
+ );
5763
+ if (!res.success) {
5764
+ console.log(pc36.red(`
5765
+ \u2718 Diff failed: ${res.error}`));
5766
+ return;
5767
+ }
5768
+ diffResult = res.data;
5769
+ } else {
5770
+ const targetUrl = await input10({
5771
+ message: "Enter target database connection URL (e.g. postgres://user:pass@host:5432/other_db):"
5772
+ });
5773
+ if (!targetUrl.trim()) {
5774
+ console.log(pc36.yellow("Target URL cannot be empty."));
5775
+ return;
5776
+ }
5777
+ console.log(pc36.dim("\nConnecting to target database and comparing..."));
5778
+ const targetConfig = await detectDatabase(targetUrl.trim());
5779
+ const targetAdapter = createDBAdapter(targetConfig);
5780
+ try {
5781
+ const res = await diffDatabases(
5782
+ adapter,
5783
+ targetAdapter,
5784
+ dbConfig.type,
5785
+ "Current Database",
5786
+ "Target Database"
5787
+ );
5788
+ if (!res.success) {
5789
+ console.log(pc36.red(`
5790
+ \u2718 Diff failed: ${res.error}`));
5791
+ return;
5792
+ }
5793
+ diffResult = res.data;
5794
+ } finally {
5795
+ await targetAdapter.close();
5796
+ }
5797
+ }
5798
+ if (!diffResult.hasChanges) {
5799
+ console.log(pc36.green("\n\u2714 No schema differences detected. Both schemas are identical!"));
5800
+ return;
5801
+ }
5802
+ console.log(pc36.bold(pc36.yellow(`
5803
+ --- Schema Differences Detected ---`)));
5804
+ console.log(` Added Tables: ${diffResult.stats.addedTablesCount}`);
5805
+ console.log(` Dropped Tables: ${diffResult.stats.droppedTablesCount}`);
5806
+ console.log(` Altered Tables: ${diffResult.stats.alteredTablesCount}`);
5807
+ console.log(` Added Columns: ${diffResult.stats.addedColumnsCount}`);
5808
+ console.log(` Dropped Columns: ${diffResult.stats.droppedColumnsCount}`);
5809
+ console.log(` Added Indexes: ${diffResult.stats.addedIndexesCount}`);
5810
+ console.log(` Dropped Indexes: ${diffResult.stats.droppedIndexesCount}`);
5811
+ const nextStep = await select15({
5812
+ message: "What would you like to inspect?",
5813
+ choices: [
5814
+ {
5815
+ name: "View Forward Migration SQL (Up)",
5816
+ value: "view-up"
5817
+ },
5818
+ {
5819
+ name: "View Rollback SQL (Down)",
5820
+ value: "view-down"
5821
+ },
5822
+ {
5823
+ name: "Save Migration SQL to File",
5824
+ value: "save-sql"
5825
+ }
5826
+ ]
5827
+ });
5828
+ if (nextStep === "view-up") {
5829
+ console.log(pc36.bold(pc36.cyan("\n--- Forward Migration SQL (Up) ---")));
5830
+ console.log(diffResult.migrationSql);
5831
+ console.log(pc36.bold(pc36.cyan("----------------------------------\n")));
5832
+ } else if (nextStep === "view-down") {
5833
+ console.log(pc36.bold(pc36.cyan("\n--- Rollback SQL (Down) ---")));
5834
+ console.log(diffResult.rollbackSql);
5835
+ console.log(pc36.bold(pc36.cyan("---------------------------\n")));
5836
+ } else if (nextStep === "save-sql") {
5837
+ const outSqlPath = await input10({
5838
+ message: "Enter destination file path:",
5839
+ default: "migration.sql"
5840
+ });
5841
+ const resolvedOut = path17.resolve(process.cwd(), outSqlPath);
5842
+ await fs17.mkdir(path17.dirname(resolvedOut), { recursive: true });
5843
+ await fs17.writeFile(resolvedOut, diffResult.migrationSql, "utf-8");
5844
+ console.log(
5845
+ pc36.green(`
5846
+ \u2714 Migration SQL successfully saved to: ${pc36.bold(resolvedOut)}`)
5847
+ );
5848
+ }
5849
+ } catch (e) {
5850
+ console.log(pc36.red(`
5851
+ \u2718 Schema diff failed: ${e.message}`));
5852
+ } finally {
5853
+ await adapter.close();
5854
+ }
5855
+ }
5856
+ var init_diffWizard = __esm({
5857
+ "src/tui/wizards/diffWizard.ts"() {
5858
+ "use strict";
5859
+ init_logic();
5860
+ }
5861
+ });
5862
+
5182
5863
  // src/studio/api.ts
5183
5864
  import { Hono } from "hono";
5184
5865
  import { spawn } from "child_process";
5185
- import path15 from "path";
5186
- import fs15 from "fs";
5866
+ import path18 from "path";
5867
+ import fs18 from "fs";
5187
5868
  function nodeToWebStream(nodeStream) {
5188
5869
  return new ReadableStream({
5189
5870
  start(controller) {
@@ -5279,15 +5960,37 @@ function registerApiRoutes(app, dbConfig) {
5279
5960
  return c.json({ success: false, error: e.message }, 500);
5280
5961
  }
5281
5962
  });
5963
+ const detectHostEnvironment = (cfg) => {
5964
+ if (cfg.type === "sqlite") {
5965
+ return { isRemote: false, host: "local", badgeLabel: "LOCAL (SQLite)" };
5966
+ }
5967
+ if (cfg.type === "mysql" || cfg.type === "postgres") {
5968
+ let host = "localhost";
5969
+ const match = cfg.targetUrl.match(/@([^:/@?]+)/);
5970
+ if (match) host = match[1];
5971
+ const isLocal = host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0" || host === "host.docker.internal";
5972
+ return {
5973
+ isRemote: !isLocal,
5974
+ host,
5975
+ badgeLabel: isLocal ? `LOCAL (${cfg.type.toUpperCase()})` : `REMOTE (${host})`
5976
+ };
5977
+ }
5978
+ return { isRemote: false, host: "", badgeLabel: "DISCONNECTED" };
5979
+ };
5282
5980
  api.get("/config", (c) => {
5283
5981
  const isConnected = !!currentAdapter && currentDbConfig.type !== "unknown";
5982
+ const envInfo = detectHostEnvironment(currentDbConfig);
5284
5983
  return c.json({
5285
5984
  success: true,
5286
5985
  data: {
5986
+ appVersion: getDrixioVersion(),
5287
5987
  connected: isConnected,
5288
5988
  dbType: isConnected ? currentDbConfig.type : "none",
5289
5989
  dbName: isConnected ? getDbName() : "No Database",
5290
- targetUrl: currentDbConfig.targetUrl || ""
5990
+ targetUrl: currentDbConfig.targetUrl || "",
5991
+ isRemote: envInfo.isRemote,
5992
+ host: envInfo.host,
5993
+ badgeLabel: isConnected ? envInfo.badgeLabel : "DISCONNECTED"
5291
5994
  }
5292
5995
  });
5293
5996
  });
@@ -5694,6 +6397,54 @@ function registerApiRoutes(app, dbConfig) {
5694
6397
  return c.json({ success: false, error: e.message }, 500);
5695
6398
  }
5696
6399
  });
6400
+ api.post("/query/explain", async (c) => {
6401
+ try {
6402
+ const { sql } = await c.req.json().catch(() => ({}));
6403
+ if (!sql || typeof sql !== "string") {
6404
+ return c.json(
6405
+ { success: false, error: "SQL query is required for explain" },
6406
+ 400
6407
+ );
6408
+ }
6409
+ const adapter = getAdapter();
6410
+ const cleanSql = sql.trim().replace(/;+$/, "");
6411
+ let explainSql = "";
6412
+ if (currentDbConfig.type === "sqlite") {
6413
+ explainSql = `EXPLAIN QUERY PLAN ${cleanSql}`;
6414
+ } else if (currentDbConfig.type === "postgres") {
6415
+ explainSql = `EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS) ${cleanSql}`;
6416
+ } else if (currentDbConfig.type === "mysql") {
6417
+ explainSql = `EXPLAIN ${cleanSql}`;
6418
+ } else {
6419
+ explainSql = `EXPLAIN ${cleanSql}`;
6420
+ }
6421
+ const startTime = performance.now();
6422
+ let res;
6423
+ try {
6424
+ res = await adapter.query(explainSql);
6425
+ } catch (primaryErr) {
6426
+ if (currentDbConfig.type === "postgres") {
6427
+ explainSql = `EXPLAIN ${cleanSql}`;
6428
+ res = await adapter.query(explainSql);
6429
+ } else {
6430
+ throw primaryErr;
6431
+ }
6432
+ }
6433
+ const durationMs = Math.round(performance.now() - startTime);
6434
+ return c.json({
6435
+ success: true,
6436
+ data: {
6437
+ columns: res.columns,
6438
+ rows: res.rows,
6439
+ durationMs,
6440
+ explainSql,
6441
+ dialect: currentDbConfig.type
6442
+ }
6443
+ });
6444
+ } catch (e) {
6445
+ return c.json({ success: false, error: e.message }, 500);
6446
+ }
6447
+ });
5697
6448
  api.post("/query/export", async (c) => {
5698
6449
  try {
5699
6450
  const body = await c.req.json();
@@ -6284,10 +7035,10 @@ function registerApiRoutes(app, dbConfig) {
6284
7035
  if (dialect === "sqlite") {
6285
7036
  const rawPath = body.url || body.sqlitePath || dbName || "drixio.sqlite";
6286
7037
  const cleanPath = rawPath.replace(/^file:/, "").trim();
6287
- const fullPath = path15.isAbsolute(cleanPath) ? cleanPath : path15.resolve(process.cwd(), cleanPath);
7038
+ const fullPath = path18.isAbsolute(cleanPath) ? cleanPath : path18.resolve(process.cwd(), cleanPath);
6288
7039
  if (mode === "create") {
6289
- const dir = path15.dirname(fullPath);
6290
- if (!fs15.existsSync(dir)) {
7040
+ const dir = path18.dirname(fullPath);
7041
+ if (!fs18.existsSync(dir)) {
6291
7042
  return c.json(
6292
7043
  {
6293
7044
  success: false,
@@ -6296,18 +7047,18 @@ function registerApiRoutes(app, dbConfig) {
6296
7047
  400
6297
7048
  );
6298
7049
  }
6299
- const exists = fs15.existsSync(fullPath);
7050
+ const exists = fs18.existsSync(fullPath);
6300
7051
  const latencyMs2 = Date.now() - startTime;
6301
7052
  return c.json({
6302
7053
  success: true,
6303
7054
  data: {
6304
7055
  latencyMs: latencyMs2,
6305
- message: exists ? `File already exists at "${path15.basename(fullPath)}". Will connect and reuse.` : `Target path is valid. File will be created on connect.`,
7056
+ message: exists ? `File already exists at "${path18.basename(fullPath)}". Will connect and reuse.` : `Target path is valid. File will be created on connect.`,
6306
7057
  fullPath
6307
7058
  }
6308
7059
  });
6309
7060
  } else {
6310
- if (!fs15.existsSync(fullPath)) {
7061
+ if (!fs18.existsSync(fullPath)) {
6311
7062
  return c.json(
6312
7063
  {
6313
7064
  success: false,
@@ -6316,7 +7067,7 @@ function registerApiRoutes(app, dbConfig) {
6316
7067
  400
6317
7068
  );
6318
7069
  }
6319
- const stats = fs15.statSync(fullPath);
7070
+ const stats = fs18.statSync(fullPath);
6320
7071
  if (stats.isDirectory()) {
6321
7072
  return c.json(
6322
7073
  {
@@ -6435,27 +7186,27 @@ import { serve } from "@hono/node-server";
6435
7186
  import { Hono as Hono2 } from "hono";
6436
7187
  import { serveStatic } from "@hono/node-server/serve-static";
6437
7188
  import open from "open";
6438
- import path16 from "path";
6439
- import pc35 from "picocolors";
6440
- import { fileURLToPath } from "url";
7189
+ import path19 from "path";
7190
+ import pc38 from "picocolors";
7191
+ import { fileURLToPath as fileURLToPath2 } from "url";
6441
7192
  async function runStudio(dbConfig) {
6442
7193
  const app = new Hono2();
6443
7194
  registerApiRoutes(app, dbConfig);
6444
7195
  const isDev = __dirname.includes("src") || __dirname.includes("studio");
6445
- const studioDistPath = isDev ? path16.resolve(__dirname, "../../dist/studio") : path16.resolve(__dirname, "./studio");
6446
- const fs16 = await import("fs/promises");
7196
+ const studioDistPath = isDev ? path19.resolve(__dirname, "../../dist/studio") : path19.resolve(__dirname, "./studio");
7197
+ const fs19 = await import("fs/promises");
6447
7198
  app.use("/*", async (c, next) => {
6448
7199
  c.header("Cache-Control", "no-cache, no-store, must-revalidate");
6449
7200
  await next();
6450
7201
  });
6451
7202
  app.use(
6452
7203
  "/*",
6453
- serveStatic({ root: path16.relative(process.cwd(), studioDistPath) })
7204
+ serveStatic({ root: path19.relative(process.cwd(), studioDistPath) })
6454
7205
  );
6455
7206
  app.get("*", async (c) => {
6456
- const indexPath = path16.join(studioDistPath, "index.html");
7207
+ const indexPath = path19.join(studioDistPath, "index.html");
6457
7208
  try {
6458
- const html = await fs16.readFile(indexPath, "utf-8");
7209
+ const html = await fs19.readFile(indexPath, "utf-8");
6459
7210
  return c.html(html);
6460
7211
  } catch (e) {
6461
7212
  return c.text(
@@ -6467,23 +7218,23 @@ async function runStudio(dbConfig) {
6467
7218
  const defaultPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 51213;
6468
7219
  const port = await getAvailablePort(defaultPort);
6469
7220
  console.log(
6470
- pc35.cyan(`
7221
+ pc38.cyan(`
6471
7222
  Starting Drixio Studio on http://localhost:${port}...`)
6472
7223
  );
6473
7224
  if (dbConfig.type === "unknown") {
6474
7225
  console.log(
6475
- pc35.yellow(
7226
+ pc38.yellow(
6476
7227
  `\u26A0\uFE0F No database detected. Studio started in standalone mode.`
6477
7228
  )
6478
7229
  );
6479
7230
  console.log(
6480
- pc35.dim(
7231
+ pc38.dim(
6481
7232
  `You can create or connect to a database in the SQL Console.
6482
7233
  `
6483
7234
  )
6484
7235
  );
6485
7236
  }
6486
- console.log(pc35.dim(`Press Ctrl+C to stop the server.
7237
+ console.log(pc38.dim(`Press Ctrl+C to stop the server.
6487
7238
  `));
6488
7239
  serve({
6489
7240
  fetch: app.fetch,
@@ -6512,14 +7263,14 @@ var init_studio = __esm({
6512
7263
  "src/studio/index.ts"() {
6513
7264
  "use strict";
6514
7265
  init_api();
6515
- __filename = fileURLToPath(import.meta.url);
6516
- __dirname = path16.dirname(__filename);
7266
+ __filename = fileURLToPath2(import.meta.url);
7267
+ __dirname = path19.dirname(__filename);
6517
7268
  }
6518
7269
  });
6519
7270
 
6520
7271
  // bin/cli.ts
6521
7272
  init_logic();
6522
- import pc36 from "picocolors";
7273
+ import pc39 from "picocolors";
6523
7274
  import { parseArgs } from "util";
6524
7275
 
6525
7276
  // src/commands/query.ts
@@ -6603,8 +7354,8 @@ async function runQueryCommand(dbConfig, args) {
6603
7354
  const adapter = createDBAdapter(dbConfig);
6604
7355
  let sql = args[0];
6605
7356
  if (!sql) {
6606
- const { input: input8 } = await import("@inquirer/prompts");
6607
- sql = await input8({
7357
+ const { input: input11 } = await import("@inquirer/prompts");
7358
+ sql = await input11({
6608
7359
  message: "Enter your SQL query:"
6609
7360
  });
6610
7361
  }
@@ -6637,8 +7388,8 @@ Query Error: ${e.message}
6637
7388
  // src/commands/export.ts
6638
7389
  init_logic();
6639
7390
  import pc3 from "picocolors";
6640
- import fs5 from "fs/promises";
6641
- import path5 from "path";
7391
+ import fs6 from "fs/promises";
7392
+ import path6 from "path";
6642
7393
  async function runExportCommand(dbConfig, args, options) {
6643
7394
  if (dbConfig.type === "unknown") {
6644
7395
  console.log(
@@ -6650,7 +7401,7 @@ async function runExportCommand(dbConfig, args, options) {
6650
7401
  let tableName = args[0];
6651
7402
  let format = options.format?.toLowerCase();
6652
7403
  const schemaOnly = options["schema-only"];
6653
- const { select: select13 } = await import("@inquirer/prompts");
7404
+ const { select: select16 } = await import("@inquirer/prompts");
6654
7405
  if (!tableName) {
6655
7406
  const allTables = await adapter.getTables();
6656
7407
  if (allTables.length === 0) {
@@ -6661,13 +7412,13 @@ async function runExportCommand(dbConfig, args, options) {
6661
7412
  { name: "All Tables (*)", value: "*" },
6662
7413
  ...allTables.map((t) => ({ name: t, value: t }))
6663
7414
  ];
6664
- tableName = await select13({
7415
+ tableName = await select16({
6665
7416
  message: "Which table do you want to export?",
6666
7417
  choices: tableChoices
6667
7418
  });
6668
7419
  }
6669
7420
  if (!format || !["csv", "json"].includes(format)) {
6670
- format = await select13({
7421
+ format = await select16({
6671
7422
  message: "Which format do you want to export?",
6672
7423
  choices: [
6673
7424
  { name: "CSV", value: "csv" },
@@ -6675,8 +7426,8 @@ async function runExportCommand(dbConfig, args, options) {
6675
7426
  ]
6676
7427
  });
6677
7428
  }
6678
- const exportDir = path5.join(process.cwd(), "drixio_exports");
6679
- await fs5.mkdir(exportDir, { recursive: true });
7429
+ const exportDir = path6.join(process.cwd(), "drixio_exports");
7430
+ await fs6.mkdir(exportDir, { recursive: true });
6680
7431
  const tablesToExport = tableName === "*" ? await adapter.getTables() : [tableName];
6681
7432
  console.log(pc3.cyan(`
6682
7433
  Starting export to ${exportDir}...`));
@@ -6695,8 +7446,8 @@ Starting export to ${exportDir}...`));
6695
7446
  const content = exportRes.data;
6696
7447
  const suffix = schemaOnly ? "_schema" : "_data";
6697
7448
  const ext = format === "json" ? ".json" : ".csv";
6698
- const fp = path5.join(exportDir, `${table}${suffix}${ext}`);
6699
- await fs5.writeFile(fp, content, "utf-8");
7449
+ const fp = path6.join(exportDir, `${table}${suffix}${ext}`);
7450
+ await fs6.writeFile(fp, content, "utf-8");
6700
7451
  const typeLabel = schemaOnly ? "Schema" : "Data";
6701
7452
  console.log(
6702
7453
  pc3.green(
@@ -6715,8 +7466,8 @@ Starting export to ${exportDir}...`));
6715
7466
  // src/commands/import.ts
6716
7467
  init_logic();
6717
7468
  import pc4 from "picocolors";
6718
- import fs6 from "fs/promises";
6719
- import path6 from "path";
7469
+ import fs7 from "fs/promises";
7470
+ import path7 from "path";
6720
7471
  async function runImportCommand(dbConfig, args, options) {
6721
7472
  if (dbConfig.type === "unknown") {
6722
7473
  console.log(
@@ -6727,15 +7478,15 @@ async function runImportCommand(dbConfig, args, options) {
6727
7478
  const adapter = createDBAdapter(dbConfig);
6728
7479
  let filePath = args[0];
6729
7480
  let tableName = options.table;
6730
- const { input: input8, select: select13 } = await import("@inquirer/prompts");
7481
+ const { input: input11, select: select16 } = await import("@inquirer/prompts");
6731
7482
  if (!filePath) {
6732
- filePath = await input8({
7483
+ filePath = await input11({
6733
7484
  message: "Enter the path to your CSV or JSON file:"
6734
7485
  });
6735
7486
  }
6736
- const resolvedPath = path6.resolve(process.cwd(), filePath);
7487
+ const resolvedPath = path7.resolve(process.cwd(), filePath);
6737
7488
  try {
6738
- await fs6.access(resolvedPath);
7489
+ await fs7.access(resolvedPath);
6739
7490
  } catch {
6740
7491
  console.log(pc4.red(`Error: File not found at ${resolvedPath}`));
6741
7492
  process.exit(1);
@@ -6748,14 +7499,14 @@ async function runImportCommand(dbConfig, args, options) {
6748
7499
  );
6749
7500
  process.exit(1);
6750
7501
  }
6751
- tableName = await select13({
7502
+ tableName = await select16({
6752
7503
  message: "Which table do you want to import data into?",
6753
7504
  choices: allTables.map((t) => ({ name: t, value: t }))
6754
7505
  });
6755
7506
  }
6756
7507
  console.log(pc4.cyan(`
6757
7508
  Reading file...`));
6758
- const fileContent = await fs6.readFile(resolvedPath, "utf-8");
7509
+ const fileContent = await fs7.readFile(resolvedPath, "utf-8");
6759
7510
  const isJson = filePath.toLowerCase().endsWith(".json");
6760
7511
  const isCsv = filePath.toLowerCase().endsWith(".csv");
6761
7512
  if (!isJson && !isCsv) {
@@ -6808,7 +7559,7 @@ async function runSeedCommand(dbConfig, args) {
6808
7559
  const adapter = createDBAdapter(dbConfig);
6809
7560
  let tableName = args[0];
6810
7561
  let countStr = args[1];
6811
- const { input: input8, select: select13 } = await import("@inquirer/prompts");
7562
+ const { input: input11, select: select16 } = await import("@inquirer/prompts");
6812
7563
  if (!tableName) {
6813
7564
  const allTables = await adapter.getTables();
6814
7565
  if (allTables.length === 0) {
@@ -6817,14 +7568,14 @@ async function runSeedCommand(dbConfig, args) {
6817
7568
  );
6818
7569
  process.exit(1);
6819
7570
  }
6820
- tableName = await select13({
7571
+ tableName = await select16({
6821
7572
  message: "Which table do you want to seed with realistic fake data?",
6822
7573
  choices: allTables.map((t) => ({ name: t, value: t }))
6823
7574
  });
6824
7575
  }
6825
7576
  let count = parseInt(countStr);
6826
7577
  if (isNaN(count) || count <= 0) {
6827
- const res = await input8({
7578
+ const res = await input11({
6828
7579
  message: "How many rows to generate?",
6829
7580
  default: "50"
6830
7581
  });
@@ -6883,19 +7634,19 @@ async function runTruncateCommand(dbConfig, args) {
6883
7634
  }
6884
7635
  const adapter = createDBAdapter(dbConfig);
6885
7636
  let tableName = args[0];
6886
- const { select: select13, confirm: confirm6 } = await import("@inquirer/prompts");
7637
+ const { select: select16, confirm: confirm8 } = await import("@inquirer/prompts");
6887
7638
  if (!tableName) {
6888
7639
  const allTables = await adapter.getTables();
6889
7640
  if (allTables.length === 0) {
6890
7641
  console.log(pc6.yellow("No tables found in the database."));
6891
7642
  process.exit(0);
6892
7643
  }
6893
- tableName = await select13({
7644
+ tableName = await select16({
6894
7645
  message: "Which table do you want to truncate (empty all data)?",
6895
7646
  choices: allTables.map((t) => ({ name: t, value: t }))
6896
7647
  });
6897
7648
  }
6898
- const sure = await confirm6({
7649
+ const sure = await confirm8({
6899
7650
  message: `Are you sure you want to TRUNCATE '${tableName}'? This will delete all rows and cannot be undone!`,
6900
7651
  default: false
6901
7652
  });
@@ -6921,8 +7672,8 @@ async function runTruncateCommand(dbConfig, args) {
6921
7672
  // src/commands/exec.ts
6922
7673
  init_logic();
6923
7674
  import pc7 from "picocolors";
6924
- import fs7 from "fs/promises";
6925
- import path7 from "path";
7675
+ import fs8 from "fs/promises";
7676
+ import path8 from "path";
6926
7677
  async function runExecCommand(dbConfig, args) {
6927
7678
  if (dbConfig.type === "unknown") {
6928
7679
  console.log(
@@ -6931,18 +7682,18 @@ async function runExecCommand(dbConfig, args) {
6931
7682
  process.exit(1);
6932
7683
  }
6933
7684
  let filePath = args[0];
6934
- const { input: input8 } = await import("@inquirer/prompts");
7685
+ const { input: input11 } = await import("@inquirer/prompts");
6935
7686
  if (!filePath) {
6936
- filePath = await input8({ message: "Enter the path to your .sql file:" });
7687
+ filePath = await input11({ message: "Enter the path to your .sql file:" });
6937
7688
  }
6938
- const resolvedPath = path7.resolve(process.cwd(), filePath);
7689
+ const resolvedPath = path8.resolve(process.cwd(), filePath);
6939
7690
  try {
6940
- await fs7.access(resolvedPath);
7691
+ await fs8.access(resolvedPath);
6941
7692
  } catch {
6942
7693
  console.log(pc7.red(`Error: File not found at ${resolvedPath}`));
6943
7694
  process.exit(1);
6944
7695
  }
6945
- const sqlContent = await fs7.readFile(resolvedPath, "utf-8");
7696
+ const sqlContent = await fs8.readFile(resolvedPath, "utf-8");
6946
7697
  if (!sqlContent.trim()) {
6947
7698
  console.log(pc7.yellow("File is empty."));
6948
7699
  process.exit(0);
@@ -7021,8 +7772,8 @@ Backup Error: ${e.message}
7021
7772
  // src/commands/restore.ts
7022
7773
  init_logic();
7023
7774
  import pc9 from "picocolors";
7024
- import fs8 from "fs/promises";
7025
- import path8 from "path";
7775
+ import fs9 from "fs/promises";
7776
+ import path9 from "path";
7026
7777
  async function runRestoreCommand(dbConfig, args, options = {}) {
7027
7778
  if (dbConfig.type === "unknown") {
7028
7779
  console.log(
@@ -7031,10 +7782,10 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
7031
7782
  process.exit(1);
7032
7783
  }
7033
7784
  let targetPath = args[0];
7034
- const { input: input8, select: select13, confirm: confirm6 } = await import("@inquirer/prompts");
7785
+ const { input: input11, select: select16, confirm: confirm8 } = await import("@inquirer/prompts");
7035
7786
  if (!targetPath) {
7036
7787
  try {
7037
- const entries = await fs8.readdir(process.cwd(), {
7788
+ const entries = await fs9.readdir(process.cwd(), {
7038
7789
  withFileTypes: true
7039
7790
  });
7040
7791
  const candidates = [];
@@ -7056,24 +7807,24 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
7056
7807
  name: "\u270F\uFE0F Enter a custom path manually...",
7057
7808
  value: "__custom__"
7058
7809
  });
7059
- const choice = await select13({
7810
+ const choice = await select16({
7060
7811
  message: "Select a backup directory or file to restore:",
7061
7812
  choices: candidates
7062
7813
  });
7063
7814
  if (choice === "__custom__") {
7064
- targetPath = await input8({
7815
+ targetPath = await input11({
7065
7816
  message: "Enter path to backup directory, .sql, or .json file:"
7066
7817
  });
7067
7818
  } else {
7068
7819
  targetPath = choice;
7069
7820
  }
7070
7821
  } else {
7071
- targetPath = await input8({
7822
+ targetPath = await input11({
7072
7823
  message: "Enter path to backup directory, .sql, or .json file:"
7073
7824
  });
7074
7825
  }
7075
7826
  } catch {
7076
- targetPath = await input8({
7827
+ targetPath = await input11({
7077
7828
  message: "Enter path to backup directory, .sql, or .json file:"
7078
7829
  });
7079
7830
  }
@@ -7082,9 +7833,9 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
7082
7833
  console.log(pc9.yellow("No restore source specified. Aborting."));
7083
7834
  process.exit(0);
7084
7835
  }
7085
- const resolvedPath = path8.resolve(process.cwd(), targetPath.trim());
7836
+ const resolvedPath = path9.resolve(process.cwd(), targetPath.trim());
7086
7837
  try {
7087
- await fs8.access(resolvedPath);
7838
+ await fs9.access(resolvedPath);
7088
7839
  } catch {
7089
7840
  console.log(pc9.red(`Error: Backup path not found: ${resolvedPath}`));
7090
7841
  process.exit(1);
@@ -7100,7 +7851,7 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
7100
7851
  console.log(pc9.dim(`Database: ${dbConfig.type} (${dbConfig.targetUrl})`));
7101
7852
  console.log(pc9.dim(`Source: ${resolvedPath}
7102
7853
  `));
7103
- const proceed = await confirm6({
7854
+ const proceed = await confirm8({
7104
7855
  message: "Are you sure you want to proceed with the database restore?",
7105
7856
  default: false
7106
7857
  });
@@ -7147,8 +7898,8 @@ Starting database restore from: ${resolvedPath}...`));
7147
7898
  // src/commands/diagram.ts
7148
7899
  init_logic();
7149
7900
  import pc10 from "picocolors";
7150
- import fs9 from "fs/promises";
7151
- import path9 from "path";
7901
+ import fs10 from "fs/promises";
7902
+ import path10 from "path";
7152
7903
  async function runDiagramCommand(dbConfig) {
7153
7904
  if (dbConfig.type === "unknown") {
7154
7905
  console.log(
@@ -7186,8 +7937,8 @@ You can paste this Mermaid code directly into [Draw.io](https://app.diagrams.net
7186
7937
  ${mermaidCode}
7187
7938
  \`\`\`
7188
7939
  `;
7189
- const outPath = path9.resolve(process.cwd(), "drixio_schema.md");
7190
- await fs9.writeFile(outPath, markdownOutput.trim(), "utf-8");
7940
+ const outPath = path10.resolve(process.cwd(), "drixio_schema.md");
7941
+ await fs10.writeFile(outPath, markdownOutput.trim(), "utf-8");
7191
7942
  console.log(pc10.green(`
7192
7943
  \u2714 Diagram generated successfully!`));
7193
7944
  console.log(pc10.white(`Output saved to: ${pc10.bold(outPath)}`));
@@ -7208,8 +7959,8 @@ ${mermaidCode}
7208
7959
  // src/commands/generateTypes.ts
7209
7960
  init_logic();
7210
7961
  import pc11 from "picocolors";
7211
- import fs10 from "fs/promises";
7212
- import path10 from "path";
7962
+ import fs11 from "fs/promises";
7963
+ import path11 from "path";
7213
7964
  async function runGenerateTypesCommand(dbConfig) {
7214
7965
  if (dbConfig.type === "unknown") {
7215
7966
  console.log(
@@ -7233,8 +7984,8 @@ Scanning database to generate TypeScript interfaces...`)
7233
7984
  process.exit(0);
7234
7985
  }
7235
7986
  const tsCode = generateTypeScriptDefinitions(tableInfos, dbConfig.type);
7236
- const outPath = path10.resolve(process.cwd(), "drixio-types.d.ts");
7237
- await fs10.writeFile(outPath, tsCode, "utf-8");
7987
+ const outPath = path11.resolve(process.cwd(), "drixio-types.d.ts");
7988
+ await fs11.writeFile(outPath, tsCode, "utf-8");
7238
7989
  console.log(pc11.green(`\u2714 TypeScript interfaces generated successfully!`));
7239
7990
  console.log(pc11.white(`Output saved to: ${pc11.bold(outPath)}`));
7240
7991
  } catch (e) {
@@ -7249,8 +8000,8 @@ Scanning database to generate TypeScript interfaces...`)
7249
8000
  // src/commands/generateOrm.ts
7250
8001
  init_logic();
7251
8002
  import pc12 from "picocolors";
7252
- import fs11 from "fs/promises";
7253
- import path11 from "path";
8003
+ import fs12 from "fs/promises";
8004
+ import path12 from "path";
7254
8005
  async function runGenerateOrmCommand(dbConfig, options = {}) {
7255
8006
  if (dbConfig.type === "unknown") {
7256
8007
  console.log(
@@ -7306,11 +8057,11 @@ Scanning database to generate ${target === "prisma" ? "Prisma" : "Drizzle"} sche
7306
8057
  if (options.print) {
7307
8058
  console.log("\n" + generatedCode);
7308
8059
  } else {
7309
- const outPath = path11.resolve(
8060
+ const outPath = path12.resolve(
7310
8061
  process.cwd(),
7311
8062
  options.out || defaultFileName
7312
8063
  );
7313
- await fs11.writeFile(outPath, generatedCode, "utf-8");
8064
+ await fs12.writeFile(outPath, generatedCode, "utf-8");
7314
8065
  console.log(
7315
8066
  pc12.green(
7316
8067
  `\u2714 ${target === "prisma" ? "Prisma" : "Drizzle"} schema generated successfully!`
@@ -7331,10 +8082,10 @@ Scanning database to generate ${target === "prisma" ? "Prisma" : "Drizzle"} sche
7331
8082
  init_logic();
7332
8083
  import pc13 from "picocolors";
7333
8084
  async function runInitCommand(args) {
7334
- const { select: select13, input: input8, password } = await import("@inquirer/prompts");
8085
+ const { select: select16, input: input11, password } = await import("@inquirer/prompts");
7335
8086
  let dialect = args[0];
7336
8087
  if (!dialect || !["sqlite", "mysql", "postgres"].includes(dialect.toLowerCase())) {
7337
- dialect = await select13({
8088
+ dialect = await select16({
7338
8089
  message: "Which database do you want to initialize locally?",
7339
8090
  choices: [
7340
8091
  { name: "SQLite (Local File)", value: "sqlite" },
@@ -7380,15 +8131,15 @@ Initializing a local ${dialect} database...`));
7380
8131
  "Please provide credentials for your local server (e.g. running via XAMPP, Homebrew, etc.)"
7381
8132
  )
7382
8133
  );
7383
- const host = await input8({
8134
+ const host = await input11({
7384
8135
  message: "Server Host:",
7385
8136
  default: "localhost"
7386
8137
  });
7387
- const port = await input8({
8138
+ const port = await input11({
7388
8139
  message: "Server Port:",
7389
8140
  default: dialect === "mysql" ? "3306" : "5432"
7390
8141
  });
7391
- const user = await input8({
8142
+ const user = await input11({
7392
8143
  message: "Username:",
7393
8144
  default: dialect === "mysql" ? "root" : "postgres"
7394
8145
  });
@@ -7397,7 +8148,7 @@ Initializing a local ${dialect} database...`));
7397
8148
  });
7398
8149
  let dbName = args[1];
7399
8150
  if (!dbName) {
7400
- dbName = await input8({
8151
+ dbName = await input11({
7401
8152
  message: "New Database Name (e.g. my_project):"
7402
8153
  });
7403
8154
  }
@@ -7489,10 +8240,10 @@ Could not connect to the local ${dialect} server on ${host}:${port}.`
7489
8240
  init_logic();
7490
8241
  import pc14 from "picocolors";
7491
8242
  async function runDropDbCommand(args) {
7492
- const { select: select13, input: input8, password, confirm: confirm6 } = await import("@inquirer/prompts");
8243
+ const { select: select16, input: input11, password, confirm: confirm8 } = await import("@inquirer/prompts");
7493
8244
  let dialect = args[0];
7494
8245
  if (!dialect || !["sqlite", "mysql", "postgres"].includes(dialect.toLowerCase())) {
7495
- dialect = await select13({
8246
+ dialect = await select16({
7496
8247
  message: "Which database type do you want to drop?",
7497
8248
  choices: [
7498
8249
  { name: "SQLite (Local File)", value: "sqlite" },
@@ -7505,12 +8256,12 @@ async function runDropDbCommand(args) {
7505
8256
  let dbName = args[1];
7506
8257
  if (dialect === "sqlite") {
7507
8258
  if (!dbName) {
7508
- dbName = await input8({
8259
+ dbName = await input11({
7509
8260
  message: "Enter the SQLite filename to delete (e.g. database.sqlite):",
7510
8261
  default: "database.sqlite"
7511
8262
  });
7512
8263
  }
7513
- const sure = await confirm6({
8264
+ const sure = await confirm8({
7514
8265
  message: `Are you absolutely sure you want to delete ${dbName}? This cannot be undone!`,
7515
8266
  default: false
7516
8267
  });
@@ -7535,15 +8286,15 @@ async function runDropDbCommand(args) {
7535
8286
  `Please provide credentials for your local ${dialect} server to drop a database.`
7536
8287
  )
7537
8288
  );
7538
- const host = await input8({
8289
+ const host = await input11({
7539
8290
  message: "Server Host:",
7540
8291
  default: "localhost"
7541
8292
  });
7542
- const port = await input8({
8293
+ const port = await input11({
7543
8294
  message: "Server Port:",
7544
8295
  default: dialect === "mysql" ? "3306" : "5432"
7545
8296
  });
7546
- const user = await input8({
8297
+ const user = await input11({
7547
8298
  message: "Username:",
7548
8299
  default: dialect === "mysql" ? "root" : "postgres"
7549
8300
  });
@@ -7551,11 +8302,11 @@ async function runDropDbCommand(args) {
7551
8302
  message: "Password (leave empty if none):"
7552
8303
  });
7553
8304
  if (!dbName) {
7554
- dbName = await input8({
8305
+ dbName = await input11({
7555
8306
  message: "Which Database Name do you want to DROP?"
7556
8307
  });
7557
8308
  }
7558
- const sure = await confirm6({
8309
+ const sure = await confirm8({
7559
8310
  message: `Are you absolutely sure you want to DROP DATABASE '${dbName}' from ${host}? All data will be lost!`,
7560
8311
  default: false
7561
8312
  });
@@ -7676,8 +8427,8 @@ async function runDescribeCommand(dbConfig, args, options = {}) {
7676
8427
  if (tables.length === 1) {
7677
8428
  tableName = tables[0];
7678
8429
  } else {
7679
- const { select: select13 } = await import("@inquirer/prompts");
7680
- tableName = await select13({
8430
+ const { select: select16 } = await import("@inquirer/prompts");
8431
+ tableName = await select16({
7681
8432
  message: "Select a table to describe:",
7682
8433
  choices: tables.map((t) => ({ name: t, value: t }))
7683
8434
  });
@@ -7766,9 +8517,9 @@ Failed to describe table: ${e.message}
7766
8517
  // src/commands/diff.ts
7767
8518
  init_logic();
7768
8519
  import pc17 from "picocolors";
7769
- import fs12 from "fs/promises";
8520
+ import fs13 from "fs/promises";
7770
8521
  import { existsSync as existsSync2 } from "fs";
7771
- import path12 from "path";
8522
+ import path13 from "path";
7772
8523
  async function runDiffCommand(dbConfig, args, options = {}) {
7773
8524
  if (dbConfig.type === "unknown") {
7774
8525
  console.log(
@@ -7789,7 +8540,7 @@ Capturing schema snapshot for ${dbConfig.type.toUpperCase()} database...`
7789
8540
  const snapshotRes = await createSchemaSnapshot(
7790
8541
  adapter,
7791
8542
  dbConfig.type,
7792
- path12.basename(outPath, ".json")
8543
+ path13.basename(outPath, ".json")
7793
8544
  );
7794
8545
  if (!snapshotRes.success) {
7795
8546
  console.log(
@@ -7797,9 +8548,9 @@ Capturing schema snapshot for ${dbConfig.type.toUpperCase()} database...`
7797
8548
  );
7798
8549
  process.exit(1);
7799
8550
  }
7800
- const resolvedPath = path12.resolve(process.cwd(), outPath);
7801
- await fs12.mkdir(path12.dirname(resolvedPath), { recursive: true });
7802
- await fs12.writeFile(
8551
+ const resolvedPath = path13.resolve(process.cwd(), outPath);
8552
+ await fs13.mkdir(path13.dirname(resolvedPath), { recursive: true });
8553
+ await fs13.writeFile(
7803
8554
  resolvedPath,
7804
8555
  JSON.stringify(snapshotRes.data, null, 2),
7805
8556
  "utf-8"
@@ -7816,9 +8567,9 @@ Capturing schema snapshot for ${dbConfig.type.toUpperCase()} database...`
7816
8567
  }
7817
8568
  let targetArg = args[0];
7818
8569
  if (!targetArg) {
7819
- if (existsSync2(path12.resolve(process.cwd(), "schema.json"))) {
8570
+ if (existsSync2(path13.resolve(process.cwd(), "schema.json"))) {
7820
8571
  targetArg = "schema.json";
7821
- } else if (existsSync2(path12.resolve(process.cwd(), ".drixio/schema.json"))) {
8572
+ } else if (existsSync2(path13.resolve(process.cwd(), ".drixio/schema.json"))) {
7822
8573
  targetArg = ".drixio/schema.json";
7823
8574
  } else {
7824
8575
  console.log(
@@ -7873,7 +8624,7 @@ Connecting to target database and computing schema diff...`
7873
8624
  });
7874
8625
  }
7875
8626
  } else {
7876
- const filePath = path12.resolve(process.cwd(), targetArg);
8627
+ const filePath = path13.resolve(process.cwd(), targetArg);
7877
8628
  if (!existsSync2(filePath)) {
7878
8629
  console.log(
7879
8630
  pc17.red(`\u2718 Target snapshot file not found: ${targetArg}`)
@@ -7886,7 +8637,7 @@ Connecting to target database and computing schema diff...`
7886
8637
  Comparing current database with snapshot: ${targetArg}...`
7887
8638
  )
7888
8639
  );
7889
- const content = await fs12.readFile(filePath, "utf-8");
8640
+ const content = await fs13.readFile(filePath, "utf-8");
7890
8641
  let snapshot;
7891
8642
  try {
7892
8643
  snapshot = JSON.parse(content);
@@ -7901,7 +8652,7 @@ Comparing current database with snapshot: ${targetArg}...`
7901
8652
  snapshot,
7902
8653
  dbConfig.type,
7903
8654
  "Current Database",
7904
- `Snapshot (${path12.basename(targetArg)})`
8655
+ `Snapshot (${path13.basename(targetArg)})`
7905
8656
  );
7906
8657
  if (!diffRes.success) {
7907
8658
  console.log(pc17.red(`\u2718 Diff failed: ${diffRes.error}`));
@@ -7916,9 +8667,9 @@ Comparing current database with snapshot: ${targetArg}...`
7916
8667
  printDiffReport(diffResult, options.reverse);
7917
8668
  const targetSql = options.reverse ? diffResult.rollbackSql : diffResult.migrationSql;
7918
8669
  if (options.out) {
7919
- const outResolved = path12.resolve(process.cwd(), options.out);
7920
- await fs12.mkdir(path12.dirname(outResolved), { recursive: true });
7921
- await fs12.writeFile(outResolved, targetSql, "utf-8");
8670
+ const outResolved = path13.resolve(process.cwd(), options.out);
8671
+ await fs13.mkdir(path13.dirname(outResolved), { recursive: true });
8672
+ await fs13.writeFile(outResolved, targetSql, "utf-8");
7922
8673
  console.log(
7923
8674
  pc17.green(`\u2714 Migration SQL written to: ${pc17.bold(options.out)}`)
7924
8675
  );
@@ -7934,8 +8685,8 @@ Nothing to apply. Schema is already in sync.`)
7934
8685
  const skipConfirm = options.force || options.y;
7935
8686
  let proceed = skipConfirm;
7936
8687
  if (!proceed) {
7937
- const { confirm: confirm6 } = await import("@inquirer/prompts");
7938
- proceed = await confirm6({
8688
+ const { confirm: confirm8 } = await import("@inquirer/prompts");
8689
+ proceed = await confirm8({
7939
8690
  message: `Apply this ${options.reverse ? "rollback" : "migration"} to "${dbConfig.type.toUpperCase()}" database?`,
7940
8691
  default: false
7941
8692
  });
@@ -8107,8 +8858,8 @@ async function runRunCommand(dbConfig, args, _options) {
8107
8858
  const targetIdent = args[0];
8108
8859
  const paramArgs = args.slice(1);
8109
8860
  if (!targetIdent) {
8110
- const { select: select13 } = await import("@inquirer/prompts");
8111
- const selectedId = await select13({
8861
+ const { select: select16 } = await import("@inquirer/prompts");
8862
+ const selectedId = await select16({
8112
8863
  message: "Select a saved query template to run:",
8113
8864
  choices: snippets.map((s) => ({
8114
8865
  name: `${s.title} ${pc18.dim(`(${s.id})`)}`,
@@ -8145,10 +8896,10 @@ async function runRunCommand(dbConfig, args, _options) {
8145
8896
  }
8146
8897
  }
8147
8898
  if (requiredParams.length > 0) {
8148
- const { input: input8 } = await import("@inquirer/prompts");
8899
+ const { input: input11 } = await import("@inquirer/prompts");
8149
8900
  for (const param of requiredParams) {
8150
8901
  if (providedParams[param] === void 0) {
8151
- const val = await input8({
8902
+ const val = await input11({
8152
8903
  message: `Enter value for :${param}:`,
8153
8904
  validate: (v) => v.trim() !== "" ? true : `:${param} cannot be empty`
8154
8905
  });
@@ -8270,7 +9021,7 @@ async function runQuickCommand(command, args, options, dbConfig) {
8270
9021
  // src/tui/index.ts
8271
9022
  init_logo();
8272
9023
  init_logic();
8273
- import pc34 from "picocolors";
9024
+ import pc37 from "picocolors";
8274
9025
 
8275
9026
  // src/tui/views/editor.ts
8276
9027
  init_logic();
@@ -8302,8 +9053,8 @@ var selectTable = async (tableChoices) => await select({
8302
9053
  init_logic();
8303
9054
  import { input, select as select2 } from "@inquirer/prompts";
8304
9055
  import pc21 from "picocolors";
8305
- import fs13 from "fs/promises";
8306
- import path13 from "path";
9056
+ import fs14 from "fs/promises";
9057
+ import path14 from "path";
8307
9058
  async function runBeginnerAdd(adapter, dbType, tableName, columns) {
8308
9059
  console.log(pc21.cyan(`
8309
9060
  --- Add Data to [${tableName}] ---`));
@@ -8423,10 +9174,10 @@ async function runExpertMode(adapter) {
8423
9174
  message: "Enter the path to your .md or .sql file:"
8424
9175
  });
8425
9176
  if (filePath && filePath.trim()) {
8426
- const absolutePath = path13.resolve(process.cwd(), filePath.trim());
9177
+ const absolutePath = path14.resolve(process.cwd(), filePath.trim());
8427
9178
  let fileContent = "";
8428
9179
  try {
8429
- fileContent = await fs13.readFile(absolutePath, "utf-8");
9180
+ fileContent = await fs14.readFile(absolutePath, "utf-8");
8430
9181
  } catch (err2) {
8431
9182
  console.log(pc21.red(`
8432
9183
  x Failed to read file: ${err2.message}`));
@@ -8543,8 +9294,8 @@ async function viewTables(dbConfig) {
8543
9294
  Error fetching data: ${e.message}
8544
9295
  `));
8545
9296
  currentWhere = "";
8546
- const { input: input8 } = await import("@inquirer/prompts");
8547
- await input8({ message: "Click Enter to continue..." });
9297
+ const { input: input11 } = await import("@inquirer/prompts");
9298
+ await input11({ message: "Click Enter to continue..." });
8548
9299
  continue;
8549
9300
  }
8550
9301
  const rows = data.rows;
@@ -8613,8 +9364,8 @@ Error fetching data: ${e.message}
8613
9364
  continue;
8614
9365
  }
8615
9366
  if (action === "search") {
8616
- const { input: input8 } = await import("@inquirer/prompts");
8617
- const searchInput = await input8({
9367
+ const { input: input11 } = await import("@inquirer/prompts");
9368
+ const searchInput = await input11({
8618
9369
  message: "Enter Search (e.g. `age > 18` or `John` for fuzzy search):"
8619
9370
  });
8620
9371
  currentWhere = buildSearchWhereClause(
@@ -8638,18 +9389,18 @@ Error fetching data: ${e.message}
8638
9389
  console.log(pc22.red(`
8639
9390
  Export Error: ${exportRes.error}`));
8640
9391
  } else {
8641
- const fs16 = await import("fs/promises");
8642
- const path17 = await import("path");
8643
- const exportDir = path17.join(
9392
+ const fs19 = await import("fs/promises");
9393
+ const path20 = await import("path");
9394
+ const exportDir = path20.join(
8644
9395
  process.cwd(),
8645
9396
  "drixio_exports"
8646
9397
  );
8647
- await fs16.mkdir(exportDir, { recursive: true });
8648
- const fp = path17.join(
9398
+ await fs19.mkdir(exportDir, { recursive: true });
9399
+ const fp = path20.join(
8649
9400
  exportDir,
8650
9401
  `${selectedTable}.${format}`
8651
9402
  );
8652
- await fs16.writeFile(fp, exportRes.data, "utf-8");
9403
+ await fs19.writeFile(fp, exportRes.data, "utf-8");
8653
9404
  console.log(pc22.green(`
8654
9405
  \u2714 Exported to ${fp}`));
8655
9406
  }
@@ -8657,8 +9408,8 @@ Export Error: ${exportRes.error}`));
8657
9408
  console.log(pc22.red(`
8658
9409
  Export Error: ${e.message}`));
8659
9410
  }
8660
- const { input: input8 } = await import("@inquirer/prompts");
8661
- await input8({ message: "Click Enter to continue..." });
9411
+ const { input: input11 } = await import("@inquirer/prompts");
9412
+ await input11({ message: "Click Enter to continue..." });
8662
9413
  continue;
8663
9414
  }
8664
9415
  const mode = await select3({
@@ -8720,8 +9471,8 @@ x Error: ${error.message}`));
8720
9471
  await adapter.close();
8721
9472
  }
8722
9473
  async function waitForEnter() {
8723
- const { input: input8 } = await import("@inquirer/prompts");
8724
- await input8({
9474
+ const { input: input11 } = await import("@inquirer/prompts");
9475
+ await input11({
8725
9476
  message: "Press Enter to continue..."
8726
9477
  });
8727
9478
  }
@@ -8837,6 +9588,24 @@ var selectAction = async (dbConfig) => await select5({
8837
9588
  description: "Create new tables, or modify/drop existing tables.",
8838
9589
  disabled: dbConfig.type === "unknown"
8839
9590
  },
9591
+ {
9592
+ name: "\u26A1 ORM & Type Generator",
9593
+ value: "orm",
9594
+ description: "Generate Prisma Schema, Drizzle models, or TypeScript definitions.",
9595
+ disabled: dbConfig.type === "unknown"
9596
+ },
9597
+ {
9598
+ name: "\u{1F4D1} SQL Snippets & Templates",
9599
+ value: "snippets",
9600
+ description: "Run parameterized diagnostic queries and high-frequency templates.",
9601
+ disabled: dbConfig.type === "unknown"
9602
+ },
9603
+ {
9604
+ name: "\u{1F504} Schema Diff & Migrations",
9605
+ value: "diff",
9606
+ description: "Compare database schemas with snapshots and generate migration SQL.",
9607
+ disabled: dbConfig.type === "unknown"
9608
+ },
8840
9609
  new Separator2(),
8841
9610
  {
8842
9611
  name: dbConfig.type === "unknown" ? " Setup Connection" : " Connection Settings",
@@ -8858,7 +9627,7 @@ async function runRepl(dbConfig) {
8858
9627
  if (dbConfig.type === "unknown") return;
8859
9628
  const dbAdapter = createDBAdapter(dbConfig);
8860
9629
  let running = true;
8861
- const { input: input8 } = await import("@inquirer/prompts");
9630
+ const { input: input11 } = await import("@inquirer/prompts");
8862
9631
  console.clear();
8863
9632
  console.log(
8864
9633
  pc25.cyan(
@@ -8889,7 +9658,7 @@ async function runRepl(dbConfig) {
8889
9658
  );
8890
9659
  while (running) {
8891
9660
  try {
8892
- const queryStr = await input8({
9661
+ const queryStr = await input11({
8893
9662
  message: pc25.green(`${dbConfig.type}>`)
8894
9663
  });
8895
9664
  const sql = queryStr.trim();
@@ -8935,7 +9704,7 @@ async function runTui(initialConfig, customUrl) {
8935
9704
  case "editor":
8936
9705
  if (dbConfig.type === "unknown") {
8937
9706
  console.log(
8938
- pc34.yellow(
9707
+ pc37.yellow(
8939
9708
  `
8940
9709
  No database connection found. Please setup database first.`
8941
9710
  )
@@ -8952,6 +9721,24 @@ No database connection found. Please setup database first.`
8952
9721
  case "repl":
8953
9722
  await runRepl(dbConfig);
8954
9723
  break;
9724
+ case "orm": {
9725
+ const { runOrmWizard: runOrmWizard2 } = await Promise.resolve().then(() => (init_ormWizard(), ormWizard_exports));
9726
+ await runOrmWizard2(dbConfig);
9727
+ await waitForEnter4();
9728
+ break;
9729
+ }
9730
+ case "snippets": {
9731
+ const { runSnippetsWizard: runSnippetsWizard2 } = await Promise.resolve().then(() => (init_snippetsWizard(), snippetsWizard_exports));
9732
+ await runSnippetsWizard2(dbConfig);
9733
+ await waitForEnter4();
9734
+ break;
9735
+ }
9736
+ case "diff": {
9737
+ const { runDiffWizard: runDiffWizard2 } = await Promise.resolve().then(() => (init_diffWizard(), diffWizard_exports));
9738
+ await runDiffWizard2(dbConfig);
9739
+ await waitForEnter4();
9740
+ break;
9741
+ }
8955
9742
  case "setup":
8956
9743
  case "re-configure":
8957
9744
  dbConfig = await runSetup(dbConfig);
@@ -8959,32 +9746,19 @@ No database connection found. Please setup database first.`
8959
9746
  break;
8960
9747
  case "exit":
8961
9748
  running = false;
8962
- console.log(pc34.dim("\nThanks for using Drixio. Goodbye!"));
9749
+ console.log(pc37.dim("\nThanks for using Drixio. Goodbye!"));
8963
9750
  break;
8964
9751
  }
8965
9752
  }
8966
9753
  async function waitForEnter4() {
8967
- const { input: input8 } = await import("@inquirer/prompts");
8968
- await input8({
9754
+ const { input: input11 } = await import("@inquirer/prompts");
9755
+ await input11({
8969
9756
  message: "Click Enter to continue..."
8970
9757
  });
8971
9758
  }
8972
9759
  }
8973
9760
 
8974
9761
  // bin/cli.ts
8975
- import { readFileSync } from "fs";
8976
- import { fileURLToPath as fileURLToPath2 } from "url";
8977
- import { dirname, join } from "path";
8978
- function getVersion() {
8979
- try {
8980
- const __dirname2 = dirname(fileURLToPath2(import.meta.url));
8981
- const pkgPath = join(__dirname2, "../package.json");
8982
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
8983
- return pkg.version || "1.1.9";
8984
- } catch {
8985
- return "1.1.9";
8986
- }
8987
- }
8988
9762
  async function main() {
8989
9763
  const args = process.argv.slice(2);
8990
9764
  let customUrl;
@@ -9012,80 +9786,80 @@ async function main() {
9012
9786
  allowPositionals: true
9013
9787
  });
9014
9788
  if (values.version) {
9015
- console.log(`drixio v${getVersion()}`);
9789
+ console.log(`drixio v${getDrixioVersion()}`);
9016
9790
  process.exit(0);
9017
9791
  }
9018
9792
  if (values.help) {
9019
- console.log(pc36.cyan(`
9793
+ console.log(pc39.cyan(`
9020
9794
  Drixio - Modern Database Manager
9021
9795
  `));
9022
- console.log(`${pc36.bold("Usage:")} npx drixio [command] [options]
9796
+ console.log(`${pc39.bold("Usage:")} npx drixio [command] [options]
9023
9797
  `);
9024
- console.log(`${pc36.bold("Tiers & Interfaces:")}`);
9798
+ console.log(`${pc39.bold("Tiers & Interfaces:")}`);
9025
9799
  console.log(
9026
- ` Interactive TUI: ${pc36.green("npx drixio")} (Terminal UI with beginner wizards)`
9800
+ ` Interactive TUI: ${pc39.green("npx drixio")} (Terminal UI with beginner wizards)`
9027
9801
  );
9028
9802
  console.log(
9029
- ` Web Studio: ${pc36.green("npx drixio studio")} (Browser UI for bulk inspection)`
9803
+ ` Web Studio: ${pc39.green("npx drixio studio")} (Browser UI for bulk inspection)`
9030
9804
  );
9031
9805
  console.log(`
9032
- ${pc36.bold("Quick Commands (Headless / Pro):")}`);
9806
+ ${pc39.bold("Quick Commands (Headless / Pro):")}`);
9033
9807
  console.log(
9034
- ` ${pc36.green("tables")} List all database tables and row counts (alias: ls)`
9808
+ ` ${pc39.green("tables")} List all database tables and row counts (alias: ls)`
9035
9809
  );
9036
9810
  console.log(
9037
- ` ${pc36.green("describe")} [table] Inspect columns, types, PKs, and indexes (alias: desc)`
9811
+ ` ${pc39.green("describe")} [table] Inspect columns, types, PKs, and indexes (alias: desc)`
9038
9812
  );
9039
9813
  console.log(
9040
- ` ${pc36.green("query")} "<sql>" Run a quick SQL query`
9814
+ ` ${pc39.green("query")} "<sql>" Run a quick SQL query`
9041
9815
  );
9042
9816
  console.log(
9043
- ` ${pc36.green("exec")} <file.sql> Execute a SQL script file`
9817
+ ` ${pc39.green("exec")} <file.sql> Execute a SQL script file`
9044
9818
  );
9045
9819
  console.log(
9046
- ` ${pc36.green("export")} [table] Export table(s) to CSV/JSON`
9820
+ ` ${pc39.green("export")} [table] Export table(s) to CSV/JSON`
9047
9821
  );
9048
9822
  console.log(
9049
- ` ${pc36.green("import")} [file] Import JSON/CSV into a table`
9823
+ ` ${pc39.green("import")} [file] Import JSON/CSV into a table`
9050
9824
  );
9051
9825
  console.log(
9052
- ` ${pc36.green("seed")} [table] [count] Generate realistic fake data for a table`
9826
+ ` ${pc39.green("seed")} [table] [count] Generate realistic fake data for a table`
9053
9827
  );
9054
9828
  console.log(
9055
- ` ${pc36.green("truncate")} [table] Empty all data in a table and reset sequence`
9829
+ ` ${pc39.green("truncate")} [table] Empty all data in a table and reset sequence`
9056
9830
  );
9057
9831
  console.log(
9058
- ` ${pc36.green("diagram")} Generate a Mermaid ER diagram`
9832
+ ` ${pc39.green("diagram")} Generate a Mermaid ER diagram`
9059
9833
  );
9060
9834
  console.log(
9061
- ` ${pc36.green("generate-types")} Generate TypeScript interfaces`
9835
+ ` ${pc39.green("generate-types")} Generate TypeScript interfaces`
9062
9836
  );
9063
9837
  console.log(
9064
- ` ${pc36.green("generate-orm")} [target] Generate Prisma or Drizzle ORM schema`
9838
+ ` ${pc39.green("generate-orm")} [target] Generate Prisma or Drizzle ORM schema`
9065
9839
  );
9066
9840
  console.log(
9067
- ` ${pc36.green("diff")} [target] Compare schemas & generate migration SQL`
9841
+ ` ${pc39.green("diff")} [target] Compare schemas & generate migration SQL`
9068
9842
  );
9069
9843
  console.log(
9070
- ` ${pc36.green("snippets")} List saved SQL snippets & templates (alias: snip)`
9844
+ ` ${pc39.green("snippets")} List saved SQL snippets & templates (alias: snip)`
9071
9845
  );
9072
9846
  console.log(
9073
- ` ${pc36.green("run")} [snippet] Execute a saved snippet or parametric query`
9847
+ ` ${pc39.green("run")} [snippet] Execute a saved snippet or parametric query`
9074
9848
  );
9075
9849
  console.log(
9076
- ` ${pc36.green("backup")} Backup the entire database`
9850
+ ` ${pc39.green("backup")} Backup the entire database`
9077
9851
  );
9078
9852
  console.log(
9079
- ` ${pc36.green("restore")} [dir|file] Restore database from a backup directory or .sql file`
9853
+ ` ${pc39.green("restore")} [dir|file] Restore database from a backup directory or .sql file`
9080
9854
  );
9081
9855
  console.log(
9082
- ` ${pc36.green("init")} [db_type] Initialize a local database & .env`
9856
+ ` ${pc39.green("init")} [db_type] Initialize a local database & .env`
9083
9857
  );
9084
9858
  console.log(
9085
- ` ${pc36.green("drop-db")} [db_type] Drop a local database`
9859
+ ` ${pc39.green("drop-db")} [db_type] Drop a local database`
9086
9860
  );
9087
9861
  console.log(`
9088
- ${pc36.bold("Options:")}`);
9862
+ ${pc39.bold("Options:")}`);
9089
9863
  console.log(` -v, --version Show drixio version`);
9090
9864
  console.log(` --help Show this help message`);
9091
9865
  console.log(` --json Output results as JSON`);