@basictech/cli 0.0.29 → 0.0.31

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 CHANGED
@@ -1,243 +1,3499 @@
1
1
  #!/usr/bin/env node
2
- import { program } from 'commander';
3
- import { MESSAGES } from './lib/constants.js';
4
- import { getVersion } from './lib/version.js';
5
- import { formatError, handleError } from './lib/errors.js';
6
- import { findSimilarCommands } from './lib/platform.js';
7
- // Set up global error handlers
8
- process.on('uncaughtException', (error) => {
9
- console.error('Fatal error:', error.message);
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
+ // dist/lib/constants.js
13
+ var CONSTANTS, COMMANDS, MESSAGES;
14
+ var init_constants = __esm({
15
+ "dist/lib/constants.js"() {
16
+ "use strict";
17
+ CONSTANTS = {
18
+ CLI_DIR: ".basic-cli",
19
+ TOKEN_FILE: "token.json",
20
+ API_BASE: "https://api.basic.tech",
21
+ OAUTH_CLIENT_ID: "9c3f6704-87e7-4af9-8dd0-36dcb9b5c18c",
22
+ OAUTH_REDIRECT: "http://localhost:8080/callback",
23
+ OAUTH_SCOPES: "profile,admin",
24
+ MAX_WIDTH: 80,
25
+ SIMILARITY_THRESHOLD: 0.4,
26
+ GITHUB_REPO: "basicdb/basic-cli"
27
+ };
28
+ COMMANDS = [
29
+ "account",
30
+ "login",
31
+ "logout",
32
+ "status",
33
+ "projects",
34
+ "teams",
35
+ "init",
36
+ "version",
37
+ "help",
38
+ "push",
39
+ "pull",
40
+ "debug",
41
+ "update"
42
+ ];
43
+ MESSAGES = {
44
+ OFFLINE: "you are offline. please check your internet connection.",
45
+ LOGGED_OUT: "you are not logged in. please login with 'basic login'",
46
+ WELCOME: "welcome to basic-cli! use 'basic help' to see all commands"
47
+ };
48
+ }
49
+ });
50
+
51
+ // dist/lib/version.js
52
+ import { readFileSync } from "fs";
53
+ import { join, dirname } from "path";
54
+ import { fileURLToPath } from "url";
55
+ function getVersion() {
56
+ if (cachedVersion) {
57
+ return cachedVersion;
58
+ }
59
+ try {
60
+ const __filename = fileURLToPath(import.meta.url);
61
+ const __dirname = dirname(__filename);
62
+ const packageJsonPath = join(__dirname, "../../package.json");
63
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
64
+ cachedVersion = packageJson.version;
65
+ return cachedVersion;
66
+ } catch (error) {
67
+ console.error("Error reading version:", error);
68
+ const fallbackVersion = "0.0.22";
69
+ cachedVersion = fallbackVersion;
70
+ return fallbackVersion;
71
+ }
72
+ }
73
+ var cachedVersion;
74
+ var init_version = __esm({
75
+ "dist/lib/version.js"() {
76
+ "use strict";
77
+ cachedVersion = null;
78
+ }
79
+ });
80
+
81
+ // dist/lib/errors.js
82
+ function handleError(error) {
83
+ if (error instanceof BasicCliError) {
84
+ return error;
85
+ }
86
+ if (error instanceof Error) {
87
+ if (error.message.includes("ENOTFOUND") || error.message.includes("network")) {
88
+ return new NetworkError();
89
+ }
90
+ if (error.message.includes("unauthorized") || error.message.includes("401")) {
91
+ return new AuthError("Authentication failed", [
92
+ "Try logging in again with 'basic login'",
93
+ "Check if your token has expired"
94
+ ]);
95
+ }
96
+ if (error.message.includes("invalid character")) {
97
+ return new SchemaError("Invalid schema format", [
98
+ "Check for trailing commas in your schema",
99
+ "Ensure valid JSON syntax"
100
+ ]);
101
+ }
102
+ return new BasicCliError(error.message, "UNKNOWN_ERROR");
103
+ }
104
+ return new BasicCliError("An unknown error occurred", "UNKNOWN_ERROR");
105
+ }
106
+ function formatError(error) {
107
+ let output = `Error: ${error.message}`;
108
+ if (error.suggestions && error.suggestions.length > 0) {
109
+ output += "\n\nSuggestions:";
110
+ error.suggestions.forEach((suggestion) => {
111
+ output += `
112
+ - ${suggestion}`;
113
+ });
114
+ }
115
+ return output;
116
+ }
117
+ var BasicCliError, AuthError, ApiError, SchemaError, NetworkError;
118
+ var init_errors = __esm({
119
+ "dist/lib/errors.js"() {
120
+ "use strict";
121
+ BasicCliError = class extends Error {
122
+ code;
123
+ suggestions;
124
+ constructor(message, code, suggestions) {
125
+ super(message);
126
+ this.code = code;
127
+ this.suggestions = suggestions;
128
+ this.name = "BasicCliError";
129
+ }
130
+ };
131
+ AuthError = class extends BasicCliError {
132
+ constructor(message, suggestions) {
133
+ super(message, "AUTH_ERROR", suggestions);
134
+ this.name = "AuthError";
135
+ }
136
+ };
137
+ ApiError = class extends BasicCliError {
138
+ statusCode;
139
+ constructor(message, statusCode, suggestions) {
140
+ super(message, "API_ERROR", suggestions);
141
+ this.statusCode = statusCode;
142
+ this.name = "ApiError";
143
+ }
144
+ };
145
+ SchemaError = class extends BasicCliError {
146
+ constructor(message, suggestions) {
147
+ super(message, "SCHEMA_ERROR", suggestions);
148
+ this.name = "SchemaError";
149
+ }
150
+ };
151
+ NetworkError = class extends BasicCliError {
152
+ constructor(message = "Network connection failed") {
153
+ super(message, "NETWORK_ERROR", [
154
+ "Check your internet connection",
155
+ "Try again in a moment"
156
+ ]);
157
+ this.name = "NetworkError";
158
+ }
159
+ };
160
+ }
161
+ });
162
+
163
+ // dist/lib/platform.js
164
+ import { exec } from "child_process";
165
+ import { promisify } from "util";
166
+ import * as os from "os";
167
+ import * as path from "path";
168
+ function getConfigPath() {
169
+ const home = os.homedir();
170
+ return path.join(home, CONSTANTS.CLI_DIR, CONSTANTS.TOKEN_FILE);
171
+ }
172
+ function getConfigDir() {
173
+ const home = os.homedir();
174
+ return path.join(home, CONSTANTS.CLI_DIR);
175
+ }
176
+ async function openBrowser(url) {
177
+ const platform = process.platform;
178
+ const commands = {
179
+ darwin: "open",
180
+ win32: "start",
181
+ linux: "xdg-open"
182
+ };
183
+ const command = commands[platform];
184
+ if (!command) {
185
+ throw new Error(`Unsupported platform: ${platform}`);
186
+ }
187
+ try {
188
+ if (platform === "win32") {
189
+ await execAsync(`${command} "" "${url}"`);
190
+ } else {
191
+ await execAsync(`${command} "${url}"`);
192
+ }
193
+ } catch (error) {
194
+ throw new Error(`Failed to open browser: ${error}`);
195
+ }
196
+ }
197
+ async function copyToClipboard(text) {
198
+ const platform = process.platform;
199
+ try {
200
+ if (platform === "darwin") {
201
+ await execAsync(`echo "${text}" | pbcopy`);
202
+ } else if (platform === "win32") {
203
+ await execAsync(`echo ${text} | clip`);
204
+ } else {
205
+ try {
206
+ await execAsync(`echo "${text}" | xclip -selection clipboard`);
207
+ } catch {
208
+ await execAsync(`echo "${text}" | xsel --clipboard --input`);
209
+ }
210
+ }
211
+ } catch (error) {
212
+ throw new Error(`Failed to copy to clipboard: ${error}`);
213
+ }
214
+ }
215
+ function isOnline() {
216
+ return fetch(CONSTANTS.API_BASE, { method: "HEAD" }).then(() => true).catch(() => false);
217
+ }
218
+ function similarity(s1, s2) {
219
+ const d = levenshteinDistance(s1, s2);
220
+ const maxLen = Math.max(s1.length, s2.length);
221
+ if (maxLen === 0)
222
+ return 1;
223
+ return 1 - d / maxLen;
224
+ }
225
+ function levenshteinDistance(s1, s2) {
226
+ if (s1.length === 0)
227
+ return s2.length;
228
+ if (s2.length === 0)
229
+ return s1.length;
230
+ const matrix = [];
231
+ for (let i = 0; i <= s1.length; i++) {
232
+ matrix[i] = [];
233
+ matrix[i][0] = i;
234
+ }
235
+ for (let j = 0; j <= s2.length; j++) {
236
+ matrix[0][j] = j;
237
+ }
238
+ for (let i = 1; i <= s1.length; i++) {
239
+ for (let j = 1; j <= s2.length; j++) {
240
+ const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
241
+ matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
242
+ }
243
+ }
244
+ return matrix[s1.length][s2.length];
245
+ }
246
+ function findSimilarCommands(input) {
247
+ const commands = COMMANDS.filter((cmd) => cmd !== input);
248
+ const suggestions = [];
249
+ for (const command of commands) {
250
+ const sim = similarity(input, command);
251
+ if (sim >= CONSTANTS.SIMILARITY_THRESHOLD) {
252
+ suggestions.push({ command, similarity: sim });
253
+ }
254
+ }
255
+ return suggestions.sort((a, b) => b.similarity - a.similarity).slice(0, 3).map((s) => s.command);
256
+ }
257
+ function generateSlug(name) {
258
+ return name.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
259
+ }
260
+ var execAsync;
261
+ var init_platform = __esm({
262
+ "dist/lib/platform.js"() {
263
+ "use strict";
264
+ init_constants();
265
+ execAsync = promisify(exec);
266
+ }
267
+ });
268
+
269
+ // dist/lib/auth.js
270
+ import { createServer } from "http";
271
+ import { promises as fs } from "fs";
272
+ var AuthService;
273
+ var init_auth = __esm({
274
+ "dist/lib/auth.js"() {
275
+ "use strict";
276
+ init_constants();
277
+ init_platform();
278
+ init_errors();
279
+ AuthService = class _AuthService {
280
+ static instance;
281
+ static getInstance() {
282
+ if (!_AuthService.instance) {
283
+ _AuthService.instance = new _AuthService();
284
+ }
285
+ return _AuthService.instance;
286
+ }
287
+ async login() {
288
+ try {
289
+ const token = await this.startOAuthFlow();
290
+ await this.saveToken(token);
291
+ } catch (error) {
292
+ throw handleError(error);
293
+ }
294
+ }
295
+ async logout() {
296
+ try {
297
+ await this.deleteToken();
298
+ } catch (error) {
299
+ throw handleError(error);
300
+ }
301
+ }
302
+ async getToken() {
303
+ try {
304
+ const tokenPath = getConfigPath();
305
+ const tokenData = await fs.readFile(tokenPath, "utf8");
306
+ const token = JSON.parse(tokenData);
307
+ if (token.expires_at && Date.now() > token.expires_at) {
308
+ const refreshedToken = await this.refreshToken(token);
309
+ await this.saveToken(refreshedToken);
310
+ return refreshedToken;
311
+ }
312
+ return token;
313
+ } catch (error) {
314
+ if (error.code === "ENOENT") {
315
+ return null;
316
+ }
317
+ throw handleError(error);
318
+ }
319
+ }
320
+ async getUserInfo() {
321
+ const token = await this.getToken();
322
+ if (!token) {
323
+ throw new AuthError("Not logged in");
324
+ }
325
+ const response = await fetch(`${CONSTANTS.API_BASE}/auth/userInfo`, {
326
+ headers: {
327
+ Authorization: `Bearer ${token.access_token}`
328
+ }
329
+ });
330
+ if (!response.ok) {
331
+ throw new AuthError("Failed to fetch user info");
332
+ }
333
+ return await response.json();
334
+ }
335
+ async startOAuthFlow() {
336
+ return new Promise((resolve, reject) => {
337
+ const server = createServer((req, res) => {
338
+ if (req.url?.startsWith("/callback")) {
339
+ const url = new URL(req.url, CONSTANTS.OAUTH_REDIRECT);
340
+ const code = url.searchParams.get("code");
341
+ const state = url.searchParams.get("state");
342
+ if (!code) {
343
+ res.writeHead(400);
344
+ res.end("Authorization code not found");
345
+ server.close();
346
+ reject(new AuthError("Authorization code not found"));
347
+ return;
348
+ }
349
+ this.exchangeCodeForToken(code).then((token) => {
350
+ res.writeHead(200, { "Content-Type": "text/html" });
351
+ res.end(this.getSuccessHtml());
352
+ server.close();
353
+ resolve(token);
354
+ }).catch((error) => {
355
+ res.writeHead(500);
356
+ res.end("Authentication failed");
357
+ server.close();
358
+ reject(error);
359
+ });
360
+ } else {
361
+ res.writeHead(404);
362
+ res.end("Not found");
363
+ }
364
+ });
365
+ server.listen(8080, async () => {
366
+ const state = this.generateState();
367
+ const authUrl = `${CONSTANTS.API_BASE}/auth/authorize?client_id=${CONSTANTS.OAUTH_CLIENT_ID}&redirect_uri=${encodeURIComponent(CONSTANTS.OAUTH_REDIRECT)}&response_type=code&scope=${encodeURIComponent(CONSTANTS.OAUTH_SCOPES)}&state=${state}`;
368
+ try {
369
+ await openBrowser(authUrl);
370
+ } catch (error) {
371
+ console.log(`Please visit this URL to log in: ${authUrl}`);
372
+ }
373
+ });
374
+ setTimeout(() => {
375
+ server.close();
376
+ reject(new AuthError("Authentication timeout"));
377
+ }, 5 * 60 * 1e3);
378
+ });
379
+ }
380
+ async exchangeCodeForToken(code) {
381
+ const response = await fetch(`${CONSTANTS.API_BASE}/auth/token`, {
382
+ method: "POST",
383
+ headers: {
384
+ "Content-Type": "application/x-www-form-urlencoded"
385
+ },
386
+ body: new URLSearchParams({
387
+ grant_type: "authorization_code",
388
+ client_id: CONSTANTS.OAUTH_CLIENT_ID,
389
+ code,
390
+ redirect_uri: CONSTANTS.OAUTH_REDIRECT
391
+ })
392
+ });
393
+ if (!response.ok) {
394
+ throw new AuthError("Failed to exchange code for token");
395
+ }
396
+ const data = await response.json();
397
+ return {
398
+ access_token: data.access_token,
399
+ refresh_token: data.refresh_token,
400
+ expires_at: Date.now() + data.expires_in * 1e3,
401
+ token_type: data.token_type || "Bearer"
402
+ };
403
+ }
404
+ async refreshToken(token) {
405
+ const response = await fetch(`${CONSTANTS.API_BASE}/auth/token`, {
406
+ method: "POST",
407
+ headers: {
408
+ "Content-Type": "application/x-www-form-urlencoded"
409
+ },
410
+ body: new URLSearchParams({
411
+ grant_type: "refresh_token",
412
+ client_id: CONSTANTS.OAUTH_CLIENT_ID,
413
+ code: token.refresh_token
414
+ })
415
+ });
416
+ if (!response.ok) {
417
+ throw new AuthError("Failed to refresh token", [
418
+ "Try logging in again with 'basic login'"
419
+ ]);
420
+ }
421
+ const data = await response.json();
422
+ return {
423
+ access_token: data.access_token,
424
+ refresh_token: data.refresh_token || token.refresh_token,
425
+ expires_at: Date.now() + data.expires_in * 1e3,
426
+ token_type: data.token_type || "Bearer"
427
+ };
428
+ }
429
+ async saveToken(token) {
430
+ const tokenPath = getConfigPath();
431
+ const configDir = getConfigDir();
432
+ await fs.mkdir(configDir, { recursive: true });
433
+ await fs.writeFile(tokenPath, JSON.stringify(token, null, 2), { mode: 384 });
434
+ }
435
+ async deleteToken() {
436
+ const tokenPath = getConfigPath();
437
+ try {
438
+ await fs.unlink(tokenPath);
439
+ } catch (error) {
440
+ if (error.code !== "ENOENT") {
441
+ throw error;
442
+ }
443
+ }
444
+ }
445
+ generateState() {
446
+ const array = new Uint8Array(24);
447
+ crypto.getRandomValues(array);
448
+ return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
449
+ }
450
+ getSuccessHtml() {
451
+ return `
452
+ <!DOCTYPE html>
453
+ <html>
454
+ <head>
455
+ <meta charset="UTF-8">
456
+ <title>Basic CLI Authentication</title>
457
+ <style>
458
+ :root { color-scheme: light dark; }
459
+ @media (prefers-color-scheme: light) {
460
+ :root {
461
+ --bg-color: #f5f5f5;
462
+ --container-bg: #ffffff;
463
+ --text-color: #000000;
464
+ --shadow: 0 2px 4px rgba(0,0,0,0.1);
465
+ }
466
+ }
467
+ @media (prefers-color-scheme: dark) {
468
+ :root {
469
+ --bg-color: #1a1a1a;
470
+ --container-bg: #2d2d2d;
471
+ --text-color: #ffffff;
472
+ --shadow: 0 2px 4px rgba(0,0,0,0.3);
473
+ }
474
+ }
475
+ body {
476
+ font-family: monospace;
477
+ display: flex;
478
+ justify-content: center;
479
+ align-items: center;
480
+ height: 100vh;
481
+ margin: 0;
482
+ background-color: var(--bg-color);
483
+ color: var(--text-color);
484
+ }
485
+ .container {
486
+ text-align: center;
487
+ padding: 2rem;
488
+ background: var(--container-bg);
489
+ border-radius: 8px;
490
+ box-shadow: var(--shadow);
491
+ }
492
+ .success-icon {
493
+ color: #AE87FF;
494
+ font-size: 32px;
495
+ margin-bottom: 1rem;
496
+ }
497
+ h2 { margin: 0 0 1rem 0; }
498
+ p { margin: 0; opacity: 0.8; }
499
+ .help-text {
500
+ margin-top: 1.5rem;
501
+ font-size: 0.9em;
502
+ opacity: 0.7;
503
+ text-align: left;
504
+ }
505
+ .help-text ol {
506
+ margin: 0;
507
+ padding-left: 1.5rem;
508
+ }
509
+ .help-text li { margin: 0.3rem 0; }
510
+ code {
511
+ background: var(--bg-color);
512
+ padding: 0.2em 0.4em;
513
+ border-radius: 4px;
514
+ font-family: monospace;
515
+ font-size: 0.9em;
516
+ }
517
+ a {
518
+ color: #AE87FF;
519
+ text-decoration: none;
520
+ }
521
+ a:hover { text-decoration: underline; }
522
+ </style>
523
+ </head>
524
+ <body>
525
+ <div class="container">
526
+ <div class="success-icon">\u2705</div>
527
+ <h2>Authentication Successful!</h2>
528
+ <p>You can close this window and return to the CLI.</p>
529
+ <div class="help-text">
530
+ <ol>
531
+ <li>Use command <code>basic help</code> to get started with the CLI</li>
532
+ <li>Visit the <a href="https://docs.basic.tech" target="_blank">Basic docs</a> for more info</li>
533
+ </ol>
534
+ </div>
535
+ </div>
536
+ <script>
537
+ setTimeout(() => window.close(), 3000);
538
+ </script>
539
+ </body>
540
+ </html>
541
+ `;
542
+ }
543
+ };
544
+ }
545
+ });
546
+
547
+ // dist/commands/login.js
548
+ var login_exports = {};
549
+ __export(login_exports, {
550
+ LoginCommand: () => LoginCommand
551
+ });
552
+ async function LoginCommand() {
553
+ if (!await isOnline()) {
554
+ throw new Error(MESSAGES.OFFLINE);
555
+ }
556
+ const authService = AuthService.getInstance();
557
+ const existingToken = await authService.getToken();
558
+ if (existingToken) {
559
+ console.log("Already logged in with a valid token.");
560
+ return;
561
+ }
562
+ console.log("\u{1F510} Opening browser for login...");
563
+ await authService.login();
564
+ console.log("\u2705 Login successful! Hello :)");
565
+ }
566
+ var init_login = __esm({
567
+ "dist/commands/login.js"() {
568
+ "use strict";
569
+ init_auth();
570
+ init_platform();
571
+ init_constants();
572
+ }
573
+ });
574
+
575
+ // dist/commands/logout.js
576
+ var logout_exports = {};
577
+ __export(logout_exports, {
578
+ LogoutCommand: () => LogoutCommand
579
+ });
580
+ async function LogoutCommand() {
581
+ const authService = AuthService.getInstance();
582
+ await authService.logout();
583
+ console.log("Logged out successfully");
584
+ }
585
+ var init_logout = __esm({
586
+ "dist/commands/logout.js"() {
587
+ "use strict";
588
+ init_auth();
589
+ }
590
+ });
591
+
592
+ // dist/commands/account.js
593
+ var account_exports = {};
594
+ __export(account_exports, {
595
+ AccountCommand: () => AccountCommand
596
+ });
597
+ async function AccountCommand() {
598
+ if (!await isOnline()) {
599
+ throw new Error(MESSAGES.OFFLINE);
600
+ }
601
+ const authService = AuthService.getInstance();
602
+ const token = await authService.getToken();
603
+ if (!token) {
604
+ throw new Error(MESSAGES.LOGGED_OUT);
605
+ }
606
+ const userInfo = await authService.getUserInfo();
607
+ console.log("Logged in user:", userInfo.email);
608
+ }
609
+ var init_account = __esm({
610
+ "dist/commands/account.js"() {
611
+ "use strict";
612
+ init_auth();
613
+ init_platform();
614
+ init_constants();
615
+ }
616
+ });
617
+
618
+ // dist/lib/api.js
619
+ var ApiClient;
620
+ var init_api = __esm({
621
+ "dist/lib/api.js"() {
622
+ "use strict";
623
+ init_constants();
624
+ init_auth();
625
+ init_errors();
626
+ ApiClient = class _ApiClient {
627
+ static instance;
628
+ authService;
629
+ constructor() {
630
+ this.authService = AuthService.getInstance();
631
+ }
632
+ static getInstance() {
633
+ if (!_ApiClient.instance) {
634
+ _ApiClient.instance = new _ApiClient();
635
+ }
636
+ return _ApiClient.instance;
637
+ }
638
+ async request(endpoint, options = {}) {
639
+ try {
640
+ const token = await this.authService.getToken();
641
+ const response = await fetch(`${CONSTANTS.API_BASE}${endpoint}`, {
642
+ ...options,
643
+ headers: {
644
+ "Content-Type": "application/json",
645
+ ...token && { Authorization: `Bearer ${token.access_token}` },
646
+ ...options.headers
647
+ }
648
+ });
649
+ if (!response.ok) {
650
+ const errorText = await response.text();
651
+ throw new ApiError(`API Error: ${response.status} - ${errorText}`, response.status);
652
+ }
653
+ return response.json();
654
+ } catch (error) {
655
+ throw handleError(error);
656
+ }
657
+ }
658
+ async getProjects() {
659
+ const response = await this.request("/project");
660
+ return response.data;
661
+ }
662
+ async createProject(data) {
663
+ const response = await this.request("/project", {
664
+ method: "POST",
665
+ body: JSON.stringify(data)
666
+ });
667
+ return response.data;
668
+ }
669
+ async createProjectWithTeam(name, slug, teamId) {
670
+ const response = await this.request("/project", {
671
+ method: "POST",
672
+ body: JSON.stringify({
673
+ name,
674
+ slug,
675
+ team_id: teamId
676
+ })
677
+ });
678
+ return response.data;
679
+ }
680
+ async getProject(projectId) {
681
+ const response = await this.request(`/project/${projectId}`);
682
+ return response.data;
683
+ }
684
+ async getTeams() {
685
+ const response = await this.request("/team");
686
+ return response.data;
687
+ }
688
+ async createTeam(name, slug) {
689
+ const response = await this.request("/team", {
690
+ method: "POST",
691
+ body: JSON.stringify({ name, slug })
692
+ });
693
+ return response.data;
694
+ }
695
+ async checkTeamSlugAvailability(slug) {
696
+ try {
697
+ const response = await this.request(`/team/slug?slug=${encodeURIComponent(slug)}`);
698
+ return response.available;
699
+ } catch (error) {
700
+ return false;
701
+ }
702
+ }
703
+ async getProjectSchema(projectId) {
704
+ try {
705
+ const response = await this.request(`/project/${projectId}/schema`);
706
+ if (response.data.length === 0) {
707
+ return null;
708
+ }
709
+ return response.data[0].schema;
710
+ } catch (error) {
711
+ if (error instanceof ApiError && error.statusCode === 404) {
712
+ return null;
713
+ }
714
+ throw error;
715
+ }
716
+ }
717
+ async pushProjectSchema(projectId, schema) {
718
+ await this.request(`/project/${projectId}/schema`, {
719
+ method: "POST",
720
+ body: JSON.stringify({ schema })
721
+ });
722
+ }
723
+ async validateSchema(schema) {
724
+ const response = await this.request("/utils/schema/verifyUpdateSchema", {
725
+ method: "POST",
726
+ body: JSON.stringify({ schema })
727
+ });
728
+ return response;
729
+ }
730
+ async compareSchema(schema) {
731
+ const response = await this.request("/utils/schema/compareSchema", {
732
+ method: "POST",
733
+ body: JSON.stringify({ schema })
734
+ });
735
+ return response;
736
+ }
737
+ async checkLatestRelease() {
738
+ try {
739
+ const response = await fetch(`https://registry.npmjs.org/@basictech/cli/latest`);
740
+ if (!response.ok) {
741
+ throw new Error("Failed to check for updates");
742
+ }
743
+ const data = await response.json();
744
+ return data.version;
745
+ } catch (error) {
746
+ throw handleError(error);
747
+ }
748
+ }
749
+ };
750
+ }
751
+ });
752
+
753
+ // dist/commands/version.js
754
+ var version_exports = {};
755
+ __export(version_exports, {
756
+ VersionCommand: () => VersionCommand
757
+ });
758
+ async function VersionCommand() {
759
+ const currentVersion = getVersion();
760
+ console.log(`basic-cli version ${currentVersion}`);
761
+ try {
762
+ const apiClient = ApiClient.getInstance();
763
+ const latestVersion = await apiClient.checkLatestRelease();
764
+ if (latestVersion !== currentVersion) {
765
+ console.log(`New version available: ${latestVersion}`);
766
+ console.log("\nPlease update with 'basic update'");
767
+ } else {
768
+ console.log("You are running the latest version!");
769
+ }
770
+ } catch (error) {
771
+ console.log("\nOopsy - could not check if new version is available.");
772
+ }
773
+ }
774
+ var init_version2 = __esm({
775
+ "dist/commands/version.js"() {
776
+ "use strict";
777
+ init_version();
778
+ init_api();
779
+ }
780
+ });
781
+
782
+ // dist/commands/update.js
783
+ var update_exports = {};
784
+ __export(update_exports, {
785
+ UpdateCommand: () => UpdateCommand
786
+ });
787
+ import { spawn } from "child_process";
788
+ async function UpdateCommand() {
789
+ try {
790
+ if (!await isOnline()) {
791
+ console.error(MESSAGES.OFFLINE);
792
+ process.exit(1);
793
+ }
794
+ const currentVersion = getVersion();
795
+ console.log(`Current version: ${currentVersion}`);
796
+ console.log("Checking for updates...");
797
+ const apiClient = ApiClient.getInstance();
798
+ const latestVersion = await apiClient.checkLatestRelease();
799
+ if (latestVersion === currentVersion) {
800
+ console.log("\u2705 You are already running the latest version!");
801
+ return;
802
+ }
803
+ console.log(`\u{1F680} New version available: ${latestVersion}`);
804
+ console.log("Updating...");
805
+ await updatePackage();
806
+ } catch (error) {
807
+ console.error("\u274C Error checking for updates:", error instanceof Error ? error.message : "Unknown error");
808
+ console.log("\n\u{1F4A1} You can try updating manually:");
809
+ console.log(" npm update -g @basictech/cli");
810
+ console.log("\n\u{1F4DA} Or visit: https://docs.basic.tech");
10
811
  process.exit(1);
812
+ }
813
+ }
814
+ async function updatePackage() {
815
+ return new Promise((resolve, reject) => {
816
+ const updateProcess = spawn("npm", ["update", "-g", "@basictech/cli"], {
817
+ stdio: "pipe",
818
+ shell: true
819
+ });
820
+ let output = "";
821
+ let errorOutput = "";
822
+ updateProcess.stdout?.on("data", (data) => {
823
+ output += data.toString();
824
+ });
825
+ updateProcess.stderr?.on("data", (data) => {
826
+ errorOutput += data.toString();
827
+ });
828
+ updateProcess.on("close", (code) => {
829
+ if (code === 0) {
830
+ console.log("\u2705 Update successful!");
831
+ console.log("\n\u{1F389} Basic CLI has been updated to the latest version.");
832
+ console.log("\u{1F4A1} Run `basic version` to verify the update.");
833
+ resolve();
834
+ } else {
835
+ console.error("\u274C Error updating CLI");
836
+ console.log("\n\u{1F4A1} Please try updating manually:");
837
+ console.log(" npm update -g @basictech/cli");
838
+ console.log("\n\u{1F4DA} Or visit: https://docs.basic.tech");
839
+ if (errorOutput) {
840
+ console.log("\nError details:", errorOutput);
841
+ }
842
+ reject(new Error(`Update process exited with code ${code}`));
843
+ }
844
+ });
845
+ updateProcess.on("error", (error) => {
846
+ console.error("\u274C Failed to start update process");
847
+ console.log("\n\u{1F4A1} Please try updating manually:");
848
+ console.log(" npm update -g @basictech/cli");
849
+ console.log("\n\u{1F4DA} Or visit: https://docs.basic.tech");
850
+ reject(error);
851
+ });
852
+ });
853
+ }
854
+ var init_update = __esm({
855
+ "dist/commands/update.js"() {
856
+ "use strict";
857
+ init_version();
858
+ init_api();
859
+ init_platform();
860
+ init_constants();
861
+ }
11
862
  });
12
- process.on('SIGINT', () => {
13
- console.log('\nOperation cancelled');
14
- process.exit(0);
863
+
864
+ // dist/commands/debug.js
865
+ var debug_exports = {};
866
+ __export(debug_exports, {
867
+ DebugCommand: () => DebugCommand
15
868
  });
16
- // Configure the CLI
17
- program
18
- .name('basic')
19
- .description('Basic CLI for creating & managing your projects')
20
- .version(getVersion());
21
- // Login command
22
- program
23
- .command('login')
24
- .description('Login to your Basic account')
25
- .action(async () => {
26
- try {
27
- const { LoginCommand } = await import('./commands/login.js');
28
- await LoginCommand();
869
+ async function DebugCommand() {
870
+ const configDir = getConfigDir();
871
+ console.log(`Basic CLI config directory: ${configDir}`);
872
+ }
873
+ var init_debug = __esm({
874
+ "dist/commands/debug.js"() {
875
+ "use strict";
876
+ init_platform();
877
+ }
878
+ });
879
+
880
+ // dist/components/Table.js
881
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
882
+ import { useState, useEffect } from "react";
883
+ import { Box, Text, useInput } from "ink";
884
+ function Table({ columns, rows, onSelect, onCopy, onOpen, onNew, onExit, helpText }) {
885
+ const [selectedIndex, setSelectedIndex] = useState(0);
886
+ const [notification, setNotification] = useState("");
887
+ const defaultHelpText = {
888
+ copyAction: "'c' to copy project ID",
889
+ openAction: "'o' to open in browser",
890
+ newAction: void 0
891
+ };
892
+ const currentHelpText = helpText || defaultHelpText;
893
+ useInput((input, key) => {
894
+ if (key.upArrow && rows.length > 0) {
895
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
896
+ } else if (key.downArrow && rows.length > 0) {
897
+ setSelectedIndex((prev) => Math.min(rows.length - 1, prev + 1));
898
+ } else if (key.return && rows[selectedIndex] && onSelect) {
899
+ onSelect(rows[selectedIndex], selectedIndex);
900
+ } else if (input === "c" && rows[selectedIndex] && onCopy) {
901
+ onCopy(rows[selectedIndex], selectedIndex);
902
+ const itemType = helpText?.copyAction.includes("team") ? "Team ID" : "Project ID";
903
+ setNotification(`${itemType} copied to clipboard!`);
904
+ setTimeout(() => setNotification(""), 3e3);
905
+ } else if (input === "o" && rows[selectedIndex] && onOpen) {
906
+ onOpen(rows[selectedIndex], selectedIndex);
907
+ } else if (input === "n" && onNew) {
908
+ onNew();
909
+ } else if (key.escape || key.ctrl && input === "c") {
910
+ if (onExit) {
911
+ onExit();
912
+ } else {
29
913
  process.exit(0);
914
+ }
30
915
  }
31
- catch (error) {
32
- const cliError = handleError(error);
33
- console.error(formatError(cliError));
34
- process.exit(1);
916
+ });
917
+ useEffect(() => {
918
+ if (selectedIndex >= rows.length) {
919
+ setSelectedIndex(Math.max(0, rows.length - 1));
35
920
  }
921
+ }, [rows.length, selectedIndex]);
922
+ const renderHeader = () => _jsx(Box, { borderStyle: "single", borderBottom: true, paddingX: 1, children: _jsx(Box, { children: columns.map((column, index) => _jsx(Box, { width: column.width, marginRight: index < columns.length - 1 ? 1 : 0, children: _jsx(Text, { bold: true, children: column.title }) }, column.key)) }) });
923
+ const renderRow = (row, index) => {
924
+ const isSelected = index === selectedIndex;
925
+ return _jsx(Box, { children: _jsx(Box, { paddingX: 1, children: columns.map((column, colIndex) => _jsx(Box, { width: column.width, marginRight: colIndex < columns.length - 1 ? 1 : 0, children: _jsx(Text, { color: isSelected ? "black" : void 0, backgroundColor: isSelected ? "magenta" : void 0, children: (row[column.key] || "").substring(0, column.width - 1) }) }, column.key)) }) }, index);
926
+ };
927
+ const renderHelp = () => {
928
+ const mainActionsText = [
929
+ currentHelpText.copyAction,
930
+ currentHelpText.openAction
931
+ ].filter(Boolean).join(" \u2022 ");
932
+ return _jsxs(Box, { marginTop: 2, children: [notification && _jsx(Box, { marginBottom: 2, children: _jsx(Text, { color: "blue", children: notification }) }), _jsxs(Box, { flexDirection: "column", children: [currentHelpText.newAction && _jsx(Text, { color: "gray", children: currentHelpText.newAction }), _jsx(Text, { color: "gray", children: mainActionsText }), _jsx(Text, { color: "gray", children: "\u2191/\u2193 to navigate \u2022 esc to quit" })] })] });
933
+ };
934
+ if (rows.length === 0) {
935
+ const itemType = helpText?.copyAction.includes("team") ? "teams" : "projects";
936
+ return _jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: ["No ", itemType, " found."] }), _jsxs(Box, { marginTop: 2, flexDirection: "column", children: [currentHelpText.newAction && _jsx(Text, { color: "gray", children: currentHelpText.newAction }), _jsx(Text, { color: "gray", children: "Press esc to quit" })] })] });
937
+ }
938
+ return _jsxs(Box, { flexDirection: "column", children: [renderHeader(), _jsx(Box, { flexDirection: "column", children: rows.map((row, index) => renderRow(row, index)) }), renderHelp()] });
939
+ }
940
+ var init_Table = __esm({
941
+ "dist/components/Table.js"() {
942
+ "use strict";
943
+ }
36
944
  });
37
- // Logout command
38
- program
39
- .command('logout')
40
- .description('Logout from your Basic account')
41
- .action(async () => {
945
+
946
+ // dist/components/Spinner.js
947
+ import { jsx as _jsx2, jsxs as _jsxs2 } from "react/jsx-runtime";
948
+ import React from "react";
949
+ import { Text as Text2 } from "ink";
950
+ var spinnerFrames, Spinner;
951
+ var init_Spinner = __esm({
952
+ "dist/components/Spinner.js"() {
953
+ "use strict";
954
+ spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
955
+ Spinner = ({ text = "Loading..." }) => {
956
+ const [frame, setFrame] = React.useState(0);
957
+ React.useEffect(() => {
958
+ const timer = setInterval(() => {
959
+ setFrame((prev) => (prev + 1) % spinnerFrames.length);
960
+ }, 80);
961
+ return () => clearInterval(timer);
962
+ }, []);
963
+ return _jsxs2(Text2, { children: [_jsx2(Text2, { color: "cyan", children: spinnerFrames[frame] }), " ", text] });
964
+ };
965
+ }
966
+ });
967
+
968
+ // dist/commands/projects.js
969
+ var projects_exports = {};
970
+ __export(projects_exports, {
971
+ ProjectsCommand: () => ProjectsCommand
972
+ });
973
+ import { jsx as _jsx3 } from "react/jsx-runtime";
974
+ import React2 from "react";
975
+ import { render, Text as Text3 } from "ink";
976
+ function ProjectsApp() {
977
+ const [state, setState] = React2.useState({
978
+ loading: true,
979
+ projects: [],
980
+ error: null
981
+ });
982
+ React2.useEffect(() => {
983
+ async function loadProjects() {
984
+ try {
985
+ if (!await isOnline()) {
986
+ setState((prev) => ({ ...prev, loading: false, error: MESSAGES.OFFLINE }));
987
+ return;
988
+ }
989
+ const authService = AuthService.getInstance();
990
+ const token = await authService.getToken();
991
+ if (!token) {
992
+ setState((prev) => ({ ...prev, loading: false, error: MESSAGES.LOGGED_OUT }));
993
+ return;
994
+ }
995
+ const apiClient = ApiClient.getInstance();
996
+ const projects = await apiClient.getProjects();
997
+ setState({
998
+ loading: false,
999
+ projects,
1000
+ error: null
1001
+ });
1002
+ } catch (error) {
1003
+ setState({
1004
+ loading: false,
1005
+ projects: [],
1006
+ error: error instanceof Error ? error.message : "Failed to load projects"
1007
+ });
1008
+ }
1009
+ }
1010
+ loadProjects();
1011
+ }, []);
1012
+ const handleCopy = async (row) => {
42
1013
  try {
43
- const { LogoutCommand } = await import('./commands/logout.js');
44
- await LogoutCommand();
45
- process.exit(0);
1014
+ await copyToClipboard(row.id);
1015
+ } catch (error) {
46
1016
  }
47
- catch (error) {
48
- const cliError = handleError(error);
49
- console.error(formatError(cliError));
50
- process.exit(1);
1017
+ };
1018
+ const handleOpen = async (row) => {
1019
+ try {
1020
+ await openBrowser(`https://app.basic.tech/project/${row.id}`);
1021
+ } catch (error) {
51
1022
  }
1023
+ };
1024
+ const handleExit = () => {
1025
+ process.exit(0);
1026
+ };
1027
+ if (state.loading) {
1028
+ return _jsx3(Spinner, { text: "Loading projects..." });
1029
+ }
1030
+ if (state.error) {
1031
+ return _jsx3(Text3, { color: "red", children: state.error });
1032
+ }
1033
+ const columns = [
1034
+ { title: "ID", width: 38, key: "id" },
1035
+ { title: "Name", width: 25, key: "name" },
1036
+ { title: "Team", width: 30, key: "team_name" }
1037
+ ];
1038
+ const rows = state.projects.map((project) => ({
1039
+ id: project.id,
1040
+ name: project.name,
1041
+ team_name: project.team_name
1042
+ }));
1043
+ return _jsx3(Table, { columns, rows, onCopy: handleCopy, onOpen: handleOpen, onExit: handleExit });
1044
+ }
1045
+ async function ProjectsCommand() {
1046
+ render(_jsx3(ProjectsApp, {}));
1047
+ }
1048
+ var init_projects = __esm({
1049
+ "dist/commands/projects.js"() {
1050
+ "use strict";
1051
+ init_Table();
1052
+ init_Spinner();
1053
+ init_api();
1054
+ init_auth();
1055
+ init_platform();
1056
+ init_constants();
1057
+ }
52
1058
  });
53
- // Account command
54
- program
55
- .command('account')
56
- .description('Show account information')
57
- .action(async () => {
58
- try {
59
- const { AccountCommand } = await import('./commands/account.js');
60
- await AccountCommand();
61
- process.exit(0);
1059
+
1060
+ // dist/components/TeamForm.js
1061
+ import { jsx as _jsx4, jsxs as _jsxs3 } from "react/jsx-runtime";
1062
+ import { useState as useState2, useEffect as useEffect2 } from "react";
1063
+ import { Box as Box2, Text as Text4, useInput as useInput2 } from "ink";
1064
+ function TeamForm({ title, onSubmit, onCancel }) {
1065
+ const [state, setState] = useState2({
1066
+ teamName: "",
1067
+ teamSlug: "",
1068
+ currentField: "name",
1069
+ isCheckingSlug: false,
1070
+ slugAvailable: null,
1071
+ error: null
1072
+ });
1073
+ useEffect2(() => {
1074
+ if (state.teamName.trim()) {
1075
+ const newSlug = generateSlug(state.teamName);
1076
+ setState((prev) => ({
1077
+ ...prev,
1078
+ teamSlug: newSlug,
1079
+ slugAvailable: null,
1080
+ error: null
1081
+ }));
1082
+ } else {
1083
+ setState((prev) => ({
1084
+ ...prev,
1085
+ teamSlug: "",
1086
+ slugAvailable: null,
1087
+ error: null
1088
+ }));
1089
+ }
1090
+ }, [state.teamName]);
1091
+ useEffect2(() => {
1092
+ if (state.teamSlug.trim() && (state.currentField === "name" || state.currentField === "slug")) {
1093
+ const checkAvailability = async () => {
1094
+ setState((prev) => ({ ...prev, isCheckingSlug: true, error: null }));
1095
+ try {
1096
+ const apiClient = ApiClient.getInstance();
1097
+ const available = await apiClient.checkTeamSlugAvailability(state.teamSlug);
1098
+ setState((prev) => ({
1099
+ ...prev,
1100
+ isCheckingSlug: false,
1101
+ slugAvailable: available,
1102
+ error: available ? null : "Team slug is already taken"
1103
+ }));
1104
+ } catch (error) {
1105
+ setState((prev) => ({
1106
+ ...prev,
1107
+ isCheckingSlug: false,
1108
+ slugAvailable: false,
1109
+ error: "Error checking slug availability"
1110
+ }));
1111
+ }
1112
+ };
1113
+ const timeoutId = setTimeout(checkAvailability, 500);
1114
+ return () => clearTimeout(timeoutId);
1115
+ }
1116
+ }, [state.teamSlug, state.currentField]);
1117
+ useInput2((input, key) => {
1118
+ if (state.currentField === "submitting") {
1119
+ return;
1120
+ }
1121
+ if (key.escape) {
1122
+ onCancel();
1123
+ return;
1124
+ }
1125
+ if (key.return) {
1126
+ if (state.currentField === "name") {
1127
+ if (!state.teamName.trim()) {
1128
+ setState((prev) => ({ ...prev, error: "Team name is required" }));
1129
+ return;
1130
+ }
1131
+ setState((prev) => ({ ...prev, currentField: "slug", error: null }));
1132
+ return;
1133
+ }
1134
+ if (state.currentField === "slug") {
1135
+ if (!state.teamSlug.trim()) {
1136
+ setState((prev) => ({ ...prev, error: "Team slug is required" }));
1137
+ return;
1138
+ }
1139
+ if (!state.slugAvailable) {
1140
+ setState((prev) => ({ ...prev, error: "Please wait for slug availability check or choose a different name" }));
1141
+ return;
1142
+ }
1143
+ setState((prev) => ({ ...prev, currentField: "submitting", error: null }));
1144
+ const result = onSubmit({ teamName: state.teamName, teamSlug: state.teamSlug });
1145
+ if (result instanceof Promise) {
1146
+ result.catch((error) => {
1147
+ setState((prev) => ({
1148
+ ...prev,
1149
+ currentField: "slug",
1150
+ error: error.message || "Failed to create team"
1151
+ }));
1152
+ });
1153
+ }
1154
+ return;
1155
+ }
1156
+ }
1157
+ if (key.backspace || key.delete) {
1158
+ if (state.currentField === "name") {
1159
+ setState((prev) => ({
1160
+ ...prev,
1161
+ teamName: prev.teamName.slice(0, -1),
1162
+ error: null
1163
+ }));
1164
+ } else if (state.currentField === "slug") {
1165
+ setState((prev) => ({
1166
+ ...prev,
1167
+ teamSlug: prev.teamSlug.slice(0, -1),
1168
+ error: null
1169
+ }));
1170
+ }
1171
+ return;
62
1172
  }
63
- catch (error) {
64
- const cliError = handleError(error);
65
- console.error(formatError(cliError));
66
- process.exit(1);
1173
+ if (input && input.length === 1) {
1174
+ if (state.currentField === "name") {
1175
+ setState((prev) => ({
1176
+ ...prev,
1177
+ teamName: prev.teamName + input,
1178
+ error: null
1179
+ }));
1180
+ } else if (state.currentField === "slug") {
1181
+ setState((prev) => ({
1182
+ ...prev,
1183
+ teamSlug: prev.teamSlug + input,
1184
+ error: null
1185
+ }));
1186
+ }
67
1187
  }
1188
+ });
1189
+ const getSlugStatus = () => {
1190
+ if (!state.teamSlug.trim())
1191
+ return null;
1192
+ if (state.isCheckingSlug)
1193
+ return "checking";
1194
+ if (state.slugAvailable === true)
1195
+ return "available";
1196
+ if (state.slugAvailable === false)
1197
+ return "unavailable";
1198
+ return null;
1199
+ };
1200
+ const getSlugStatusText = () => {
1201
+ const status = getSlugStatus();
1202
+ switch (status) {
1203
+ case "checking":
1204
+ return "\u23F3 Checking availability...";
1205
+ case "available":
1206
+ return "\u2705 Slug available";
1207
+ case "unavailable":
1208
+ return "\u274C Slug not available";
1209
+ default:
1210
+ return "";
1211
+ }
1212
+ };
1213
+ const getSlugStatusColor = () => {
1214
+ const status = getSlugStatus();
1215
+ switch (status) {
1216
+ case "checking":
1217
+ return "yellow";
1218
+ case "available":
1219
+ return "green";
1220
+ case "unavailable":
1221
+ return "red";
1222
+ default:
1223
+ return "gray";
1224
+ }
1225
+ };
1226
+ const canSubmit = state.teamName.trim() && state.slugAvailable === true && !state.isCheckingSlug;
1227
+ const getHelpText = () => {
1228
+ if (state.currentField === "name") {
1229
+ return state.teamName.trim() ? "Enter to edit slug \u2022 esc to cancel" : "Type team name \u2022 esc to cancel";
1230
+ } else if (state.currentField === "slug") {
1231
+ return canSubmit ? "Enter to create team \u2022 esc to cancel" : "Edit team slug \u2022 esc to cancel";
1232
+ }
1233
+ return "esc to cancel";
1234
+ };
1235
+ return _jsxs3(Box2, { flexDirection: "column", padding: 1, children: [_jsx4(Box2, { marginBottom: 2, children: _jsx4(Text4, { bold: true, color: "blue", children: title }) }), _jsxs3(Box2, { flexDirection: "column", marginBottom: 1, children: [_jsx4(Box2, { children: _jsxs3(Text4, { color: state.currentField === "name" ? "blue" : "gray", children: [state.currentField === "name" ? ">" : "\u2713", " Team Name:"] }) }), _jsx4(Box2, { marginLeft: 2, children: _jsxs3(Text4, { children: [state.teamName, state.currentField === "name" && _jsx4(Text4, { backgroundColor: "white", color: "black", children: "\u2588" })] }) })] }), state.teamSlug && _jsxs3(Box2, { flexDirection: "column", marginBottom: 1, children: [_jsx4(Box2, { children: _jsxs3(Text4, { color: state.currentField === "slug" ? "blue" : "gray", children: [state.currentField === "slug" ? ">" : "\u2713", " Team Slug", state.currentField === "name" ? " (auto-generated)" : "", ":"] }) }), _jsx4(Box2, { marginLeft: 2, children: _jsxs3(Text4, { children: [state.teamSlug, state.currentField === "slug" && _jsx4(Text4, { backgroundColor: "white", color: "black", children: "\u2588" })] }) }), getSlugStatus() && _jsx4(Box2, { marginLeft: 2, children: _jsx4(Text4, { color: getSlugStatusColor(), children: getSlugStatusText() }) })] }), state.error && _jsx4(Box2, { marginLeft: 2, marginBottom: 1, children: _jsxs3(Text4, { color: "red", children: ["Error: ", state.error] }) }), _jsx4(Box2, { marginTop: 2, children: _jsx4(Text4, { color: "gray", children: getHelpText() }) })] });
1236
+ }
1237
+ var init_TeamForm = __esm({
1238
+ "dist/components/TeamForm.js"() {
1239
+ "use strict";
1240
+ init_api();
1241
+ init_platform();
1242
+ }
1243
+ });
1244
+
1245
+ // dist/commands/teams.js
1246
+ var teams_exports = {};
1247
+ __export(teams_exports, {
1248
+ TeamsCommand: () => TeamsCommand
68
1249
  });
69
- // Version command (override default to show update info)
70
- program
71
- .command('version')
72
- .description('Show CLI version')
73
- .action(async () => {
1250
+ import { jsx as _jsx5, jsxs as _jsxs4 } from "react/jsx-runtime";
1251
+ import React3 from "react";
1252
+ import { render as render2, Box as Box3, Text as Text5 } from "ink";
1253
+ function TeamsApp() {
1254
+ const [state, setState] = React3.useState({
1255
+ loading: true,
1256
+ teams: [],
1257
+ error: null
1258
+ });
1259
+ React3.useEffect(() => {
1260
+ async function loadTeams() {
1261
+ try {
1262
+ if (!await isOnline()) {
1263
+ setState((prev) => ({ ...prev, loading: false, error: MESSAGES.OFFLINE }));
1264
+ return;
1265
+ }
1266
+ const authService = AuthService.getInstance();
1267
+ const token = await authService.getToken();
1268
+ if (!token) {
1269
+ setState((prev) => ({ ...prev, loading: false, error: MESSAGES.LOGGED_OUT }));
1270
+ return;
1271
+ }
1272
+ const apiClient = ApiClient.getInstance();
1273
+ const teams = await apiClient.getTeams();
1274
+ setState({
1275
+ loading: false,
1276
+ teams,
1277
+ error: null
1278
+ });
1279
+ } catch (error) {
1280
+ setState({
1281
+ loading: false,
1282
+ teams: [],
1283
+ error: error instanceof Error ? error.message : "Failed to load teams"
1284
+ });
1285
+ }
1286
+ }
1287
+ loadTeams();
1288
+ }, []);
1289
+ const handleCopy = async (row) => {
74
1290
  try {
75
- const { VersionCommand } = await import('./commands/version.js');
76
- await VersionCommand();
77
- process.exit(0);
1291
+ await copyToClipboard(row.id);
1292
+ } catch (error) {
78
1293
  }
79
- catch (error) {
80
- const cliError = handleError(error);
81
- console.error(formatError(cliError));
82
- process.exit(1);
1294
+ };
1295
+ const handleOpen = async (row) => {
1296
+ try {
1297
+ await openBrowser(`https://app.basic.tech/team/${row.slug}`);
1298
+ } catch (error) {
83
1299
  }
84
- });
85
- // Update command
86
- program
87
- .command('update')
88
- .description('Update CLI to the latest version')
89
- .action(async () => {
1300
+ };
1301
+ const handleExit = () => {
1302
+ process.exit(0);
1303
+ };
1304
+ const handleNew = () => {
1305
+ render2(_jsx5(NewTeamApp, {}));
1306
+ };
1307
+ if (state.loading) {
1308
+ return _jsx5(Spinner, { text: "Loading teams..." });
1309
+ }
1310
+ if (state.error) {
1311
+ return _jsx5(Text5, { color: "red", children: state.error });
1312
+ }
1313
+ const columns = [
1314
+ { title: "ID", width: 38, key: "id" },
1315
+ { title: "Name", width: 25, key: "name" },
1316
+ { title: "Role", width: 20, key: "role_name" }
1317
+ ];
1318
+ const rows = state.teams.map((team) => ({
1319
+ id: team.id,
1320
+ name: team.name,
1321
+ role_name: team.role_name || "Member",
1322
+ slug: team.slug
1323
+ }));
1324
+ return _jsx5(Table, { columns, rows, onCopy: handleCopy, onOpen: handleOpen, onExit: handleExit, onNew: handleNew, helpText: {
1325
+ copyAction: "'c' to copy team ID",
1326
+ openAction: "'o' to open in browser",
1327
+ newAction: "'n' to create a new team"
1328
+ } });
1329
+ }
1330
+ function NewTeamApp() {
1331
+ const [state, setState] = React3.useState({
1332
+ loading: false,
1333
+ error: null,
1334
+ success: false,
1335
+ teamName: "",
1336
+ teamSlug: ""
1337
+ });
1338
+ const handleSubmit = async (data) => {
1339
+ setState((prev) => ({ ...prev, loading: true, error: null }));
90
1340
  try {
91
- const { UpdateCommand } = await import('./commands/update.js');
92
- await UpdateCommand();
1341
+ if (!await isOnline()) {
1342
+ setState((prev) => ({ ...prev, loading: false, error: MESSAGES.OFFLINE }));
1343
+ return;
1344
+ }
1345
+ const authService = AuthService.getInstance();
1346
+ const token = await authService.getToken();
1347
+ if (!token) {
1348
+ setState((prev) => ({ ...prev, loading: false, error: MESSAGES.LOGGED_OUT }));
1349
+ return;
1350
+ }
1351
+ const apiClient = ApiClient.getInstance();
1352
+ await apiClient.createTeam(data.teamName, data.teamSlug);
1353
+ setState({
1354
+ loading: false,
1355
+ error: null,
1356
+ success: true,
1357
+ teamName: data.teamName,
1358
+ teamSlug: data.teamSlug
1359
+ });
1360
+ setTimeout(() => {
93
1361
  process.exit(0);
1362
+ }, 2e3);
1363
+ } catch (error) {
1364
+ setState((prev) => ({
1365
+ ...prev,
1366
+ loading: false,
1367
+ error: error instanceof Error ? error.message : "Failed to create team"
1368
+ }));
94
1369
  }
95
- catch (error) {
96
- const cliError = handleError(error);
97
- console.error(formatError(cliError));
98
- process.exit(1);
99
- }
1370
+ };
1371
+ if (state.loading) {
1372
+ return _jsx5(Spinner, { text: "Creating team..." });
1373
+ }
1374
+ if (state.success) {
1375
+ return _jsxs4(Box3, { flexDirection: "column", children: [_jsxs4(Text5, { color: "green", children: ['\u2705 Team "', state.teamName, '" created successfully!'] }), _jsxs4(Text5, { children: ["Team slug: ", state.teamSlug] })] });
1376
+ }
1377
+ if (state.error) {
1378
+ return _jsx5(Text5, { color: "red", children: state.error });
1379
+ }
1380
+ return _jsx5(TeamForm, { title: "Create New Team", onSubmit: handleSubmit, onCancel: () => process.exit(0) });
1381
+ }
1382
+ async function TeamsCommand(action) {
1383
+ if (action === "new") {
1384
+ render2(_jsx5(NewTeamApp, {}));
1385
+ } else {
1386
+ render2(_jsx5(TeamsApp, {}));
1387
+ }
1388
+ }
1389
+ var init_teams = __esm({
1390
+ "dist/commands/teams.js"() {
1391
+ "use strict";
1392
+ init_Table();
1393
+ init_Spinner();
1394
+ init_TeamForm();
1395
+ init_api();
1396
+ init_auth();
1397
+ init_platform();
1398
+ init_constants();
1399
+ }
100
1400
  });
101
- // Help command
102
- program
103
- .command('help')
104
- .description('Show help information')
105
- .action(() => {
106
- program.help();
1401
+
1402
+ // dist/lib/schema.js
1403
+ var schema_exports = {};
1404
+ __export(schema_exports, {
1405
+ compareVersions: () => compareVersions,
1406
+ parseSchemaFile: () => parseSchemaFile,
1407
+ readSchemaFromConfig: () => readSchemaFromConfig,
1408
+ saveSchemaToConfig: () => saveSchemaToConfig
107
1409
  });
108
- // Debug command
109
- program
110
- .command('debug')
111
- .description('Show Basic config directory location')
112
- .action(async () => {
1410
+ import * as fs2 from "fs/promises";
1411
+ import * as path2 from "path";
1412
+ import { parse } from "@babel/parser";
1413
+ async function readSchemaFromConfig(targetDir = process.cwd()) {
1414
+ const possibleFiles = [
1415
+ "basic.config.ts",
1416
+ "basic.config.js",
1417
+ "basic.config.json"
1418
+ ];
1419
+ for (const filename of possibleFiles) {
1420
+ const filePath = path2.join(targetDir, filename);
113
1421
  try {
114
- const { DebugCommand } = await import('./commands/debug.js');
115
- await DebugCommand();
116
- process.exit(0);
1422
+ await fs2.access(filePath);
1423
+ const content = await fs2.readFile(filePath, "utf8");
1424
+ let schema;
1425
+ if (filename.endsWith(".json")) {
1426
+ schema = JSON.parse(content);
1427
+ } else {
1428
+ schema = extractSchemaFromCode(content);
1429
+ }
1430
+ if (!schema.project_id) {
1431
+ throw new Error("No project_id found in schema");
1432
+ }
1433
+ return {
1434
+ schema,
1435
+ projectId: schema.project_id,
1436
+ filePath
1437
+ };
1438
+ } catch (error) {
1439
+ if (error.code === "ENOENT") {
1440
+ continue;
1441
+ }
1442
+ throw new Error(`Error reading ${filename}: ${error instanceof Error ? error.message : "Unknown error"}`);
1443
+ }
1444
+ }
1445
+ return null;
1446
+ }
1447
+ function extractSchemaFromCode(content) {
1448
+ try {
1449
+ const ast = parse(content, {
1450
+ sourceType: "module",
1451
+ plugins: ["typescript", "jsx"]
1452
+ });
1453
+ const schemaExport = ast.program.body.find((node) => {
1454
+ if (node.type === "ExportNamedDeclaration") {
1455
+ const declaration = node.declaration;
1456
+ if (declaration?.type === "VariableDeclaration") {
1457
+ const variable = declaration.declarations[0];
1458
+ return variable.id.type === "Identifier" && variable.id.name === "schema";
1459
+ }
1460
+ }
1461
+ return false;
1462
+ });
1463
+ if (!schemaExport) {
1464
+ throw new Error("Could not find schema export in config file");
117
1465
  }
118
- catch (error) {
119
- const cliError = handleError(error);
120
- console.error(formatError(cliError));
121
- process.exit(1);
1466
+ const schemaNode = schemaExport.declaration.declarations[0].init;
1467
+ if (!schemaNode || schemaNode.type !== "ObjectExpression") {
1468
+ throw new Error("Schema export must be an object");
122
1469
  }
1470
+ const schema = convertAstToObject(schemaNode);
1471
+ if (!schema.project_id || typeof schema.project_id !== "string") {
1472
+ throw new Error("Schema must have a project_id string field");
1473
+ }
1474
+ if (typeof schema.version !== "number") {
1475
+ throw new Error("Schema must have a version number field");
1476
+ }
1477
+ if (!schema.tables || typeof schema.tables !== "object") {
1478
+ throw new Error("Schema must have a tables object field");
1479
+ }
1480
+ return schema;
1481
+ } catch (error) {
1482
+ throw new Error(`Error parsing schema: ${error instanceof Error ? error.message : "Unknown error"}`);
1483
+ }
1484
+ }
1485
+ function convertAstToObject(node) {
1486
+ if (node.type === "ObjectExpression") {
1487
+ const obj = {};
1488
+ for (const prop of node.properties) {
1489
+ if (prop.type === "ObjectProperty") {
1490
+ const key = getPropertyKey(prop);
1491
+ obj[key] = convertAstToObject(prop.value);
1492
+ }
1493
+ }
1494
+ return obj;
1495
+ }
1496
+ if (node.type === "ArrayExpression") {
1497
+ return node.elements.map((element) => element ? convertAstToObject(element) : null);
1498
+ }
1499
+ if (node.type === "StringLiteral") {
1500
+ return node.value;
1501
+ }
1502
+ if (node.type === "NumericLiteral") {
1503
+ return node.value;
1504
+ }
1505
+ if (node.type === "BooleanLiteral") {
1506
+ return node.value;
1507
+ }
1508
+ if (node.type === "NullLiteral") {
1509
+ return null;
1510
+ }
1511
+ if (node.type === "Identifier") {
1512
+ if (node.name === "true")
1513
+ return true;
1514
+ if (node.name === "false")
1515
+ return false;
1516
+ if (node.name === "null")
1517
+ return null;
1518
+ throw new Error(`Unexpected identifier: ${node.name}`);
1519
+ }
1520
+ throw new Error(`Unsupported node type: ${node.type}`);
1521
+ }
1522
+ function getPropertyKey(prop) {
1523
+ if (prop.key.type === "Identifier") {
1524
+ return prop.key.name;
1525
+ }
1526
+ if (prop.key.type === "StringLiteral") {
1527
+ return prop.key.value;
1528
+ }
1529
+ throw new Error(`Unsupported property key type: ${prop.key.type}`);
1530
+ }
1531
+ async function saveSchemaToConfig(schema, targetDir = process.cwd()) {
1532
+ const existing = await readSchemaFromConfig(targetDir);
1533
+ if (existing) {
1534
+ const content = await fs2.readFile(existing.filePath, "utf8");
1535
+ const updatedContent = updateSchemaInCode(content, schema);
1536
+ await fs2.writeFile(existing.filePath, updatedContent, "utf8");
1537
+ return existing.filePath;
1538
+ } else {
1539
+ const filePath = path2.join(targetDir, "basic.config.ts");
1540
+ const content = generateConfigContent(schema);
1541
+ await fs2.writeFile(filePath, content, "utf8");
1542
+ return filePath;
1543
+ }
1544
+ }
1545
+ function updateSchemaInCode(content, newSchema) {
1546
+ const schemaStr = JSON.stringify(newSchema, null, 2);
1547
+ const patterns = [
1548
+ /(const\s+schema\s*=\s*)({[^;]+})(;)/g,
1549
+ /(export\s+const\s+schema\s*=\s*)({[^;]+})(;)/g,
1550
+ /(schema\s*=\s*)({[^;]+})(;)/g
1551
+ ];
1552
+ for (const pattern of patterns) {
1553
+ if (pattern.test(content)) {
1554
+ return content.replace(pattern, `$1${schemaStr}$3`);
1555
+ }
1556
+ }
1557
+ throw new Error("Could not update schema in config file");
1558
+ }
1559
+ function generateConfigContent(schema) {
1560
+ return `// Basic Project Configuration
1561
+ // see the docs for more info: https://docs.basic.tech
1562
+
1563
+ const schema = ${JSON.stringify(schema, null, 2)};
1564
+
1565
+ export default schema;
1566
+ `;
1567
+ }
1568
+ function compareVersions(local, remote) {
1569
+ const localVersion = local.version || 0;
1570
+ const remoteVersion = remote.version || 0;
1571
+ let status;
1572
+ if (localVersion === remoteVersion) {
1573
+ status = "equal";
1574
+ } else if (localVersion > remoteVersion) {
1575
+ status = "ahead";
1576
+ } else {
1577
+ status = "behind";
1578
+ }
1579
+ return {
1580
+ status,
1581
+ localVersion,
1582
+ remoteVersion
1583
+ };
1584
+ }
1585
+ async function parseSchemaFile(filePath) {
1586
+ const content = await fs2.readFile(filePath, "utf8");
1587
+ const ast = parse(content, {
1588
+ sourceType: "module",
1589
+ plugins: ["typescript"]
1590
+ });
1591
+ }
1592
+ var init_schema = __esm({
1593
+ "dist/lib/schema.js"() {
1594
+ "use strict";
1595
+ }
123
1596
  });
124
- // Projects command
125
- program
126
- .command('projects')
127
- .description('List and browse your projects')
128
- .action(async () => {
129
- try {
130
- const { ProjectsCommand } = await import('./commands/projects.js');
131
- await ProjectsCommand();
1597
+
1598
+ // dist/commands/status.js
1599
+ var status_exports = {};
1600
+ __export(status_exports, {
1601
+ StatusCommand: () => StatusCommand
1602
+ });
1603
+ import { jsx as _jsx6, jsxs as _jsxs5 } from "react/jsx-runtime";
1604
+ import React4 from "react";
1605
+ import { render as render3, Box as Box4, Text as Text6 } from "ink";
1606
+ function StatusApp() {
1607
+ const [state, setState] = React4.useState({
1608
+ loading: true,
1609
+ error: null
1610
+ });
1611
+ React4.useEffect(() => {
1612
+ async function checkStatus() {
1613
+ try {
1614
+ if (!await isOnline()) {
1615
+ setState({
1616
+ loading: false,
1617
+ error: MESSAGES.OFFLINE
1618
+ });
1619
+ return;
1620
+ }
1621
+ const authService = AuthService.getInstance();
1622
+ const token = await authService.getToken();
1623
+ if (!token) {
1624
+ setState({
1625
+ loading: false,
1626
+ error: MESSAGES.LOGGED_OUT
1627
+ });
1628
+ return;
1629
+ }
1630
+ const localConfig = await readSchemaFromConfig();
1631
+ if (!localConfig) {
1632
+ setState({
1633
+ loading: false,
1634
+ error: null,
1635
+ result: {
1636
+ status: "no-schema",
1637
+ projectId: "",
1638
+ localVersion: 0,
1639
+ remoteVersion: 0,
1640
+ message: ["No schema found in config files"],
1641
+ suggestions: [
1642
+ "Run 'basic init' to create a new project or import an existing project",
1643
+ "Make sure you're in a directory with a basic.config.ts/js file",
1644
+ "Check if your config file has the correct name and format"
1645
+ ]
1646
+ }
1647
+ });
1648
+ return;
1649
+ }
1650
+ const apiClient = ApiClient.getInstance();
1651
+ let remoteSchema = null;
1652
+ try {
1653
+ remoteSchema = await apiClient.getProjectSchema(localConfig.projectId);
1654
+ } catch (error) {
1655
+ setState({
1656
+ loading: false,
1657
+ error: null,
1658
+ result: {
1659
+ status: "invalid",
1660
+ projectId: localConfig.projectId,
1661
+ localVersion: localConfig.schema.version || 0,
1662
+ remoteVersion: 0,
1663
+ message: [
1664
+ `Project ID: ${localConfig.projectId}`,
1665
+ `Error fetching remote schema: ${error instanceof Error ? error.message : "Unknown error"}`
1666
+ ],
1667
+ suggestions: [
1668
+ "Check if the project ID is correct",
1669
+ "Ensure you have access to this project",
1670
+ "Verify your internet connection",
1671
+ "Try running 'basic login' if authentication has expired"
1672
+ ]
1673
+ }
1674
+ });
1675
+ return;
1676
+ }
1677
+ if (!remoteSchema) {
1678
+ remoteSchema = {
1679
+ project_id: localConfig.projectId,
1680
+ version: 0,
1681
+ tables: {}
1682
+ };
1683
+ }
1684
+ const comparison = compareVersions(localConfig.schema, remoteSchema);
1685
+ const result = await analyzeStatus(localConfig, remoteSchema, comparison);
1686
+ setState({
1687
+ loading: false,
1688
+ error: null,
1689
+ result
1690
+ });
1691
+ } catch (error) {
1692
+ setState({
1693
+ loading: false,
1694
+ error: error instanceof Error ? error.message : "Failed to check status"
1695
+ });
1696
+ }
1697
+ }
1698
+ checkStatus();
1699
+ }, []);
1700
+ if (state.loading) {
1701
+ return _jsx6(Spinner, { text: "Checking status..." });
1702
+ }
1703
+ if (state.error) {
1704
+ return _jsx6(Box4, { flexDirection: "column", children: _jsxs5(Text6, { color: "red", children: ["Error: ", state.error] }) });
1705
+ }
1706
+ if (state.result) {
1707
+ return _jsx6(StatusDisplay, { result: state.result });
1708
+ }
1709
+ return _jsx6(Text6, { children: "Unknown status" });
1710
+ }
1711
+ async function analyzeStatus(localConfig, remoteSchema, comparison) {
1712
+ const apiClient = ApiClient.getInstance();
1713
+ const { schema: localSchema, projectId } = localConfig;
1714
+ const baseResult = {
1715
+ projectId,
1716
+ localVersion: comparison.localVersion,
1717
+ remoteVersion: comparison.remoteVersion,
1718
+ message: [`Project ID: ${projectId}`],
1719
+ suggestions: []
1720
+ };
1721
+ if (comparison.remoteVersion > 0) {
1722
+ baseResult.message.push(`Remote schema version: ${comparison.remoteVersion}`);
1723
+ }
1724
+ switch (comparison.status) {
1725
+ case "behind":
1726
+ return {
1727
+ ...baseResult,
1728
+ status: "behind",
1729
+ message: [
1730
+ ...baseResult.message,
1731
+ `Schema is out of date! Current: ${comparison.localVersion}, Latest: ${comparison.remoteVersion}`
1732
+ ],
1733
+ suggestions: [
1734
+ "Run 'basic pull' to update your local schema",
1735
+ "Review the changes before pulling if you have local modifications",
1736
+ "Consider backing up your current schema if you have unsaved work"
1737
+ ]
1738
+ };
1739
+ case "ahead":
1740
+ try {
1741
+ const validation = await apiClient.validateSchema(localSchema);
1742
+ if (validation.valid === false && validation.errors) {
1743
+ return {
1744
+ ...baseResult,
1745
+ status: "invalid",
1746
+ message: [
1747
+ ...baseResult.message,
1748
+ `Changes found: Local schema version ${comparison.localVersion} is ahead of remote version ${comparison.remoteVersion}`,
1749
+ "Errors found in schema! Please fix:"
1750
+ ],
1751
+ validationErrors: validation.errors,
1752
+ suggestions: [
1753
+ "Fix the validation errors shown below",
1754
+ "Run 'basic status' again after fixing errors",
1755
+ "Review your schema syntax and field definitions"
1756
+ ]
1757
+ };
1758
+ }
1759
+ return {
1760
+ ...baseResult,
1761
+ status: "ahead",
1762
+ message: [
1763
+ ...baseResult.message,
1764
+ `Changes found: Local schema version ${comparison.localVersion} is ahead of remote version ${comparison.remoteVersion}`,
1765
+ "Schema changes are valid!"
1766
+ ],
1767
+ suggestions: [
1768
+ "Run 'basic push' to publish your changes",
1769
+ "Review your changes before publishing",
1770
+ "Test your schema locally if possible"
1771
+ ]
1772
+ };
1773
+ } catch (error) {
1774
+ return {
1775
+ ...baseResult,
1776
+ status: "invalid",
1777
+ message: [
1778
+ ...baseResult.message,
1779
+ `Error validating schema: ${error instanceof Error ? error.message : "Unknown error"}`
1780
+ ],
1781
+ suggestions: [
1782
+ "Check your schema for syntax errors",
1783
+ "Ensure all required fields are present",
1784
+ "Verify your basic.config file is valid JSON/JavaScript"
1785
+ ]
1786
+ };
1787
+ }
1788
+ case "equal":
1789
+ if (comparison.localVersion === 0 && comparison.remoteVersion === 0) {
1790
+ try {
1791
+ const validation = await apiClient.validateSchema(localSchema);
1792
+ if (validation.valid === false && validation.errors) {
1793
+ return {
1794
+ ...baseResult,
1795
+ status: "invalid",
1796
+ message: [
1797
+ ...baseResult.message,
1798
+ "Errors found in schema! Please fix:"
1799
+ ],
1800
+ validationErrors: validation.errors,
1801
+ suggestions: [
1802
+ "Fix the validation errors shown below",
1803
+ "Run 'basic status' again after fixing errors"
1804
+ ]
1805
+ };
1806
+ }
1807
+ return {
1808
+ ...baseResult,
1809
+ status: "ahead",
1810
+ message: [
1811
+ ...baseResult.message,
1812
+ "",
1813
+ "Schema changes are valid!",
1814
+ "Please increment your version number to 1",
1815
+ "and run 'basic push' if you are ready to publish your changes."
1816
+ ],
1817
+ suggestions: [
1818
+ "Update the version field in your schema from 0 to 1",
1819
+ "Run 'basic push' after incrementing the version",
1820
+ "Ensure your schema changes are tested and ready for production"
1821
+ ]
1822
+ };
1823
+ } catch (error) {
1824
+ return {
1825
+ ...baseResult,
1826
+ status: "invalid",
1827
+ message: [
1828
+ ...baseResult.message,
1829
+ `Error validating schema: ${error instanceof Error ? error.message : "Unknown error"}`
1830
+ ],
1831
+ suggestions: [
1832
+ "Check your schema for syntax errors"
1833
+ ]
1834
+ };
1835
+ }
1836
+ } else {
1837
+ try {
1838
+ const comparison2 = await apiClient.compareSchema(localSchema);
1839
+ if (comparison2.valid) {
1840
+ return {
1841
+ ...baseResult,
1842
+ status: "current",
1843
+ message: [
1844
+ ...baseResult.message,
1845
+ "Schema is up to date!"
1846
+ ],
1847
+ suggestions: [
1848
+ "Continue working on your project",
1849
+ "Make schema modifications if needed",
1850
+ "Run 'basic status' again after making changes"
1851
+ ]
1852
+ };
1853
+ } else {
1854
+ return {
1855
+ ...baseResult,
1856
+ status: "conflict",
1857
+ message: [
1858
+ ...baseResult.message,
1859
+ "",
1860
+ "Schema conflicts found! Your local schema is different from the remote schema."
1861
+ ],
1862
+ suggestions: [
1863
+ "Run 'basic pull' to override local changes with remote schema",
1864
+ "Or increment the version number in your local schema",
1865
+ "Compare your local changes with the remote version before deciding",
1866
+ "Consider creating a backup of your local changes"
1867
+ ]
1868
+ };
1869
+ }
1870
+ } catch (error) {
1871
+ return {
1872
+ ...baseResult,
1873
+ status: "invalid",
1874
+ message: [
1875
+ ...baseResult.message,
1876
+ `Error checking schema conflict: ${error instanceof Error ? error.message : "Unknown error"}`
1877
+ ],
1878
+ suggestions: [
1879
+ "Check your network connection",
1880
+ "Ensure the project ID is correct"
1881
+ ]
1882
+ };
1883
+ }
1884
+ }
1885
+ default:
1886
+ return {
1887
+ ...baseResult,
1888
+ status: "invalid",
1889
+ message: [
1890
+ ...baseResult.message,
1891
+ "Unknown schema status"
1892
+ ],
1893
+ suggestions: [
1894
+ "Try running 'basic status' again"
1895
+ ]
1896
+ };
1897
+ }
1898
+ }
1899
+ function StatusDisplay({ result }) {
1900
+ const getStatusColor = () => {
1901
+ switch (result.status) {
1902
+ case "current":
1903
+ return "green";
1904
+ case "ahead":
1905
+ return "blue";
1906
+ case "behind":
1907
+ return "yellow";
1908
+ case "conflict":
1909
+ return "magenta";
1910
+ case "invalid":
1911
+ return "red";
1912
+ case "no-schema":
1913
+ return "gray";
1914
+ default:
1915
+ return "white";
132
1916
  }
133
- catch (error) {
134
- const cliError = handleError(error);
135
- console.error(formatError(cliError));
136
- process.exit(1);
1917
+ };
1918
+ const getStatusIcon = () => {
1919
+ switch (result.status) {
1920
+ case "current":
1921
+ return "\u2705";
1922
+ case "ahead":
1923
+ return "\u{1F680}";
1924
+ case "behind":
1925
+ return "\u2B07\uFE0F";
1926
+ case "conflict":
1927
+ return "\u26A0\uFE0F";
1928
+ case "invalid":
1929
+ return "\u274C";
1930
+ case "no-schema":
1931
+ return "\u{1F4C4}";
1932
+ default:
1933
+ return "\u2753";
137
1934
  }
1935
+ };
1936
+ const getStatusDescription = () => {
1937
+ switch (result.status) {
1938
+ case "current":
1939
+ return "Schema is up to date";
1940
+ case "ahead":
1941
+ return "Schema is ready to push";
1942
+ case "behind":
1943
+ return "Schema is out of date";
1944
+ case "conflict":
1945
+ return "Schema conflicts detected";
1946
+ case "invalid":
1947
+ return "Schema has validation errors";
1948
+ case "no-schema":
1949
+ return "No schema file found";
1950
+ default:
1951
+ return "Unknown status";
1952
+ }
1953
+ };
1954
+ const statusMessages = result.message.filter((msg) => !msg.startsWith("Project ID:") && !msg.startsWith("Remote schema version:"));
1955
+ return _jsxs5(Box4, { flexDirection: "column", children: [result.projectId && _jsxs5(Box4, { flexDirection: "column", marginBottom: 1, children: [_jsxs5(Text6, { color: "cyan", children: ["Project ID: ", result.projectId] }), _jsxs5(Box4, { children: [_jsxs5(Text6, { color: "gray", children: ["Local version: ", result.localVersion] }), result.remoteVersion > 0 && _jsxs5(Text6, { color: "gray", children: [" \u2022 Remote version: ", result.remoteVersion] })] })] }), _jsxs5(Box4, { flexDirection: "column", marginBottom: 1, children: [_jsx6(Box4, { marginBottom: 1, children: _jsxs5(Text6, { color: getStatusColor(), children: [getStatusIcon(), " ", getStatusDescription()] }) }), statusMessages.length > 0 && _jsx6(Box4, { flexDirection: "column", children: statusMessages.map((line, index) => _jsx6(Text6, { children: line }, index)) })] }), result.validationErrors && result.validationErrors.length > 0 && _jsxs5(Box4, { flexDirection: "column", marginBottom: 1, children: [_jsx6(Text6, { color: "red", children: "Validation errors:" }), result.validationErrors.map((error, index) => _jsxs5(Text6, { color: "red", children: ["\u2022 ", error.message, " at ", error.instancePath || "root"] }, index))] }), result.suggestions.length > 0 && _jsxs5(Box4, { flexDirection: "column", marginTop: 1, children: [_jsx6(Text6, { color: "blue", children: "Next steps:" }), result.suggestions.map((suggestion, index) => _jsxs5(Text6, { color: "gray", children: ["\u2022 ", suggestion] }, index))] })] });
1956
+ }
1957
+ async function StatusCommand() {
1958
+ const { waitUntilExit } = render3(_jsx6(StatusApp, {}));
1959
+ await waitUntilExit();
1960
+ process.exit(0);
1961
+ }
1962
+ var init_status = __esm({
1963
+ "dist/commands/status.js"() {
1964
+ "use strict";
1965
+ init_Spinner();
1966
+ init_api();
1967
+ init_auth();
1968
+ init_schema();
1969
+ init_platform();
1970
+ init_constants();
1971
+ }
1972
+ });
1973
+
1974
+ // dist/commands/pull.js
1975
+ var pull_exports = {};
1976
+ __export(pull_exports, {
1977
+ PullCommand: () => PullCommand
138
1978
  });
139
- // Teams command
140
- program
141
- .command('teams')
142
- .argument('[action]', 'Teams action (new)', 'list')
143
- .description('List teams or create a new team')
144
- .action(async (action) => {
1979
+ import { jsx as _jsx7, jsxs as _jsxs6, Fragment as _Fragment } from "react/jsx-runtime";
1980
+ import React5 from "react";
1981
+ import { render as render4, Box as Box5, Text as Text7, useInput as useInput3 } from "ink";
1982
+ function PullApp() {
1983
+ const [state, setState] = React5.useState({
1984
+ phase: "checking",
1985
+ error: null
1986
+ });
1987
+ const [selectedOption, setSelectedOption] = React5.useState("yes");
1988
+ React5.useEffect(() => {
1989
+ async function checkPullStatus() {
1990
+ try {
1991
+ if (!await isOnline()) {
1992
+ setState({
1993
+ phase: "error",
1994
+ error: MESSAGES.OFFLINE
1995
+ });
1996
+ return;
1997
+ }
1998
+ const authService = AuthService.getInstance();
1999
+ const token = await authService.getToken();
2000
+ if (!token) {
2001
+ setState({
2002
+ phase: "error",
2003
+ error: MESSAGES.LOGGED_OUT
2004
+ });
2005
+ return;
2006
+ }
2007
+ const localConfig = await readSchemaFromConfig();
2008
+ if (!localConfig) {
2009
+ setState({
2010
+ phase: "no-action",
2011
+ error: null,
2012
+ statusResult: {
2013
+ status: "no-schema",
2014
+ projectId: "",
2015
+ localVersion: 0,
2016
+ remoteVersion: 0,
2017
+ message: [
2018
+ "No schema found in config files",
2019
+ "Run 'basic init' to create a new project or import an existing project"
2020
+ ],
2021
+ needsConfirmation: false,
2022
+ confirmationTitle: "",
2023
+ confirmationMessage: ""
2024
+ }
2025
+ });
2026
+ return;
2027
+ }
2028
+ const apiClient = ApiClient.getInstance();
2029
+ let remoteSchema = null;
2030
+ try {
2031
+ remoteSchema = await apiClient.getProjectSchema(localConfig.projectId);
2032
+ } catch (error) {
2033
+ setState({
2034
+ phase: "error",
2035
+ error: `Error fetching remote schema: ${error instanceof Error ? error.message : "Unknown error"}`
2036
+ });
2037
+ return;
2038
+ }
2039
+ if (!remoteSchema) {
2040
+ remoteSchema = {
2041
+ project_id: localConfig.projectId,
2042
+ version: 0,
2043
+ tables: {}
2044
+ };
2045
+ }
2046
+ const comparison = compareVersions(localConfig.schema, remoteSchema);
2047
+ const result = await analyzePullAction(localConfig, remoteSchema, comparison, apiClient);
2048
+ setState({
2049
+ phase: result.needsConfirmation ? "confirming" : "no-action",
2050
+ error: null,
2051
+ statusResult: result
2052
+ });
2053
+ } catch (error) {
2054
+ setState({
2055
+ phase: "error",
2056
+ error: error instanceof Error ? error.message : "Failed to check pull status"
2057
+ });
2058
+ }
2059
+ }
2060
+ checkPullStatus();
2061
+ }, []);
2062
+ useInput3((input, key) => {
2063
+ if (state.phase === "confirming") {
2064
+ if (key.upArrow || key.downArrow) {
2065
+ setSelectedOption((prev) => prev === "yes" ? "no" : "yes");
2066
+ } else if (key.return) {
2067
+ if (selectedOption === "yes") {
2068
+ handlePull();
2069
+ } else {
2070
+ setState((prev) => ({ ...prev, phase: "no-action" }));
2071
+ }
2072
+ } else if (key.escape || input === "q") {
2073
+ setState((prev) => ({ ...prev, phase: "no-action" }));
2074
+ }
2075
+ }
2076
+ });
2077
+ const handlePull = async () => {
2078
+ setState((prev) => ({ ...prev, phase: "pulling" }));
145
2079
  try {
146
- const { TeamsCommand } = await import('./commands/teams.js');
147
- await TeamsCommand(action);
2080
+ if (!state.statusResult) {
2081
+ throw new Error("No status result available");
2082
+ }
2083
+ const localConfig = await readSchemaFromConfig();
2084
+ if (!localConfig) {
2085
+ throw new Error("Local schema not found");
2086
+ }
2087
+ const apiClient = ApiClient.getInstance();
2088
+ const remoteSchema = await apiClient.getProjectSchema(localConfig.projectId);
2089
+ if (!remoteSchema) {
2090
+ throw new Error("Remote schema not found");
2091
+ }
2092
+ const filePath = await saveSchemaToConfig(remoteSchema);
2093
+ setState({
2094
+ phase: "success",
2095
+ error: null,
2096
+ pullResult: {
2097
+ projectId: localConfig.projectId,
2098
+ oldVersion: localConfig.schema.version || 0,
2099
+ newVersion: remoteSchema.version || 0,
2100
+ filePath
2101
+ }
2102
+ });
2103
+ } catch (error) {
2104
+ setState({
2105
+ phase: "error",
2106
+ error: error instanceof Error ? error.message : "Failed to pull schema"
2107
+ });
2108
+ }
2109
+ };
2110
+ if (state.phase === "checking") {
2111
+ return _jsx7(Spinner, { text: "Checking pull status..." });
2112
+ }
2113
+ if (state.phase === "pulling") {
2114
+ return _jsx7(Spinner, { text: "Pulling latest schema..." });
2115
+ }
2116
+ if (state.phase === "error") {
2117
+ setTimeout(() => process.exit(1), 0);
2118
+ return _jsxs6(Box5, { flexDirection: "column", children: [_jsxs6(Text7, { color: "red", children: ["Error: ", state.error] }), _jsxs6(Box5, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [_jsx7(Text7, { color: "blue", children: "Next steps:" }), state.error?.includes("offline") || state.error?.includes("network") ? _jsxs6(_Fragment, { children: [_jsx7(Text7, { color: "gray", children: "\u2022 Check your internet connection" }), _jsx7(Text7, { color: "gray", children: "\u2022 Try again in a moment" })] }) : state.error?.includes("logged") || state.error?.includes("auth") ? _jsxs6(_Fragment, { children: [_jsx7(Text7, { color: "gray", children: "\u2022 Run 'basic login' to authenticate" }), _jsx7(Text7, { color: "gray", children: "\u2022 Ensure you have a valid account" })] }) : state.error?.includes("schema") || state.error?.includes("project") ? _jsxs6(_Fragment, { children: [_jsx7(Text7, { color: "gray", children: "\u2022 Check if the project ID is correct" }), _jsx7(Text7, { color: "gray", children: "\u2022 Ensure you have access to this project" }), _jsx7(Text7, { color: "gray", children: "\u2022 Run 'basic status' for more details" })] }) : _jsxs6(_Fragment, { children: [_jsx7(Text7, { color: "gray", children: "\u2022 Try running the command again" }), _jsx7(Text7, { color: "gray", children: "\u2022 Run 'basic status' to check your project state" }), _jsx7(Text7, { color: "gray", children: "\u2022 Check the Basic documentation if the issue persists" })] })] })] });
2119
+ }
2120
+ if (state.phase === "success" && state.pullResult) {
2121
+ setTimeout(() => process.exit(0), 0);
2122
+ return _jsx7(PullSuccessDisplay, { result: state.pullResult });
2123
+ }
2124
+ if (state.phase === "confirming" && state.statusResult) {
2125
+ return _jsx7(PullConfirmationDialog, { statusResult: state.statusResult, selectedOption });
2126
+ }
2127
+ if (state.phase === "no-action" && state.statusResult) {
2128
+ setTimeout(() => process.exit(0), 0);
2129
+ return _jsx7(PullStatusDisplay, { result: state.statusResult });
2130
+ }
2131
+ return _jsx7(Text7, { children: "Unknown state" });
2132
+ }
2133
+ async function analyzePullAction(localConfig, remoteSchema, comparison, apiClient) {
2134
+ const { projectId } = localConfig;
2135
+ const baseResult = {
2136
+ projectId,
2137
+ localVersion: comparison.localVersion,
2138
+ remoteVersion: comparison.remoteVersion,
2139
+ message: [],
2140
+ needsConfirmation: false,
2141
+ confirmationTitle: "",
2142
+ confirmationMessage: ""
2143
+ };
2144
+ switch (comparison.status) {
2145
+ case "behind":
2146
+ return {
2147
+ ...baseResult,
2148
+ status: "behind",
2149
+ message: [
2150
+ "Your local schema is behind the remote version.",
2151
+ "Pull the latest changes?"
2152
+ ],
2153
+ needsConfirmation: true,
2154
+ confirmationTitle: "Pull Remote Schema",
2155
+ confirmationMessage: "This will update your local schema to the latest version."
2156
+ };
2157
+ case "equal":
2158
+ if (comparison.localVersion === 0 && comparison.remoteVersion === 0) {
2159
+ return {
2160
+ ...baseResult,
2161
+ status: "current",
2162
+ message: [
2163
+ "Schema is up to date!",
2164
+ "No pull needed."
2165
+ ]
2166
+ };
2167
+ }
2168
+ try {
2169
+ const comparisonResult = await apiClient.compareSchema(localConfig.schema);
2170
+ if (comparisonResult.valid) {
2171
+ return {
2172
+ ...baseResult,
2173
+ status: "current",
2174
+ message: [
2175
+ "Schema is up to date!",
2176
+ "No pull needed."
2177
+ ]
2178
+ };
2179
+ } else {
2180
+ return {
2181
+ ...baseResult,
2182
+ status: "conflict",
2183
+ message: [
2184
+ "Schema conflicts detected!",
2185
+ "Your local schema differs from the remote schema at the same version.",
2186
+ "Pull the remote version to override local changes?"
2187
+ ],
2188
+ needsConfirmation: true,
2189
+ confirmationTitle: "Override Local Changes",
2190
+ confirmationMessage: "This will replace your local schema with the remote version."
2191
+ };
2192
+ }
2193
+ } catch (error) {
2194
+ return {
2195
+ ...baseResult,
2196
+ status: "current",
2197
+ message: [
2198
+ "Schema is up to date!",
2199
+ "No pull needed.",
2200
+ "(Unable to verify schema content - assuming current)"
2201
+ ]
2202
+ };
2203
+ }
2204
+ case "ahead":
2205
+ return {
2206
+ ...baseResult,
2207
+ status: "ahead",
2208
+ message: [
2209
+ "Your local schema is ahead of the remote version.",
2210
+ "Did you mean to push instead?",
2211
+ "Use 'basic push' to publish your changes."
2212
+ ]
2213
+ };
2214
+ default:
2215
+ return {
2216
+ ...baseResult,
2217
+ status: "current",
2218
+ message: [
2219
+ "Schema is up to date!",
2220
+ "No pull needed."
2221
+ ]
2222
+ };
2223
+ }
2224
+ }
2225
+ function PullConfirmationDialog({ statusResult, selectedOption }) {
2226
+ const getStatusIcon = () => {
2227
+ switch (statusResult.status) {
2228
+ case "behind":
2229
+ return "\u2B07\uFE0F";
2230
+ case "conflict":
2231
+ return "\u26A0\uFE0F";
2232
+ default:
2233
+ return "\u{1F4E5}";
148
2234
  }
149
- catch (error) {
150
- const cliError = handleError(error);
151
- console.error(formatError(cliError));
152
- process.exit(1);
2235
+ };
2236
+ const getStatusText = () => {
2237
+ switch (statusResult.status) {
2238
+ case "behind":
2239
+ return "Schema is out of date";
2240
+ case "conflict":
2241
+ return "Schema conflicts detected";
2242
+ default:
2243
+ return "Schema update available";
2244
+ }
2245
+ };
2246
+ const getStatusColor = () => {
2247
+ switch (statusResult.status) {
2248
+ case "behind":
2249
+ return "yellow";
2250
+ case "conflict":
2251
+ return "magenta";
2252
+ default:
2253
+ return "blue";
2254
+ }
2255
+ };
2256
+ return _jsxs6(Box5, { flexDirection: "column", children: [_jsxs6(Box5, { flexDirection: "column", marginBottom: 1, children: [_jsxs6(Text7, { color: "cyan", children: ["Project ID: ", statusResult.projectId] }), _jsxs6(Box5, { children: [_jsxs6(Text7, { color: "gray", children: ["Local version: ", statusResult.localVersion] }), statusResult.remoteVersion > 0 && _jsxs6(Text7, { color: "gray", children: [" \u2022 Remote version: ", statusResult.remoteVersion] })] })] }), _jsx7(Box5, { marginBottom: 1, children: _jsxs6(Text7, { color: getStatusColor(), children: [getStatusIcon(), " ", getStatusText()] }) }), _jsx7(Box5, { flexDirection: "column", marginBottom: 2, children: statusResult.message.map((line, index) => _jsx7(Text7, { children: line }, index)) }), _jsxs6(Box5, { flexDirection: "column", children: [_jsx7(Box5, { children: _jsxs6(Text7, { color: selectedOption === "yes" ? "green" : "gray", children: [selectedOption === "yes" ? "\u276F" : " ", " Yes, pull changes"] }) }), _jsx7(Box5, { children: _jsxs6(Text7, { color: selectedOption === "no" ? "green" : "gray", children: [selectedOption === "no" ? "\u276F" : " ", " No, cancel"] }) })] }), _jsx7(Box5, { marginTop: 1, children: _jsx7(Text7, { color: "gray", children: "Use \u2191\u2193 to navigate, Enter to confirm, Esc to cancel" }) })] });
2257
+ }
2258
+ function PullStatusDisplay({ result }) {
2259
+ const getStatusColor = () => {
2260
+ switch (result.status) {
2261
+ case "current":
2262
+ return "green";
2263
+ case "ahead":
2264
+ return "blue";
2265
+ case "conflict":
2266
+ return "magenta";
2267
+ case "no-schema":
2268
+ return "gray";
2269
+ default:
2270
+ return "white";
153
2271
  }
2272
+ };
2273
+ const getStatusIcon = () => {
2274
+ switch (result.status) {
2275
+ case "current":
2276
+ return "\u2705";
2277
+ case "ahead":
2278
+ return "\u{1F680}";
2279
+ case "conflict":
2280
+ return "\u26A0\uFE0F";
2281
+ case "no-schema":
2282
+ return "\u{1F4C4}";
2283
+ default:
2284
+ return "\u2753";
2285
+ }
2286
+ };
2287
+ const getStatusDescription = () => {
2288
+ switch (result.status) {
2289
+ case "current":
2290
+ return "Schema is up to date";
2291
+ case "ahead":
2292
+ return "Local schema is ahead";
2293
+ case "conflict":
2294
+ return "Schema conflicts detected";
2295
+ case "no-schema":
2296
+ return "No schema file found";
2297
+ default:
2298
+ return "Unknown status";
2299
+ }
2300
+ };
2301
+ const getNextSteps = () => {
2302
+ switch (result.status) {
2303
+ case "current":
2304
+ return [
2305
+ "Continue working on your project",
2306
+ "Run 'basic status' to check for changes",
2307
+ "Make schema modifications if needed"
2308
+ ];
2309
+ case "ahead":
2310
+ return [
2311
+ "Run 'basic push' to publish your changes",
2312
+ "Or run 'basic status' for more details"
2313
+ ];
2314
+ case "conflict":
2315
+ return [
2316
+ "Run 'basic pull' again to override local changes",
2317
+ "Or run 'basic status' to understand the differences",
2318
+ "Consider backing up your local changes first"
2319
+ ];
2320
+ case "no-schema":
2321
+ return [
2322
+ "Run 'basic init' to create a new project or import an existing project",
2323
+ "Make sure you're in a directory with a basic.config.ts/js file"
2324
+ ];
2325
+ default:
2326
+ return [];
2327
+ }
2328
+ };
2329
+ return _jsxs6(Box5, { flexDirection: "column", children: [result.projectId && _jsxs6(Box5, { flexDirection: "column", marginBottom: 1, children: [_jsxs6(Text7, { color: "cyan", children: ["Project ID: ", result.projectId] }), _jsxs6(Box5, { children: [_jsxs6(Text7, { color: "gray", children: ["Local version: ", result.localVersion] }), result.remoteVersion > 0 && _jsxs6(Text7, { color: "gray", children: [" \u2022 Remote version: ", result.remoteVersion] })] })] }), _jsx7(Box5, { marginBottom: 1, children: _jsxs6(Text7, { color: getStatusColor(), children: [getStatusIcon(), " ", getStatusDescription()] }) }), _jsx7(Box5, { flexDirection: "column", marginBottom: 1, children: result.message.map((line, index) => _jsx7(Text7, { children: line }, index)) }), getNextSteps().length > 0 && _jsxs6(Box5, { flexDirection: "column", marginBottom: 1, children: [_jsx7(Text7, { color: "blue", children: "Next steps:" }), getNextSteps().map((step, index) => _jsxs6(Text7, { color: "gray", children: ["\u2022 ", step] }, index))] })] });
2330
+ }
2331
+ function PullSuccessDisplay({ result }) {
2332
+ return _jsxs6(Box5, { flexDirection: "column", children: [_jsx7(Box5, { marginBottom: 1, children: _jsx7(Text7, { color: "green", children: "\u2705 Schema updated successfully!" }) }), _jsxs6(Box5, { flexDirection: "column", marginBottom: 1, children: [_jsxs6(Text7, { children: ["Updated: ", result.filePath.split("/").pop()] }), _jsxs6(Text7, { children: ["Version: ", result.oldVersion, " \u2192 ", result.newVersion] }), _jsxs6(Text7, { children: ["Project: ", result.projectId] })] }), _jsxs6(Box5, { flexDirection: "column", marginTop: 1, children: [_jsx7(Text7, { color: "blue", children: "Next steps:" }), _jsx7(Text7, { color: "gray", children: "\u2022 Review the updated schema changes" }), _jsx7(Text7, { color: "gray", children: "\u2022 Continue working on your project" }), _jsx7(Text7, { color: "gray", children: "\u2022 Run 'basic status' to check your project state" })] })] });
2333
+ }
2334
+ async function PullCommand() {
2335
+ render4(_jsx7(PullApp, {}));
2336
+ }
2337
+ var init_pull = __esm({
2338
+ "dist/commands/pull.js"() {
2339
+ "use strict";
2340
+ init_Spinner();
2341
+ init_api();
2342
+ init_auth();
2343
+ init_schema();
2344
+ init_platform();
2345
+ init_constants();
2346
+ }
154
2347
  });
155
- // Status command
156
- program
157
- .command('status')
158
- .description('Show project status')
159
- .action(async () => {
2348
+
2349
+ // dist/commands/push.js
2350
+ var push_exports = {};
2351
+ __export(push_exports, {
2352
+ PushCommand: () => PushCommand
2353
+ });
2354
+ import { jsx as _jsx8, jsxs as _jsxs7, Fragment as _Fragment2 } from "react/jsx-runtime";
2355
+ import React6 from "react";
2356
+ import { render as render5, Box as Box6, Text as Text8, useInput as useInput4 } from "ink";
2357
+ function PushApp() {
2358
+ const [state, setState] = React6.useState({
2359
+ phase: "checking",
2360
+ error: null
2361
+ });
2362
+ const [selectedOption, setSelectedOption] = React6.useState("yes");
2363
+ React6.useEffect(() => {
2364
+ async function checkPushStatus() {
2365
+ try {
2366
+ if (!await isOnline()) {
2367
+ setState({
2368
+ phase: "error",
2369
+ error: MESSAGES.OFFLINE
2370
+ });
2371
+ return;
2372
+ }
2373
+ const authService = AuthService.getInstance();
2374
+ const token = await authService.getToken();
2375
+ if (!token) {
2376
+ setState({
2377
+ phase: "error",
2378
+ error: MESSAGES.LOGGED_OUT
2379
+ });
2380
+ return;
2381
+ }
2382
+ const localConfig = await readSchemaFromConfig();
2383
+ if (!localConfig) {
2384
+ setState({
2385
+ phase: "no-action",
2386
+ error: null,
2387
+ statusResult: {
2388
+ status: "no-schema",
2389
+ projectId: "",
2390
+ localVersion: 0,
2391
+ remoteVersion: 0,
2392
+ message: [
2393
+ "No schema found in config files",
2394
+ "Run 'basic init' to create a new project or import an existing project"
2395
+ ],
2396
+ needsConfirmation: false,
2397
+ confirmationTitle: "",
2398
+ confirmationMessage: ""
2399
+ }
2400
+ });
2401
+ return;
2402
+ }
2403
+ const apiClient = ApiClient.getInstance();
2404
+ let remoteSchema = null;
2405
+ try {
2406
+ remoteSchema = await apiClient.getProjectSchema(localConfig.projectId);
2407
+ } catch (error) {
2408
+ setState({
2409
+ phase: "error",
2410
+ error: `Error fetching remote schema: ${error instanceof Error ? error.message : "Unknown error"}`
2411
+ });
2412
+ return;
2413
+ }
2414
+ if (!remoteSchema) {
2415
+ remoteSchema = {
2416
+ project_id: localConfig.projectId,
2417
+ version: 0,
2418
+ tables: {}
2419
+ };
2420
+ }
2421
+ const comparison = compareVersions(localConfig.schema, remoteSchema);
2422
+ const result = await analyzePushAction(localConfig, remoteSchema, comparison, apiClient);
2423
+ setState({
2424
+ phase: result.needsConfirmation ? "confirming" : "no-action",
2425
+ error: null,
2426
+ statusResult: result
2427
+ });
2428
+ } catch (error) {
2429
+ setState({
2430
+ phase: "error",
2431
+ error: error instanceof Error ? error.message : "Failed to check push status"
2432
+ });
2433
+ }
2434
+ }
2435
+ checkPushStatus();
2436
+ }, []);
2437
+ useInput4((input, key) => {
2438
+ if (state.phase === "confirming") {
2439
+ if (key.upArrow || key.downArrow) {
2440
+ setSelectedOption((prev) => prev === "yes" ? "no" : "yes");
2441
+ } else if (key.return) {
2442
+ if (selectedOption === "yes") {
2443
+ handlePush();
2444
+ } else {
2445
+ setState((prev) => ({ ...prev, phase: "no-action" }));
2446
+ }
2447
+ } else if (key.escape || input === "q") {
2448
+ setState((prev) => ({ ...prev, phase: "no-action" }));
2449
+ }
2450
+ }
2451
+ });
2452
+ const handlePush = async () => {
2453
+ setState((prev) => ({ ...prev, phase: "pushing" }));
160
2454
  try {
161
- const { StatusCommand } = await import('./commands/status.js');
162
- await StatusCommand();
2455
+ if (!state.statusResult) {
2456
+ throw new Error("No status result available");
2457
+ }
2458
+ const localConfig = await readSchemaFromConfig();
2459
+ if (!localConfig) {
2460
+ throw new Error("Local schema not found");
2461
+ }
2462
+ const apiClient = ApiClient.getInstance();
2463
+ await apiClient.pushProjectSchema(localConfig.projectId, localConfig.schema);
2464
+ setState({
2465
+ phase: "success",
2466
+ error: null,
2467
+ pushResult: {
2468
+ projectId: localConfig.projectId,
2469
+ oldVersion: state.statusResult.remoteVersion,
2470
+ newVersion: localConfig.schema.version || 0,
2471
+ filePath: localConfig.filePath
2472
+ }
2473
+ });
2474
+ } catch (error) {
2475
+ setState({
2476
+ phase: "error",
2477
+ error: error instanceof Error ? error.message : "Failed to push schema"
2478
+ });
2479
+ }
2480
+ };
2481
+ if (state.phase === "checking") {
2482
+ return _jsx8(Spinner, { text: "Checking push status..." });
2483
+ }
2484
+ if (state.phase === "pushing") {
2485
+ return _jsx8(Spinner, { text: "Pushing schema to remote..." });
2486
+ }
2487
+ if (state.phase === "error") {
2488
+ setTimeout(() => process.exit(1), 0);
2489
+ return _jsxs7(Box6, { flexDirection: "column", children: [_jsxs7(Text8, { color: "red", children: ["Error: ", state.error] }), _jsxs7(Box6, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [_jsx8(Text8, { color: "blue", children: "Next steps:" }), state.error?.includes("offline") || state.error?.includes("network") ? _jsxs7(_Fragment2, { children: [_jsx8(Text8, { color: "gray", children: "\u2022 Check your internet connection" }), _jsx8(Text8, { color: "gray", children: "\u2022 Try again in a moment" })] }) : state.error?.includes("logged") || state.error?.includes("auth") ? _jsxs7(_Fragment2, { children: [_jsx8(Text8, { color: "gray", children: "\u2022 Run 'basic login' to authenticate" }), _jsx8(Text8, { color: "gray", children: "\u2022 Ensure you have a valid account" })] }) : state.error?.includes("schema") || state.error?.includes("project") ? _jsxs7(_Fragment2, { children: [_jsx8(Text8, { color: "gray", children: "\u2022 Check if the project ID is correct" }), _jsx8(Text8, { color: "gray", children: "\u2022 Ensure you have access to this project" }), _jsx8(Text8, { color: "gray", children: "\u2022 Run 'basic status' for more details" })] }) : _jsxs7(_Fragment2, { children: [_jsx8(Text8, { color: "gray", children: "\u2022 Try running the command again" }), _jsx8(Text8, { color: "gray", children: "\u2022 Run 'basic status' to check your project state" }), _jsx8(Text8, { color: "gray", children: "\u2022 Check the Basic documentation if the issue persists" })] })] })] });
2490
+ }
2491
+ if (state.phase === "success" && state.pushResult) {
2492
+ setTimeout(() => process.exit(0), 0);
2493
+ return _jsx8(PushSuccessDisplay, { result: state.pushResult });
2494
+ }
2495
+ if (state.phase === "confirming" && state.statusResult) {
2496
+ return _jsx8(PushConfirmationDialog, { statusResult: state.statusResult, selectedOption });
2497
+ }
2498
+ if (state.phase === "no-action" && state.statusResult) {
2499
+ setTimeout(() => process.exit(0), 0);
2500
+ return _jsx8(PushStatusDisplay, { result: state.statusResult });
2501
+ }
2502
+ return _jsx8(Text8, { children: "Unknown state" });
2503
+ }
2504
+ async function analyzePushAction(localConfig, remoteSchema, comparison, apiClient) {
2505
+ const { projectId } = localConfig;
2506
+ const baseResult = {
2507
+ projectId,
2508
+ localVersion: comparison.localVersion,
2509
+ remoteVersion: comparison.remoteVersion,
2510
+ message: [],
2511
+ needsConfirmation: false,
2512
+ confirmationTitle: "",
2513
+ confirmationMessage: ""
2514
+ };
2515
+ switch (comparison.status) {
2516
+ case "ahead":
2517
+ try {
2518
+ const validation = await apiClient.validateSchema(localConfig.schema);
2519
+ if (validation.valid === false && validation.errors) {
2520
+ return {
2521
+ ...baseResult,
2522
+ status: "invalid",
2523
+ message: [
2524
+ "Errors found in schema! Please fix:",
2525
+ "Your local schema has validation errors that must be resolved before pushing."
2526
+ ],
2527
+ validationErrors: validation.errors
2528
+ };
2529
+ }
2530
+ return {
2531
+ ...baseResult,
2532
+ status: "ahead",
2533
+ message: [
2534
+ "Your local schema is ahead of the remote version.",
2535
+ "Push your changes to publish them?"
2536
+ ],
2537
+ needsConfirmation: true,
2538
+ confirmationTitle: "Push Schema Changes",
2539
+ confirmationMessage: "This will publish your local schema changes to the remote project."
2540
+ };
2541
+ } catch (error) {
2542
+ return {
2543
+ ...baseResult,
2544
+ status: "invalid",
2545
+ message: [
2546
+ `Error validating schema: ${error instanceof Error ? error.message : "Unknown error"}`,
2547
+ "Please check your schema for syntax errors."
2548
+ ]
2549
+ };
2550
+ }
2551
+ case "equal":
2552
+ if (comparison.localVersion === 0 && comparison.remoteVersion === 0) {
2553
+ try {
2554
+ const validation = await apiClient.validateSchema(localConfig.schema);
2555
+ if (validation.valid === false && validation.errors) {
2556
+ return {
2557
+ ...baseResult,
2558
+ status: "invalid",
2559
+ message: [
2560
+ "Errors found in schema! Please fix:"
2561
+ ],
2562
+ validationErrors: validation.errors
2563
+ };
2564
+ }
2565
+ return {
2566
+ ...baseResult,
2567
+ status: "invalid",
2568
+ message: [
2569
+ "Schema changes are valid!",
2570
+ "Please increment your version number to 1",
2571
+ "and run 'basic push' if you are ready to publish your changes."
2572
+ ]
2573
+ };
2574
+ } catch (error) {
2575
+ return {
2576
+ ...baseResult,
2577
+ status: "invalid",
2578
+ message: [
2579
+ `Error validating schema: ${error instanceof Error ? error.message : "Unknown error"}`
2580
+ ]
2581
+ };
2582
+ }
2583
+ }
2584
+ try {
2585
+ const comparisonResult = await apiClient.compareSchema(localConfig.schema);
2586
+ if (comparisonResult.valid) {
2587
+ return {
2588
+ ...baseResult,
2589
+ status: "current",
2590
+ message: [
2591
+ "Schema is up to date!",
2592
+ "No push needed."
2593
+ ]
2594
+ };
2595
+ } else {
2596
+ return {
2597
+ ...baseResult,
2598
+ status: "invalid",
2599
+ message: [
2600
+ "Your local schema differs from the remote schema.",
2601
+ "Please increment your version number before pushing changes."
2602
+ ]
2603
+ };
2604
+ }
2605
+ } catch (error) {
2606
+ return {
2607
+ ...baseResult,
2608
+ status: "current",
2609
+ message: [
2610
+ "Schema appears to be up to date.",
2611
+ "(Unable to verify schema content - assuming current)"
2612
+ ]
2613
+ };
2614
+ }
2615
+ case "behind":
2616
+ return {
2617
+ ...baseResult,
2618
+ status: "behind",
2619
+ message: [
2620
+ "Your local schema is behind the remote version.",
2621
+ "Did you mean to pull instead?",
2622
+ "Use 'basic pull' to get the latest changes."
2623
+ ]
2624
+ };
2625
+ default:
2626
+ return {
2627
+ ...baseResult,
2628
+ status: "current",
2629
+ message: [
2630
+ "Schema is up to date!",
2631
+ "No push needed."
2632
+ ]
2633
+ };
2634
+ }
2635
+ }
2636
+ function PushConfirmationDialog({ statusResult, selectedOption }) {
2637
+ const getStatusIcon = () => {
2638
+ switch (statusResult.status) {
2639
+ case "ahead":
2640
+ return "\u2B06\uFE0F";
2641
+ default:
2642
+ return "\u{1F4E4}";
2643
+ }
2644
+ };
2645
+ const getStatusText = () => {
2646
+ switch (statusResult.status) {
2647
+ case "ahead":
2648
+ return "Ready to push changes";
2649
+ default:
2650
+ return "Schema update ready";
2651
+ }
2652
+ };
2653
+ const getStatusColor = () => {
2654
+ switch (statusResult.status) {
2655
+ case "ahead":
2656
+ return "green";
2657
+ default:
2658
+ return "blue";
2659
+ }
2660
+ };
2661
+ return _jsxs7(Box6, { flexDirection: "column", children: [_jsxs7(Box6, { flexDirection: "column", marginBottom: 1, children: [_jsxs7(Text8, { color: "cyan", children: ["Project ID: ", statusResult.projectId] }), _jsxs7(Box6, { children: [_jsxs7(Text8, { color: "gray", children: ["Local version: ", statusResult.localVersion] }), statusResult.remoteVersion > 0 && _jsxs7(Text8, { color: "gray", children: [" \u2022 Remote version: ", statusResult.remoteVersion] })] })] }), _jsx8(Box6, { marginBottom: 1, children: _jsxs7(Text8, { color: getStatusColor(), children: [getStatusIcon(), " ", getStatusText()] }) }), _jsx8(Box6, { flexDirection: "column", marginBottom: 2, children: statusResult.message.map((line, index) => _jsx8(Text8, { children: line }, index)) }), _jsxs7(Box6, { flexDirection: "column", children: [_jsx8(Box6, { children: _jsxs7(Text8, { color: selectedOption === "yes" ? "green" : "gray", children: [selectedOption === "yes" ? "\u276F" : " ", " Yes, push changes"] }) }), _jsx8(Box6, { children: _jsxs7(Text8, { color: selectedOption === "no" ? "green" : "gray", children: [selectedOption === "no" ? "\u276F" : " ", " No, cancel"] }) })] }), _jsx8(Box6, { marginTop: 1, children: _jsx8(Text8, { color: "gray", children: "Use \u2191\u2193 to navigate, Enter to confirm, Esc to cancel" }) })] });
2662
+ }
2663
+ function PushStatusDisplay({ result }) {
2664
+ const getStatusColor = () => {
2665
+ switch (result.status) {
2666
+ case "current":
2667
+ return "green";
2668
+ case "behind":
2669
+ return "yellow";
2670
+ case "invalid":
2671
+ return "red";
2672
+ case "no-schema":
2673
+ return "gray";
2674
+ default:
2675
+ return "white";
2676
+ }
2677
+ };
2678
+ const getStatusIcon = () => {
2679
+ switch (result.status) {
2680
+ case "current":
2681
+ return "\u2705";
2682
+ case "behind":
2683
+ return "\u2B07\uFE0F";
2684
+ case "invalid":
2685
+ return "\u274C";
2686
+ case "no-schema":
2687
+ return "\u{1F4C4}";
2688
+ default:
2689
+ return "\u2753";
163
2690
  }
164
- catch (error) {
165
- const cliError = handleError(error);
166
- console.error(formatError(cliError));
167
- process.exit(1);
2691
+ };
2692
+ const getStatusDescription = () => {
2693
+ switch (result.status) {
2694
+ case "current":
2695
+ return "Schema is up to date";
2696
+ case "behind":
2697
+ return "Local schema is behind remote";
2698
+ case "invalid":
2699
+ return "Schema has validation errors";
2700
+ case "no-schema":
2701
+ return "No schema file found";
2702
+ default:
2703
+ return "Unknown status";
168
2704
  }
2705
+ };
2706
+ const getNextSteps = () => {
2707
+ switch (result.status) {
2708
+ case "current":
2709
+ return [
2710
+ "Continue working on your project",
2711
+ "Run 'basic status' to check for changes",
2712
+ "Make schema modifications if needed"
2713
+ ];
2714
+ case "behind":
2715
+ return [
2716
+ "Run 'basic pull' to get the latest changes",
2717
+ "Or run 'basic status' for more details"
2718
+ ];
2719
+ case "invalid":
2720
+ return [
2721
+ "Fix the validation errors shown below",
2722
+ "Run 'basic status' again after fixing errors",
2723
+ "Review your schema syntax and field definitions"
2724
+ ];
2725
+ case "no-schema":
2726
+ return [
2727
+ "Run 'basic init' to create a new project or import an existing project",
2728
+ "Make sure you're in a directory with a basic.config.ts/js file"
2729
+ ];
2730
+ default:
2731
+ return [];
2732
+ }
2733
+ };
2734
+ return _jsxs7(Box6, { flexDirection: "column", children: [result.projectId && _jsxs7(Box6, { flexDirection: "column", marginBottom: 1, children: [_jsxs7(Text8, { color: "cyan", children: ["Project ID: ", result.projectId] }), _jsxs7(Box6, { children: [_jsxs7(Text8, { color: "gray", children: ["Local version: ", result.localVersion] }), result.remoteVersion > 0 && _jsxs7(Text8, { color: "gray", children: [" \u2022 Remote version: ", result.remoteVersion] })] })] }), _jsx8(Box6, { marginBottom: 1, children: _jsxs7(Text8, { color: getStatusColor(), children: [getStatusIcon(), " ", getStatusDescription()] }) }), _jsx8(Box6, { flexDirection: "column", marginBottom: 1, children: result.message.map((line, index) => _jsx8(Text8, { children: line }, index)) }), result.validationErrors && result.validationErrors.length > 0 && _jsx8(Box6, { flexDirection: "column", marginBottom: 1, children: result.validationErrors.map((error, index) => _jsxs7(Text8, { color: "red", children: ["\u2022 ", error.message, " at ", error.instancePath || "root"] }, index)) }), getNextSteps().length > 0 && _jsxs7(Box6, { flexDirection: "column", marginBottom: 1, children: [_jsx8(Text8, { color: "blue", children: "Next steps:" }), getNextSteps().map((step, index) => _jsxs7(Text8, { color: "gray", children: ["\u2022 ", step] }, index))] })] });
2735
+ }
2736
+ function PushSuccessDisplay({ result }) {
2737
+ return _jsxs7(Box6, { flexDirection: "column", children: [_jsx8(Box6, { marginBottom: 1, children: _jsx8(Text8, { color: "green", children: "\u2705 Schema pushed successfully!" }) }), _jsxs7(Box6, { flexDirection: "column", marginBottom: 1, children: [_jsxs7(Text8, { children: ["Source: ", result.filePath.split("/").pop()] }), _jsxs7(Text8, { children: ["Version: ", result.oldVersion, " \u2192 ", result.newVersion] }), _jsxs7(Text8, { children: ["Project: ", result.projectId] })] }), _jsxs7(Box6, { flexDirection: "column", marginTop: 1, children: [_jsx8(Text8, { color: "blue", children: "Next steps:" }), _jsx8(Text8, { color: "gray", children: "\u2022 Your schema changes are now live" }), _jsx8(Text8, { color: "gray", children: "\u2022 Continue working on your project" }), _jsx8(Text8, { color: "gray", children: "\u2022 Run 'basic status' to check your project state" })] })] });
2738
+ }
2739
+ async function PushCommand() {
2740
+ render5(_jsx8(PushApp, {}));
2741
+ }
2742
+ var init_push = __esm({
2743
+ "dist/commands/push.js"() {
2744
+ "use strict";
2745
+ init_Spinner();
2746
+ init_api();
2747
+ init_auth();
2748
+ init_schema();
2749
+ init_platform();
2750
+ init_constants();
2751
+ }
169
2752
  });
170
- // Pull command
171
- program
172
- .command('pull')
173
- .description('Pull schema from remote')
174
- .action(async () => {
2753
+
2754
+ // dist/lib/config-templates.js
2755
+ var config_templates_exports = {};
2756
+ __export(config_templates_exports, {
2757
+ CONFIG_TEMPLATES: () => CONFIG_TEMPLATES,
2758
+ checkForExistingConfig: () => checkForExistingConfig,
2759
+ createConfigFile: () => createConfigFile,
2760
+ generateConfigContent: () => generateConfigContent2,
2761
+ readExistingConfig: () => readExistingConfig
2762
+ });
2763
+ import * as fs3 from "fs/promises";
2764
+ import * as path3 from "path";
2765
+ function generateConfigContent2(template, projectId, projectName) {
2766
+ const baseConfig = {
2767
+ project_id: projectId,
2768
+ version: 0,
2769
+ tables: {
2770
+ example: {
2771
+ type: "collection",
2772
+ fields: {
2773
+ value: {
2774
+ type: "string"
2775
+ }
2776
+ }
2777
+ }
2778
+ }
2779
+ };
2780
+ switch (template) {
2781
+ case "typescript":
2782
+ return `// Basic Project Configuration
2783
+ // see the docs for more info: https://docs.basic.tech
2784
+
2785
+ const schema = ${JSON.stringify(baseConfig, null, 2)};
2786
+
2787
+ export default schema;
2788
+ `;
2789
+ case "javascript":
2790
+ return `// Basic Project Configuration
2791
+ // see the docs for more info: https://docs.basic.tech
2792
+
2793
+ const schema = ${JSON.stringify(baseConfig, null, 2)};
2794
+
2795
+ module.exports = schema;
2796
+ `;
2797
+ case "none":
2798
+ return "";
2799
+ default:
2800
+ throw new Error(`Unknown template: ${template}`);
2801
+ }
2802
+ }
2803
+ async function createConfigFile(template, projectId, projectName, targetDir = process.cwd()) {
2804
+ if (template === "none") {
2805
+ return null;
2806
+ }
2807
+ const templateInfo = CONFIG_TEMPLATES[template];
2808
+ const configPath = path3.join(targetDir, templateInfo.filename);
2809
+ const content = generateConfigContent2(template, projectId, projectName);
2810
+ try {
2811
+ await fs3.writeFile(configPath, content, "utf8");
2812
+ return configPath;
2813
+ } catch (error) {
2814
+ throw new Error(`Failed to create config file: ${error instanceof Error ? error.message : "Unknown error"}`);
2815
+ }
2816
+ }
2817
+ async function checkForExistingConfig(targetDir = process.cwd()) {
2818
+ const possibleConfigs = [
2819
+ "basic.config.ts",
2820
+ "basic.config.js",
2821
+ "basic.config.json"
2822
+ ];
2823
+ for (const filename of possibleConfigs) {
2824
+ const filePath = path3.join(targetDir, filename);
175
2825
  try {
176
- const { PullCommand } = await import('./commands/pull.js');
177
- await PullCommand();
2826
+ await fs3.access(filePath);
2827
+ return filePath;
2828
+ } catch {
2829
+ }
2830
+ }
2831
+ return null;
2832
+ }
2833
+ async function readExistingConfig(targetDir = process.cwd()) {
2834
+ const configPath = await checkForExistingConfig(targetDir);
2835
+ if (!configPath) {
2836
+ return null;
2837
+ }
2838
+ try {
2839
+ const content = await fs3.readFile(configPath, "utf8");
2840
+ if (configPath.endsWith(".json")) {
2841
+ const config = JSON.parse(content);
2842
+ return { projectId: config.project_id };
178
2843
  }
179
- catch (error) {
180
- const cliError = handleError(error);
181
- console.error(formatError(cliError));
182
- process.exit(1);
2844
+ const projectIdMatch = content.match(/["']?project_id["']?\s*:\s*["']([^"']+)["']/);
2845
+ if (projectIdMatch) {
2846
+ return { projectId: projectIdMatch[1] };
183
2847
  }
2848
+ return null;
2849
+ } catch (error) {
2850
+ throw new Error(`Failed to read existing config: ${error instanceof Error ? error.message : "Unknown error"}`);
2851
+ }
2852
+ }
2853
+ var CONFIG_TEMPLATES;
2854
+ var init_config_templates = __esm({
2855
+ "dist/lib/config-templates.js"() {
2856
+ "use strict";
2857
+ CONFIG_TEMPLATES = {
2858
+ typescript: {
2859
+ name: "TypeScript",
2860
+ description: "",
2861
+ filename: "basic.config.ts",
2862
+ extension: "ts"
2863
+ },
2864
+ javascript: {
2865
+ name: "JavaScript",
2866
+ description: "",
2867
+ filename: "basic.config.js",
2868
+ extension: "js"
2869
+ },
2870
+ none: {
2871
+ name: "None",
2872
+ description: "No configuration file",
2873
+ filename: "",
2874
+ extension: ""
2875
+ }
2876
+ };
2877
+ }
184
2878
  });
185
- // Push command
186
- program
187
- .command('push')
188
- .description('Push schema to remote')
189
- .action(async () => {
2879
+
2880
+ // dist/components/InitForm.js
2881
+ import { jsx as _jsx9, jsxs as _jsxs8, Fragment as _Fragment3 } from "react/jsx-runtime";
2882
+ import { useState as useState3, useEffect as useEffect3 } from "react";
2883
+ import { Box as Box7, Text as Text9, useInput as useInput5 } from "ink";
2884
+ function InitForm({ onSuccess, onCancel, initialData }) {
2885
+ const [state, setState] = useState3({
2886
+ step: initialData?.source ? initialData.source === "new" ? "project-details" : "existing-selection" : "source",
2887
+ source: initialData?.source || null,
2888
+ projectName: initialData?.projectName || "",
2889
+ projectSlug: initialData?.projectName ? generateSlug(initialData.projectName) : "",
2890
+ selectedTeamId: null,
2891
+ selectedProjectId: initialData?.projectId || null,
2892
+ configTemplate: initialData?.configTemplate || null,
2893
+ availableTeams: [],
2894
+ availableProjects: [],
2895
+ isLoading: false,
2896
+ error: null
2897
+ });
2898
+ const [selectedOptionIndex, setSelectedOptionIndex] = useState3(0);
2899
+ const [showTeamForm, setShowTeamForm] = useState3(false);
2900
+ useEffect3(() => {
2901
+ async function loadData() {
2902
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
2903
+ try {
2904
+ const apiClient = ApiClient.getInstance();
2905
+ const [teams, projects] = await Promise.all([
2906
+ apiClient.getTeams(),
2907
+ apiClient.getProjects()
2908
+ ]);
2909
+ setState((prev) => ({
2910
+ ...prev,
2911
+ availableTeams: teams,
2912
+ availableProjects: projects,
2913
+ isLoading: false,
2914
+ selectedTeamId: teams.length > 0 ? teams[0].id : null
2915
+ }));
2916
+ } catch (error) {
2917
+ setState((prev) => ({
2918
+ ...prev,
2919
+ isLoading: false,
2920
+ error: error instanceof Error ? error.message : "Failed to load data"
2921
+ }));
2922
+ }
2923
+ }
2924
+ loadData();
2925
+ }, []);
2926
+ useEffect3(() => {
2927
+ if (state.projectName.trim()) {
2928
+ const newSlug = generateSlug(state.projectName);
2929
+ setState((prev) => ({ ...prev, projectSlug: newSlug }));
2930
+ }
2931
+ }, [state.projectName]);
2932
+ useInput5((input, key) => {
2933
+ if (showTeamForm) {
2934
+ return;
2935
+ }
2936
+ if (key.escape) {
2937
+ if (state.step === "source") {
2938
+ onCancel();
2939
+ } else {
2940
+ goToPreviousStep();
2941
+ }
2942
+ return;
2943
+ }
2944
+ if (state.step === "project-details") {
2945
+ handleProjectDetailsInput(input, key);
2946
+ } else if (state.step === "source" || state.step === "team-selection" || state.step === "existing-selection" || state.step === "config-template" || state.step === "confirmation") {
2947
+ handleSelectionInput(input, key);
2948
+ }
2949
+ });
2950
+ const handleProjectDetailsInput = (input, key) => {
2951
+ if (key.return) {
2952
+ if (state.projectName.trim()) {
2953
+ setState((prev) => ({ ...prev, step: "team-selection" }));
2954
+ setSelectedOptionIndex(0);
2955
+ }
2956
+ return;
2957
+ }
2958
+ if (key.backspace || key.delete) {
2959
+ setState((prev) => ({
2960
+ ...prev,
2961
+ projectName: prev.projectName.slice(0, -1)
2962
+ }));
2963
+ return;
2964
+ }
2965
+ if (input && input.length === 1) {
2966
+ setState((prev) => ({
2967
+ ...prev,
2968
+ projectName: prev.projectName + input
2969
+ }));
2970
+ }
2971
+ };
2972
+ const handleSelectionInput = (input, key) => {
2973
+ const options = getOptionsForCurrentStep();
2974
+ if (key.upArrow) {
2975
+ setSelectedOptionIndex((prev) => prev > 0 ? prev - 1 : options.length - 1);
2976
+ return;
2977
+ }
2978
+ if (key.downArrow) {
2979
+ setSelectedOptionIndex((prev) => prev < options.length - 1 ? prev + 1 : 0);
2980
+ return;
2981
+ }
2982
+ if (key.return) {
2983
+ handleOptionSelection();
2984
+ }
2985
+ };
2986
+ const getOptionsForCurrentStep = () => {
2987
+ switch (state.step) {
2988
+ case "source":
2989
+ return [
2990
+ { label: "Create new project", value: "new" },
2991
+ { label: "Import existing project", value: "existing" }
2992
+ ];
2993
+ case "team-selection":
2994
+ const teamOptions = state.availableTeams.map((team) => ({
2995
+ label: `${team.name} (${team.slug})`,
2996
+ value: team.id
2997
+ }));
2998
+ teamOptions.push({ label: "Create new team...", value: "new" });
2999
+ return teamOptions;
3000
+ case "existing-selection":
3001
+ return state.availableProjects.map((project) => ({
3002
+ label: `${project.name} (${project.team_name || "Unknown team"})`,
3003
+ value: project.id
3004
+ }));
3005
+ case "config-template":
3006
+ return Object.entries(CONFIG_TEMPLATES).map(([key, template]) => ({
3007
+ label: `${template.name} - ${template.description}`,
3008
+ value: key
3009
+ }));
3010
+ case "confirmation":
3011
+ return [
3012
+ {
3013
+ label: state.source === "new" ? "Yes, create project" : "Yes, import project",
3014
+ value: "confirm"
3015
+ },
3016
+ { label: "No, go back", value: "back" }
3017
+ ];
3018
+ default:
3019
+ return [];
3020
+ }
3021
+ };
3022
+ const handleOptionSelection = () => {
3023
+ const options = getOptionsForCurrentStep();
3024
+ const selectedOption = options[selectedOptionIndex];
3025
+ switch (state.step) {
3026
+ case "source":
3027
+ setState((prev) => ({
3028
+ ...prev,
3029
+ source: selectedOption.value,
3030
+ step: selectedOption.value === "new" ? "project-details" : "existing-selection"
3031
+ }));
3032
+ setSelectedOptionIndex(0);
3033
+ break;
3034
+ case "team-selection":
3035
+ if (selectedOption.value === "new") {
3036
+ setShowTeamForm(true);
3037
+ } else {
3038
+ setState((prev) => ({
3039
+ ...prev,
3040
+ selectedTeamId: selectedOption.value,
3041
+ step: "config-template"
3042
+ }));
3043
+ setSelectedOptionIndex(0);
3044
+ }
3045
+ break;
3046
+ case "existing-selection":
3047
+ setState((prev) => ({
3048
+ ...prev,
3049
+ selectedProjectId: selectedOption.value,
3050
+ step: "config-template"
3051
+ }));
3052
+ setSelectedOptionIndex(0);
3053
+ break;
3054
+ case "config-template":
3055
+ setState((prev) => ({
3056
+ ...prev,
3057
+ configTemplate: selectedOption.value,
3058
+ step: "confirmation"
3059
+ }));
3060
+ setSelectedOptionIndex(0);
3061
+ break;
3062
+ case "confirmation":
3063
+ if (selectedOption.value === "confirm") {
3064
+ handleSubmit();
3065
+ } else {
3066
+ goToPreviousStep();
3067
+ }
3068
+ break;
3069
+ }
3070
+ };
3071
+ const goToPreviousStep = () => {
3072
+ switch (state.step) {
3073
+ case "project-details":
3074
+ setState((prev) => ({ ...prev, step: "source" }));
3075
+ break;
3076
+ case "team-selection":
3077
+ setState((prev) => ({ ...prev, step: "project-details" }));
3078
+ break;
3079
+ case "existing-selection":
3080
+ setState((prev) => ({ ...prev, step: "source" }));
3081
+ break;
3082
+ case "config-template":
3083
+ setState((prev) => ({
3084
+ ...prev,
3085
+ step: state.source === "new" ? "team-selection" : "existing-selection"
3086
+ }));
3087
+ break;
3088
+ case "confirmation":
3089
+ setState((prev) => ({ ...prev, step: "config-template" }));
3090
+ break;
3091
+ }
3092
+ setSelectedOptionIndex(0);
3093
+ };
3094
+ const handleTeamCreated = async (teamData) => {
3095
+ setState((prev) => ({ ...prev, isLoading: true }));
190
3096
  try {
191
- const { PushCommand } = await import('./commands/push.js');
192
- await PushCommand();
193
- }
194
- catch (error) {
195
- const cliError = handleError(error);
196
- console.error(formatError(cliError));
197
- process.exit(1);
198
- }
199
- });
200
- // Init command
201
- program
202
- .command('init')
203
- .description('Create a new project or import an existing project')
204
- .option('--new', 'Create a new project (skip project type selection)')
205
- .option('--existing', 'Import an existing project')
206
- .option('--name <name>', 'Project name for new projects')
207
- .option('--project <id>', 'Project ID for existing projects')
208
- .option('--ts', 'Use TypeScript configuration template')
209
- .option('--js', 'Use JavaScript configuration template')
210
- .action(async (options) => {
3097
+ const apiClient = ApiClient.getInstance();
3098
+ const newTeam = await apiClient.createTeam(teamData.teamName, teamData.teamSlug);
3099
+ setState((prev) => ({
3100
+ ...prev,
3101
+ availableTeams: [...prev.availableTeams, newTeam],
3102
+ selectedTeamId: newTeam.id,
3103
+ step: "config-template",
3104
+ isLoading: false
3105
+ }));
3106
+ setShowTeamForm(false);
3107
+ setSelectedOptionIndex(0);
3108
+ } catch (error) {
3109
+ setState((prev) => ({
3110
+ ...prev,
3111
+ isLoading: false,
3112
+ error: error instanceof Error ? error.message : "Failed to create team"
3113
+ }));
3114
+ }
3115
+ };
3116
+ const handleSubmit = async () => {
3117
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
211
3118
  try {
212
- const { InitCommand } = await import('./commands/init.js');
213
- await InitCommand(options);
3119
+ const apiClient = ApiClient.getInstance();
3120
+ let projectId;
3121
+ let projectName;
3122
+ if (state.source === "new") {
3123
+ if (!state.selectedTeamId || !state.configTemplate) {
3124
+ throw new Error("Missing required data for project creation");
3125
+ }
3126
+ const project = await apiClient.createProjectWithTeam(state.projectName, state.projectSlug, state.selectedTeamId);
3127
+ projectId = project.id;
3128
+ projectName = project.name;
3129
+ } else {
3130
+ if (!state.selectedProjectId) {
3131
+ throw new Error("No project selected");
3132
+ }
3133
+ const project = await apiClient.getProject(state.selectedProjectId);
3134
+ projectId = project.id;
3135
+ projectName = project.name;
3136
+ }
3137
+ let configPath = null;
3138
+ if (state.configTemplate && state.configTemplate !== "none") {
3139
+ const { createConfigFile: createConfigFile2 } = await Promise.resolve().then(() => (init_config_templates(), config_templates_exports));
3140
+ configPath = await createConfigFile2(state.configTemplate, projectId, projectName);
3141
+ try {
3142
+ const remoteSchema = await apiClient.getProjectSchema(projectId);
3143
+ if (remoteSchema && remoteSchema.version > 0) {
3144
+ const { saveSchemaToConfig: saveSchemaToConfig2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
3145
+ await saveSchemaToConfig2(remoteSchema);
3146
+ }
3147
+ } catch (error) {
3148
+ console.warn("Failed to pull latest schema during init:", error);
3149
+ }
3150
+ }
3151
+ onSuccess({ projectId, projectName, configPath });
3152
+ } catch (error) {
3153
+ setState((prev) => ({
3154
+ ...prev,
3155
+ isLoading: false,
3156
+ error: error instanceof Error ? error.message : "Failed to create project"
3157
+ }));
214
3158
  }
215
- catch (error) {
216
- const cliError = handleError(error);
217
- console.error(formatError(cliError));
218
- process.exit(1);
3159
+ };
3160
+ if (showTeamForm) {
3161
+ return _jsx9(TeamForm, { title: "Create New Team", onSubmit: handleTeamCreated, onCancel: () => setShowTeamForm(false) });
3162
+ }
3163
+ if (state.isLoading) {
3164
+ return _jsx9(Spinner, { text: "Loading..." });
3165
+ }
3166
+ if (state.error) {
3167
+ return _jsxs8(Box7, { flexDirection: "column", children: [_jsxs8(Text9, { color: "red", children: ["Error: ", state.error] }), _jsx9(Text9, { color: "gray", children: "Press Esc to go back" })] });
3168
+ }
3169
+ return _jsx9(Box7, { flexDirection: "column", padding: 1, children: renderCurrentStep() });
3170
+ function renderCurrentStep() {
3171
+ const stepNumber = getStepNumber();
3172
+ const totalSteps = getTotalSteps();
3173
+ switch (state.step) {
3174
+ case "source":
3175
+ return _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { bold: true, color: "blue", children: ["Project Setup (", stepNumber, "/", totalSteps, ")"] }), _jsx9(Box7, { marginTop: 1, marginBottom: 2, children: _jsx9(Text9, { children: "How would you like to proceed?" }) }), renderOptions(), _jsx9(Box7, { marginTop: 2, children: _jsx9(Text9, { color: "gray", children: "\u2191/\u2193 select \u2022 enter to continue \u2022 esc to cancel" }) })] });
3176
+ case "project-details":
3177
+ return _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { bold: true, color: "blue", children: ["Create New Project (", stepNumber, "/", totalSteps, ")"] }), _jsx9(Box7, { marginTop: 1, marginBottom: 1, children: _jsxs8(Text9, { color: "blue", children: [">", " Project Name:"] }) }), _jsx9(Box7, { marginLeft: 2, marginBottom: 1, children: _jsxs8(Text9, { children: [state.projectName, _jsx9(Text9, { backgroundColor: "white", color: "black", children: "\u2588" })] }) }), state.projectSlug && _jsxs8(Box7, { marginBottom: 1, children: [_jsx9(Box7, { children: _jsx9(Text9, { color: "gray", children: "\u2713 Project Slug (auto-generated):" }) }), _jsx9(Box7, { marginLeft: 2, children: _jsx9(Text9, { children: state.projectSlug }) })] }), _jsx9(Box7, { marginTop: 2, children: _jsx9(Text9, { color: "gray", children: state.projectName.trim() ? "Enter to continue \u2022 esc to go back" : "Type project name \u2022 esc to go back" }) })] });
3178
+ case "team-selection":
3179
+ return _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { bold: true, color: "blue", children: ["Create New Project (", stepNumber, "/", totalSteps, ")"] }), _jsxs8(Box7, { marginTop: 1, children: [_jsxs8(Text9, { color: "gray", children: ["\u2713 Project Name: ", state.projectName] }), _jsxs8(Text9, { color: "gray", children: ["\u2713 Project Slug: ", state.projectSlug] })] }), _jsx9(Box7, { marginTop: 1, marginBottom: 2, children: _jsx9(Text9, { children: "Select Team:" }) }), renderOptions(), _jsx9(Box7, { marginTop: 2, children: _jsx9(Text9, { color: "gray", children: "\u2191/\u2193 select \u2022 enter to continue \u2022 esc to go back" }) })] });
3180
+ case "existing-selection":
3181
+ return _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { bold: true, color: "blue", children: ["Import Existing Project (", stepNumber, "/", totalSteps, ")"] }), _jsx9(Box7, { marginTop: 1, marginBottom: 2, children: _jsx9(Text9, { children: "Select Project:" }) }), renderOptions(), _jsx9(Box7, { marginTop: 2, children: _jsx9(Text9, { color: "gray", children: "\u2191/\u2193 select \u2022 enter to continue \u2022 esc to go back" }) })] });
3182
+ case "config-template":
3183
+ return _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { bold: true, color: "blue", children: ["Configuration Setup (", stepNumber, "/", totalSteps, ")"] }), _jsx9(Box7, { marginTop: 1, marginBottom: 2, children: _jsx9(Text9, { children: "Choose config template:" }) }), renderOptions(), _jsx9(Box7, { marginTop: 2, children: _jsx9(Text9, { color: "gray", children: "\u2191/\u2193 select \u2022 enter to continue \u2022 esc to go back" }) })] });
3184
+ case "confirmation":
3185
+ return _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { bold: true, color: "blue", children: ["Ready to ", state.source === "new" ? "Create" : "Import", " (", stepNumber, "/", totalSteps, ")"] }), _jsxs8(Box7, { marginTop: 1, marginBottom: 2, flexDirection: "column", children: [state.source === "new" ? _jsxs8(_Fragment3, { children: [_jsxs8(Text9, { children: ["\u2713 Project: ", state.projectName] }), _jsxs8(Text9, { children: ["\u2713 Team: ", getSelectedTeamName()] })] }) : _jsxs8(Text9, { children: ["\u2713 Project: ", getSelectedProjectName()] }), _jsxs8(Text9, { children: ["\u2713 Config: ", getSelectedTemplateName()] }), state.configTemplate !== "none" && _jsxs8(Text9, { children: ["\u2713 Location: ./", CONFIG_TEMPLATES[state.configTemplate].filename] })] }), renderOptions(), _jsx9(Box7, { marginTop: 2, children: _jsx9(Text9, { color: "gray", children: "\u2191/\u2193 select \u2022 enter to confirm \u2022 esc to go back" }) })] });
3186
+ default:
3187
+ return _jsx9(Text9, { children: "Unknown step" });
219
3188
  }
3189
+ }
3190
+ function renderOptions() {
3191
+ const options = getOptionsForCurrentStep();
3192
+ return _jsx9(Box7, { flexDirection: "column", children: options.map((option, index) => _jsx9(Box7, { marginLeft: 2, children: _jsxs8(Text9, { color: index === selectedOptionIndex ? "blue" : "white", children: [index === selectedOptionIndex ? "\u25CF" : "\u25CB", " ", option.label] }) }, option.value)) });
3193
+ }
3194
+ function getStepNumber() {
3195
+ const stepOrder = ["source", "project-details", "team-selection", "existing-selection", "config-template", "confirmation"];
3196
+ return stepOrder.indexOf(state.step) + 1;
3197
+ }
3198
+ function getTotalSteps() {
3199
+ return state.source === "new" ? 5 : 4;
3200
+ }
3201
+ function getSelectedTeamName() {
3202
+ const team = state.availableTeams.find((t) => t.id === state.selectedTeamId);
3203
+ return team ? team.name : "Unknown";
3204
+ }
3205
+ function getSelectedProjectName() {
3206
+ const project = state.availableProjects.find((p) => p.id === state.selectedProjectId);
3207
+ return project ? project.name : "Unknown";
3208
+ }
3209
+ function getSelectedTemplateName() {
3210
+ return state.configTemplate ? CONFIG_TEMPLATES[state.configTemplate].name : "None";
3211
+ }
3212
+ }
3213
+ var init_InitForm = __esm({
3214
+ "dist/components/InitForm.js"() {
3215
+ "use strict";
3216
+ init_api();
3217
+ init_platform();
3218
+ init_config_templates();
3219
+ init_Spinner();
3220
+ init_TeamForm();
3221
+ }
220
3222
  });
221
- // Handle unknown commands
222
- program.on('command:*', (operands) => {
223
- const unknownCommand = operands[0];
224
- const suggestions = findSimilarCommands(unknownCommand);
225
- console.error(`Unknown command: ${unknownCommand}\n`);
226
- if (suggestions.length > 0) {
227
- console.error('Did you mean:');
228
- suggestions.forEach(suggestion => {
229
- console.error(` - ${suggestion}`);
3223
+
3224
+ // dist/commands/init.js
3225
+ var init_exports = {};
3226
+ __export(init_exports, {
3227
+ InitCommand: () => InitCommand
3228
+ });
3229
+ import { jsx as _jsx10, jsxs as _jsxs9 } from "react/jsx-runtime";
3230
+ import React7 from "react";
3231
+ import { render as render6, Box as Box8, Text as Text10 } from "ink";
3232
+ function InitApp({ options }) {
3233
+ const [state, setState] = React7.useState({
3234
+ loading: true,
3235
+ error: null,
3236
+ success: false
3237
+ });
3238
+ const [initialData, setInitialData] = React7.useState(null);
3239
+ React7.useEffect(() => {
3240
+ async function initialize() {
3241
+ try {
3242
+ if (!await isOnline()) {
3243
+ setState({ loading: false, error: MESSAGES.OFFLINE, success: false });
3244
+ return;
3245
+ }
3246
+ const authService = AuthService.getInstance();
3247
+ const token = await authService.getToken();
3248
+ if (!token) {
3249
+ setState({ loading: false, error: MESSAGES.LOGGED_OUT, success: false });
3250
+ return;
3251
+ }
3252
+ const existingConfigPath = await checkForExistingConfig();
3253
+ if (existingConfigPath) {
3254
+ const existingConfig = await readExistingConfig();
3255
+ if (existingConfig?.projectId) {
3256
+ setState({
3257
+ loading: false,
3258
+ error: `A basic.config already exists in this directory
3259
+ Project ID: ${existingConfig.projectId}
3260
+
3261
+ To reinitialize, please remove the existing config file first.`,
3262
+ success: false
3263
+ });
3264
+ return;
3265
+ }
3266
+ }
3267
+ const parsedData = parseCliOptions(options);
3268
+ setInitialData(parsedData);
3269
+ setState({ loading: false, error: null, success: false });
3270
+ } catch (error) {
3271
+ setState({
3272
+ loading: false,
3273
+ error: error instanceof Error ? error.message : "Failed to initialize",
3274
+ success: false
230
3275
  });
231
- console.error('');
3276
+ }
232
3277
  }
233
- console.error("Use 'basic help' to see all commands.");
3278
+ initialize();
3279
+ }, [options]);
3280
+ const handleSuccess = (result) => {
3281
+ setState({ loading: false, error: null, success: true, result });
3282
+ setTimeout(() => {
3283
+ process.exit(0);
3284
+ }, 2e3);
3285
+ };
3286
+ const handleCancel = () => {
3287
+ process.exit(0);
3288
+ };
3289
+ if (state.loading) {
3290
+ return _jsx10(Spinner, { text: "Initializing..." });
3291
+ }
3292
+ if (state.error) {
3293
+ return _jsxs9(Box8, { flexDirection: "column", children: [_jsxs9(Text10, { color: "red", children: ["Error: ", state.error] }), _jsx10(Text10, { color: "gray", children: "Please resolve the issue and try again." })] });
3294
+ }
3295
+ if (state.success && state.result) {
3296
+ return _jsxs9(Box8, { flexDirection: "column", children: [_jsx10(Text10, { color: "green", children: "\u2705 Project setup complete!" }), _jsx10(Text10, {}), _jsxs9(Text10, { children: ["Project: ", state.result.projectName] }), _jsxs9(Text10, { children: ["Project ID: ", state.result.projectId] }), state.result.configPath && _jsxs9(Text10, { children: ["Config file: ", state.result.configPath] }), _jsx10(Text10, {}), _jsx10(Text10, { color: "gray", children: "Visit https://docs.basic.tech for next steps." })] });
3297
+ }
3298
+ return _jsx10(InitForm, { onSuccess: handleSuccess, onCancel: handleCancel, initialData: initialData || void 0 });
3299
+ }
3300
+ function parseCliOptions(options) {
3301
+ const result = {};
3302
+ if (options.new) {
3303
+ result.source = "new";
3304
+ } else if (options.existing) {
3305
+ result.source = "existing";
3306
+ }
3307
+ if (options.name) {
3308
+ result.projectName = options.name;
3309
+ }
3310
+ if (options.project) {
3311
+ result.projectId = options.project;
3312
+ result.source = "existing";
3313
+ }
3314
+ if (options.ts) {
3315
+ result.configTemplate = "typescript";
3316
+ } else if (options.js) {
3317
+ result.configTemplate = "javascript";
3318
+ }
3319
+ return result;
3320
+ }
3321
+ async function InitCommand(args = {}) {
3322
+ render6(_jsx10(InitApp, { options: args }));
3323
+ }
3324
+ var init_init = __esm({
3325
+ "dist/commands/init.js"() {
3326
+ "use strict";
3327
+ init_InitForm();
3328
+ init_Spinner();
3329
+ init_auth();
3330
+ init_config_templates();
3331
+ init_platform();
3332
+ init_constants();
3333
+ }
3334
+ });
3335
+
3336
+ // dist/index.js
3337
+ init_constants();
3338
+ init_version();
3339
+ init_errors();
3340
+ init_platform();
3341
+ import { program } from "commander";
3342
+ process.on("uncaughtException", (error) => {
3343
+ console.error("Fatal error:", error.message);
3344
+ process.exit(1);
3345
+ });
3346
+ process.on("SIGINT", () => {
3347
+ console.log("\nOperation cancelled");
3348
+ process.exit(0);
3349
+ });
3350
+ program.name("basic").description("Basic CLI for creating & managing your projects").version(getVersion());
3351
+ program.command("login").description("Login to your Basic account").action(async () => {
3352
+ try {
3353
+ const { LoginCommand: LoginCommand2 } = await Promise.resolve().then(() => (init_login(), login_exports));
3354
+ await LoginCommand2();
3355
+ process.exit(0);
3356
+ } catch (error) {
3357
+ const cliError = handleError(error);
3358
+ console.error(formatError(cliError));
234
3359
  process.exit(1);
3360
+ }
235
3361
  });
236
- // Show welcome message if no command provided
237
- if (process.argv.length <= 2) {
238
- console.log(MESSAGES.WELCOME);
3362
+ program.command("logout").description("Logout from your Basic account").action(async () => {
3363
+ try {
3364
+ const { LogoutCommand: LogoutCommand2 } = await Promise.resolve().then(() => (init_logout(), logout_exports));
3365
+ await LogoutCommand2();
3366
+ process.exit(0);
3367
+ } catch (error) {
3368
+ const cliError = handleError(error);
3369
+ console.error(formatError(cliError));
3370
+ process.exit(1);
3371
+ }
3372
+ });
3373
+ program.command("account").description("Show account information").action(async () => {
3374
+ try {
3375
+ const { AccountCommand: AccountCommand2 } = await Promise.resolve().then(() => (init_account(), account_exports));
3376
+ await AccountCommand2();
239
3377
  process.exit(0);
3378
+ } catch (error) {
3379
+ const cliError = handleError(error);
3380
+ console.error(formatError(cliError));
3381
+ process.exit(1);
3382
+ }
3383
+ });
3384
+ program.command("version").description("Show CLI version").action(async () => {
3385
+ try {
3386
+ const { VersionCommand: VersionCommand2 } = await Promise.resolve().then(() => (init_version2(), version_exports));
3387
+ await VersionCommand2();
3388
+ process.exit(0);
3389
+ } catch (error) {
3390
+ const cliError = handleError(error);
3391
+ console.error(formatError(cliError));
3392
+ process.exit(1);
3393
+ }
3394
+ });
3395
+ program.command("update").description("Update CLI to the latest version").action(async () => {
3396
+ try {
3397
+ const { UpdateCommand: UpdateCommand2 } = await Promise.resolve().then(() => (init_update(), update_exports));
3398
+ await UpdateCommand2();
3399
+ process.exit(0);
3400
+ } catch (error) {
3401
+ const cliError = handleError(error);
3402
+ console.error(formatError(cliError));
3403
+ process.exit(1);
3404
+ }
3405
+ });
3406
+ program.command("help").description("Show help information").action(() => {
3407
+ program.help();
3408
+ });
3409
+ program.command("debug").description("Show Basic config directory location").action(async () => {
3410
+ try {
3411
+ const { DebugCommand: DebugCommand2 } = await Promise.resolve().then(() => (init_debug(), debug_exports));
3412
+ await DebugCommand2();
3413
+ process.exit(0);
3414
+ } catch (error) {
3415
+ const cliError = handleError(error);
3416
+ console.error(formatError(cliError));
3417
+ process.exit(1);
3418
+ }
3419
+ });
3420
+ program.command("projects").description("List and browse your projects").action(async () => {
3421
+ try {
3422
+ const { ProjectsCommand: ProjectsCommand2 } = await Promise.resolve().then(() => (init_projects(), projects_exports));
3423
+ await ProjectsCommand2();
3424
+ } catch (error) {
3425
+ const cliError = handleError(error);
3426
+ console.error(formatError(cliError));
3427
+ process.exit(1);
3428
+ }
3429
+ });
3430
+ program.command("teams").argument("[action]", "Teams action (new)", "list").description("List teams or create a new team").action(async (action) => {
3431
+ try {
3432
+ const { TeamsCommand: TeamsCommand2 } = await Promise.resolve().then(() => (init_teams(), teams_exports));
3433
+ await TeamsCommand2(action);
3434
+ } catch (error) {
3435
+ const cliError = handleError(error);
3436
+ console.error(formatError(cliError));
3437
+ process.exit(1);
3438
+ }
3439
+ });
3440
+ program.command("status").description("Show project status").action(async () => {
3441
+ try {
3442
+ const { StatusCommand: StatusCommand2 } = await Promise.resolve().then(() => (init_status(), status_exports));
3443
+ await StatusCommand2();
3444
+ } catch (error) {
3445
+ const cliError = handleError(error);
3446
+ console.error(formatError(cliError));
3447
+ process.exit(1);
3448
+ }
3449
+ });
3450
+ program.command("pull").description("Pull schema from remote").action(async () => {
3451
+ try {
3452
+ const { PullCommand: PullCommand2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
3453
+ await PullCommand2();
3454
+ } catch (error) {
3455
+ const cliError = handleError(error);
3456
+ console.error(formatError(cliError));
3457
+ process.exit(1);
3458
+ }
3459
+ });
3460
+ program.command("push").description("Push schema to remote").action(async () => {
3461
+ try {
3462
+ const { PushCommand: PushCommand2 } = await Promise.resolve().then(() => (init_push(), push_exports));
3463
+ await PushCommand2();
3464
+ } catch (error) {
3465
+ const cliError = handleError(error);
3466
+ console.error(formatError(cliError));
3467
+ process.exit(1);
3468
+ }
3469
+ });
3470
+ program.command("init").description("Create a new project or import an existing project").option("--new", "Create a new project (skip project type selection)").option("--existing", "Import an existing project").option("--name <name>", "Project name for new projects").option("--project <id>", "Project ID for existing projects").option("--ts", "Use TypeScript configuration template").option("--js", "Use JavaScript configuration template").action(async (options) => {
3471
+ try {
3472
+ const { InitCommand: InitCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
3473
+ await InitCommand2(options);
3474
+ } catch (error) {
3475
+ const cliError = handleError(error);
3476
+ console.error(formatError(cliError));
3477
+ process.exit(1);
3478
+ }
3479
+ });
3480
+ program.on("command:*", (operands) => {
3481
+ const unknownCommand = operands[0];
3482
+ const suggestions = findSimilarCommands(unknownCommand);
3483
+ console.error(`Unknown command: ${unknownCommand}
3484
+ `);
3485
+ if (suggestions.length > 0) {
3486
+ console.error("Did you mean:");
3487
+ suggestions.forEach((suggestion) => {
3488
+ console.error(` - ${suggestion}`);
3489
+ });
3490
+ console.error("");
3491
+ }
3492
+ console.error("Use 'basic help' to see all commands.");
3493
+ process.exit(1);
3494
+ });
3495
+ if (process.argv.length <= 2) {
3496
+ console.log(MESSAGES.WELCOME);
3497
+ process.exit(0);
240
3498
  }
241
- // Parse command line arguments
242
3499
  program.parse();
243
- //# sourceMappingURL=index.js.map