@base44-preview/cli 0.0.15-pr.19.d9072f9 → 0.0.15-pr.87.46d28c7

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.
Files changed (29) hide show
  1. package/dist/{program.js → cli/index.js} +258 -113
  2. package/package.json +8 -14
  3. package/bin/dev.cmd +0 -2
  4. package/bin/dev.js +0 -20
  5. package/bin/run.cmd +0 -2
  6. package/bin/run.js +0 -20
  7. /package/dist/{templates → cli/templates}/backend-and-client/.nvmrc +0 -0
  8. /package/dist/{templates → cli/templates}/backend-and-client/README.md +0 -0
  9. /package/dist/{templates → cli/templates}/backend-and-client/base44/app.jsonc.ejs +0 -0
  10. /package/dist/{templates → cli/templates}/backend-and-client/base44/config.jsonc.ejs +0 -0
  11. /package/dist/{templates → cli/templates}/backend-and-client/base44/entities/task.jsonc +0 -0
  12. /package/dist/{templates → cli/templates}/backend-and-client/components.json +0 -0
  13. /package/dist/{templates → cli/templates}/backend-and-client/index.html +0 -0
  14. /package/dist/{templates → cli/templates}/backend-and-client/jsconfig.json +0 -0
  15. /package/dist/{templates → cli/templates}/backend-and-client/package.json +0 -0
  16. /package/dist/{templates → cli/templates}/backend-and-client/postcss.config.js +0 -0
  17. /package/dist/{templates → cli/templates}/backend-and-client/src/App.jsx +0 -0
  18. /package/dist/{templates → cli/templates}/backend-and-client/src/api/base44Client.js.ejs +0 -0
  19. /package/dist/{templates → cli/templates}/backend-and-client/src/components/Base44Logo.jsx +0 -0
  20. /package/dist/{templates → cli/templates}/backend-and-client/src/components/ui/button.jsx +0 -0
  21. /package/dist/{templates → cli/templates}/backend-and-client/src/components/ui/checkbox.jsx +0 -0
  22. /package/dist/{templates → cli/templates}/backend-and-client/src/components/ui/input.jsx +0 -0
  23. /package/dist/{templates → cli/templates}/backend-and-client/src/index.css +0 -0
  24. /package/dist/{templates → cli/templates}/backend-and-client/src/main.jsx +0 -0
  25. /package/dist/{templates → cli/templates}/backend-and-client/tailwind.config.js +0 -0
  26. /package/dist/{templates → cli/templates}/backend-and-client/vite.config.js +0 -0
  27. /package/dist/{templates → cli/templates}/backend-only/base44/app.jsonc.ejs +0 -0
  28. /package/dist/{templates → cli/templates}/backend-only/base44/config.jsonc.ejs +0 -0
  29. /package/dist/{templates → cli/templates}/templates.json +0 -0
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  import { createRequire } from "node:module";
2
3
  import { EventEmitter, addAbortListener, on, once, setMaxListeners } from "node:events";
