@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.
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # VibeDB CLI
2
+
3
+ Command-line interface for VibeDB - instant database provisioning for AI-assisted development.
4
+
5
+ ## Installation
6
+
7
+ ### Via NPX (Recommended)
8
+ ```bash
9
+ npx @vibedb/cli signup
10
+ ```
11
+
12
+ ### Global Installation
13
+ ```bash
14
+ npm install -g @vibedb/cli
15
+ vibedb signup
16
+ ```
17
+
18
+ ### Local Development
19
+ ```bash
20
+ git clone <repo>
21
+ cd cli
22
+ npm install
23
+ node bin/vibedb.js --help
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Create an Account
29
+ ```bash
30
+ npx @vibedb/cli signup
31
+ ```
32
+
33
+ You'll be prompted for:
34
+ - Email address
35
+ - Password (minimum 8 characters)
36
+ - Password confirmation
37
+
38
+ Your API key will be saved to `~/.vibedb`
39
+
40
+ ### 2. Or Login to Existing Account
41
+ ```bash
42
+ npx @vibedb/cli login
43
+ ```
44
+
45
+ ### 3. Initialize Your Project
46
+ ```bash
47
+ cd your-project
48
+ npx @vibedb/cli init
49
+ ```
50
+
51
+ This downloads `VIBEDB.md` to your current directory. This file tells your AI assistant how to provision databases.
52
+
53
+ ### 4. Tell Your AI to Create a Database
54
+ Open your AI coding assistant (Claude, Cursor, etc.) and say:
55
+
56
+ > "I need a PostgreSQL database for my blog app"
57
+
58
+ The AI will read `VIBEDB.md`, use your API key from `~/.vibedb`, and provision a database automatically!
59
+
60
+ ## Commands
61
+
62
+ ### `vibedb signup`
63
+ Create a new VibeDB account.
64
+
65
+ **Interactive prompts:**
66
+ - Email
67
+ - Password
68
+ - Confirm password
69
+
70
+ **Output:**
71
+ - Account ID
72
+ - API key (saved to ~/.vibedb)
73
+
74
+ ### `vibedb login`
75
+ Login to existing account.
76
+
77
+ **Interactive prompts:**
78
+ - Email
79
+ - Password
80
+
81
+ **Output:**
82
+ - API key (saved to ~/.vibedb)
83
+
84
+ ### `vibedb init`
85
+ Download the VIBEDB.md prompt file to your project.
86
+
87
+ **Requirements:**
88
+ - Must be logged in (run `vibedb signup` or `vibedb login` first)
89
+
90
+ **Output:**
91
+ - Downloads `VIBEDB.md` to current directory
92
+ - Shows your configured API key
93
+
94
+ ### `vibedb list` (alias: `ls`)
95
+ List all your databases.
96
+
97
+ **Requirements:**
98
+ - Must be logged in
99
+
100
+ **Output:**
101
+ - Table showing all databases with ID, Name, Type, and Status
102
+
103
+ ## Configuration
104
+
105
+ The CLI stores your credentials in `~/.vibedb`:
106
+
107
+ ```json
108
+ {
109
+ "api_key": "vdb_xxx...",
110
+ "email": "you@example.com",
111
+ "api_url": "https://api.vibedb.dev"
112
+ }
113
+ ```
114
+
115
+ **Security Note:** Keep this file secure. Anyone with your API key can manage your databases.
116
+
117
+ ## Examples
118
+
119
+ ### Complete Workflow
120
+ ```bash
121
+ # 1. Sign up
122
+ $ npx @vibedb/cli signup
123
+ ? Email: john@example.com
124
+ ? Password: ********
125
+ ? Confirm password: ********
126
+
127
+ āœ“ Account created successfully!
128
+ Email: john@example.com
129
+ API Key: vdb_abc123...
130
+
131
+ # 2. Initialize project
132
+ $ cd my-project
133
+ $ npx @vibedb/cli init
134
+
135
+ āœ“ VIBEDB.md downloaded successfully!
136
+ Location: /path/to/my-project/VIBEDB.md
137
+
138
+ # 3. Tell your AI assistant
139
+ > "I need a Postgres database for user authentication"
140
+
141
+ # 4. Check your databases
142
+ $ npx @vibedb/cli list
143
+
144
+ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
145
+ │ ID │ Name │ Type │ Status │
146
+ ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
147
+ │ db_abc123 │ auth-db │ postgres │ ready │
148
+ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
149
+
150
+ Total: 1 database
151
+ ```
152
+
153
+ ## Supported Databases
154
+
155
+ - **PostgreSQL** - General purpose relational database
156
+ - **MySQL** - Traditional relational database
157
+ - **Redis** - In-memory cache and session store
158
+
159
+ Coming soon:
160
+ - MongoDB
161
+ - ClickHouse
162
+
163
+ ## Troubleshooting
164
+
165
+ ### "Not logged in" Error
166
+ Run `vibedb login` or `vibedb signup` first.
167
+
168
+ ### "Email already exists" During Signup
169
+ The email is already registered. Use `vibedb login` instead.
170
+
171
+ ### "Invalid credentials" During Login
172
+ Check your email and password. Passwords are case-sensitive.
173
+
174
+ ### API Connection Issues
175
+ - Check your internet connection
176
+ - Verify api.vibedb.dev is accessible
177
+ - Check firewall settings
178
+
179
+ ### Config File Issues
180
+ Your config is at `~/.vibedb`. If corrupted:
181
+ ```bash
182
+ rm ~/.vibedb
183
+ vibedb login
184
+ ```
185
+
186
+ ## API Reference
187
+
188
+ The CLI interacts with these VibeDB API endpoints:
189
+
190
+ - `POST /v1/auth/signup` - Create account
191
+ - `POST /v1/auth/login` - Authenticate
192
+ - `GET /v1/databases` - List databases
193
+ - `GET /v1/prompt-file` - Download prompt file
194
+ - `GET /v1/account` - Get account info
195
+
196
+ Full API docs: https://api.vibedb.dev/docs
197
+
198
+ ## Support
199
+
200
+ - Website: https://vibedb.dev
201
+ - Email: support@vibedb.dev
202
+ - Issues: https://github.com/vibedb/cli/issues
203
+
204
+ ## License
205
+
206
+ MIT
package/bin/vibedb.js ADDED
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Command } = require('commander');
4
+ const chalk = require('chalk');
5
+ const signupCommand = require('../src/commands/signup');
6
+ const loginCommand = require('../src/commands/login');
7
+ const initCommand = require('../src/commands/init');
8
+ const listCommand = require('../src/commands/list');
9
+ const billingInfoCommand = require('../src/commands/billing-info');
10
+ const billingSubscribeCommand = require('../src/commands/billing-subscribe');
11
+ const billingCancelCommand = require('../src/commands/billing-cancel');
12
+ const billingInvoicesCommand = require('../src/commands/billing-invoices');
13
+
14
+ const program = new Command();
15
+
16
+ program
17
+ .name('vibedb')
18
+ .description('VibeDB CLI - Instant database provisioning for AI-assisted development')
19
+ .version('1.0.0');
20
+
21
+ program
22
+ .command('signup')
23
+ .description('Create a new VibeDB account')
24
+ .action(async () => {
25
+ try {
26
+ await signupCommand();
27
+ } catch (error) {
28
+ console.error(chalk.red('Unexpected error:'), error.message);
29
+ process.exit(1);
30
+ }
31
+ });
32
+
33
+ program
34
+ .command('login')
35
+ .description('Login to your VibeDB account')
36
+ .action(async () => {
37
+ try {
38
+ await loginCommand();
39
+ } catch (error) {
40
+ console.error(chalk.red('Unexpected error:'), error.message);
41
+ process.exit(1);
42
+ }
43
+ });
44
+
45
+ program
46
+ .command('init')
47
+ .description('Download VIBEDB.md prompt file to your project')
48
+ .action(async () => {
49
+ try {
50
+ await initCommand();
51
+ } catch (error) {
52
+ console.error(chalk.red('Unexpected error:'), error.message);
53
+ process.exit(1);
54
+ }
55
+ });
56
+
57
+ program
58
+ .command('list')
59
+ .alias('ls')
60
+ .description('List all your databases')
61
+ .action(async () => {
62
+ try {
63
+ await listCommand();
64
+ } catch (error) {
65
+ console.error(chalk.red('Unexpected error:'), error.message);
66
+ process.exit(1);
67
+ }
68
+ });
69
+
70
+ // Billing commands
71
+ const billing = program
72
+ .command('billing')
73
+ .description('Manage billing and subscriptions');
74
+
75
+ billing
76
+ .command('info')
77
+ .description('View billing information and subscription status')
78
+ .action(async () => {
79
+ try {
80
+ await billingInfoCommand();
81
+ } catch (error) {
82
+ console.error(chalk.red('Unexpected error:'), error.message);
83
+ process.exit(1);
84
+ }
85
+ });
86
+
87
+ billing
88
+ .command('subscribe')
89
+ .description('Subscribe to VibeDB')
90
+ .action(async () => {
91
+ try {
92
+ await billingSubscribeCommand();
93
+ } catch (error) {
94
+ console.error(chalk.red('Unexpected error:'), error.message);
95
+ process.exit(1);
96
+ }
97
+ });
98
+
99
+ billing
100
+ .command('cancel')
101
+ .description('Cancel your subscription')
102
+ .action(async () => {
103
+ try {
104
+ await billingCancelCommand();
105
+ } catch (error) {
106
+ console.error(chalk.red('Unexpected error:'), error.message);
107
+ process.exit(1);
108
+ }
109
+ });
110
+
111
+ billing
112
+ .command('invoices')
113
+ .description('View your invoices')
114
+ .action(async () => {
115
+ try {
116
+ await billingInvoicesCommand();
117
+ } catch (error) {
118
+ console.error(chalk.red('Unexpected error:'), error.message);
119
+ process.exit(1);
120
+ }
121
+ });
122
+
123
+ // Global error handler
124
+ process.on('unhandledRejection', (error) => {
125
+ console.error(chalk.red.bold('\nāœ— Unhandled error:'), error.message);
126
+ process.exit(1);
127
+ });
128
+
129
+ process.on('uncaughtException', (error) => {
130
+ console.error(chalk.red.bold('\nāœ— Uncaught error:'), error.message);
131
+ process.exit(1);
132
+ });
133
+
134
+ program.parse(process.argv);
135
+
136
+ // Show help if no command provided
137
+ if (!process.argv.slice(2).length) {
138
+ program.outputHelp();
139
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@vibe-db/cli",
3
+ "version": "1.0.0",
4
+ "description": "Command-line interface for VibeDB - instant database provisioning for AI-assisted development",
5
+ "main": "bin/vibedb.js",
6
+ "bin": {
7
+ "vibedb": "./bin/vibedb.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node bin/vibedb.js --help"
11
+ },
12
+ "keywords": [
13
+ "database",
14
+ "postgres",
15
+ "mysql",
16
+ "redis",
17
+ "provisioning",
18
+ "cli",
19
+ "vibedb",
20
+ "ai",
21
+ "development"
22
+ ],
23
+ "author": "VibeDB",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "axios": "^1.6.0",
27
+ "chalk": "^4.1.2",
28
+ "cli-table3": "^0.6.3",
29
+ "commander": "^11.0.0",
30
+ "inquirer": "^8.2.5"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ }
35
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@vibedb/cli",
3
+ "version": "1.0.0",
4
+ "description": "Command-line interface for VibeDB - instant database provisioning for AI-assisted development",
5
+ "main": "bin/vibedb.js",
6
+ "bin": {
7
+ "vibedb": "./bin/vibedb.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node bin/vibedb.js --help"
11
+ },
12
+ "keywords": [
13
+ "database",
14
+ "postgres",
15
+ "mysql",
16
+ "redis",
17
+ "provisioning",
18
+ "cli",
19
+ "vibedb",
20
+ "ai",
21
+ "development"
22
+ ],
23
+ "author": "VibeDB",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "axios": "^1.6.0",
27
+ "chalk": "^4.1.2",
28
+ "cli-table3": "^0.6.3",
29
+ "commander": "^11.0.0",
30
+ "inquirer": "^8.2.5"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ }
35
+ }
package/src/api.js ADDED
@@ -0,0 +1,196 @@
1
+ const axios = require('axios');
2
+
3
+ const API_BASE_URL = 'https://api.vibedb.dev';
4
+
5
+ /**
6
+ * Signup a new user
7
+ */
8
+ async function signup(email, password) {
9
+ try {
10
+ const response = await axios.post(`${API_BASE_URL}/v1/auth/signup`, {
11
+ email,
12
+ password,
13
+ });
14
+ return response.data;
15
+ } catch (error) {
16
+ if (error.response) {
17
+ const { error: errorCode, message } = error.response.data;
18
+ throw new Error(message || errorCode || 'Signup failed');
19
+ }
20
+ throw new Error(`Network error: ${error.message}`);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Login existing user
26
+ */
27
+ async function login(email, password) {
28
+ try {
29
+ const response = await axios.post(`${API_BASE_URL}/v1/auth/login`, {
30
+ email,
31
+ password,
32
+ });
33
+ return response.data;
34
+ } catch (error) {
35
+ if (error.response) {
36
+ const { error: errorCode, message } = error.response.data;
37
+ throw new Error(message || errorCode || 'Login failed');
38
+ }
39
+ throw new Error(`Network error: ${error.message}`);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * List all databases for authenticated user
45
+ */
46
+ async function listDatabases(apiKey) {
47
+ try {
48
+ const response = await axios.get(`${API_BASE_URL}/v1/databases`, {
49
+ headers: {
50
+ Authorization: `Bearer ${apiKey}`,
51
+ },
52
+ });
53
+ return response.data.databases || [];
54
+ } catch (error) {
55
+ if (error.response) {
56
+ const { error: errorCode, message } = error.response.data;
57
+ throw new Error(message || errorCode || 'Failed to list databases');
58
+ }
59
+ throw new Error(`Network error: ${error.message}`);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Get prompt file content
65
+ */
66
+ async function getPromptFile() {
67
+ try {
68
+ const response = await axios.get(`${API_BASE_URL}/v1/prompt-file`);
69
+ return response.data;
70
+ } catch (error) {
71
+ if (error.response) {
72
+ throw new Error('Failed to download prompt file');
73
+ }
74
+ throw new Error(`Network error: ${error.message}`);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Get account information
80
+ */
81
+ async function getAccount(apiKey) {
82
+ try {
83
+ const response = await axios.get(`${API_BASE_URL}/v1/account`, {
84
+ headers: {
85
+ Authorization: `Bearer ${apiKey}`,
86
+ },
87
+ });
88
+ return response.data;
89
+ } catch (error) {
90
+ if (error.response) {
91
+ const { error: errorCode, message } = error.response.data;
92
+ throw new Error(message || errorCode || 'Failed to get account info');
93
+ }
94
+ throw new Error(`Network error: ${error.message}`);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Get billing information
100
+ */
101
+ async function getBillingInfo(apiKey) {
102
+ try {
103
+ const response = await axios.get(`${API_BASE_URL}/v1/billing/info`, {
104
+ headers: {
105
+ Authorization: `Bearer ${apiKey}`,
106
+ },
107
+ });
108
+ return response.data;
109
+ } catch (error) {
110
+ if (error.response) {
111
+ const { error: errorCode, message } = error.response.data;
112
+ throw new Error(message || errorCode || 'Failed to get billing info');
113
+ }
114
+ throw new Error(`Network error: ${error.message}`);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Create subscription
120
+ */
121
+ async function createSubscription(apiKey, priceId = null) {
122
+ try {
123
+ const response = await axios.post(
124
+ `${API_BASE_URL}/v1/billing/subscribe`,
125
+ priceId ? { price_id: priceId } : {},
126
+ {
127
+ headers: {
128
+ Authorization: `Bearer ${apiKey}`,
129
+ },
130
+ }
131
+ );
132
+ return response.data;
133
+ } catch (error) {
134
+ if (error.response) {
135
+ const { error: errorCode, message } = error.response.data;
136
+ throw new Error(message || errorCode || 'Failed to create subscription');
137
+ }
138
+ throw new Error(`Network error: ${error.message}`);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Cancel subscription
144
+ */
145
+ async function cancelSubscription(apiKey) {
146
+ try {
147
+ const response = await axios.post(
148
+ `${API_BASE_URL}/v1/billing/cancel`,
149
+ {},
150
+ {
151
+ headers: {
152
+ Authorization: `Bearer ${apiKey}`,
153
+ },
154
+ }
155
+ );
156
+ return response.data;
157
+ } catch (error) {
158
+ if (error.response) {
159
+ const { error: errorCode, message } = error.response.data;
160
+ throw new Error(message || errorCode || 'Failed to cancel subscription');
161
+ }
162
+ throw new Error(`Network error: ${error.message}`);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get invoices
168
+ */
169
+ async function getInvoices(apiKey) {
170
+ try {
171
+ const response = await axios.get(`${API_BASE_URL}/v1/billing/invoices`, {
172
+ headers: {
173
+ Authorization: `Bearer ${apiKey}`,
174
+ },
175
+ });
176
+ return response.data;
177
+ } catch (error) {
178
+ if (error.response) {
179
+ const { error: errorCode, message } = error.response.data;
180
+ throw new Error(message || errorCode || 'Failed to get invoices');
181
+ }
182
+ throw new Error(`Network error: ${error.message}`);
183
+ }
184
+ }
185
+
186
+ module.exports = {
187
+ signup,
188
+ login,
189
+ listDatabases,
190
+ getPromptFile,
191
+ getAccount,
192
+ getBillingInfo,
193
+ createSubscription,
194
+ cancelSubscription,
195
+ getInvoices,
196
+ };
@@ -0,0 +1,89 @@
1
+ const chalk = require('chalk');
2
+ const inquirer = require('inquirer');
3
+ const api = require('../api');
4
+ const config = require('../config');
5
+
6
+ async function billingCancelCommand() {
7
+ console.log(chalk.blue.bold('\nšŸ’³ Cancel Subscription\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...\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 has active subscription
35
+ if (!billingInfo.subscription || billingInfo.subscription.status !== 'active') {
36
+ console.log(chalk.yellow('⚠ No active subscription found'));
37
+ console.log(chalk.gray('Nothing to cancel.'));
38
+ console.log();
39
+ process.exit(0);
40
+ }
41
+
42
+ const sub = billingInfo.subscription;
43
+
44
+ // Show current subscription
45
+ console.log(chalk.white.bold('Current Subscription:'));
46
+ console.log(chalk.gray('Status:'), chalk.green('Active'));
47
+ console.log(chalk.gray('Period ends:'), chalk.white(new Date(sub.current_period_end).toLocaleDateString()));
48
+ console.log();
49
+
50
+ // Confirm cancellation
51
+ console.log(chalk.yellow.bold('⚠ Warning:'));
52
+ console.log(chalk.gray('Your subscription will remain active until'), chalk.white(new Date(sub.current_period_end).toLocaleDateString()));
53
+ console.log(chalk.gray('After that, your databases may be paused or limited.'));
54
+ console.log();
55
+
56
+ const { confirm } = await inquirer.prompt([
57
+ {
58
+ type: 'confirm',
59
+ name: 'confirm',
60
+ message: 'Are you sure you want to cancel?',
61
+ default: false,
62
+ },
63
+ ]);
64
+
65
+ if (!confirm) {
66
+ console.log(chalk.gray('\nCancellation aborted.'));
67
+ return;
68
+ }
69
+
70
+ console.log(chalk.gray('\nCancelling subscription...'));
71
+
72
+ const result = await api.cancelSubscription(apiKey);
73
+
74
+ console.log();
75
+ console.log(chalk.green.bold('āœ“ Subscription cancelled'));
76
+ console.log();
77
+ console.log(chalk.gray('Status:'), chalk.yellow(result.status));
78
+ console.log(chalk.gray('Access until:'), chalk.white(new Date(result.current_period_end).toLocaleDateString()));
79
+ console.log();
80
+ console.log(chalk.gray('You can resubscribe anytime with:'), chalk.cyan('vibedb billing subscribe'));
81
+ console.log();
82
+
83
+ } catch (error) {
84
+ console.error(chalk.red.bold('\nāœ— Failed to cancel subscription:'), chalk.red(error.message));
85
+ process.exit(1);
86
+ }
87
+ }
88
+
89
+ module.exports = billingCancelCommand;