kolaybase-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1913 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // node_modules/tsup/assets/esm_shims.js
13
+ import path from "path";
14
+ import { fileURLToPath } from "url";
15
+ var init_esm_shims = __esm({
16
+ "node_modules/tsup/assets/esm_shims.js"() {
17
+ "use strict";
18
+ }
19
+ });
20
+
21
+ // src/lib/config.ts
22
+ var config_exports = {};
23
+ __export(config_exports, {
24
+ DEFAULT_API_URL: () => DEFAULT_API_URL,
25
+ clearUserConfig: () => clearUserConfig,
26
+ getAccessToken: () => getAccessToken,
27
+ getApiUrl: () => getApiUrl,
28
+ getLocalEnv: () => getLocalEnv,
29
+ getProjectConfig: () => getProjectConfig,
30
+ getProjectRoot: () => getProjectRoot,
31
+ getRefreshToken: () => getRefreshToken,
32
+ getUserConfig: () => getUserConfig,
33
+ isLoggedIn: () => isLoggedIn,
34
+ setAccessToken: () => setAccessToken,
35
+ setApiUrl: () => setApiUrl,
36
+ setLocalEnv: () => setLocalEnv,
37
+ setProjectConfig: () => setProjectConfig,
38
+ setRefreshToken: () => setRefreshToken,
39
+ setUserConfig: () => setUserConfig,
40
+ unsetLocalEnv: () => unsetLocalEnv,
41
+ writeEnvFile: () => writeEnvFile
42
+ });
43
+ import Conf from "conf";
44
+ import path2 from "path";
45
+ import fs from "fs/promises";
46
+ async function getProjectRoot() {
47
+ let currentDir = process.cwd();
48
+ while (currentDir !== path2.parse(currentDir).root) {
49
+ const configPath = path2.join(currentDir, ".kolaybase");
50
+ try {
51
+ await fs.access(configPath);
52
+ return currentDir;
53
+ } catch {
54
+ currentDir = path2.dirname(currentDir);
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ async function getProjectConfig() {
60
+ const projectRoot = await getProjectRoot();
61
+ if (!projectRoot) return null;
62
+ const configPath = path2.join(projectRoot, ".kolaybase", "config.json");
63
+ try {
64
+ const data = await fs.readFile(configPath, "utf-8");
65
+ return JSON.parse(data);
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ async function setProjectConfig(config) {
71
+ const projectRoot = process.cwd();
72
+ const configDir = path2.join(projectRoot, ".kolaybase");
73
+ const configPath = path2.join(configDir, "config.json");
74
+ await fs.mkdir(configDir, { recursive: true });
75
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2));
76
+ }
77
+ function getUserConfig() {
78
+ return userConfig.store;
79
+ }
80
+ function setUserConfig(config) {
81
+ userConfig.set(config);
82
+ }
83
+ function clearUserConfig() {
84
+ userConfig.clear();
85
+ }
86
+ function getApiUrl() {
87
+ return userConfig.get("apiUrl") || DEFAULT_API_URL;
88
+ }
89
+ function getAccessToken() {
90
+ return userConfig.get("accessToken");
91
+ }
92
+ function setAccessToken(token) {
93
+ userConfig.set("accessToken", token);
94
+ }
95
+ function getRefreshToken() {
96
+ return userConfig.get("refreshToken");
97
+ }
98
+ function setRefreshToken(token) {
99
+ userConfig.set("refreshToken", token);
100
+ }
101
+ function isLoggedIn() {
102
+ return !!userConfig.get("accessToken");
103
+ }
104
+ function setApiUrl(url) {
105
+ userConfig.set("apiUrl", url);
106
+ }
107
+ async function writeEnvFile(project) {
108
+ const lines = [
109
+ '# Kolaybase \u2014 generated by "kb init" / "kb link"',
110
+ "",
111
+ `PROJECT_ID=${project.id}`,
112
+ `PROJECT_SLUG=${project.slug}`,
113
+ "",
114
+ `DB_HOST=${project.dbHost}`,
115
+ `DB_PORT=${project.dbPort}`,
116
+ `DB_NAME=${project.dbName}`,
117
+ `DB_USER=${project.dbUser}`,
118
+ `DB_PASSWORD=${project.dbPassword}`,
119
+ `DATABASE_URL=postgresql://${project.dbUser}:${project.dbPassword}@${project.dbHost}:${project.dbPort}/${project.dbName}`,
120
+ "",
121
+ `KEYCLOAK_REALM=${project.keycloakRealm}`,
122
+ `ANON_KEY=${project.anonKey}`,
123
+ `SERVICE_KEY=${project.serviceKey}`,
124
+ ""
125
+ ];
126
+ await fs.writeFile(".env", lines.join("\n"));
127
+ try {
128
+ let gi = "";
129
+ try {
130
+ gi = await fs.readFile(".gitignore", "utf-8");
131
+ } catch {
132
+ }
133
+ if (!gi.includes(".env")) {
134
+ await fs.writeFile(".gitignore", gi + "\n.env\n");
135
+ }
136
+ } catch {
137
+ }
138
+ }
139
+ async function getLocalEnv() {
140
+ const projectRoot = await getProjectRoot();
141
+ if (!projectRoot) return {};
142
+ const envPath = path2.join(projectRoot, ".env");
143
+ try {
144
+ const content = await fs.readFile(envPath, "utf-8");
145
+ const env = {};
146
+ content.split("\n").forEach((line) => {
147
+ line = line.trim();
148
+ if (!line || line.startsWith("#")) return;
149
+ const [key, ...valueParts] = line.split("=");
150
+ if (key && valueParts.length > 0) {
151
+ env[key.trim()] = valueParts.join("=").trim();
152
+ }
153
+ });
154
+ return env;
155
+ } catch {
156
+ return {};
157
+ }
158
+ }
159
+ async function setLocalEnv(key, value) {
160
+ const projectRoot = await getProjectRoot();
161
+ if (!projectRoot) {
162
+ throw new Error("Not in a Kolaybase project directory");
163
+ }
164
+ const envPath = path2.join(projectRoot, ".env");
165
+ let content = "";
166
+ try {
167
+ content = await fs.readFile(envPath, "utf-8");
168
+ } catch {
169
+ }
170
+ const lines = content.split("\n");
171
+ let found = false;
172
+ const newLines = lines.map((line) => {
173
+ const trimmed = line.trim();
174
+ if (trimmed.startsWith(`${key}=`)) {
175
+ found = true;
176
+ return `${key}=${value}`;
177
+ }
178
+ return line;
179
+ });
180
+ if (!found) {
181
+ newLines.push(`${key}=${value}`);
182
+ }
183
+ await fs.writeFile(envPath, newLines.join("\n"));
184
+ }
185
+ async function unsetLocalEnv(key) {
186
+ const projectRoot = await getProjectRoot();
187
+ if (!projectRoot) {
188
+ throw new Error("Not in a Kolaybase project directory");
189
+ }
190
+ const envPath = path2.join(projectRoot, ".env");
191
+ try {
192
+ const content = await fs.readFile(envPath, "utf-8");
193
+ const lines = content.split("\n").filter((line) => {
194
+ const trimmed = line.trim();
195
+ return !trimmed.startsWith(`${key}=`);
196
+ });
197
+ await fs.writeFile(envPath, lines.join("\n"));
198
+ } catch {
199
+ }
200
+ }
201
+ var userConfig, DEFAULT_API_URL;
202
+ var init_config = __esm({
203
+ "src/lib/config.ts"() {
204
+ "use strict";
205
+ init_esm_shims();
206
+ userConfig = new Conf({
207
+ projectName: "kolaybase",
208
+ configName: "config"
209
+ });
210
+ DEFAULT_API_URL = "https://api.kolaybase.com";
211
+ }
212
+ });
213
+
214
+ // src/lib/api.ts
215
+ import axios from "axios";
216
+ import chalk from "chalk";
217
+ function handleApiError(error2) {
218
+ if (axios.isAxiosError(error2)) {
219
+ if (error2.response) {
220
+ const message = error2.response.data?.message || error2.response.data?.error || error2.message;
221
+ console.error(chalk.red(`API Error: ${message}`));
222
+ if (error2.response.status === 401) {
223
+ console.error(chalk.yellow("Please login first with: kb login"));
224
+ }
225
+ } else if (error2.request) {
226
+ console.error(chalk.red("Network error: Could not connect to Kolaybase API"));
227
+ console.error(chalk.yellow(`Make sure the API is running at: ${getApiUrl()}`));
228
+ } else {
229
+ console.error(chalk.red(`Error: ${error2.message}`));
230
+ }
231
+ } else {
232
+ console.error(chalk.red(`Error: ${error2.message || error2}`));
233
+ }
234
+ process.exit(1);
235
+ }
236
+ var ApiClient, apiClient;
237
+ var init_api = __esm({
238
+ "src/lib/api.ts"() {
239
+ "use strict";
240
+ init_esm_shims();
241
+ init_config();
242
+ ApiClient = class {
243
+ client;
244
+ constructor() {
245
+ this.client = axios.create({
246
+ baseURL: getApiUrl(),
247
+ timeout: 3e4,
248
+ headers: {
249
+ "Content-Type": "application/json"
250
+ }
251
+ });
252
+ this.client.interceptors.request.use((config) => {
253
+ const token = getAccessToken();
254
+ if (token) {
255
+ config.headers.Authorization = `Bearer ${token}`;
256
+ }
257
+ return config;
258
+ });
259
+ this.client.interceptors.response.use(
260
+ (response) => response,
261
+ async (error2) => {
262
+ const originalRequest = error2.config;
263
+ if (error2.response?.status === 401 && originalRequest && !originalRequest._retry) {
264
+ originalRequest._retry = true;
265
+ try {
266
+ const refreshToken = getRefreshToken();
267
+ if (!refreshToken) {
268
+ throw new Error("No refresh token available");
269
+ }
270
+ const { data } = await axios.post(`${getApiUrl()}/api/auth/refresh`, {
271
+ refreshToken
272
+ });
273
+ setAccessToken(data.accessToken);
274
+ setRefreshToken(data.refreshToken);
275
+ originalRequest.headers.Authorization = `Bearer ${data.accessToken}`;
276
+ return this.client(originalRequest);
277
+ } catch (refreshError) {
278
+ console.error(chalk.red("Session expired. Please login again with: kb login"));
279
+ process.exit(1);
280
+ }
281
+ }
282
+ return Promise.reject(error2);
283
+ }
284
+ );
285
+ }
286
+ // Auth endpoints
287
+ async login(username, password) {
288
+ const { data } = await this.client.post("/api/auth/login", { username, password });
289
+ return data;
290
+ }
291
+ async signup(userData) {
292
+ const { data } = await this.client.post("/api/auth/signup", userData);
293
+ return data;
294
+ }
295
+ // Projects endpoints
296
+ async getProjects(teamId) {
297
+ const { data } = await this.client.get("/api/projects", {
298
+ params: { teamId }
299
+ });
300
+ return data;
301
+ }
302
+ async getProject(projectId) {
303
+ const { data } = await this.client.get(`/api/projects/${projectId}`);
304
+ return data;
305
+ }
306
+ async createProject(projectData) {
307
+ const { data } = await this.client.post("/api/projects", projectData);
308
+ return data;
309
+ }
310
+ async deleteProject(projectId) {
311
+ const { data } = await this.client.delete(`/api/projects/${projectId}`);
312
+ return data;
313
+ }
314
+ // SQL endpoints
315
+ async executeSQL(projectId, query) {
316
+ const { data } = await this.client.post("/api/sql/execute", {
317
+ projectId,
318
+ query
319
+ });
320
+ return data;
321
+ }
322
+ // Teams endpoints
323
+ async getTeams() {
324
+ const { data } = await this.client.get("/api/teams");
325
+ return data;
326
+ }
327
+ async getActiveTeam() {
328
+ const { data } = await this.client.get("/api/teams/active");
329
+ return data;
330
+ }
331
+ // Project data endpoints
332
+ async getTables(projectId) {
333
+ const { data } = await this.client.get(`/api/projects/${projectId}/data/tables`);
334
+ return data;
335
+ }
336
+ async getTableSchema(projectId, tableName) {
337
+ const { data } = await this.client.get(`/api/projects/${projectId}/data/tables/${tableName}/schema`);
338
+ return data;
339
+ }
340
+ async getTableData(projectId, tableName, options) {
341
+ const { data } = await this.client.get(`/api/projects/${projectId}/data/tables/${tableName}/rows`, {
342
+ params: options
343
+ });
344
+ return data;
345
+ }
346
+ };
347
+ apiClient = new ApiClient();
348
+ }
349
+ });
350
+
351
+ // src/lib/ui.ts
352
+ import chalk2 from "chalk";
353
+ import ora from "ora";
354
+ import boxen from "boxen";
355
+ function success(message) {
356
+ console.log(chalk2.green("\u2713"), message);
357
+ }
358
+ function error(message) {
359
+ console.log(chalk2.red("\u2717"), message);
360
+ }
361
+ function warning(message) {
362
+ console.log(chalk2.yellow("\u26A0"), message);
363
+ }
364
+ function info(message) {
365
+ console.log(chalk2.blue("\u2139"), message);
366
+ }
367
+ function createSpinner(text) {
368
+ return ora(text).start();
369
+ }
370
+ function printHeader(text) {
371
+ console.log();
372
+ console.log(chalk2.bold.cyan(text));
373
+ console.log(chalk2.cyan("\u2500".repeat(text.length)));
374
+ }
375
+ function printTable(headers, rows) {
376
+ const columnWidths = headers.map((header, i) => {
377
+ const maxRowWidth = Math.max(...rows.map((row2) => (row2[i] || "").length));
378
+ return Math.max(header.length, maxRowWidth);
379
+ });
380
+ const headerRow = headers.map(
381
+ (header, i) => header.padEnd(columnWidths[i])
382
+ ).join(" ");
383
+ console.log(chalk2.bold(headerRow));
384
+ console.log(chalk2.gray("\u2500".repeat(headerRow.length)));
385
+ rows.forEach((row2) => {
386
+ const rowStr = row2.map(
387
+ (cell, i) => (cell || "").padEnd(columnWidths[i])
388
+ ).join(" ");
389
+ console.log(rowStr);
390
+ });
391
+ }
392
+ function printKeyValue(data) {
393
+ const maxKeyLength = Math.max(...Object.keys(data).map((k) => k.length));
394
+ Object.entries(data).forEach(([key, value]) => {
395
+ const paddedKey = chalk2.bold(key.padEnd(maxKeyLength));
396
+ const displayValue = value ?? chalk2.gray("(not set)");
397
+ console.log(`${paddedKey} ${displayValue}`);
398
+ });
399
+ }
400
+ function printLogo() {
401
+ const logo = `
402
+ ${chalk2.cyan("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510")}
403
+ ${chalk2.cyan("\u2502")} ${chalk2.bold.cyan("K O L A Y B A S E")} ${chalk2.cyan("\u2502")}
404
+ ${chalk2.cyan("\u2502")} ${chalk2.gray("Backend-as-a-Service Platform")} ${chalk2.cyan("\u2502")}
405
+ ${chalk2.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518")}
406
+ `;
407
+ console.log(logo);
408
+ }
409
+ var init_ui = __esm({
410
+ "src/lib/ui.ts"() {
411
+ "use strict";
412
+ init_esm_shims();
413
+ }
414
+ });
415
+
416
+ // src/commands/db.ts
417
+ var db_exports = {};
418
+ __export(db_exports, {
419
+ dbCommand: () => dbCommand,
420
+ dbDiff: () => dbDiff,
421
+ dbDump: () => dbDump,
422
+ dbPull: () => dbPull,
423
+ dbPush: () => dbPush,
424
+ dbReset: () => dbReset,
425
+ dbSeed: () => dbSeed
426
+ });
427
+ import inquirer5 from "inquirer";
428
+ import chalk9 from "chalk";
429
+ import { Pool } from "pg";
430
+ import fs3 from "fs/promises";
431
+ import path4 from "path";
432
+ async function dbCommand() {
433
+ console.log(chalk9.bold.cyan("Database Management\n"));
434
+ info("Use db subcommands: push, pull, reset, seed, diff");
435
+ }
436
+ async function dbPush() {
437
+ console.log(chalk9.bold.cyan("Push Database Schema\n"));
438
+ const config = await getProjectConfig();
439
+ if (!config) {
440
+ error("Not in a Kolaybase project. Run: kb init");
441
+ process.exit(1);
442
+ }
443
+ const spinner = createSpinner("Analyzing schema changes...");
444
+ try {
445
+ const env = await getLocalEnv();
446
+ const schemaPath = await findSchemaFile();
447
+ if (!schemaPath) {
448
+ spinner.fail("No schema file found");
449
+ error("Could not find schema.prisma, schema.sql, or migrations directory");
450
+ process.exit(1);
451
+ }
452
+ spinner.text = "Pushing schema to database...";
453
+ if (schemaPath.endsWith(".prisma")) {
454
+ const { execa } = await import("execa");
455
+ await execa("npx", ["prisma", "db", "push"], {
456
+ stdio: "inherit",
457
+ env: {
458
+ ...process.env,
459
+ DATABASE_URL: env.DATABASE_URL
460
+ }
461
+ });
462
+ } else {
463
+ const sql = await fs3.readFile(schemaPath, "utf-8");
464
+ await apiClient.executeSQL(config.projectId, sql);
465
+ }
466
+ spinner.succeed("Schema pushed successfully");
467
+ success("Database is up to date");
468
+ } catch (err) {
469
+ spinner.fail("Failed to push schema");
470
+ handleApiError(err);
471
+ }
472
+ }
473
+ async function dbPull() {
474
+ console.log(chalk9.bold.cyan("Pull Database Schema\n"));
475
+ const config = await getProjectConfig();
476
+ if (!config) {
477
+ error("Not in a Kolaybase project. Run: kb init");
478
+ process.exit(1);
479
+ }
480
+ const spinner = createSpinner("Pulling schema from database...");
481
+ try {
482
+ const env = await getLocalEnv();
483
+ const prismaPath = path4.join(process.cwd(), "prisma", "schema.prisma");
484
+ try {
485
+ await fs3.access(prismaPath);
486
+ const { execa } = await import("execa");
487
+ await execa("npx", ["prisma", "db", "pull"], {
488
+ stdio: "inherit",
489
+ env: {
490
+ ...process.env,
491
+ DATABASE_URL: env.DATABASE_URL
492
+ }
493
+ });
494
+ spinner.succeed("Schema pulled successfully");
495
+ } catch {
496
+ spinner.text = "Generating SQL dump...";
497
+ const pool = new Pool({
498
+ connectionString: env.DATABASE_URL
499
+ });
500
+ const client = await pool.connect();
501
+ try {
502
+ const { rows } = await client.query(`
503
+ SELECT table_name
504
+ FROM information_schema.tables
505
+ WHERE table_schema = 'public'
506
+ ORDER BY table_name
507
+ `);
508
+ const tables = rows.map((r) => r.table_name);
509
+ let schemaDump = "-- Database schema dump\n\n";
510
+ for (const table of tables) {
511
+ const { rows: columns } = await client.query(`
512
+ SELECT column_name, data_type, is_nullable, column_default
513
+ FROM information_schema.columns
514
+ WHERE table_name = $1
515
+ ORDER BY ordinal_position
516
+ `, [table]);
517
+ schemaDump += `CREATE TABLE IF NOT EXISTS ${table} (
518
+ `;
519
+ schemaDump += columns.map((col) => {
520
+ let def = ` ${col.column_name} ${col.data_type}`;
521
+ if (col.is_nullable === "NO") def += " NOT NULL";
522
+ if (col.column_default) def += ` DEFAULT ${col.column_default}`;
523
+ return def;
524
+ }).join(",\n");
525
+ schemaDump += "\n);\n\n";
526
+ }
527
+ await fs3.mkdir("db", { recursive: true });
528
+ await fs3.writeFile("db/schema.sql", schemaDump);
529
+ spinner.succeed("Schema pulled successfully");
530
+ info("Schema saved to db/schema.sql");
531
+ } finally {
532
+ client.release();
533
+ await pool.end();
534
+ }
535
+ }
536
+ } catch (err) {
537
+ spinner.fail("Failed to pull schema");
538
+ handleApiError(err);
539
+ }
540
+ }
541
+ async function dbReset(options) {
542
+ console.log(chalk9.bold.cyan("Reset Database\n"));
543
+ const config = await getProjectConfig();
544
+ if (!config) {
545
+ error("Not in a Kolaybase project. Run: kb init");
546
+ process.exit(1);
547
+ }
548
+ console.log(chalk9.yellow("\u26A0 WARNING: This will delete all data in the database!"));
549
+ console.log();
550
+ if (!options.force) {
551
+ const answers = await inquirer5.prompt([
552
+ {
553
+ type: "confirm",
554
+ name: "confirm",
555
+ message: "Are you sure you want to reset the database?",
556
+ default: false
557
+ }
558
+ ]);
559
+ if (!answers.confirm) {
560
+ info("Reset cancelled");
561
+ return;
562
+ }
563
+ }
564
+ const spinner = createSpinner("Resetting database...");
565
+ try {
566
+ const env = await getLocalEnv();
567
+ const pool = new Pool({
568
+ connectionString: env.DATABASE_URL
569
+ });
570
+ const client = await pool.connect();
571
+ try {
572
+ const { rows } = await client.query(`
573
+ SELECT tablename
574
+ FROM pg_tables
575
+ WHERE schemaname = 'public'
576
+ `);
577
+ for (const row2 of rows) {
578
+ await client.query(`DROP TABLE IF EXISTS "${row2.tablename}" CASCADE`);
579
+ }
580
+ spinner.succeed("Database reset successfully");
581
+ success("All tables dropped");
582
+ console.log();
583
+ info("To recreate schema, run: kb db push");
584
+ } finally {
585
+ client.release();
586
+ await pool.end();
587
+ }
588
+ } catch (err) {
589
+ spinner.fail("Failed to reset database");
590
+ handleApiError(err);
591
+ }
592
+ }
593
+ async function dbSeed() {
594
+ console.log(chalk9.bold.cyan("Seed Database\n"));
595
+ const config = await getProjectConfig();
596
+ if (!config) {
597
+ error("Not in a Kolaybase project. Run: kb init");
598
+ process.exit(1);
599
+ }
600
+ const spinner = createSpinner("Looking for seed file...");
601
+ try {
602
+ const seedPaths = [
603
+ "prisma/seed.ts",
604
+ "prisma/seed.js",
605
+ "db/seed.sql",
606
+ "seeds/seed.sql"
607
+ ];
608
+ let seedPath = null;
609
+ for (const p of seedPaths) {
610
+ try {
611
+ await fs3.access(p);
612
+ seedPath = p;
613
+ break;
614
+ } catch {
615
+ }
616
+ }
617
+ if (!seedPath) {
618
+ spinner.fail("No seed file found");
619
+ warning("Create a seed file at prisma/seed.ts or db/seed.sql");
620
+ return;
621
+ }
622
+ spinner.text = "Running seed...";
623
+ if (seedPath.endsWith(".sql")) {
624
+ const sql = await fs3.readFile(seedPath, "utf-8");
625
+ await apiClient.executeSQL(config.projectId, sql);
626
+ } else {
627
+ const { execa } = await import("execa");
628
+ await execa("npx", ["prisma", "db", "seed"], {
629
+ stdio: "inherit"
630
+ });
631
+ }
632
+ spinner.succeed("Database seeded successfully");
633
+ } catch (err) {
634
+ spinner.fail("Failed to seed database");
635
+ handleApiError(err);
636
+ }
637
+ }
638
+ async function dbDiff() {
639
+ console.log(chalk9.bold.cyan("Database Schema Diff\n"));
640
+ const config = await getProjectConfig();
641
+ if (!config) {
642
+ error("Not in a Kolaybase project. Run: kb init");
643
+ process.exit(1);
644
+ }
645
+ info("Checking for schema differences...");
646
+ try {
647
+ const { execa } = await import("execa");
648
+ await execa("npx", ["prisma", "migrate", "diff"], {
649
+ stdio: "inherit"
650
+ });
651
+ } catch (err) {
652
+ warning("Could not generate diff. Make sure Prisma is configured.");
653
+ }
654
+ }
655
+ async function dbDump(options) {
656
+ console.log(chalk9.bold.cyan("Dump Database Schema\n"));
657
+ const config = await getProjectConfig();
658
+ if (!config) {
659
+ error("Not in a Kolaybase project. Run: kb init");
660
+ process.exit(1);
661
+ }
662
+ const spinner = createSpinner("Dumping schema\u2026");
663
+ try {
664
+ const env = await getLocalEnv();
665
+ const pool = new Pool({ connectionString: env.DATABASE_URL });
666
+ const client = await pool.connect();
667
+ try {
668
+ const { rows: tables } = await client.query(`
669
+ SELECT table_name
670
+ FROM information_schema.tables
671
+ WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
672
+ ORDER BY table_name
673
+ `);
674
+ let dump = "-- Kolaybase schema dump\n-- Generated: " + (/* @__PURE__ */ new Date()).toISOString() + "\n\n";
675
+ for (const t of tables) {
676
+ const { rows: cols } = await client.query(`
677
+ SELECT column_name, udt_name, is_nullable, column_default, character_maximum_length
678
+ FROM information_schema.columns
679
+ WHERE table_name = $1
680
+ ORDER BY ordinal_position
681
+ `, [t.table_name]);
682
+ dump += `CREATE TABLE IF NOT EXISTS "${t.table_name}" (
683
+ `;
684
+ dump += cols.map((c) => {
685
+ let def = ` "${c.column_name}" ${c.udt_name}`;
686
+ if (c.character_maximum_length) def += `(${c.character_maximum_length})`;
687
+ if (c.is_nullable === "NO") def += " NOT NULL";
688
+ if (c.column_default) def += ` DEFAULT ${c.column_default}`;
689
+ return def;
690
+ }).join(",\n");
691
+ dump += "\n);\n\n";
692
+ }
693
+ const outFile = options.output || "schema.sql";
694
+ await fs3.writeFile(outFile, dump);
695
+ spinner.succeed(`Schema dumped to ${chalk9.cyan(outFile)}`);
696
+ } finally {
697
+ client.release();
698
+ await pool.end();
699
+ }
700
+ } catch (err) {
701
+ spinner.fail("Failed to dump schema");
702
+ handleApiError(err);
703
+ }
704
+ }
705
+ async function findSchemaFile() {
706
+ const paths = [
707
+ "prisma/schema.prisma",
708
+ "db/schema.sql",
709
+ "schema.sql",
710
+ "migrations"
711
+ ];
712
+ for (const p of paths) {
713
+ try {
714
+ await fs3.access(p);
715
+ return p;
716
+ } catch {
717
+ }
718
+ }
719
+ return null;
720
+ }
721
+ var init_db = __esm({
722
+ "src/commands/db.ts"() {
723
+ "use strict";
724
+ init_esm_shims();
725
+ init_api();
726
+ init_config();
727
+ init_ui();
728
+ }
729
+ });
730
+
731
+ // src/commands/inspect.ts
732
+ var inspect_exports = {};
733
+ __export(inspect_exports, {
734
+ inspectCommand: () => inspectCommand
735
+ });
736
+ import chalk10 from "chalk";
737
+ import { Pool as Pool2 } from "pg";
738
+ async function inspectCommand(options) {
739
+ const config = await getProjectConfig();
740
+ if (!config?.projectId) {
741
+ error("Not linked to a project. Run: kb link or kb init");
742
+ process.exit(1);
743
+ }
744
+ const env = await getLocalEnv();
745
+ if (!env.DATABASE_URL) {
746
+ error("DATABASE_URL not found in .env \u2014 run kb link to refresh credentials");
747
+ process.exit(1);
748
+ }
749
+ const pool = new Pool2({ connectionString: env.DATABASE_URL });
750
+ try {
751
+ if (options.table) {
752
+ await inspectTable(pool, options.table);
753
+ } else {
754
+ await inspectAll(pool);
755
+ }
756
+ } catch (err) {
757
+ error(`Database error: ${err.message}`);
758
+ process.exit(1);
759
+ } finally {
760
+ await pool.end();
761
+ }
762
+ }
763
+ async function inspectAll(pool) {
764
+ const spinner = createSpinner("Querying database\u2026");
765
+ const { rows } = await pool.query(`
766
+ SELECT
767
+ t.table_name,
768
+ pg_total_relation_size(quote_ident(t.table_name)) AS total_bytes,
769
+ pg_size_pretty(pg_total_relation_size(quote_ident(t.table_name))) AS size,
770
+ (SELECT reltuples::bigint FROM pg_class WHERE relname = t.table_name) AS est_rows
771
+ FROM information_schema.tables t
772
+ WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE'
773
+ ORDER BY total_bytes DESC
774
+ `);
775
+ spinner.stop();
776
+ if (!rows.length) {
777
+ console.log(chalk10.gray(" No tables found. Push a schema first: kb db push"));
778
+ return;
779
+ }
780
+ printHeader("Tables");
781
+ console.log();
782
+ const nameW = Math.max(10, ...rows.map((r) => r.table_name.length));
783
+ console.log(
784
+ ` ${chalk10.bold("Table".padEnd(nameW))} ${chalk10.bold("Rows".padStart(10))} ${chalk10.bold("Size".padStart(10))}`
785
+ );
786
+ console.log(chalk10.gray(" " + "\u2500".repeat(nameW + 24)));
787
+ for (const r of rows) {
788
+ const rowCount = Number(r.est_rows) >= 0 ? Number(r.est_rows).toLocaleString() : "\u2014";
789
+ console.log(
790
+ ` ${chalk10.cyan(r.table_name.padEnd(nameW))} ${rowCount.padStart(10)} ${String(r.size).padStart(10)}`
791
+ );
792
+ }
793
+ console.log();
794
+ console.log(chalk10.gray(` ${rows.length} table(s)`));
795
+ console.log(chalk10.gray(" Inspect a table: kb inspect --table <name>"));
796
+ }
797
+ async function inspectTable(pool, tableName) {
798
+ const spinner = createSpinner(`Inspecting ${tableName}\u2026`);
799
+ const { rows: columns } = await pool.query(`
800
+ SELECT
801
+ c.column_name,
802
+ c.data_type,
803
+ c.udt_name,
804
+ c.is_nullable,
805
+ c.column_default,
806
+ c.character_maximum_length
807
+ FROM information_schema.columns c
808
+ WHERE c.table_schema = 'public' AND c.table_name = $1
809
+ ORDER BY c.ordinal_position
810
+ `, [tableName]);
811
+ if (!columns.length) {
812
+ spinner.fail(`Table "${tableName}" not found`);
813
+ process.exit(1);
814
+ }
815
+ const { rows: indexes } = await pool.query(`
816
+ SELECT indexname, indexdef
817
+ FROM pg_indexes
818
+ WHERE schemaname = 'public' AND tablename = $1
819
+ `, [tableName]);
820
+ const { rows: fkeys } = await pool.query(`
821
+ SELECT
822
+ kcu.column_name,
823
+ ccu.table_name AS foreign_table,
824
+ ccu.column_name AS foreign_column
825
+ FROM information_schema.table_constraints tc
826
+ JOIN information_schema.key_column_usage kcu
827
+ ON tc.constraint_name = kcu.constraint_name
828
+ JOIN information_schema.constraint_column_usage ccu
829
+ ON tc.constraint_name = ccu.constraint_name
830
+ WHERE tc.table_name = $1 AND tc.constraint_type = 'FOREIGN KEY'
831
+ `, [tableName]);
832
+ const { rows: meta } = await pool.query(`
833
+ SELECT
834
+ pg_size_pretty(pg_total_relation_size(quote_ident($1))) AS size,
835
+ (SELECT reltuples::bigint FROM pg_class WHERE relname = $1) AS est_rows
836
+ `, [tableName]);
837
+ spinner.stop();
838
+ printHeader(`Table: ${tableName}`);
839
+ console.log();
840
+ if (meta[0]) {
841
+ console.log(` ${chalk10.gray("Rows")} ${Number(meta[0].est_rows).toLocaleString()}`);
842
+ console.log(` ${chalk10.gray("Size")} ${meta[0].size}`);
843
+ console.log();
844
+ }
845
+ console.log(chalk10.bold(" Columns"));
846
+ const nameW = Math.max(6, ...columns.map((c) => c.column_name.length));
847
+ const typeW = Math.max(4, ...columns.map((c) => formatType(c).length));
848
+ console.log(
849
+ ` ${chalk10.gray("Name".padEnd(nameW))} ${chalk10.gray("Type".padEnd(typeW))} ${chalk10.gray("Nullable")} ${chalk10.gray("Default")}`
850
+ );
851
+ console.log(chalk10.gray(" " + "\u2500".repeat(nameW + typeW + 24)));
852
+ for (const col of columns) {
853
+ const nullable = col.is_nullable === "YES" ? chalk10.yellow("YES") : chalk10.gray("NO ");
854
+ const def = col.column_default ? chalk10.gray(truncate2(col.column_default, 30)) : "";
855
+ const fk = fkeys.find((f) => f.column_name === col.column_name);
856
+ const fkLabel = fk ? chalk10.blue(` \u2192 ${fk.foreign_table}.${fk.foreign_column}`) : "";
857
+ console.log(
858
+ ` ${chalk10.cyan(col.column_name.padEnd(nameW))} ${formatType(col).padEnd(typeW)} ${nullable} ${def}${fkLabel}`
859
+ );
860
+ }
861
+ if (indexes.length) {
862
+ console.log();
863
+ console.log(chalk10.bold(" Indexes"));
864
+ for (const idx of indexes) {
865
+ console.log(` ${chalk10.gray("\u2022")} ${idx.indexname}`);
866
+ }
867
+ }
868
+ console.log();
869
+ }
870
+ function formatType(col) {
871
+ let t = col.udt_name || col.data_type;
872
+ if (col.character_maximum_length) t += `(${col.character_maximum_length})`;
873
+ return t;
874
+ }
875
+ function truncate2(s, max) {
876
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
877
+ }
878
+ var init_inspect = __esm({
879
+ "src/commands/inspect.ts"() {
880
+ "use strict";
881
+ init_esm_shims();
882
+ init_config();
883
+ init_ui();
884
+ }
885
+ });
886
+
887
+ // src/commands/gen.ts
888
+ var gen_exports = {};
889
+ __export(gen_exports, {
890
+ genClient: () => genClient,
891
+ genTypes: () => genTypes
892
+ });
893
+ import chalk11 from "chalk";
894
+ import fs4 from "fs/promises";
895
+ import path5 from "path";
896
+ import { Pool as Pool3 } from "pg";
897
+ async function genTypes(options) {
898
+ console.log(chalk11.bold.cyan("Generate TypeScript Types\n"));
899
+ const config = await getProjectConfig();
900
+ if (!config) {
901
+ error("Not in a Kolaybase project. Run: kb init");
902
+ process.exit(1);
903
+ }
904
+ const spinner = createSpinner("Generating types from database schema...");
905
+ try {
906
+ const env = await getLocalEnv();
907
+ const pool = new Pool3({
908
+ connectionString: env.DATABASE_URL
909
+ });
910
+ const client = await pool.connect();
911
+ try {
912
+ const { rows: tables } = await client.query(`
913
+ SELECT table_name
914
+ FROM information_schema.tables
915
+ WHERE table_schema = 'public'
916
+ ORDER BY table_name
917
+ `);
918
+ let typesContent = `// Generated by Kolaybase CLI
919
+ // Do not edit manually
920
+
921
+ export interface Database {
922
+ ${tables.map((t) => ` ${t.table_name}: ${toPascalCase(t.table_name)};`).join("\n")}
923
+ }
924
+
925
+ `;
926
+ for (const table of tables) {
927
+ const { rows: columns } = await client.query(`
928
+ SELECT
929
+ column_name,
930
+ data_type,
931
+ is_nullable,
932
+ column_default
933
+ FROM information_schema.columns
934
+ WHERE table_name = $1
935
+ ORDER BY ordinal_position
936
+ `, [table.table_name]);
937
+ const typeName = toPascalCase(table.table_name);
938
+ typesContent += `export interface ${typeName} {
939
+ `;
940
+ columns.forEach((col) => {
941
+ const tsType = pgTypeToTs(col.data_type);
942
+ const optional = col.is_nullable === "YES" || col.column_default ? "?" : "";
943
+ typesContent += ` ${col.column_name}${optional}: ${tsType};
944
+ `;
945
+ });
946
+ typesContent += `}
947
+
948
+ `;
949
+ }
950
+ const outputDir = options.output || "types";
951
+ await fs4.mkdir(outputDir, { recursive: true });
952
+ const outputPath = path5.join(outputDir, "database.ts");
953
+ await fs4.writeFile(outputPath, typesContent);
954
+ spinner.succeed("Types generated successfully");
955
+ success(`Written to ${chalk11.cyan(outputPath)}`);
956
+ } finally {
957
+ client.release();
958
+ await pool.end();
959
+ }
960
+ } catch (err) {
961
+ spinner.fail("Failed to generate types");
962
+ handleApiError(err);
963
+ }
964
+ }
965
+ async function genClient(options) {
966
+ console.log(chalk11.bold.cyan("Generate API Client\n"));
967
+ const config = await getProjectConfig();
968
+ if (!config) {
969
+ error("Not in a Kolaybase project. Run: kb init");
970
+ process.exit(1);
971
+ }
972
+ const spinner = createSpinner("Generating API client...");
973
+ try {
974
+ const lang = options.lang || "typescript";
975
+ const outputDir = options.output || "lib";
976
+ if (lang === "typescript") {
977
+ await generateTsClient(config, outputDir);
978
+ } else if (lang === "javascript") {
979
+ await generateJsClient(config, outputDir);
980
+ } else if (lang === "python") {
981
+ await generatePyClient(config, outputDir);
982
+ } else {
983
+ throw new Error(`Unsupported language: ${lang}`);
984
+ }
985
+ spinner.succeed("Client generated successfully");
986
+ success(`Written to ${chalk11.cyan(outputDir)}`);
987
+ } catch (err) {
988
+ spinner.fail("Failed to generate client");
989
+ handleApiError(err);
990
+ }
991
+ }
992
+ async function generateTsClient(config, outputDir) {
993
+ const clientContent = `// Generated by Kolaybase CLI
994
+ import axios, { AxiosInstance } from 'axios';
995
+
996
+ export interface KolaybaseConfig {
997
+ url?: string;
998
+ anonKey?: string;
999
+ serviceKey?: string;
1000
+ }
1001
+
1002
+ export class KolaybaseClient {
1003
+ private client: AxiosInstance;
1004
+ private projectId: string;
1005
+
1006
+ constructor(config: KolaybaseConfig = {}) {
1007
+ this.projectId = '${config.projectId}';
1008
+
1009
+ this.client = axios.create({
1010
+ baseURL: config.url || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000',
1011
+ headers: {
1012
+ 'Content-Type': 'application/json',
1013
+ 'Authorization': \`Bearer \${config.anonKey || process.env.ANON_KEY}\`,
1014
+ },
1015
+ });
1016
+ }
1017
+
1018
+ // Execute raw SQL
1019
+ async sql<T = any>(query: string): Promise<T[]> {
1020
+ const { data } = await this.client.post('/sql/execute', {
1021
+ projectId: this.projectId,
1022
+ query,
1023
+ });
1024
+ return data.rows;
1025
+ }
1026
+
1027
+ // Table operations
1028
+ table<T = any>(tableName: string) {
1029
+ return {
1030
+ select: async (columns = '*', options?: {
1031
+ where?: Record<string, any>;
1032
+ limit?: number;
1033
+ offset?: number;
1034
+ orderBy?: string;
1035
+ }): Promise<T[]> => {
1036
+ let query = \`SELECT \${columns} FROM \${tableName}\`;
1037
+
1038
+ if (options?.where) {
1039
+ const conditions = Object.entries(options.where)
1040
+ .map(([k, v]) => \`\${k} = '\${v}'\`)
1041
+ .join(' AND ');
1042
+ query += \` WHERE \${conditions}\`;
1043
+ }
1044
+
1045
+ if (options?.orderBy) {
1046
+ query += \` ORDER BY \${options.orderBy}\`;
1047
+ }
1048
+
1049
+ if (options?.limit) {
1050
+ query += \` LIMIT \${options.limit}\`;
1051
+ }
1052
+
1053
+ if (options?.offset) {
1054
+ query += \` OFFSET \${options.offset}\`;
1055
+ }
1056
+
1057
+ return this.sql<T>(query);
1058
+ },
1059
+
1060
+ insert: async (data: Partial<T> | Partial<T>[]): Promise<T[]> => {
1061
+ const rows = Array.isArray(data) ? data : [data];
1062
+ const keys = Object.keys(rows[0]);
1063
+ const values = rows.map(row =>
1064
+ \`(\${keys.map(k => \`'\${(row as any)[k]}'\`).join(', ')})\`
1065
+ ).join(', ');
1066
+
1067
+ const query = \`
1068
+ INSERT INTO \${tableName} (\${keys.join(', ')})
1069
+ VALUES \${values}
1070
+ RETURNING *
1071
+ \`;
1072
+
1073
+ return this.sql<T>(query);
1074
+ },
1075
+
1076
+ update: async (data: Partial<T>, where: Record<string, any>): Promise<T[]> => {
1077
+ const sets = Object.entries(data)
1078
+ .map(([k, v]) => \`\${k} = '\${v}'\`)
1079
+ .join(', ');
1080
+
1081
+ const conditions = Object.entries(where)
1082
+ .map(([k, v]) => \`\${k} = '\${v}'\`)
1083
+ .join(' AND ');
1084
+
1085
+ const query = \`
1086
+ UPDATE \${tableName}
1087
+ SET \${sets}
1088
+ WHERE \${conditions}
1089
+ RETURNING *
1090
+ \`;
1091
+
1092
+ return this.sql<T>(query);
1093
+ },
1094
+
1095
+ delete: async (where: Record<string, any>): Promise<T[]> => {
1096
+ const conditions = Object.entries(where)
1097
+ .map(([k, v]) => \`\${k} = '\${v}'\`)
1098
+ .join(' AND ');
1099
+
1100
+ const query = \`DELETE FROM \${tableName} WHERE \${conditions} RETURNING *\`;
1101
+ return this.sql<T>(query);
1102
+ },
1103
+ };
1104
+ }
1105
+ }
1106
+
1107
+ export function createClient(config?: KolaybaseConfig): KolaybaseClient {
1108
+ return new KolaybaseClient(config);
1109
+ }
1110
+ `;
1111
+ await fs4.mkdir(outputDir, { recursive: true });
1112
+ await fs4.writeFile(path5.join(outputDir, "kolaybase.ts"), clientContent);
1113
+ }
1114
+ async function generateJsClient(config, outputDir) {
1115
+ const clientContent = `// Generated by Kolaybase CLI
1116
+ const axios = require('axios');
1117
+
1118
+ class KolaybaseClient {
1119
+ constructor(config = {}) {
1120
+ this.projectId = '${config.projectId}';
1121
+
1122
+ this.client = axios.create({
1123
+ baseURL: config.url || process.env.API_URL || 'http://localhost:4000',
1124
+ headers: {
1125
+ 'Content-Type': 'application/json',
1126
+ 'Authorization': \`Bearer \${config.anonKey || process.env.ANON_KEY}\`,
1127
+ },
1128
+ });
1129
+ }
1130
+
1131
+ async sql(query) {
1132
+ const { data } = await this.client.post('/sql/execute', {
1133
+ projectId: this.projectId,
1134
+ query,
1135
+ });
1136
+ return data.rows;
1137
+ }
1138
+
1139
+ table(tableName) {
1140
+ return {
1141
+ select: async (columns = '*', options = {}) => {
1142
+ let query = \`SELECT \${columns} FROM \${tableName}\`;
1143
+
1144
+ if (options.where) {
1145
+ const conditions = Object.entries(options.where)
1146
+ .map(([k, v]) => \`\${k} = '\${v}'\`)
1147
+ .join(' AND ');
1148
+ query += \` WHERE \${conditions}\`;
1149
+ }
1150
+
1151
+ return this.sql(query);
1152
+ },
1153
+
1154
+ insert: async (data) => {
1155
+ const rows = Array.isArray(data) ? data : [data];
1156
+ const keys = Object.keys(rows[0]);
1157
+ const values = rows.map(row =>
1158
+ \`(\${keys.map(k => \`'\${row[k]}'\`).join(', ')})\`
1159
+ ).join(', ');
1160
+
1161
+ const query = \`INSERT INTO \${tableName} (\${keys.join(', ')}) VALUES \${values} RETURNING *\`;
1162
+ return this.sql(query);
1163
+ },
1164
+ };
1165
+ }
1166
+ }
1167
+
1168
+ function createClient(config) {
1169
+ return new KolaybaseClient(config);
1170
+ }
1171
+
1172
+ module.exports = { KolaybaseClient, createClient };
1173
+ `;
1174
+ await fs4.mkdir(outputDir, { recursive: true });
1175
+ await fs4.writeFile(path5.join(outputDir, "kolaybase.js"), clientContent);
1176
+ }
1177
+ async function generatePyClient(config, outputDir) {
1178
+ const clientContent = `# Generated by Kolaybase CLI
1179
+ import os
1180
+ import requests
1181
+ from typing import List, Dict, Any, Optional
1182
+
1183
+ class KolaybaseClient:
1184
+ def __init__(self, config: Optional[Dict[str, str]] = None):
1185
+ config = config or {}
1186
+ self.project_id = '${config.projectId}'
1187
+ self.base_url = config.get('url', os.getenv('API_URL', 'http://localhost:4000'))
1188
+ self.anon_key = config.get('anon_key', os.getenv('ANON_KEY'))
1189
+
1190
+ self.session = requests.Session()
1191
+ self.session.headers.update({
1192
+ 'Content-Type': 'application/json',
1193
+ 'Authorization': f'Bearer {self.anon_key}'
1194
+ })
1195
+
1196
+ def sql(self, query: str) -> List[Dict[str, Any]]:
1197
+ response = self.session.post(
1198
+ f'{self.base_url}/sql/execute',
1199
+ json={'projectId': self.project_id, 'query': query}
1200
+ )
1201
+ response.raise_for_status()
1202
+ return response.json()['rows']
1203
+
1204
+ def table(self, table_name: str):
1205
+ class TableOperations:
1206
+ def __init__(self, client, table):
1207
+ self.client = client
1208
+ self.table = table
1209
+
1210
+ def select(self, columns='*', where=None, limit=None):
1211
+ query = f'SELECT {columns} FROM {self.table}'
1212
+
1213
+ if where:
1214
+ conditions = ' AND '.join([f"{k} = '{v}'" for k, v in where.items()])
1215
+ query += f' WHERE {conditions}'
1216
+
1217
+ if limit:
1218
+ query += f' LIMIT {limit}'
1219
+
1220
+ return self.client.sql(query)
1221
+
1222
+ return TableOperations(self, table_name)
1223
+
1224
+ def create_client(config: Optional[Dict[str, str]] = None) -> KolaybaseClient:
1225
+ return KolaybaseClient(config)
1226
+ `;
1227
+ await fs4.mkdir(outputDir, { recursive: true });
1228
+ await fs4.writeFile(path5.join(outputDir, "kolaybase.py"), clientContent);
1229
+ }
1230
+ function toPascalCase(str) {
1231
+ return str.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
1232
+ }
1233
+ function pgTypeToTs(pgType) {
1234
+ const typeMap = {
1235
+ "integer": "number",
1236
+ "bigint": "number",
1237
+ "smallint": "number",
1238
+ "decimal": "number",
1239
+ "numeric": "number",
1240
+ "real": "number",
1241
+ "double precision": "number",
1242
+ "serial": "number",
1243
+ "bigserial": "number",
1244
+ "character varying": "string",
1245
+ "varchar": "string",
1246
+ "character": "string",
1247
+ "char": "string",
1248
+ "text": "string",
1249
+ "boolean": "boolean",
1250
+ "date": "string",
1251
+ "timestamp": "string",
1252
+ "timestamp without time zone": "string",
1253
+ "timestamp with time zone": "string",
1254
+ "time": "string",
1255
+ "json": "any",
1256
+ "jsonb": "any",
1257
+ "uuid": "string",
1258
+ "bytea": "Buffer"
1259
+ };
1260
+ return typeMap[pgType.toLowerCase()] || "any";
1261
+ }
1262
+ var init_gen = __esm({
1263
+ "src/commands/gen.ts"() {
1264
+ "use strict";
1265
+ init_esm_shims();
1266
+ init_api();
1267
+ init_config();
1268
+ init_ui();
1269
+ }
1270
+ });
1271
+
1272
+ // src/commands/secrets.ts
1273
+ var secrets_exports = {};
1274
+ __export(secrets_exports, {
1275
+ listSecrets: () => listSecrets,
1276
+ setSecret: () => setSecret,
1277
+ unsetSecret: () => unsetSecret
1278
+ });
1279
+ import chalk12 from "chalk";
1280
+ async function listSecrets() {
1281
+ console.log(chalk12.bold.cyan("Environment Secrets\n"));
1282
+ const config = await getProjectConfig();
1283
+ if (!config) {
1284
+ error("Not in a Kolaybase project. Run: kb init");
1285
+ process.exit(1);
1286
+ }
1287
+ try {
1288
+ const env = await getLocalEnv();
1289
+ if (Object.keys(env).length === 0) {
1290
+ info("No secrets configured");
1291
+ console.log();
1292
+ console.log(chalk12.gray("Add a secret with:"), chalk12.cyan("kb secrets set KEY VALUE"));
1293
+ return;
1294
+ }
1295
+ const masked = Object.entries(env).reduce((acc, [key, value]) => {
1296
+ const sensitive = ["PASSWORD", "SECRET", "KEY", "TOKEN"].some(
1297
+ (s) => key.toUpperCase().includes(s)
1298
+ );
1299
+ acc[key] = sensitive ? maskValue(value) : value;
1300
+ return acc;
1301
+ }, {});
1302
+ printKeyValue(masked);
1303
+ console.log();
1304
+ console.log(chalk12.gray(`Total: ${Object.keys(env).length} secret(s)`));
1305
+ } catch (err) {
1306
+ error(`Failed to list secrets: ${err.message}`);
1307
+ }
1308
+ }
1309
+ async function setSecret(key, value) {
1310
+ console.log(chalk12.bold.cyan("Set Secret\n"));
1311
+ const config = await getProjectConfig();
1312
+ if (!config) {
1313
+ error("Not in a Kolaybase project. Run: kb init");
1314
+ process.exit(1);
1315
+ }
1316
+ try {
1317
+ await setLocalEnv(key, value);
1318
+ success(`Secret ${chalk12.cyan(key)} set successfully`);
1319
+ console.log();
1320
+ info("Secret saved to .env file");
1321
+ } catch (err) {
1322
+ error(`Failed to set secret: ${err.message}`);
1323
+ }
1324
+ }
1325
+ async function unsetSecret(key) {
1326
+ console.log(chalk12.bold.cyan("Remove Secret\n"));
1327
+ const config = await getProjectConfig();
1328
+ if (!config) {
1329
+ error("Not in a Kolaybase project. Run: kb init");
1330
+ process.exit(1);
1331
+ }
1332
+ try {
1333
+ await unsetLocalEnv(key);
1334
+ success(`Secret ${chalk12.cyan(key)} removed successfully`);
1335
+ } catch (err) {
1336
+ error(`Failed to remove secret: ${err.message}`);
1337
+ }
1338
+ }
1339
+ function maskValue(value) {
1340
+ if (value.length <= 8) {
1341
+ return "*".repeat(value.length);
1342
+ }
1343
+ return value.substring(0, 4) + "*".repeat(value.length - 8) + value.substring(value.length - 4);
1344
+ }
1345
+ var init_secrets = __esm({
1346
+ "src/commands/secrets.ts"() {
1347
+ "use strict";
1348
+ init_esm_shims();
1349
+ init_config();
1350
+ init_ui();
1351
+ }
1352
+ });
1353
+
1354
+ // src/index.ts
1355
+ init_esm_shims();
1356
+ import { Command } from "commander";
1357
+
1358
+ // src/commands/login.ts
1359
+ init_esm_shims();
1360
+ init_api();
1361
+ init_config();
1362
+ init_ui();
1363
+ import inquirer from "inquirer";
1364
+ import chalk3 from "chalk";
1365
+ async function loginCommand(options) {
1366
+ printLogo();
1367
+ if (options.apiUrl) {
1368
+ setApiUrl(options.apiUrl);
1369
+ }
1370
+ const answers = await inquirer.prompt([
1371
+ {
1372
+ type: "input",
1373
+ name: "username",
1374
+ message: "Username:",
1375
+ validate: (v) => v.length > 0 || "Required"
1376
+ },
1377
+ {
1378
+ type: "password",
1379
+ name: "password",
1380
+ message: "Password:",
1381
+ mask: "*",
1382
+ validate: (v) => v.length > 0 || "Required"
1383
+ }
1384
+ ]);
1385
+ const spinner = createSpinner("Authenticating\u2026");
1386
+ try {
1387
+ const data = await apiClient.login(answers.username, answers.password);
1388
+ setAccessToken(data.accessToken);
1389
+ setRefreshToken(data.refreshToken);
1390
+ setUserConfig({ username: answers.username });
1391
+ spinner.succeed("Logged in");
1392
+ console.log();
1393
+ success(`Welcome, ${chalk3.cyan(answers.username)}`);
1394
+ console.log(chalk3.gray(" Run kb init to create a project or kb link to connect to one"));
1395
+ } catch (err) {
1396
+ spinner.fail("Authentication failed");
1397
+ handleApiError(err);
1398
+ }
1399
+ }
1400
+
1401
+ // src/commands/init.ts
1402
+ init_esm_shims();
1403
+ init_api();
1404
+ init_config();
1405
+ init_ui();
1406
+ import inquirer2 from "inquirer";
1407
+ import chalk4 from "chalk";
1408
+ import path3 from "path";
1409
+ async function initCommand(options) {
1410
+ if (!isLoggedIn()) {
1411
+ error("Not logged in. Run: kb login");
1412
+ process.exit(1);
1413
+ }
1414
+ const existingConfig = await getProjectConfig();
1415
+ if (existingConfig?.projectId) {
1416
+ warning(`This directory is already linked to project "${existingConfig.projectName}"`);
1417
+ console.log(chalk4.gray(` ID: ${existingConfig.projectId}`));
1418
+ console.log();
1419
+ console.log(chalk4.gray(" To link to a different project run: kb link"));
1420
+ console.log(chalk4.gray(" To unlink first: kb unlink"));
1421
+ return;
1422
+ }
1423
+ const spinner = createSpinner("Loading teams\u2026");
1424
+ try {
1425
+ const teams = await apiClient.getTeams();
1426
+ spinner.stop();
1427
+ if (!teams?.length) {
1428
+ error("No teams found. Create an account first via the Admin UI.");
1429
+ process.exit(1);
1430
+ }
1431
+ const answers = await inquirer2.prompt([
1432
+ {
1433
+ type: "list",
1434
+ name: "teamId",
1435
+ message: "Team:",
1436
+ choices: teams.map((t) => ({
1437
+ name: t.personalForUserId ? `${t.name} ${chalk4.gray("(personal)")}` : t.name,
1438
+ value: t.id
1439
+ })),
1440
+ when: teams.length > 1
1441
+ },
1442
+ {
1443
+ type: "input",
1444
+ name: "name",
1445
+ message: "Project name:",
1446
+ default: options.name || path3.basename(process.cwd()),
1447
+ validate: (v) => v.trim().length > 0 || "Required"
1448
+ },
1449
+ {
1450
+ type: "input",
1451
+ name: "description",
1452
+ message: "Description (optional):"
1453
+ }
1454
+ ]);
1455
+ const teamId = answers.teamId || teams[0].id;
1456
+ const createSpinnerInstance = createSpinner("Creating project\u2026");
1457
+ const project = await apiClient.createProject({
1458
+ name: answers.name,
1459
+ description: answers.description || void 0,
1460
+ teamId
1461
+ });
1462
+ createSpinnerInstance.succeed("Project created");
1463
+ await setProjectConfig({
1464
+ projectId: project.id,
1465
+ projectName: project.name,
1466
+ projectSlug: project.slug,
1467
+ teamId: project.teamId,
1468
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString()
1469
+ });
1470
+ await writeEnvFile(project);
1471
+ console.log();
1472
+ printHeader("Project ready");
1473
+ console.log();
1474
+ console.log(` ${chalk4.gray("Name")} ${project.name}`);
1475
+ console.log(` ${chalk4.gray("ID")} ${project.id}`);
1476
+ console.log(` ${chalk4.gray("Database")} ${project.dbName}`);
1477
+ console.log(` ${chalk4.gray("Realm")} ${project.keycloakRealm}`);
1478
+ console.log();
1479
+ success("Configuration saved to .kolaybase/config.json");
1480
+ success("Credentials saved to .env");
1481
+ console.log();
1482
+ console.log(chalk4.gray(" Next steps:"));
1483
+ console.log(chalk4.gray(" kb status \u2014 view full connection details"));
1484
+ console.log(chalk4.gray(" kb inspect \u2014 list database tables"));
1485
+ console.log(chalk4.gray(" kb gen types \u2014 generate TypeScript types"));
1486
+ console.log(chalk4.gray(" kb db push \u2014 push a local schema"));
1487
+ } catch (err) {
1488
+ handleApiError(err);
1489
+ }
1490
+ }
1491
+
1492
+ // src/commands/projects.ts
1493
+ init_esm_shims();
1494
+ init_api();
1495
+ init_config();
1496
+ init_ui();
1497
+ import inquirer3 from "inquirer";
1498
+ import chalk5 from "chalk";
1499
+ async function projectsCommand() {
1500
+ if (!isLoggedIn()) {
1501
+ error("You must be logged in to view projects");
1502
+ console.log(chalk5.gray("Run: kb login"));
1503
+ process.exit(1);
1504
+ }
1505
+ const spinner = createSpinner("Loading projects...");
1506
+ try {
1507
+ const teams = await apiClient.getTeams();
1508
+ const team = teams[0];
1509
+ const projects = await apiClient.getProjects(team.id);
1510
+ spinner.stop();
1511
+ if (!projects || projects.length === 0) {
1512
+ info("No projects found");
1513
+ console.log();
1514
+ console.log(chalk5.gray("Create your first project with:"), chalk5.cyan("kb init"));
1515
+ return;
1516
+ }
1517
+ printHeader("Your Projects");
1518
+ console.log();
1519
+ const rows = projects.map((project) => [
1520
+ chalk5.cyan(project.name),
1521
+ project.slug,
1522
+ project.status,
1523
+ new Date(project.createdAt).toLocaleDateString(),
1524
+ project.id
1525
+ ]);
1526
+ printTable(
1527
+ ["Name", "Slug", "Status", "Created", "ID"],
1528
+ rows
1529
+ );
1530
+ console.log();
1531
+ console.log(chalk5.gray(`Total: ${projects.length} project(s)`));
1532
+ } catch (err) {
1533
+ spinner.fail("Failed to load projects");
1534
+ handleApiError(err);
1535
+ }
1536
+ }
1537
+ async function createProject(options) {
1538
+ if (!isLoggedIn()) {
1539
+ error("You must be logged in to create a project");
1540
+ console.log(chalk5.gray("Run: kb login"));
1541
+ process.exit(1);
1542
+ }
1543
+ try {
1544
+ const teams = await apiClient.getTeams();
1545
+ const team = teams[0];
1546
+ let name = options.name;
1547
+ let description = options.description;
1548
+ if (!name) {
1549
+ const answers = await inquirer3.prompt([
1550
+ {
1551
+ type: "input",
1552
+ name: "name",
1553
+ message: "Project name:",
1554
+ validate: (input) => input.length > 0 || "Project name is required"
1555
+ },
1556
+ {
1557
+ type: "input",
1558
+ name: "description",
1559
+ message: "Description (optional):"
1560
+ }
1561
+ ]);
1562
+ name = answers.name;
1563
+ description = answers.description;
1564
+ }
1565
+ const spinner = createSpinner("Creating project...");
1566
+ const project = await apiClient.createProject({
1567
+ name,
1568
+ description,
1569
+ teamId: team.id
1570
+ });
1571
+ spinner.succeed("Project created successfully");
1572
+ console.log();
1573
+ console.log(chalk5.gray("Name:"), chalk5.cyan(project.name));
1574
+ console.log(chalk5.gray("ID:"), project.id);
1575
+ console.log(chalk5.gray("Slug:"), project.slug);
1576
+ console.log(chalk5.gray("Database:"), project.dbName);
1577
+ console.log();
1578
+ console.log(chalk5.gray("To start working with this project:"));
1579
+ console.log(chalk5.cyan(" kb init --link"));
1580
+ } catch (err) {
1581
+ handleApiError(err);
1582
+ }
1583
+ }
1584
+ async function deleteProject(projectId) {
1585
+ if (!isLoggedIn()) {
1586
+ error("You must be logged in to delete a project");
1587
+ console.log(chalk5.gray("Run: kb login"));
1588
+ process.exit(1);
1589
+ }
1590
+ try {
1591
+ const spinner = createSpinner("Loading project...");
1592
+ const project = await apiClient.getProject(projectId);
1593
+ spinner.stop();
1594
+ console.log();
1595
+ console.log(chalk5.yellow("\u26A0 WARNING: This action cannot be undone!"));
1596
+ console.log();
1597
+ console.log(chalk5.gray("Project:"), chalk5.cyan(project.name));
1598
+ console.log(chalk5.gray("Database:"), project.dbName);
1599
+ console.log();
1600
+ const answers = await inquirer3.prompt([
1601
+ {
1602
+ type: "confirm",
1603
+ name: "confirm",
1604
+ message: "Are you sure you want to delete this project?",
1605
+ default: false
1606
+ },
1607
+ {
1608
+ type: "input",
1609
+ name: "confirmName",
1610
+ message: `Type the project name "${project.name}" to confirm:`,
1611
+ when: (answers2) => answers2.confirm,
1612
+ validate: (input) => input === project.name || `You must type "${project.name}" exactly`
1613
+ }
1614
+ ]);
1615
+ if (!answers.confirm) {
1616
+ info("Deletion cancelled");
1617
+ return;
1618
+ }
1619
+ const deleteSpinner = createSpinner("Deleting project...");
1620
+ await apiClient.deleteProject(projectId);
1621
+ deleteSpinner.succeed("Project deleted successfully");
1622
+ } catch (err) {
1623
+ handleApiError(err);
1624
+ }
1625
+ }
1626
+
1627
+ // src/commands/status.ts
1628
+ init_esm_shims();
1629
+ init_api();
1630
+ init_config();
1631
+ init_ui();
1632
+ import chalk6 from "chalk";
1633
+ async function statusCommand(options) {
1634
+ const config = await getProjectConfig();
1635
+ if (!config?.projectId) {
1636
+ error("Not linked to a project. Run: kb link or kb init");
1637
+ process.exit(1);
1638
+ }
1639
+ if (!isLoggedIn()) {
1640
+ error("Not logged in. Run: kb login");
1641
+ process.exit(1);
1642
+ }
1643
+ const spinner = createSpinner("Fetching project details\u2026");
1644
+ try {
1645
+ const project = await apiClient.getProject(config.projectId);
1646
+ spinner.stop();
1647
+ const mask = (val) => options.showKeys ? val : val.slice(0, 6) + "\u2022".repeat(Math.max(0, val.length - 10)) + val.slice(-4);
1648
+ printHeader(`Project: ${project.name}`);
1649
+ console.log();
1650
+ section("General");
1651
+ row("Project ID", project.id);
1652
+ row("Name", project.name);
1653
+ row("Slug", project.slug);
1654
+ row("Status", statusBadge(project.status));
1655
+ row("Created", new Date(project.createdAt).toLocaleString());
1656
+ console.log();
1657
+ section("Database");
1658
+ row("Host", project.dbHost);
1659
+ row("Port", String(project.dbPort));
1660
+ row("Database", project.dbName);
1661
+ row("User", project.dbUser);
1662
+ row("Password", mask(project.dbPassword));
1663
+ console.log();
1664
+ const connStr = `postgresql://${project.dbUser}:${options.showKeys ? project.dbPassword : "\u2022\u2022\u2022\u2022\u2022\u2022"}@${project.dbHost}:${project.dbPort}/${project.dbName}`;
1665
+ row("Connection string", chalk6.cyan(connStr));
1666
+ console.log();
1667
+ section("Authentication (Keycloak)");
1668
+ row("Realm", project.keycloakRealm);
1669
+ row("Anon Key", mask(project.anonKey));
1670
+ row("Service Key", mask(project.serviceKey));
1671
+ console.log();
1672
+ if (!options.showKeys) {
1673
+ console.log(chalk6.gray(" Tip: use kb status --show-keys to reveal secrets"));
1674
+ }
1675
+ console.log();
1676
+ } catch (err) {
1677
+ spinner.fail("Could not fetch project");
1678
+ handleApiError(err);
1679
+ }
1680
+ }
1681
+ function section(title) {
1682
+ console.log(chalk6.bold(` ${title}`));
1683
+ }
1684
+ function row(label, value) {
1685
+ console.log(` ${chalk6.gray(label.padEnd(20))} ${value}`);
1686
+ }
1687
+ function statusBadge(status) {
1688
+ switch (status) {
1689
+ case "ACTIVE":
1690
+ return chalk6.green("\u25CF ACTIVE");
1691
+ case "PAUSED":
1692
+ return chalk6.yellow("\u25CF PAUSED");
1693
+ case "DELETED":
1694
+ return chalk6.red("\u25CF DELETED");
1695
+ default:
1696
+ return status;
1697
+ }
1698
+ }
1699
+
1700
+ // src/commands/link.ts
1701
+ init_esm_shims();
1702
+ init_api();
1703
+ init_config();
1704
+ init_ui();
1705
+ import inquirer4 from "inquirer";
1706
+ import chalk7 from "chalk";
1707
+ import fs2 from "fs/promises";
1708
+ async function linkCommand(options) {
1709
+ if (!isLoggedIn()) {
1710
+ error("Not logged in. Run: kb login");
1711
+ process.exit(1);
1712
+ }
1713
+ try {
1714
+ let projectId = options.projectId;
1715
+ if (!projectId) {
1716
+ const spinner2 = createSpinner("Loading projects\u2026");
1717
+ const teams = await apiClient.getTeams();
1718
+ let allProjects = [];
1719
+ for (const team of teams) {
1720
+ const projects = await apiClient.getProjects(team.id);
1721
+ allProjects.push(
1722
+ ...projects.map((p) => ({ ...p, teamName: team.name }))
1723
+ );
1724
+ }
1725
+ spinner2.stop();
1726
+ if (!allProjects.length) {
1727
+ error("No projects found. Create one first: kb init");
1728
+ process.exit(1);
1729
+ }
1730
+ const { selected } = await inquirer4.prompt([
1731
+ {
1732
+ type: "list",
1733
+ name: "selected",
1734
+ message: "Select a project to link:",
1735
+ choices: allProjects.map((p) => ({
1736
+ name: `${p.name} ${chalk7.gray(p.slug)} ${chalk7.gray("\u2014 " + p.teamName)}`,
1737
+ value: p.id
1738
+ }))
1739
+ }
1740
+ ]);
1741
+ projectId = selected;
1742
+ }
1743
+ const spinner = createSpinner("Linking\u2026");
1744
+ const project = await apiClient.getProject(projectId);
1745
+ await setProjectConfig({
1746
+ projectId: project.id,
1747
+ projectName: project.name,
1748
+ projectSlug: project.slug,
1749
+ teamId: project.teamId,
1750
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString()
1751
+ });
1752
+ await writeEnvFile(project);
1753
+ spinner.succeed(`Linked to ${chalk7.cyan(project.name)}`);
1754
+ console.log();
1755
+ console.log(` ${chalk7.gray("Database")} ${project.dbName}`);
1756
+ console.log(` ${chalk7.gray("Realm")} ${project.keycloakRealm}`);
1757
+ console.log();
1758
+ success("Credentials saved to .env");
1759
+ console.log(chalk7.gray(" Run kb status to see full connection details"));
1760
+ } catch (err) {
1761
+ handleApiError(err);
1762
+ }
1763
+ }
1764
+ async function unlinkProject() {
1765
+ try {
1766
+ await fs2.rm(".kolaybase", { recursive: true, force: true });
1767
+ success("Project unlinked");
1768
+ } catch (err) {
1769
+ error(`Failed to unlink: ${err.message}`);
1770
+ }
1771
+ }
1772
+
1773
+ // src/commands/logs.ts
1774
+ init_esm_shims();
1775
+ init_api();
1776
+ init_config();
1777
+ init_ui();
1778
+ import chalk8 from "chalk";
1779
+ async function logsCommand(options) {
1780
+ const config = await getProjectConfig();
1781
+ if (!config?.projectId) {
1782
+ error("Not linked to a project. Run: kb link or kb init");
1783
+ process.exit(1);
1784
+ }
1785
+ if (!isLoggedIn()) {
1786
+ error("Not logged in. Run: kb login");
1787
+ process.exit(1);
1788
+ }
1789
+ const limit = parseInt(options.tail || "50", 10);
1790
+ const spinner = createSpinner("Fetching SQL audit logs\u2026");
1791
+ try {
1792
+ const result = await apiClient.executeSQL(
1793
+ config.projectId,
1794
+ `SELECT 1`
1795
+ // quick connectivity test
1796
+ );
1797
+ } catch {
1798
+ }
1799
+ try {
1800
+ const { Pool: Pool4 } = await import("pg");
1801
+ const { getLocalEnv: getLocalEnv2 } = await Promise.resolve().then(() => (init_config(), config_exports));
1802
+ const env = await getLocalEnv2();
1803
+ const host = env.DB_HOST || "localhost";
1804
+ const port = env.DB_PORT || "5432";
1805
+ const platformUrl = `postgresql://kolaybase:kolaybase_secret@${host}:${port}/kolaybase`;
1806
+ const pool = new Pool4({ connectionString: platformUrl });
1807
+ const client = await pool.connect();
1808
+ try {
1809
+ const { rows } = await client.query(
1810
+ `SELECT created_at, user_id, query, row_count, duration, error
1811
+ FROM sql_audit_logs
1812
+ WHERE project_id = $1
1813
+ ORDER BY created_at DESC
1814
+ LIMIT $2`,
1815
+ [config.projectId, limit]
1816
+ );
1817
+ spinner.stop();
1818
+ if (!rows.length) {
1819
+ console.log(chalk8.gray(" No SQL logs yet for this project."));
1820
+ return;
1821
+ }
1822
+ printHeader("SQL Audit Logs");
1823
+ console.log();
1824
+ rows.reverse().forEach((r) => {
1825
+ const ts = new Date(r.created_at).toLocaleString();
1826
+ const dur = r.duration != null ? `${r.duration}ms` : "";
1827
+ const badge = r.error ? chalk8.red("ERR") : chalk8.green("OK ");
1828
+ console.log(` ${chalk8.gray(ts)} ${badge} ${chalk8.gray(dur)}`);
1829
+ console.log(` ${chalk8.cyan(truncate(r.query, 100))}`);
1830
+ if (r.error) {
1831
+ console.log(` ${chalk8.red(r.error)}`);
1832
+ } else if (r.row_count != null) {
1833
+ console.log(chalk8.gray(` ${r.row_count} row(s)`));
1834
+ }
1835
+ console.log();
1836
+ });
1837
+ console.log(chalk8.gray(` Showing ${rows.length} entries`));
1838
+ } finally {
1839
+ client.release();
1840
+ await pool.end();
1841
+ }
1842
+ } catch (err) {
1843
+ spinner.fail("Could not fetch logs");
1844
+ console.log(chalk8.gray(` ${err.message}`));
1845
+ console.log(chalk8.gray(" Make sure the platform database is accessible."));
1846
+ }
1847
+ }
1848
+ function truncate(s, max) {
1849
+ const oneLine = s.replace(/\s+/g, " ").trim();
1850
+ return oneLine.length > max ? oneLine.slice(0, max - 1) + "\u2026" : oneLine;
1851
+ }
1852
+
1853
+ // src/index.ts
1854
+ var program = new Command();
1855
+ program.name("kb").description("Kolaybase CLI \u2014 manage your Kolaybase projects").version("0.1.0");
1856
+ program.command("login").description("Authenticate with the Kolaybase platform").option("--api-url <url>", "Platform API URL (default: http://localhost:4000)").action(loginCommand);
1857
+ program.command("init").description("Create a new Kolaybase project and link it to the current directory").option("-n, --name <name>", "Project name").action(initCommand);
1858
+ program.command("link").description("Link current directory to an existing remote project").option("--project-id <id>", "Project ID to link directly").action(linkCommand);
1859
+ program.command("unlink").description("Remove the project link from the current directory").action(unlinkProject);
1860
+ program.command("status").description("Show credentials, keys, and connection info for the linked project").option("--show-keys", "Reveal secret values instead of masking them").action(statusCommand);
1861
+ program.command("projects").alias("list").description("List all projects in your team").action(projectsCommand);
1862
+ program.command("projects:create").description("Create a new project without linking").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").action(createProject);
1863
+ program.command("projects:delete <projectId>").description("Delete a remote project (requires confirmation)").action(deleteProject);
1864
+ var db = program.command("db").description("Manage the project database");
1865
+ db.command("push").description("Push local schema to the project database").action(async () => {
1866
+ const { dbPush: dbPush2 } = await Promise.resolve().then(() => (init_db(), db_exports));
1867
+ await dbPush2();
1868
+ });
1869
+ db.command("pull").description("Introspect the remote database and save schema locally").action(async () => {
1870
+ const { dbPull: dbPull2 } = await Promise.resolve().then(() => (init_db(), db_exports));
1871
+ await dbPull2();
1872
+ });
1873
+ db.command("reset").description("Drop all tables in the project database").option("-f, --force", "Skip confirmation prompt").action(async (options) => {
1874
+ const { dbReset: dbReset2 } = await Promise.resolve().then(() => (init_db(), db_exports));
1875
+ await dbReset2(options);
1876
+ });
1877
+ db.command("seed").description("Run the seed file against the project database").action(async () => {
1878
+ const { dbSeed: dbSeed2 } = await Promise.resolve().then(() => (init_db(), db_exports));
1879
+ await dbSeed2();
1880
+ });
1881
+ db.command("dump").description("Dump the full database schema to SQL").option("-o, --output <file>", "Output file", "schema.sql").action(async (options) => {
1882
+ const { dbDump: dbDump2 } = await Promise.resolve().then(() => (init_db(), db_exports));
1883
+ await dbDump2(options);
1884
+ });
1885
+ program.command("inspect").description("Show database tables, columns, sizes, and row counts").option("-t, --table <name>", "Inspect a specific table").action(async (options) => {
1886
+ const { inspectCommand: inspectCommand2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
1887
+ await inspectCommand2(options);
1888
+ });
1889
+ var gen = program.command("gen").description("Generate code from the project database");
1890
+ gen.command("types").description("Generate TypeScript types from the database schema").option("-o, --output <path>", "Output directory", "./types").action(async (options) => {
1891
+ const { genTypes: genTypes2 } = await Promise.resolve().then(() => (init_gen(), gen_exports));
1892
+ await genTypes2(options);
1893
+ });
1894
+ gen.command("client").description("Generate a ready-to-use API client").option("-l, --lang <language>", "Language: typescript | javascript | python", "typescript").option("-o, --output <path>", "Output directory", "./lib").action(async (options) => {
1895
+ const { genClient: genClient2 } = await Promise.resolve().then(() => (init_gen(), gen_exports));
1896
+ await genClient2(options);
1897
+ });
1898
+ program.command("logs").description("Show SQL audit logs for the linked project").option("-n, --tail <lines>", "Number of recent entries", "50").action(logsCommand);
1899
+ var secrets = program.command("secrets").description("Manage local .env variables for the linked project");
1900
+ secrets.command("list").description("List all variables (sensitive values masked)").action(async () => {
1901
+ const { listSecrets: listSecrets2 } = await Promise.resolve().then(() => (init_secrets(), secrets_exports));
1902
+ await listSecrets2();
1903
+ });
1904
+ secrets.command("set <key> <value>").description("Set or update a variable").action(async (key, value) => {
1905
+ const { setSecret: setSecret2 } = await Promise.resolve().then(() => (init_secrets(), secrets_exports));
1906
+ await setSecret2(key, value);
1907
+ });
1908
+ secrets.command("unset <key>").description("Remove a variable").action(async (key) => {
1909
+ const { unsetSecret: unsetSecret2 } = await Promise.resolve().then(() => (init_secrets(), secrets_exports));
1910
+ await unsetSecret2(key);
1911
+ });
1912
+ program.parse();
1913
+ //# sourceMappingURL=index.js.map