@vibe-db/cli 1.0.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.
@@ -0,0 +1,101 @@
1
+ const chalk = require('chalk');
2
+ const api = require('../api');
3
+ const config = require('../config');
4
+
5
+ async function billingInfoCommand() {
6
+ console.log(chalk.blue.bold('\nšŸ’³ Billing Information\n'));
7
+
8
+ try {
9
+ // Check if logged in
10
+ if (!config.isLoggedIn()) {
11
+ console.error(chalk.red.bold('āœ— Not logged in'));
12
+ console.log(chalk.gray('\nPlease run'), chalk.cyan('vibedb login'), chalk.gray('or'), chalk.cyan('vibedb signup'), chalk.gray('first.'));
13
+ process.exit(1);
14
+ }
15
+
16
+ const apiKey = config.getAPIKey();
17
+
18
+ console.log(chalk.gray('Fetching billing info...'));
19
+
20
+ const billingInfo = await api.getBillingInfo(apiKey);
21
+
22
+ console.log();
23
+
24
+ // Customer ID
25
+ if (billingInfo.customer_id) {
26
+ console.log(chalk.white('Stripe Customer ID:'), chalk.cyan(billingInfo.customer_id));
27
+ } else {
28
+ console.log(chalk.yellow('⚠ No Stripe customer found'));
29
+ console.log(chalk.gray('Your account will be linked to Stripe on your first subscription.'));
30
+ console.log();
31
+ return;
32
+ }
33
+
34
+ console.log();
35
+
36
+ // Subscription info
37
+ if (billingInfo.subscription) {
38
+ const sub = billingInfo.subscription;
39
+ console.log(chalk.white.bold('Subscription:'));
40
+ console.log(chalk.gray(' Status:'), getStatusBadge(sub.status));
41
+ console.log(chalk.gray(' Period:'), chalk.white(formatDate(sub.current_period_start)), chalk.gray('→'), chalk.white(formatDate(sub.current_period_end)));
42
+ if (sub.cancel_at_period_end) {
43
+ console.log(chalk.yellow(' ⚠ Subscription will cancel at period end'));
44
+ }
45
+ console.log();
46
+ } else {
47
+ console.log(chalk.gray('Subscription:'), chalk.yellow('None'));
48
+ console.log(chalk.gray('Run'), chalk.cyan('vibedb billing subscribe'), chalk.gray('to start a subscription.'));
49
+ console.log();
50
+ }
51
+
52
+ // Payment method
53
+ if (billingInfo.payment_method) {
54
+ const pm = billingInfo.payment_method;
55
+ console.log(chalk.white.bold('Payment Method:'));
56
+ console.log(chalk.gray(' Card:'), chalk.white(`${pm.brand} ****${pm.last4}`));
57
+ console.log(chalk.gray(' Expires:'), chalk.white(`${pm.exp_month}/${pm.exp_year}`));
58
+ console.log();
59
+ } else {
60
+ console.log(chalk.gray('Payment Method:'), chalk.yellow('None'));
61
+ console.log(chalk.gray('Add a payment method in the Stripe dashboard.'));
62
+ console.log();
63
+ }
64
+
65
+ // Upcoming invoice
66
+ if (billingInfo.upcoming_invoice) {
67
+ const invoice = billingInfo.upcoming_invoice;
68
+ console.log(chalk.white.bold('Upcoming Invoice:'));
69
+ console.log(chalk.gray(' Amount:'), chalk.white(`$${(invoice.amount_due / 100).toFixed(2)}`));
70
+ console.log(chalk.gray(' Period:'), chalk.white(formatDate(invoice.period_start)), chalk.gray('→'), chalk.white(formatDate(invoice.period_end)));
71
+ console.log();
72
+ }
73
+
74
+ } catch (error) {
75
+ if (error.message.includes('503') || error.message.includes('billing_unavailable')) {
76
+ console.error(chalk.yellow.bold('\n⚠ Billing not configured'));
77
+ console.log(chalk.gray('Stripe billing is not set up on the server.'));
78
+ } else {
79
+ console.error(chalk.red.bold('\nāœ— Failed to fetch billing info:'), chalk.red(error.message));
80
+ }
81
+ process.exit(1);
82
+ }
83
+ }
84
+
85
+ function getStatusBadge(status) {
86
+ const badges = {
87
+ 'active': chalk.green('ā— Active'),
88
+ 'trialing': chalk.blue('ā— Trialing'),
89
+ 'past_due': chalk.red('ā— Past Due'),
90
+ 'canceled': chalk.gray('ā— Canceled'),
91
+ 'unpaid': chalk.red('ā— Unpaid'),
92
+ };
93
+ return badges[status] || chalk.gray(`ā— ${status}`);
94
+ }
95
+
96
+ function formatDate(dateString) {
97
+ const date = new Date(dateString);
98
+ return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
99
+ }
100
+
101
+ module.exports = billingInfoCommand;
@@ -0,0 +1,103 @@
1
+ const chalk = require('chalk');
2
+ const Table = require('cli-table3');
3
+ const api = require('../api');
4
+ const config = require('../config');
5
+
6
+ async function billingInvoicesCommand() {
7
+ console.log(chalk.blue.bold('\nšŸ“„ Your Invoices\n'));
8
+
9
+ try {
10
+ // Check if logged in
11
+ if (!config.isLoggedIn()) {
12
+ console.error(chalk.red.bold('āœ— Not logged in'));
13
+ console.log(chalk.gray('\nPlease run'), chalk.cyan('vibedb login'), chalk.gray('or'), chalk.cyan('vibedb signup'), chalk.gray('first.'));
14
+ process.exit(1);
15
+ }
16
+
17
+ const apiKey = config.getAPIKey();
18
+
19
+ console.log(chalk.gray('Fetching invoices...'));
20
+
21
+ const response = await api.getInvoices(apiKey);
22
+ const invoices = response.invoices || [];
23
+
24
+ if (invoices.length === 0) {
25
+ console.log(chalk.yellow('\nNo invoices found.'));
26
+ console.log(chalk.gray('Invoices will appear here after you subscribe.'));
27
+ console.log();
28
+ return;
29
+ }
30
+
31
+ // Create table
32
+ const table = new Table({
33
+ head: [
34
+ chalk.white.bold('Date'),
35
+ chalk.white.bold('Amount'),
36
+ chalk.white.bold('Status'),
37
+ chalk.white.bold('Period'),
38
+ ],
39
+ colWidths: [15, 12, 12, 30],
40
+ style: {
41
+ head: [],
42
+ border: ['gray'],
43
+ },
44
+ });
45
+
46
+ invoices.forEach((inv) => {
47
+ const statusColor =
48
+ inv.status === 'paid'
49
+ ? chalk.green
50
+ : inv.status === 'open'
51
+ ? chalk.yellow
52
+ : chalk.red;
53
+
54
+ const date = new Date(inv.period_start).toLocaleDateString('en-US', {
55
+ month: 'short',
56
+ day: 'numeric',
57
+ year: 'numeric'
58
+ });
59
+
60
+ const amount = `$${(inv.amount_paid / 100).toFixed(2)}`;
61
+
62
+ const periodStart = new Date(inv.period_start).toLocaleDateString('en-US', {
63
+ month: 'short',
64
+ day: 'numeric'
65
+ });
66
+ const periodEnd = new Date(inv.period_end).toLocaleDateString('en-US', {
67
+ month: 'short',
68
+ day: 'numeric'
69
+ });
70
+ const period = `${periodStart} - ${periodEnd}`;
71
+
72
+ table.push([
73
+ date,
74
+ chalk.white(amount),
75
+ statusColor(inv.status),
76
+ chalk.gray(period),
77
+ ]);
78
+ });
79
+
80
+ console.log();
81
+ console.log(table.toString());
82
+ console.log();
83
+ console.log(chalk.gray(`Total: ${invoices.length} invoice${invoices.length === 1 ? '' : 's'}`));
84
+
85
+ // Show download link for latest invoice
86
+ if (invoices.length > 0 && invoices[0].invoice_pdf) {
87
+ console.log();
88
+ console.log(chalk.gray('Latest invoice PDF:'), chalk.cyan(invoices[0].invoice_pdf));
89
+ }
90
+
91
+ console.log();
92
+ } catch (error) {
93
+ if (error.message.includes('503') || error.message.includes('billing_unavailable')) {
94
+ console.error(chalk.yellow.bold('\n⚠ Billing not configured'));
95
+ console.log(chalk.gray('Stripe billing is not set up on the server.'));
96
+ } else {
97
+ console.error(chalk.red.bold('\nāœ— Failed to fetch invoices:'), chalk.red(error.message));
98
+ }
99
+ process.exit(1);
100
+ }
101
+ }
102
+
103
+ module.exports = billingInvoicesCommand;
@@ -0,0 +1,103 @@
1
+ const chalk = require('chalk');
2
+ const inquirer = require('inquirer');
3
+ const api = require('../api');
4
+ const config = require('../config');
5
+
6
+ async function billingSubscribeCommand() {
7
+ console.log(chalk.blue.bold('\nšŸ’³ Subscribe to VibeDB\n'));
8
+
9
+ try {
10
+ // Check if logged in
11
+ if (!config.isLoggedIn()) {
12
+ console.error(chalk.red.bold('āœ— Not logged in'));
13
+ console.log(chalk.gray('\nPlease run'), chalk.cyan('vibedb login'), chalk.gray('or'), chalk.cyan('vibedb signup'), chalk.gray('first.'));
14
+ process.exit(1);
15
+ }
16
+
17
+ const apiKey = config.getAPIKey();
18
+
19
+ // Check current billing info
20
+ console.log(chalk.gray('Checking current subscription status...\n'));
21
+
22
+ let billingInfo;
23
+ try {
24
+ billingInfo = await api.getBillingInfo(apiKey);
25
+ } catch (error) {
26
+ if (error.message.includes('503') || error.message.includes('billing_unavailable')) {
27
+ console.error(chalk.red.bold('āœ— Billing not available'));
28
+ console.log(chalk.gray('Stripe billing is not configured on the server.'));
29
+ process.exit(1);
30
+ }
31
+ throw error;
32
+ }
33
+
34
+ // Check if already subscribed
35
+ if (billingInfo.subscription && billingInfo.subscription.status === 'active') {
36
+ console.log(chalk.yellow('⚠ You already have an active subscription'));
37
+ console.log(chalk.gray('Status:'), chalk.green('Active'));
38
+ console.log(chalk.gray('Period ends:'), chalk.white(new Date(billingInfo.subscription.current_period_end).toLocaleDateString()));
39
+ console.log();
40
+ process.exit(0);
41
+ }
42
+
43
+ // Check if customer exists
44
+ if (!billingInfo.customer_id) {
45
+ console.error(chalk.red.bold('āœ— No Stripe customer found'));
46
+ console.log(chalk.gray('Please contact support to set up your billing.'));
47
+ process.exit(1);
48
+ }
49
+
50
+ // Check if payment method exists
51
+ if (!billingInfo.payment_method) {
52
+ console.log(chalk.yellow.bold('⚠ No payment method on file\n'));
53
+ console.log(chalk.gray('To subscribe, you need to add a payment method first:'));
54
+ console.log();
55
+ console.log(chalk.cyan('1.'), chalk.white('Go to:'), chalk.underline('https://dashboard.stripe.com/test/customers/' + billingInfo.customer_id));
56
+ console.log(chalk.cyan('2.'), chalk.white('Click "Add payment method"'));
57
+ console.log(chalk.cyan('3.'), chalk.white('Add a test card (use 4242 4242 4242 4242)'));
58
+ console.log(chalk.cyan('4.'), chalk.white('Come back and run this command again'));
59
+ console.log();
60
+ process.exit(1);
61
+ }
62
+
63
+ // Confirm subscription
64
+ console.log(chalk.white.bold('Subscription Details:'));
65
+ console.log(chalk.gray('Payment method:'), chalk.white(`${billingInfo.payment_method.brand} ****${billingInfo.payment_method.last4}`));
66
+ console.log(chalk.gray('Customer ID:'), chalk.cyan(billingInfo.customer_id));
67
+ console.log();
68
+
69
+ const { confirm } = await inquirer.prompt([
70
+ {
71
+ type: 'confirm',
72
+ name: 'confirm',
73
+ message: 'Create subscription?',
74
+ default: false,
75
+ },
76
+ ]);
77
+
78
+ if (!confirm) {
79
+ console.log(chalk.gray('\nSubscription cancelled.'));
80
+ return;
81
+ }
82
+
83
+ console.log(chalk.gray('\nCreating subscription...'));
84
+
85
+ const result = await api.createSubscription(apiKey);
86
+
87
+ console.log();
88
+ console.log(chalk.green.bold('āœ“ Subscription created successfully!'));
89
+ console.log();
90
+ console.log(chalk.gray('Subscription ID:'), chalk.cyan(result.subscription_id));
91
+ console.log(chalk.gray('Status:'), chalk.green(result.status));
92
+ console.log(chalk.gray('Period ends:'), chalk.white(new Date(result.current_period_end).toLocaleDateString()));
93
+ console.log();
94
+ console.log(chalk.gray('Run'), chalk.cyan('vibedb billing info'), chalk.gray('to see full details.'));
95
+ console.log();
96
+
97
+ } catch (error) {
98
+ console.error(chalk.red.bold('\nāœ— Failed to create subscription:'), chalk.red(error.message));
99
+ process.exit(1);
100
+ }
101
+ }
102
+
103
+ module.exports = billingSubscribeCommand;
@@ -0,0 +1,62 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const inquirer = require('inquirer');
5
+ const api = require('../api');
6
+ const config = require('../config');
7
+
8
+ async function initCommand() {
9
+ console.log(chalk.blue.bold('\nšŸš€ Initialize VibeDB in your project\n'));
10
+
11
+ try {
12
+ // Check if logged in
13
+ if (!config.isLoggedIn()) {
14
+ console.error(chalk.red.bold('āœ— Not logged in'));
15
+ console.log(chalk.gray('\nPlease run'), chalk.cyan('vibedb login'), chalk.gray('or'), chalk.cyan('vibedb signup'), chalk.gray('first.'));
16
+ process.exit(1);
17
+ }
18
+
19
+ const promptFilePath = path.join(process.cwd(), 'VIBEDB.md');
20
+
21
+ // Check if file already exists
22
+ if (fs.existsSync(promptFilePath)) {
23
+ const { overwrite } = await inquirer.prompt([
24
+ {
25
+ type: 'confirm',
26
+ name: 'overwrite',
27
+ message: 'VIBEDB.md already exists. Overwrite?',
28
+ default: false,
29
+ },
30
+ ]);
31
+
32
+ if (!overwrite) {
33
+ console.log(chalk.yellow('\nOperation cancelled.'));
34
+ process.exit(0);
35
+ }
36
+ }
37
+
38
+ console.log(chalk.gray('Downloading prompt file...'));
39
+
40
+ const promptContent = await api.getPromptFile();
41
+
42
+ // Write to file
43
+ fs.writeFileSync(promptFilePath, promptContent, 'utf8');
44
+
45
+ const userConfig = config.readConfig();
46
+
47
+ console.log(chalk.green.bold('\nāœ“ VIBEDB.md downloaded successfully!\n'));
48
+ console.log(chalk.white('Location:'), chalk.cyan(promptFilePath));
49
+ console.log(chalk.white('API Key:'), chalk.cyan(userConfig.api_key));
50
+ console.log(chalk.white('Email:'), chalk.cyan(userConfig.email));
51
+ console.log(chalk.white('\nNext steps:'));
52
+ console.log(chalk.gray(' 1. Add VIBEDB.md to your project repository'));
53
+ console.log(chalk.gray(' 2. Tell your AI assistant: "I need a database for my app"'));
54
+ console.log(chalk.gray(' 3. The AI will read VIBEDB.md and provision a database for you!'));
55
+ console.log();
56
+ } catch (error) {
57
+ console.error(chalk.red.bold('\nāœ— Init failed:'), chalk.red(error.message));
58
+ process.exit(1);
59
+ }
60
+ }
61
+
62
+ module.exports = initCommand;
@@ -0,0 +1,73 @@
1
+ const chalk = require('chalk');
2
+ const Table = require('cli-table3');
3
+ const api = require('../api');
4
+ const config = require('../config');
5
+
6
+ async function listCommand() {
7
+ console.log(chalk.blue.bold('\nšŸ“Š Your Databases\n'));
8
+
9
+ try {
10
+ // Check if logged in
11
+ if (!config.isLoggedIn()) {
12
+ console.error(chalk.red.bold('āœ— Not logged in'));
13
+ console.log(chalk.gray('\nPlease run'), chalk.cyan('vibedb login'), chalk.gray('or'), chalk.cyan('vibedb signup'), chalk.gray('first.'));
14
+ process.exit(1);
15
+ }
16
+
17
+ const apiKey = config.getAPIKey();
18
+
19
+ console.log(chalk.gray('Fetching databases...'));
20
+
21
+ const databases = await api.listDatabases(apiKey);
22
+
23
+ if (databases.length === 0) {
24
+ console.log(chalk.yellow('\nNo databases found.'));
25
+ console.log(chalk.gray('\nCreate your first database by telling your AI assistant:'));
26
+ console.log(chalk.cyan(' "I need a Postgres database for my app"'));
27
+ console.log();
28
+ return;
29
+ }
30
+
31
+ // Create table
32
+ const table = new Table({
33
+ head: [
34
+ chalk.white.bold('ID'),
35
+ chalk.white.bold('Name'),
36
+ chalk.white.bold('Type'),
37
+ chalk.white.bold('Status'),
38
+ ],
39
+ colWidths: [20, 25, 12, 12],
40
+ style: {
41
+ head: [],
42
+ border: ['gray'],
43
+ },
44
+ });
45
+
46
+ databases.forEach((db) => {
47
+ const statusColor =
48
+ db.status === 'ready'
49
+ ? chalk.green
50
+ : db.status === 'provisioning'
51
+ ? chalk.yellow
52
+ : chalk.gray;
53
+
54
+ table.push([
55
+ chalk.cyan(db.id),
56
+ db.name,
57
+ chalk.blue(db.type),
58
+ statusColor(db.status),
59
+ ]);
60
+ });
61
+
62
+ console.log();
63
+ console.log(table.toString());
64
+ console.log();
65
+ console.log(chalk.gray(`Total: ${databases.length} database${databases.length === 1 ? '' : 's'}`));
66
+ console.log();
67
+ } catch (error) {
68
+ console.error(chalk.red.bold('\nāœ— Failed to list databases:'), chalk.red(error.message));
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ module.exports = listCommand;
@@ -0,0 +1,53 @@
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const api = require('../api');
4
+ const config = require('../config');
5
+
6
+ async function loginCommand() {
7
+ console.log(chalk.blue.bold('\nšŸ” VibeDB Login\n'));
8
+
9
+ try {
10
+ const answers = await inquirer.prompt([
11
+ {
12
+ type: 'input',
13
+ name: 'email',
14
+ message: 'Email:',
15
+ validate: (input) => {
16
+ if (!input || input.length < 3) {
17
+ return 'Email is required';
18
+ }
19
+ return true;
20
+ },
21
+ },
22
+ {
23
+ type: 'password',
24
+ name: 'password',
25
+ message: 'Password:',
26
+ mask: '*',
27
+ validate: (input) => {
28
+ if (!input) {
29
+ return 'Password is required';
30
+ }
31
+ return true;
32
+ },
33
+ },
34
+ ]);
35
+
36
+ console.log(chalk.gray('\nAuthenticating...'));
37
+
38
+ const result = await api.login(answers.email.trim().toLowerCase(), answers.password);
39
+
40
+ // Save API key to config
41
+ config.saveAuth(result.api_key, result.email);
42
+
43
+ console.log(chalk.green.bold('\nāœ“ Login successful!\n'));
44
+ console.log(chalk.white('Email:'), chalk.cyan(result.email));
45
+ console.log(chalk.gray(`API key saved to ${config.getConfigPath()}`));
46
+ console.log();
47
+ } catch (error) {
48
+ console.error(chalk.red.bold('\nāœ— Login failed:'), chalk.red(error.message));
49
+ process.exit(1);
50
+ }
51
+ }
52
+
53
+ module.exports = loginCommand;
@@ -0,0 +1,73 @@
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const api = require('../api');
4
+ const config = require('../config');
5
+
6
+ async function signupCommand() {
7
+ console.log(chalk.blue.bold('\nšŸ“ VibeDB Signup\n'));
8
+
9
+ try {
10
+ const answers = await inquirer.prompt([
11
+ {
12
+ type: 'input',
13
+ name: 'email',
14
+ message: 'Email:',
15
+ validate: (input) => {
16
+ if (!input || input.length < 3) {
17
+ return 'Email is required';
18
+ }
19
+ if (!input.includes('@')) {
20
+ return 'Please enter a valid email address';
21
+ }
22
+ return true;
23
+ },
24
+ },
25
+ {
26
+ type: 'password',
27
+ name: 'password',
28
+ message: 'Password:',
29
+ mask: '*',
30
+ validate: (input) => {
31
+ if (!input || input.length < 8) {
32
+ return 'Password must be at least 8 characters long';
33
+ }
34
+ return true;
35
+ },
36
+ },
37
+ {
38
+ type: 'password',
39
+ name: 'confirmPassword',
40
+ message: 'Confirm password:',
41
+ mask: '*',
42
+ validate: (input, answers) => {
43
+ if (input !== answers.password) {
44
+ return 'Passwords do not match';
45
+ }
46
+ return true;
47
+ },
48
+ },
49
+ ]);
50
+
51
+ console.log(chalk.gray('\nCreating account...'));
52
+
53
+ const result = await api.signup(answers.email.trim().toLowerCase(), answers.password);
54
+
55
+ // Save API key to config
56
+ config.saveAuth(result.api_key, result.email);
57
+
58
+ console.log(chalk.green.bold('\nāœ“ Account created successfully!\n'));
59
+ console.log(chalk.white('Email:'), chalk.cyan(result.email));
60
+ console.log(chalk.white('API Key:'), chalk.cyan(result.api_key));
61
+ console.log(chalk.gray(`\nAPI key saved to ${config.getConfigPath()}`));
62
+ console.log(chalk.white('\nNext steps:'));
63
+ console.log(chalk.gray(' 1. Run'), chalk.cyan('vibedb init'), chalk.gray('to download the prompt file'));
64
+ console.log(chalk.gray(' 2. Add VIBEDB.md to your project'));
65
+ console.log(chalk.gray(' 3. Tell your AI assistant to provision a database!'));
66
+ console.log();
67
+ } catch (error) {
68
+ console.error(chalk.red.bold('\nāœ— Signup failed:'), chalk.red(error.message));
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ module.exports = signupCommand;
package/src/config.js ADDED
@@ -0,0 +1,78 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ const CONFIG_FILE = path.join(os.homedir(), '.vibedb');
6
+
7
+ /**
8
+ * Get the config file path
9
+ */
10
+ function getConfigPath() {
11
+ return CONFIG_FILE;
12
+ }
13
+
14
+ /**
15
+ * Read configuration from ~/.vibedb
16
+ */
17
+ function readConfig() {
18
+ try {
19
+ if (!fs.existsSync(CONFIG_FILE)) {
20
+ return null;
21
+ }
22
+ const content = fs.readFileSync(CONFIG_FILE, 'utf8');
23
+ return JSON.parse(content);
24
+ } catch (error) {
25
+ throw new Error(`Failed to read config file: ${error.message}`);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Write configuration to ~/.vibedb
31
+ */
32
+ function writeConfig(config) {
33
+ try {
34
+ const content = JSON.stringify(config, null, 2);
35
+ fs.writeFileSync(CONFIG_FILE, content, 'utf8');
36
+ } catch (error) {
37
+ throw new Error(`Failed to write config file: ${error.message}`);
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Check if user is logged in (has API key)
43
+ */
44
+ function isLoggedIn() {
45
+ const config = readConfig();
46
+ return config && config.api_key;
47
+ }
48
+
49
+ /**
50
+ * Get API key from config
51
+ */
52
+ function getAPIKey() {
53
+ const config = readConfig();
54
+ if (!config || !config.api_key) {
55
+ throw new Error('Not logged in. Please run "vibedb login" or "vibedb signup" first.');
56
+ }
57
+ return config.api_key;
58
+ }
59
+
60
+ /**
61
+ * Save API key and email to config
62
+ */
63
+ function saveAuth(apiKey, email) {
64
+ const config = readConfig() || {};
65
+ config.api_key = apiKey;
66
+ config.email = email;
67
+ config.api_url = 'https://api.vibedb.dev';
68
+ writeConfig(config);
69
+ }
70
+
71
+ module.exports = {
72
+ getConfigPath,
73
+ readConfig,
74
+ writeConfig,
75
+ isLoggedIn,
76
+ getAPIKey,
77
+ saveAuth,
78
+ };