3
4
  import childProcess, { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
@@ -30351,31 +30352,11 @@ async function deployAll(projectData) {
30351
30352
  //#region src/core/project/app-config.ts
30352
30353
  let cache = null;
30353
30354
  /**
30354
- * Load app config from BASE44_CLI_TEST_OVERRIDES env var.
30355
- * @returns true if override was applied, false otherwise
30356
- */
30357
- function loadFromTestOverrides() {
30358
- const overrides = process.env.BASE44_CLI_TEST_OVERRIDES;
30359
- if (!overrides) return false;
30360
- try {
30361
- const data = JSON.parse(overrides);
30362
- if (data.appConfig?.id && data.appConfig?.projectRoot) {
30363
- cache = {
30364
- id: data.appConfig.id,
30365
- projectRoot: data.appConfig.projectRoot
30366
- };
30367
- return true;
30368
- }
30369
- } catch {}
30370
- return false;
30371
- }
30372
- /**
30373
30355
  * Initialize app config by reading from .app.jsonc.
30374
30356
  * Must be called before using getAppConfig().
30375
30357
  * @throws Error if no project found or .app.jsonc missing
30376
30358
  */
30377
30359
  async function initAppConfig() {
30378
- if (loadFromTestOverrides()) return;
30379
30360
  if (cache) return;
30380
30361
  const projectRoot = await findProjectRoot();
30381
30362
  if (!projectRoot) throw new Error("No Base44 project found. Run this command from a project directory with a config.jsonc file.");
@@ -31069,6 +31050,58 @@ async function printBanner() {
31069
31050
  else console.log(theme.colors.base44Orange(BANNER_LINES.join("\n")));
31070
31051
  }
31071
31052
 
31053
+ //#endregion
31054
+ //#region src/cli/utils/json.ts
31055
+ /**
31056
+ * JSON output utilities for CLI commands.
31057
+ *
31058
+ * These utilities support the `--json` flag which outputs machine-readable JSON
31059
+ * instead of human-friendly formatted output.
31060
+ */
31061
+ let jsonModeEnabled = false;
31062
+ /**
31063
+ * Enable JSON output mode. Called by runCommand when --json flag is detected.
31064
+ */
31065
+ function setJsonMode(enabled) {
31066
+ jsonModeEnabled = enabled;
31067
+ }
31068
+ /**
31069
+ * Check if JSON output mode is currently active.
31070
+ */
31071
+ function isJsonMode() {
31072
+ return jsonModeEnabled;
31073
+ }
31074
+ /**
31075
+ * Output a success JSON response to stdout.
31076
+ * Only outputs if JSON mode is enabled.
31077
+ */
31078
+ function outputJson(data) {
31079
+ if (!jsonModeEnabled) return;
31080
+ const response = {
31081
+ success: true,
31082
+ data
31083
+ };
31084
+ console.log(JSON.stringify(response, null, 2));
31085
+ }
31086
+ /**
31087
+ * Output an error JSON response to stderr.
31088
+ * Only outputs if JSON mode is enabled.
31089
+ *
31090
+ * @param error - The error to output
31091
+ * @param code - Optional error code
31092
+ */
31093
+ function outputJsonError(error, code$1) {
31094
+ if (!jsonModeEnabled) return;
31095
+ const response = {
31096
+ success: false,
31097
+ error: {
31098
+ message: error instanceof Error ? error.message : error,
31099
+ ...code$1 && { code: code$1 }
31100
+ }
31101
+ };
31102
+ console.error(JSON.stringify(response, null, 2));
31103
+ }
31104
+
31072
31105
  //#endregion
31073
31106
  //#region src/cli/utils/runCommand.ts
31074
31107
  /**
@@ -31102,25 +31135,35 @@ async function printBanner() {
31102
31135
  * });
31103
31136
  */
31104
31137
  async function runCommand(commandFn, options) {
31105
- console.log();
31106
- if (options?.fullBanner) {
31107
- await printBanner();
31108
- Ie("");
31109
- } else Ie(theme.colors.base44OrangeBackground(" Base 44 "));
31138
+ const jsonMode = isJsonMode();
31139
+ if (!jsonMode) {
31140
+ console.log();
31141
+ if (options?.fullBanner) {
31142
+ await printBanner();
31143
+ Ie("");
31144
+ } else Ie(theme.colors.base44OrangeBackground(" Base 44 "));
31145
+ }
31110
31146
  try {
31111
31147
  if (options?.requireAuth) {
31112
31148
  if (!await isLoggedIn()) {
31149
+ if (jsonMode) throw new Error("Authentication required. Please run 'base44 login' first.");
31113
31150
  M.info("You need to login first to continue.");
31114
31151
  await login();
31115
31152
  }
31116
31153
  }
31117
31154
  if (options?.requireAppConfig !== false) await initAppConfig();
31118
- const { outroMessage } = await commandFn();
31119
- Se(outroMessage || "");
31155
+ const { outroMessage, data } = await commandFn();
31156
+ if (jsonMode) outputJson(data ?? {});
31157
+ else Se(outroMessage || "");
31120
31158
  } catch (e$1) {
31121
- if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
31122
- else M.error(String(e$1));
31123
- throw new CLIExitError(1);
31159
+ if (jsonMode) {
31160
+ outputJsonError(e$1 instanceof Error ? e$1 : String(e$1));
31161
+ process.exit(1);
31162
+ } else {
31163
+ if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
31164
+ else M.error(String(e$1));
31165
+ process.exit(1);
31166
+ }
31124
31167
  }
31125
31168
  }
31126
31169
 
@@ -31130,6 +31173,8 @@ async function runCommand(commandFn, options) {
31130
31173
  * Wraps an async operation with automatic spinner management.
31131
31174
  * The spinner is automatically started, and stopped on both success and error.
31132
31175
  *
31176
+ * In JSON mode, the spinner is suppressed and the operation runs silently.
31177
+ *
31133
31178
  * @param startMessage - Message to show when spinner starts
31134
31179
  * @param operation - The async operation to execute. Receives an updateMessage function
31135
31180
  * to update the spinner text during long-running operations.
@@ -31165,6 +31210,10 @@ async function runCommand(commandFn, options) {
31165
31210
  * );
31166
31211
  */
31167
31212
  async function runTask(startMessage, operation, options) {
31213
+ if (isJsonMode()) {
31214
+ const noopUpdateMessage = () => {};
31215
+ return await operation(noopUpdateMessage);
31216
+ }
31168
31217
  const s = Y();
31169
31218
  s.start(startMessage);
31170
31219
  const updateMessage = (message) => s.message(message);
@@ -31205,6 +31254,10 @@ function getDashboardUrl(projectId) {
31205
31254
 
31206
31255
  //#endregion
31207
31256
  //#region src/cli/commands/auth/login.ts
31257
+ /**
31258
+ * Login command does not support --json output.
31259
+ * It requires interactive browser authentication via device code flow.
31260
+ */
31208
31261
  async function generateAndDisplayDeviceCode() {
31209
31262
  const deviceCodeResponse = await runTask("Generating device code...", async () => {
31210
31263
  return await generateDeviceCode();
@@ -31266,7 +31319,13 @@ const loginCommand = new Command("login").description("Authenticate with Base44"
31266
31319
  //#region src/cli/commands/auth/whoami.ts
31267
31320
  async function whoami() {
31268
31321
  const auth = await readAuth();
31269
- return { outroMessage: `Logged in as: ${theme.styles.bold(auth.email)}` };
31322
+ return {
31323
+ outroMessage: `Logged in as: ${theme.styles.bold(auth.email)}`,
31324
+ data: {
31325
+ email: auth.email,
31326
+ name: auth.name
31327
+ }
31328
+ };
31270
31329
  }
31271
31330
  const whoamiCommand = new Command("whoami").description("Display current authenticated user").action(async () => {
31272
31331
  await runCommand(whoami, {
@@ -31277,6 +31336,10 @@ const whoamiCommand = new Command("whoami").description("Display current authent
31277
31336
 
31278
31337
  //#endregion
31279
31338
  //#region src/cli/commands/auth/logout.ts
31339
+ /**
31340
+ * Logout command does not support --json output.
31341
+ * It is a user-facing auth command that is rarely scripted.
31342
+ */
31280
31343
  async function logout() {
31281
31344
  await deleteAuth();
31282
31345
  return { outroMessage: "Logged out successfully" };
@@ -31289,19 +31352,31 @@ const logoutCommand = new Command("logout").description("Logout from current dev
31289
31352
  //#region src/cli/commands/entities/push.ts
31290
31353
  async function pushEntitiesAction() {
31291
31354
  const { entities } = await readProjectConfig();
31292
- if (entities.length === 0) return { outroMessage: "No entities found in project" };
31293
- const entityNames = entities.map((e$1) => e$1.name).join(", ");
31294
- M.info(`Found ${entities.length} entities to push: ${entityNames}`);
31355
+ if (entities.length === 0) return {
31356
+ outroMessage: "No entities found in project",
31357
+ data: {
31358
+ created: [],
31359
+ updated: [],
31360
+ deleted: []
31361
+ }
31362
+ };
31363
+ if (!isJsonMode()) M.info(`Found ${entities.length} entities to push`);
31295
31364
  const result = await runTask("Pushing entities to Base44", async () => {
31296
31365
  return await pushEntities(entities);
31297
31366
  }, {
31298
31367
  successMessage: "Entities pushed successfully",
31299
31368
  errorMessage: "Failed to push entities"
31300
31369
  });
31301
- if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31302
- if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31303
- if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31304
- return {};
31370
+ if (!isJsonMode()) {
31371
+ if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31372
+ if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31373
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31374
+ }
31375
+ return { data: {
31376
+ created: result.created,
31377
+ updated: result.updated,
31378
+ deleted: result.deleted
31379
+ } };
31305
31380
  }
31306
31381
  const entitiesPushCommand = new Command("entities").description("Manage project entities").addCommand(new Command("push").description("Push local entities to Base44").action(async () => {
31307
31382
  await runCommand(pushEntitiesAction, { requireAuth: true });
@@ -31311,21 +31386,32 @@ const entitiesPushCommand = new Command("entities").description("Manage project
31311
31386
  //#region src/cli/commands/functions/deploy.ts
31312
31387
  async function deployFunctionsAction() {
31313
31388
  const { functions } = await readProjectConfig();
31314
- if (functions.length === 0) return { outroMessage: "No functions found. Create functions in the 'functions' directory." };
31315
- M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31389
+ if (functions.length === 0) return {
31390
+ outroMessage: "No functions found. Create functions in the 'functions' directory.",
31391
+ data: {
31392
+ deployed: [],
31393
+ deleted: []
31394
+ }
31395
+ };
31396
+ if (!isJsonMode()) M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31316
31397
  const result = await runTask("Deploying functions to Base44", async () => {
31317
31398
  return await pushFunctions(functions);
31318
31399
  }, {
31319
31400
  successMessage: "Functions deployed successfully",
31320
31401
  errorMessage: "Failed to deploy functions"
31321
31402
  });
31322
- if (result.deployed.length > 0) M.success(`Deployed: ${result.deployed.join(", ")}`);
31323
- if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31403
+ if (!isJsonMode()) {
31404
+ if (result.deployed.length > 0) M.success(`Deployed: ${result.deployed.join(", ")}`);
31405
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31406
+ }
31324
31407
  if (result.errors && result.errors.length > 0) {
31325
31408
  const errorMessages = result.errors.map((e$1) => `'${e$1.name}' function: ${e$1.message}`).join("\n");
31326
31409
  throw new Error(`Function deployment errors:\n${errorMessages}`);
31327
31410
  }
31328
- return {};
31411
+ return { data: {
31412
+ deployed: result.deployed,
31413
+ deleted: result.deleted
31414
+ } };
31329
31415
  }
31330
31416
  const functionsDeployCommand = new Command("functions").description("Manage project functions").addCommand(new Command("deploy").description("Deploy local functions to Base44").action(async () => {
31331
31417
  await runCommand(deployFunctionsAction, { requireAuth: true });
@@ -38009,10 +38095,11 @@ async function getTemplateById(templateId) {
38009
38095
  }
38010
38096
  return template;
38011
38097
  }
38012
- function validateNonInteractiveFlags$1(command) {
38013
- const { name: name$1, path: path$16 } = command.opts();
38098
+ function validateNonInteractiveFlags$2(command) {
38099
+ const { name: name$1, path: path$16, json } = command.optsWithGlobals();
38014
38100
  const providedCount = [name$1, path$16].filter(Boolean).length;
38015
- if (providedCount > 0 && providedCount < 2) command.error("Non-interactive mode requires all flags: --name, --path");
38101
+ if (json && providedCount < 2) throw new Error("JSON mode requires all flags: --name, --path");
38102
+ if (providedCount > 0 && providedCount < 2) throw new Error("Non-interactive mode requires all flags: --name, --path");
38016
38103
  }
38017
38104
  async function chooseCreate(options) {
38018
38105
  if (!!(options.name && options.path)) await runCommand(() => createNonInteractive(options), {
@@ -38135,12 +38222,23 @@ async function executeCreate({ template, name: rawName, description, projectPath
38135
38222
  finalAppUrl = appUrl;
38136
38223
  }
38137
38224
  }
38138
- M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38139
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl(projectId))}`);
38140
- if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38141
- return { outroMessage: "Your project is set up and ready to use" };
38225
+ const dashboardUrl = getDashboardUrl(projectId);
38226
+ if (!isJsonMode()) {
38227
+ M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38228
+ M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38229
+ if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38230
+ }
38231
+ return {
38232
+ outroMessage: "Your project is set up and ready to use",
38233
+ data: {
38234
+ projectId,
38235
+ path: resolvedPath,
38236
+ dashboardUrl,
38237
+ ...finalAppUrl && { appUrl: finalAppUrl }
38238
+ }
38239
+ };
38142
38240
  }
38143
- const createCommand = new Command("create").description("Create a new Base44 project").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-p, --path <path>", "Path where to create the project").option("-t, --template <id>", "Template ID (e.g., backend-only, backend-and-client)").option("--deploy", "Build and deploy the site").hook("preAction", validateNonInteractiveFlags$1).action(async (options) => {
38241
+ const createCommand = new Command("create").description("Create a new Base44 project").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-p, --path <path>", "Path where to create the project").option("-t, --template <id>", "Template ID (e.g., backend-only, backend-and-client)").option("--deploy", "Build and deploy the site").hook("preAction", validateNonInteractiveFlags$2).action(async (options) => {
38144
38242
  await chooseCreate(options);
38145
38243
  });
38146
38244
 
@@ -38685,20 +38783,36 @@ var open_default = open;
38685
38783
 
38686
38784
  //#endregion
38687
38785
  //#region src/cli/commands/project/dashboard.ts
38688
- async function openDashboard() {
38786
+ async function openDashboard(options) {
38689
38787
  const dashboardUrl = getDashboardUrl();
38690
- if (!process.env.CI) await open_default(dashboardUrl);
38691
- return { outroMessage: `Dashboard opened at ${dashboardUrl}` };
38788
+ const shouldOpen = !isJsonMode() && options.open !== false;
38789
+ if (shouldOpen) await open_default(dashboardUrl);
38790
+ return {
38791
+ outroMessage: shouldOpen ? `Dashboard opened at ${dashboardUrl}` : `Dashboard URL: ${dashboardUrl}`,
38792
+ data: { dashboardUrl }
38793
+ };
38692
38794
  }
38693
- const dashboardCommand = new Command("dashboard").description("Open the app dashboard in your browser").action(async () => {
38694
- await runCommand(openDashboard, { requireAuth: true });
38795
+ const dashboardCommand = new Command("dashboard").description("Open the app dashboard in your browser").option("--no-open", "Print the URL without opening the browser").action(async (options) => {
38796
+ await runCommand(() => openDashboard(options), { requireAuth: true });
38695
38797
  });
38696
38798
 
38697
38799
  //#endregion
38698
38800
  //#region src/cli/commands/project/deploy.ts
38801
+ function validateNonInteractiveFlags$1(command) {
38802
+ const opts = command.optsWithGlobals();
38803
+ if (opts.json && !opts.yes) throw new Error("JSON mode requires: --yes (-y) to skip confirmation");
38804
+ }
38699
38805
  async function deployAction$1(options) {
38700
38806
  const projectData = await readProjectConfig();
38701
- if (!hasResourcesToDeploy(projectData)) return { outroMessage: "No resources found to deploy" };
38807
+ if (!hasResourcesToDeploy(projectData)) return {
38808
+ outroMessage: "No resources found to deploy",
38809
+ data: {
38810
+ dashboardUrl: getDashboardUrl(),
38811
+ entitiesCount: 0,
38812
+ functionsCount: 0,
38813
+ siteDeployed: false
38814
+ }
38815
+ };
38702
38816
  const { project, entities, functions } = projectData;
38703
38817
  const summaryLines = [];
38704
38818
  if (entities.length > 0) summaryLines.push(` - ${entities.length} ${entities.length === 1 ? "entity" : "entities"}`);
@@ -38707,27 +38821,49 @@ async function deployAction$1(options) {
38707
38821
  if (!options.yes) {
38708
38822
  M.warn(`This will update your Base44 app with:\n${summaryLines.join("\n")}`);
38709
38823
  const shouldDeploy = await ye({ message: "Are you sure you want to continue?" });
38710
- if (pD(shouldDeploy) || !shouldDeploy) return { outroMessage: "Deployment cancelled" };
38711
- } else M.info(`Deploying:\n${summaryLines.join("\n")}`);
38824
+ if (pD(shouldDeploy) || !shouldDeploy) return {
38825
+ outroMessage: "Deployment cancelled",
38826
+ data: {
38827
+ dashboardUrl: getDashboardUrl(),
38828
+ entitiesCount: entities.length,
38829
+ functionsCount: functions.length,
38830
+ siteDeployed: false,
38831
+ cancelled: true
38832
+ }
38833
+ };
38834
+ } else if (!isJsonMode()) M.info(`Deploying:\n${summaryLines.join("\n")}`);
38712
38835
  const result = await runTask("Deploying your app...", async () => {
38713
38836
  return await deployAll(projectData);
38714
38837
  }, {
38715
38838
  successMessage: theme.colors.base44Orange("Deployment completed"),
38716
38839
  errorMessage: "Deployment failed"
38717
38840
  });
38718
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl())}`);
38719
- if (result.appUrl) M.message(`${theme.styles.header("App URL")}: ${theme.colors.links(result.appUrl)}`);
38720
- return { outroMessage: "App deployed successfully" };
38841
+ const dashboardUrl = getDashboardUrl();
38842
+ if (!isJsonMode()) {
38843
+ M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38844
+ if (result.appUrl) M.message(`${theme.styles.header("App URL")}: ${theme.colors.links(result.appUrl)}`);
38845
+ }
38846
+ return {
38847
+ outroMessage: "App deployed successfully",
38848
+ data: {
38849
+ dashboardUrl,
38850
+ appUrl: result.appUrl,
38851
+ entitiesCount: entities.length,
38852
+ functionsCount: functions.length,
38853
+ siteDeployed: !!project.site?.outputDirectory
38854
+ }
38855
+ };
38721
38856
  }
38722
- const deployCommand = new Command("deploy").description("Deploy all project resources (entities, functions, and site)").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
38857
+ const deployCommand = new Command("deploy").description("Deploy all project resources (entities, functions, and site)").option("-y, --yes", "Skip confirmation prompt").hook("preAction", validateNonInteractiveFlags$1).action(async (options) => {
38723
38858
  await runCommand(() => deployAction$1(options), { requireAuth: true });
38724
38859
  });
38725
38860
 
38726
38861
  //#endregion
38727
38862
  //#region src/cli/commands/project/link.ts
38728
38863
  function validateNonInteractiveFlags(command) {
38729
- const { create: create$1, name: name$1 } = command.opts();
38730
- if (create$1 && !name$1) command.error("--name is required when using --create");
38864
+ const { create: create$1, name: name$1, json } = command.optsWithGlobals();
38865
+ if (json && (!create$1 || !name$1)) throw new Error("JSON mode requires flags: --create, --name");
38866
+ if (create$1 && !name$1) throw new Error("--name is required when using --create");
38731
38867
  }
38732
38868
  async function promptForProjectDetails() {
38733
38869
  const actionOptions = [{
@@ -38778,8 +38914,15 @@ async function link(options) {
38778
38914
  id: projectId,
38779
38915
  projectRoot: projectRoot.root
38780
38916
  });
38781
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl(projectId))}`);
38782
- return { outroMessage: "Project linked" };
38917
+ const dashboardUrl = getDashboardUrl(projectId);
38918
+ if (!isJsonMode()) M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38919
+ return {
38920
+ outroMessage: "Project linked",
38921
+ data: {
38922
+ projectId,
38923
+ dashboardUrl
38924
+ }
38925
+ };
38783
38926
  }
38784
38927
  const linkCommand = new Command("link").description("Link a local project to a Base44 project").option("-c, --create", "Create a new project (skip selection prompt)").option("-n, --name <name>", "Project name (required when --create is used)").option("-d, --description <description>", "Project description").hook("preAction", validateNonInteractiveFlags).action(async (options) => {
38785
38928
  await runCommand(() => link(options), {
@@ -38794,16 +38937,23 @@ async function deployAction(options) {
38794
38937
  const { project } = await readProjectConfig();
38795
38938
  if (!project.site?.outputDirectory) throw new Error("No site configuration found. Please add 'site.outputDirectory' to your config.jsonc");
38796
38939
  const outputDir = resolve(project.root, project.site.outputDirectory);
38797
- if (!options.yes) {
38940
+ if (!options.yes && !isJsonMode()) {
38798
38941
  const shouldDeploy = await ye({ message: `Deploy site from ${project.site.outputDirectory}?` });
38799
- if (pD(shouldDeploy) || !shouldDeploy) return { outroMessage: "Deployment cancelled" };
38942
+ if (pD(shouldDeploy) || !shouldDeploy) return {
38943
+ outroMessage: "Deployment cancelled",
38944
+ data: { cancelled: true }
38945
+ };
38800
38946
  }
38801
- return { outroMessage: `Visit your site at: ${(await runTask("Creating archive and deploying site...", async () => {
38947
+ const result = await runTask("Creating archive and deploying site...", async () => {
38802
38948
  return await deploySite(outputDir);
38803
38949
  }, {
38804
38950
  successMessage: "Site deployed successfully",
38805
38951
  errorMessage: "Deployment failed"
38806
- })).appUrl}` };
38952
+ });
38953
+ return {
38954
+ outroMessage: `Visit your site at: ${result.appUrl}`,
38955
+ data: { appUrl: result.appUrl }
38956
+ };
38807
38957
  }
38808
38958
  const siteDeployCommand = new Command("site").description("Manage site deployments").addCommand(new Command("deploy").description("Deploy built site files to Base44 hosting").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
38809
38959
  await runCommand(() => deployAction(options), { requireAuth: true });
@@ -38814,47 +38964,42 @@ const siteDeployCommand = new Command("site").description("Manage site deploymen
38814
38964
  var version = "0.0.15";
38815
38965
 
38816
38966
  //#endregion
38817
- //#region src/cli/program.ts
38818
- /**
38819
- * Custom error class for CLI exit codes.
38820
- * Thrown instead of calling process.exit() directly to allow testing.
38821
- * The bin/run.js entry point catches this and calls process.exit().
38822
- */
38823
- var CLIExitError = class extends Error {
38824
- constructor(code$1) {
38825
- super(`CLI exited with code ${code$1}`);
38826
- this.code = code$1;
38827
- this.name = "CLIExitError";
38828
- }
38829
- };
38830
- /**
38831
- * Creates a new Commander program instance with all commands registered.
38832
- * Use this factory for testing to get a fresh program instance per test.
38833
- */
38834
- function createProgram() {
38835
- const program$2 = new Command();
38836
- program$2.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version);
38837
- program$2.configureHelp({ sortSubcommands: true });
38838
- program$2.exitOverride((err) => {
38839
- throw err;
38840
- });
38841
- program$2.configureOutput({
38842
- writeOut: (str) => process.stdout.write(str),
38843
- writeErr: (str) => process.stderr.write(str)
38844
- });
38845
- program$2.addCommand(loginCommand);
38846
- program$2.addCommand(whoamiCommand);
38847
- program$2.addCommand(logoutCommand);
38848
- program$2.addCommand(createCommand);
38849
- program$2.addCommand(dashboardCommand);
38850
- program$2.addCommand(deployCommand);
38851
- program$2.addCommand(linkCommand);
38852
- program$2.addCommand(entitiesPushCommand);
38853
- program$2.addCommand(functionsDeployCommand);
38854
- program$2.addCommand(siteDeployCommand);
38855
- return program$2;
38856
- }
38857
- const program = createProgram();
38967
+ //#region src/cli/index.ts
38968
+ if (process.argv.includes("--json")) setJsonMode(true);
38969
+ const program = new Command();
38970
+ program.exitOverride();
38971
+ program.configureOutput({ outputError: (str, write) => {
38972
+ if (isJsonMode()) return;
38973
+ write(str);
38974
+ } });
38975
+ program.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version).option("--json", "Output results as JSON (for scripting)");
38976
+ program.hook("preAction", (thisCommand) => {
38977
+ if (thisCommand.optsWithGlobals().json) setJsonMode(true);
38978
+ });
38979
+ program.configureHelp({ sortSubcommands: true });
38980
+ program.addCommand(loginCommand);
38981
+ program.addCommand(whoamiCommand);
38982
+ program.addCommand(logoutCommand);
38983
+ program.addCommand(createCommand);
38984
+ program.addCommand(dashboardCommand);
38985
+ program.addCommand(deployCommand);
38986
+ program.addCommand(linkCommand);
38987
+ program.addCommand(entitiesPushCommand);
38988
+ program.addCommand(functionsDeployCommand);
38989
+ program.addCommand(siteDeployCommand);
38990
+ program.parseAsync().catch((err) => {
38991
+ if (err instanceof CommanderError) {
38992
+ if (isJsonMode()) outputJsonError(err.message, err.code);
38993
+ process.exit(err.exitCode);
38994
+ }
38995
+ if (isJsonMode()) {
38996
+ outputJsonError(err instanceof Error ? err : String(err));
38997
+ process.exit(1);
38998
+ }
38999
+ const message = err instanceof Error ? err.message : String(err);
39000
+ console.error(`error: ${message}`);
39001
+ process.exit(1);
39002
+ });
38858
39003
 
38859
39004
  //#endregion
38860
- export { CLIExitError, createProgram, program };
39005
+ export { };
package/package.json CHANGED
@@ -1,26 +1,23 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.15-pr.19.d9072f9",
3
+ "version": "0.0.15-pr.87.46d28c7",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
- "main": "./dist/program.js",
7
- "bin": {
8
- "base44": "./bin/run.js"
9
- },
6
+ "main": "./dist/cli/index.js",
7
+ "bin": "./dist/cli/index.js",
10
8
  "exports": {
11
- ".": "./dist/program.js"
9
+ ".": "./dist/cli/index.js"
12
10
  },
13
11
  "files": [
14
- "dist",
15
- "bin"
12
+ "dist"
16
13
  ],
17
14
  "scripts": {
18
15
  "build": "tsdown",
19
16
  "typecheck": "tsc --noEmit",
20
- "dev": "./bin/dev.js",
21
- "start": "./bin/run.js",
17
+ "dev": "tsx src/cli/index.ts",
18
+ "start": "node dist/cli/index.js",
22
19
  "clean": "rm -rf dist",
23
- "lint": "eslint src tests",
20
+ "lint": "eslint src",
24
21
  "test": "vitest run",
25
22
  "test:watch": "vitest"
26
23
  },
@@ -56,12 +53,9 @@
56
53
  "json5": "^2.2.3",
57
54
  "ky": "^1.14.2",
58
55
  "lodash.kebabcase": "^4.1.1",
59
- "msw": "^2.12.7",
60
56
  "open": "^11.0.0",
61
57
  "p-wait-for": "^6.0.0",
62
- "strip-ansi": "^7.1.2",
63
58
  "tar": "^7.5.4",
64
- "tmp-promise": "^3.0.3",
65
59
  "tsdown": "^0.12.4",
66
60
  "tsx": "^4.19.2",
67
61
  "typescript": "^5.7.2",
package/bin/dev.cmd DELETED
@@ -1,2 +0,0 @@
1
- @echo off
2
- npx tsx "%~dp0\dev.js" %*
package/bin/dev.js DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env tsx
2
- import { program, CLIExitError } from '../src/cli/program.ts';
3
-
4
- try {
5
- await program.parseAsync();
6
- } catch (e) {
7
- if (e instanceof CLIExitError) {
8
- process.exit(e.code); // Clean exit, no stack trace
9
- }
10
- // Commander throws for --help and --version with exitCode 0
11
- if (e?.code === 'commander.helpDisplayed' || e?.code === 'commander.version') {
12
- process.exit(0);
13
- }
14
- // For other Commander errors, exit with the provided code
15
- if (e?.exitCode !== undefined) {
16
- process.exit(e.exitCode);
17
- }
18
- console.error(e);
19
- process.exit(1);
20
- }
package/bin/run.cmd DELETED
@@ -1,2 +0,0 @@
1
- @echo off
2
- node "%~dp0\run.js" %*
package/bin/run.js DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program, CLIExitError } from '../dist/program.js';
3
-
4
- try {
5
- await program.parseAsync();
6
- } catch (e) {
7
- if (e instanceof CLIExitError) {
8
- process.exit(e.code); // Clean exit, no stack trace
9
- }
10
- // Commander throws for --help and --version with exitCode 0
11
- if (e?.code === 'commander.helpDisplayed' || e?.code === 'commander.version') {
12
- process.exit(0);
13
- }
14
- // For other Commander errors, exit with the provided code
15
- if (e?.exitCode !== undefined) {
16
- process.exit(e.exitCode);
17
- }
18
- console.error(e);
19
- process.exit(1);
20
- }