@base44-preview/cli 0.0.55-pr.541.4704675 → 0.0.55-pr.545.63956fa

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/cli/index.js CHANGED
@@ -218285,7 +218285,6 @@ var PROJECT_CONFIG_PATTERNS = [
218285
218285
  `${PROJECT_SUBDIR}/config.${CONFIG_FILE_EXTENSION_GLOB}`,
218286
218286
  `config.${CONFIG_FILE_EXTENSION_GLOB}`
218287
218287
  ];
218288
- var BASE44_APP_ID_ENV_VAR = "BASE44_APP_ID";
218289
218288
  var TYPES_OUTPUT_SUBDIR = ".types";
218290
218289
  var TYPES_FILENAME = "types.d.ts";
218291
218290
  var AUTH_CLIENT_ID = "base44_cli";
@@ -233981,7 +233980,7 @@ async function parseEnvFile(filePath) {
233981
233980
  }
233982
233981
  var STRIPE_ENV_PREFIX = "BASE44_PROJECTS_";
233983
233982
  var BASE44_ENV_KEYS = [
233984
- BASE44_APP_ID_ENV_VAR,
233983
+ "BASE44_APP_ID",
233985
233984
  "BASE44_ACCESS_TOKEN",
233986
233985
  "BASE44_REFRESH_TOKEN",
233987
233986
  "BASE44_API_URL"
@@ -241695,35 +241694,18 @@ function loadFromTestOverrides() {
241695
241694
  }
241696
241695
  return null;
241697
241696
  }
241698
- async function initAppContext(options = {}) {
241697
+ async function initAppContext() {
241699
241698
  const testConfig = loadFromTestOverrides();
241700
241699
  if (testConfig) {
241701
241700
  cache2 = testConfig;
241702
241701
  return cache2;
241703
241702
  }
241704
- const projectRoot = findProjectRoot();
241705
- if (options.appId !== undefined) {
241706
- const id = options.appId.trim();
241707
- if (!id) {
241708
- throw new InvalidInputError("App id cannot be empty.");
241709
- }
241710
- cache2 = { id, projectRoot: projectRoot?.root };
241711
- return cache2;
241712
- }
241713
241703
  if (cache2) {
241714
241704
  return cache2;
241715
241705
  }
241706
+ const projectRoot = findProjectRoot();
241716
241707
  if (!projectRoot) {
241717
- throw new ConfigNotFoundError(`No Base44 app ID found. Pass --app-id, set ${BASE44_APP_ID_ENV_VAR}, or run this command from a linked project with base44/.app.jsonc.`, {
241718
- hints: [
241719
- { message: "Pass an app ID explicitly with --app-id <id>" },
241720
- { message: `Set ${BASE44_APP_ID_ENV_VAR} in your environment` },
241721
- {
241722
- message: "Run from a linked Base44 project with base44/.app.jsonc, or run 'base44 link'",
241723
- command: "base44 link"
241724
- }
241725
- ]
241726
- });
241708
+ throw new ConfigNotFoundError("No Base44 project found. Run this command from a project directory with a config.jsonc file.");
241727
241709
  }
241728
241710
  const config3 = await readAppConfig(projectRoot.root);
241729
241711
  const appConfigPath = await findAppConfigPath(projectRoot.root);
@@ -241861,8 +241843,8 @@ async function getAppUserToken() {
241861
241843
  throw await ApiError.fromHttpError(error48, "exchanging platform token for app user token");
241862
241844
  }
241863
241845
  }
241864
- async function getSiteUrl(projectId) {
241865
- const id = projectId ?? getAppContext().id;
241846
+ async function getSiteUrl() {
241847
+ const id = getAppContext().id;
241866
241848
  let response;
241867
241849
  try {
241868
241850
  response = await base44Client.get(`api/apps/platform/${id}/published-url`);
@@ -244451,8 +244433,8 @@ async function ensureAuth(ctx) {
244451
244433
  });
244452
244434
  } catch {}
244453
244435
  }
244454
- async function ensureAppContext(ctx, options = {}) {
244455
- const appContext = await initAppContext(options);
244436
+ async function ensureAppContext(ctx) {
244437
+ const appContext = await initAppContext();
244456
244438
  ctx.app = appContext;
244457
244439
  ctx.errorReporter.setContext({ appId: appContext.id });
244458
244440
  }
@@ -251118,8 +251100,7 @@ class Base44Command extends Command {
251118
251100
  await ensureAuth(this.context);
251119
251101
  }
251120
251102
  if (this._commandOptions.requireAppContext) {
251121
- const { appId } = this.optsWithGlobals();
251122
- await ensureAppContext(this.context, { appId });
251103
+ await ensureAppContext(this.context);
251123
251104
  }
251124
251105
  const result = await fn(this.context, ...args) ?? {};
251125
251106
  if (!quiet) {
@@ -253088,11 +253069,7 @@ function printProjectSummary({ name: name2, dashboardUrl, appUrl }, log) {
253088
253069
  }
253089
253070
 
253090
253071
  // src/cli/commands/project/create.ts
253091
- function validateCreateOptions(command2) {
253092
- const { appId } = command2.optsWithGlobals();
253093
- if (appId !== undefined) {
253094
- command2.error(`base44 create cannot be used with --app-id or ${BASE44_APP_ID_ENV_VAR}.`);
253095
- }
253072
+ function validateNonInteractiveFlags(command2) {
253096
253073
  const { path: path17 } = command2.opts();
253097
253074
  if (path17 && !command2.args.length) {
253098
253075
  command2.error("--path requires a project name argument. Usage: base44 create <name> --path <path>");
@@ -253209,7 +253186,7 @@ function getCreateCommand() {
253209
253186
  Examples:
253210
253187
  $ base44 create my-app Creates a base44 project at ./my-app
253211
253188
  $ base44 create my-todo-app --template backend-and-client Creates a base44 backend-and-client project at ./my-todo-app
253212
- $ base44 create my-app --path ./projects/my-app --deploy Creates a base44 project at ./project/my-app and deploys it`).hook("preAction", validateCreateOptions).action(createAction);
253189
+ $ base44 create my-app --path ./projects/my-app --deploy Creates a base44 project at ./project/my-app and deploys it`).hook("preAction", validateNonInteractiveFlags).action(createAction);
253213
253190
  }
253214
253191
 
253215
253192
  // src/cli/commands/project/deploy.ts
@@ -253305,32 +253282,11 @@ function printStripeResult(r, log) {
253305
253282
  log.info(` Connectors dashboard: ${theme.colors.links(getConnectorsUrl())}`);
253306
253283
  }
253307
253284
 
253308
- // src/cli/commands/project/app-id-options.ts
253309
- function readExplicitAppId(command2) {
253310
- const { appId } = command2.optsWithGlobals();
253311
- const { projectId } = command2.opts();
253312
- const explicitAppId = command2.getOptionValueSourceWithGlobals("appId") === "cli" ? appId : undefined;
253313
- const legacyProjectId = command2.getOptionValueSource("projectId") === "cli" ? projectId : undefined;
253314
- return {
253315
- appId: explicitAppId,
253316
- legacyProjectId,
253317
- value: explicitAppId ?? legacyProjectId
253318
- };
253319
- }
253320
-
253321
253285
  // src/cli/commands/project/link.ts
253322
- function validateNonInteractiveFlags(command2) {
253323
- const { create: create4, name: name2 } = command2.opts();
253324
- const {
253325
- appId,
253326
- legacyProjectId,
253327
- value: selectedAppId
253328
- } = readExplicitAppId(command2);
253329
- if (appId && legacyProjectId) {
253330
- command2.error("--app-id and --project-id cannot be used together");
253331
- }
253332
- if (create4 && selectedAppId) {
253333
- command2.error("--create and --app-id cannot be used together");
253286
+ function validateNonInteractiveFlags2(command2) {
253287
+ const { create: create4, name: name2, projectId } = command2.opts();
253288
+ if (create4 && projectId) {
253289
+ command2.error("--create and --projectId cannot be used together");
253334
253290
  }
253335
253291
  if (create4 && !name2) {
253336
253292
  command2.error("--name is required when using --create");
@@ -253399,12 +253355,11 @@ async function promptForExistingProject(linkableProjects) {
253399
253355
  }
253400
253356
  return selectedProject;
253401
253357
  }
253402
- async function link(ctx, options, command2) {
253358
+ async function link(ctx, options) {
253403
253359
  const { log, runTask: runTask2, isNonInteractive } = ctx;
253404
- const appId = readExplicitAppId(command2).value;
253405
- const skipPrompts = !!options.create || !!appId;
253360
+ const skipPrompts = !!options.create || !!options.projectId;
253406
253361
  if (!skipPrompts && isNonInteractive) {
253407
- throw new InvalidInputError("--create with --name, or --app-id, is required in non-interactive mode");
253362
+ throw new InvalidInputError("--create with --name, or --projectId, is required in non-interactive mode");
253408
253363
  }
253409
253364
  const projectRoot = findProjectRoot();
253410
253365
  if (!projectRoot) {
@@ -253419,8 +253374,8 @@ async function link(ctx, options, command2) {
253419
253374
  ]
253420
253375
  });
253421
253376
  }
253422
- let finalAppId;
253423
- const action = appId ? "choose" : options.create ? "create" : await promptForLinkAction();
253377
+ let finalProjectId;
253378
+ const action = options.projectId ? "choose" : options.create ? "create" : await promptForLinkAction();
253424
253379
  if (action === "choose") {
253425
253380
  const projects = await runTask2("Fetching projects...", async () => listProjects(), {
253426
253381
  successMessage: "Projects fetched",
@@ -253430,32 +253385,32 @@ async function link(ctx, options, command2) {
253430
253385
  if (!linkableProjects.length) {
253431
253386
  return { outroMessage: "No projects available for linking" };
253432
253387
  }
253433
- let linkedAppId;
253434
- if (appId) {
253435
- const project2 = linkableProjects.find((p) => p.id === appId);
253388
+ let projectId;
253389
+ if (options.projectId) {
253390
+ const project2 = linkableProjects.find((p) => p.id === options.projectId);
253436
253391
  if (!project2) {
253437
- throw new InvalidInputError(`App with ID "${appId}" not found or not available for linking.`, {
253392
+ throw new InvalidInputError(`Project with ID "${options.projectId}" not found or not available for linking.`, {
253438
253393
  hints: [
253439
- { message: "Check the app ID is correct" },
253394
+ { message: "Check the project ID is correct" },
253440
253395
  {
253441
- message: "Use 'base44 link' without --app-id to see available projects"
253396
+ message: "Use 'base44 link' without --projectId to see available projects"
253442
253397
  }
253443
253398
  ]
253444
253399
  });
253445
253400
  }
253446
- linkedAppId = appId;
253401
+ projectId = options.projectId;
253447
253402
  } else {
253448
253403
  const selectedProject = await promptForExistingProject(linkableProjects);
253449
- linkedAppId = selectedProject.id;
253404
+ projectId = selectedProject.id;
253450
253405
  }
253451
253406
  await runTask2("Linking project...", async () => {
253452
- await writeAppConfig(projectRoot.root, linkedAppId);
253453
- setAppContext({ id: linkedAppId, projectRoot: projectRoot.root });
253407
+ await writeAppConfig(projectRoot.root, projectId);
253408
+ setAppContext({ id: projectId, projectRoot: projectRoot.root });
253454
253409
  }, {
253455
253410
  successMessage: "Project linked successfully",
253456
253411
  errorMessage: "Failed to link project"
253457
253412
  });
253458
- finalAppId = linkedAppId;
253413
+ finalProjectId = projectId;
253459
253414
  }
253460
253415
  if (action === "create") {
253461
253416
  const { name: name2, description } = options.create ? { name: options.name.trim(), description: options.description?.trim() } : await promptForNewProjectDetails();
@@ -253467,15 +253422,13 @@ async function link(ctx, options, command2) {
253467
253422
  });
253468
253423
  await writeAppConfig(projectRoot.root, projectId);
253469
253424
  setAppContext({ id: projectId, projectRoot: projectRoot.root });
253470
- finalAppId = projectId;
253425
+ finalProjectId = projectId;
253471
253426
  }
253472
- log.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl(finalAppId))}`);
253427
+ log.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl(finalProjectId))}`);
253473
253428
  return { outroMessage: "Project linked" };
253474
253429
  }
253475
253430
  function getLinkCommand() {
253476
- return new Base44Command("link", {
253477
- requireAppContext: false
253478
- }).description("Link a local project to a Base44 project (create new or link existing)").configureHelp({ showGlobalOptions: true }).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").addOption(new Option("-p, --project-id <id>", "Project ID to link to an existing project").hideHelp()).addOption(new Option("--projectId <id>", "Project ID to link to an existing project").hideHelp()).hook("preAction", validateNonInteractiveFlags).action(link);
253431
+ return new Base44Command("link", { requireAppContext: false }).description("Link a local project to a Base44 project (create new or link existing)").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").option("-p, --projectId <id>", "Project ID to link to an existing project (skips selection prompt)").hook("preAction", validateNonInteractiveFlags2).action(link);
253479
253432
  }
253480
253433
 
253481
253434
  // src/cli/commands/project/logs.ts
@@ -253565,12 +253518,8 @@ async function fetchLogsForFunctions(functionNames, options, availableFunctionNa
253565
253518
  }
253566
253519
  return allEntries;
253567
253520
  }
253568
- async function getProjectFunctionNames(projectRoot) {
253569
- const { functions } = await readProjectConfig(projectRoot);
253570
- return functions.map((fn) => fn.name);
253571
- }
253572
- async function getRemoteFunctionNames() {
253573
- const { functions } = await listDeployedFunctions();
253521
+ async function getAllFunctionNames() {
253522
+ const { functions } = await readProjectConfig();
253574
253523
  return functions.map((fn) => fn.name);
253575
253524
  }
253576
253525
  function validateLimit(limit) {
@@ -253581,18 +253530,15 @@ function validateLimit(limit) {
253581
253530
  throw new InvalidInputError(`Invalid limit: "${limit}". Must be a number between 1 and 1000.`);
253582
253531
  }
253583
253532
  }
253584
- async function logsAction(ctx, options) {
253533
+ async function logsAction(_ctx, options) {
253585
253534
  validateLimit(options.limit);
253586
253535
  const specifiedFunctions = parseFunctionNames(options.function);
253587
- const localProjectRoot = ctx.app?.projectRoot;
253588
- const availableFunctionNames = localProjectRoot ? await getProjectFunctionNames(localProjectRoot) : await getRemoteFunctionNames();
253589
- const functionNames = specifiedFunctions.length > 0 ? specifiedFunctions : availableFunctionNames;
253536
+ const allProjectFunctions = await getAllFunctionNames();
253537
+ const functionNames = specifiedFunctions.length > 0 ? specifiedFunctions : allProjectFunctions;
253590
253538
  if (functionNames.length === 0) {
253591
- return {
253592
- outroMessage: localProjectRoot ? "No functions found in this project." : "No functions found in this app."
253593
- };
253539
+ return { outroMessage: "No functions found in this project." };
253594
253540
  }
253595
- let entries = await fetchLogsForFunctions(functionNames, options, availableFunctionNames);
253541
+ let entries = await fetchLogsForFunctions(functionNames, options, allProjectFunctions);
253596
253542
  const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
253597
253543
  if (limit !== undefined && entries.length > limit) {
253598
253544
  entries = entries.slice(0, limit);
@@ -253608,20 +253554,17 @@ function getLogsCommand() {
253608
253554
  // src/cli/commands/project/scaffold.ts
253609
253555
  import { basename as basename5, resolve as resolve6 } from "node:path";
253610
253556
  function resolveAppId(options) {
253611
- const appId = options.appId;
253557
+ const appId = options.appId ?? process.env.BASE44_APP_ID;
253612
253558
  if (!appId) {
253613
253559
  throw new InvalidInputError("No app ID found. `base44 scaffold` sets up a local project for an existing Base44 app.", {
253614
- hints: [
253615
- { message: "Pass it explicitly with --app-id <id>" },
253616
- { message: `Set ${BASE44_APP_ID_ENV_VAR} in your environment` }
253617
- ]
253560
+ hints: [{ message: "Pass it explicitly with --app-id <id>" }]
253618
253561
  });
253619
253562
  }
253620
253563
  return appId;
253621
253564
  }
253622
- async function scaffoldAction(ctx, name2, options, command2) {
253565
+ async function scaffoldAction(ctx, name2, options) {
253623
253566
  const { log, runTask: runTask2 } = ctx;
253624
- const appId = resolveAppId(command2.optsWithGlobals());
253567
+ const appId = resolveAppId(options);
253625
253568
  const resolvedPath = resolve6("./");
253626
253569
  const projectName = (name2 ?? basename5(resolvedPath)).trim();
253627
253570
  const template2 = await getTemplateById("backend-only");
@@ -253653,7 +253596,7 @@ function getScaffoldCommand() {
253653
253596
  return new Base44Command("scaffold", {
253654
253597
  requireAppContext: false,
253655
253598
  fullBanner: true
253656
- }).description("Scaffold a local project for an existing Base44 app").addArgument(new Argument("name", "Project name").argOptional()).option("--no-skills", "Skip AI agent skills installation").addHelpText("after", `
253599
+ }).description("Scaffold a local project for an existing Base44 app").addArgument(new Argument("name", "Project name").argOptional()).option("--app-id <id>", "Existing Base44 app ID").option("--no-skills", "Skip AI agent skills installation").addHelpText("after", `
253657
253600
  Examples:
253658
253601
  $ base44 scaffold --app-id app_123 Scaffolds the current dir for the given app
253659
253602
  $ base44 scaffold my-app --app-id app_123 Scaffolds the current dir, named "my-app"`).action(scaffoldAction);
@@ -253955,7 +253898,6 @@ function getTypesCommand() {
253955
253898
 
253956
253899
  // src/cli/commands/dev.ts
253957
253900
  import { join as join28 } from "node:path";
253958
- import process21 from "node:process";
253959
253901
 
253960
253902
  // src/cli/dev/dev-server/main.ts
253961
253903
  var import_cors = __toESM(require_lib4(), 1);
@@ -254112,12 +254054,11 @@ var stringify = (item) => {
254112
254054
  return String(item);
254113
254055
  }
254114
254056
  };
254115
- function createDevLogger() {
254057
+ function createDevLogger(label2, labelColor = theme.styles.dim) {
254058
+ const prefix = label2 ? `${labelColor(`[${label2}]`)} ` : "";
254116
254059
  const print = (type, ...args) => {
254117
254060
  const colorize = colorByType[type];
254118
- console[type](...args.map((item) => {
254119
- return colorize(stringify(item));
254120
- }));
254061
+ console[type](prefix + args.map((item) => colorize(stringify(item))).join(" "));
254121
254062
  };
254122
254063
  return {
254123
254064
  log: (...args) => print("log", ...args),
@@ -255484,6 +255425,92 @@ function createCustomIntegrationRoutes(remoteProxy, logger2) {
255484
255425
  return router;
255485
255426
  }
255486
255427
 
255428
+ // src/cli/dev/dev-server/serve-runner.ts
255429
+ import { spawn as spawn3 } from "node:child_process";
255430
+ import process21 from "node:process";
255431
+
255432
+ class ServeRunner {
255433
+ command;
255434
+ cwd;
255435
+ env;
255436
+ logger;
255437
+ child;
255438
+ stopping = false;
255439
+ exitListeners = [];
255440
+ constructor(options8) {
255441
+ this.command = options8.command;
255442
+ this.cwd = options8.cwd;
255443
+ this.env = options8.env;
255444
+ this.logger = options8.logger;
255445
+ }
255446
+ start() {
255447
+ if (this.child) {
255448
+ return;
255449
+ }
255450
+ const child = spawn3(this.command, {
255451
+ cwd: this.cwd,
255452
+ shell: true,
255453
+ detached: process21.platform !== "win32",
255454
+ env: { ...process21.env, ...this.env },
255455
+ stdio: ["inherit", "pipe", "pipe"]
255456
+ });
255457
+ this.child = child;
255458
+ this.setupHandlers(child);
255459
+ }
255460
+ onExit(listener) {
255461
+ this.exitListeners.push(listener);
255462
+ }
255463
+ async stop() {
255464
+ const child = this.child;
255465
+ if (!child || child.exitCode !== null) {
255466
+ return;
255467
+ }
255468
+ this.stopping = true;
255469
+ const exited = new Promise((resolve10) => child.once("exit", () => resolve10()));
255470
+ if (process21.platform === "win32" && child.pid) {
255471
+ spawn3("taskkill", ["/pid", String(child.pid), "/T", "/F"]);
255472
+ } else if (child.pid) {
255473
+ try {
255474
+ process21.kill(-child.pid, "SIGTERM");
255475
+ } catch {
255476
+ child.kill();
255477
+ }
255478
+ }
255479
+ await exited;
255480
+ }
255481
+ setupHandlers(child) {
255482
+ child.stdout?.on("data", (data) => this.emitLines(data, "log"));
255483
+ child.stderr?.on("data", (data) => this.emitLines(data, "error"));
255484
+ child.on("error", (error48) => {
255485
+ this.logger.error("Frontend dev server failed to start:", error48);
255486
+ this.notifyExit(null);
255487
+ });
255488
+ child.on("exit", (code2) => {
255489
+ if (this.stopping) {
255490
+ return;
255491
+ }
255492
+ this.logger.error(`Frontend dev server exited with code ${code2}`);
255493
+ this.notifyExit(code2);
255494
+ });
255495
+ }
255496
+ notifyExit(code2) {
255497
+ for (const listener of this.exitListeners) {
255498
+ listener(code2);
255499
+ }
255500
+ }
255501
+ emitLines(data, type) {
255502
+ const lines = data.toString().trimEnd().split(`
255503
+ `);
255504
+ for (const line3 of lines) {
255505
+ if (type === "error") {
255506
+ this.logger.error(line3);
255507
+ } else {
255508
+ this.logger.log(line3);
255509
+ }
255510
+ }
255511
+ }
255512
+ }
255513
+
255487
255514
  // src/cli/dev/dev-server/watcher.ts
255488
255515
  import { EventEmitter as EventEmitter4 } from "node:events";
255489
255516
  import { relative as relative6 } from "node:path";
@@ -257207,7 +257234,7 @@ async function createDevServer(options8) {
257207
257234
  }
257208
257235
  next();
257209
257236
  });
257210
- const devLogger = createDevLogger();
257237
+ const devLogger = createDevLogger("backend", theme.styles.info);
257211
257238
  const functionManager = new FunctionManager(functions, devLogger, options8.denoWrapperPath);
257212
257239
  const functionRoutes = createFunctionRouter(functionManager, devLogger);
257213
257240
  app.use("/api/apps/:appId/functions", functionRoutes);
@@ -257305,59 +257332,94 @@ async function createDevServer(options8) {
257305
257332
  }
257306
257333
  });
257307
257334
  await base44ConfigWatcher.start();
257335
+ let serveRunner;
257336
+ if (options8.serve) {
257337
+ serveRunner = new ServeRunner({
257338
+ command: options8.serve.command,
257339
+ cwd: options8.serve.cwd,
257340
+ env: {
257341
+ VITE_BASE44_APP_ID: options8.serve.appId,
257342
+ VITE_BASE44_APP_BASE_URL: baseUrl
257343
+ },
257344
+ logger: createDevLogger("frontend", theme.colors.base44Orange)
257345
+ });
257346
+ }
257308
257347
  const shutdown = async () => {
257309
257348
  base44ConfigWatcher.close();
257310
257349
  io6.close();
257311
257350
  await functionManager.stopAll();
257351
+ await serveRunner?.stop();
257312
257352
  server.close();
257313
257353
  };
257314
257354
  process.on("SIGINT", shutdown);
257315
257355
  process.on("SIGTERM", shutdown);
257356
+ serveRunner?.onExit(() => {
257357
+ shutdown().finally(() => process.exit(1));
257358
+ });
257359
+ serveRunner?.start();
257316
257360
  return { port, server };
257317
257361
  }
257318
257362
 
257319
257363
  // src/cli/commands/dev.ts
257364
+ var ENV_HEADER = "# Edited by the base44 dev process";
257365
+ var MANAGED_ENV_KEYS = ["VITE_BASE44_APP_ID", "VITE_BASE44_APP_BASE_URL"];
257320
257366
  function localServerUrl(port) {
257321
257367
  return `http://localhost:${port}`;
257322
257368
  }
257323
- async function writeEnvLocalIfMissing(projectRoot, port, log) {
257369
+ async function writeEnvLocal(projectRoot, port, appId, log) {
257324
257370
  const envLocalPath = join28(projectRoot, ".env.local");
257371
+ const managed = [
257372
+ `VITE_BASE44_APP_ID=${appId}`,
257373
+ `VITE_BASE44_APP_BASE_URL=${localServerUrl(port)}`
257374
+ ];
257375
+ let preserved = "";
257325
257376
  if (await pathExists(envLocalPath)) {
257326
- return;
257377
+ const existing = await readTextFile(envLocalPath);
257378
+ preserved = existing.split(`
257379
+ `).map((line3) => {
257380
+ const key2 = line3.match(/^\s*(\w+)\s*=/)?.[1];
257381
+ return key2 && MANAGED_ENV_KEYS.includes(key2) ? `# ${line3}` : line3;
257382
+ }).join(`
257383
+ `).trimEnd();
257327
257384
  }
257328
- const { id: appId } = await initAppContext();
257329
- await writeFile(envLocalPath, `VITE_BASE44_APP_ID=${appId}
257330
- VITE_BASE44_APP_BASE_URL=${localServerUrl(port)}
257331
- `);
257332
- log.info("Created .env.local with app ID and dev server URL");
257385
+ const block = `${ENV_HEADER}
257386
+ ${managed.join(`
257387
+ `)}
257388
+ `;
257389
+ await writeFile(envLocalPath, preserved ? `${preserved}
257390
+
257391
+ ${block}` : block);
257392
+ log.info("Wrote .env.local with app ID and dev server URL");
257333
257393
  }
257334
257394
  async function devAction({ log }, options8) {
257335
257395
  const port = options8.port ? Number(options8.port) : undefined;
257336
- let projectRoot;
257396
+ const serveEnabled = options8.serve !== false;
257397
+ const { project: project2 } = await readProjectConfig();
257398
+ const serveCommand = project2.site?.serveCommand;
257399
+ const appId = serveEnabled || options8.writeEnv ? (await initAppContext()).id : undefined;
257337
257400
  const { port: resolvedPort } = await createDevServer({
257338
257401
  log,
257339
257402
  port,
257340
- cwd: process21.cwd(),
257341
257403
  denoWrapperPath: getDenoWrapperPath(),
257404
+ serve: serveEnabled && serveCommand && appId ? { command: serveCommand, cwd: project2.root, appId } : undefined,
257342
257405
  loadResources: async () => {
257343
- const { functions, entities, project: project2 } = await readProjectConfig();
257344
- projectRoot = project2.root;
257345
- return { functions, entities, project: project2 };
257406
+ const { functions, entities, project: project3 } = await readProjectConfig();
257407
+ return { functions, entities, project: project3 };
257346
257408
  }
257347
257409
  });
257348
- if (projectRoot) {
257349
- await writeEnvLocalIfMissing(projectRoot, resolvedPort, log);
257410
+ if (options8.writeEnv && appId) {
257411
+ await writeEnvLocal(project2.root, resolvedPort, appId, log);
257350
257412
  }
257351
257413
  return {
257352
257414
  outroMessage: `Dev server is available at ${theme.colors.links(localServerUrl(resolvedPort))}`
257353
257415
  };
257354
257416
  }
257355
257417
  function getDevCommand() {
257356
- return new Base44Command("dev").description("Start the development server").option("-p, --port <number>", "Port for the development server").action(devAction);
257418
+ return new Base44Command("dev").description("Start the development server").option("-p, --port <number>", "Port for the development server").option("--no-serve", "Do not start the frontend dev server").option("--write-env", "Write the app ID and dev server URL to .env.local").action(devAction);
257357
257419
  }
257358
257420
 
257359
257421
  // src/core/exec/run-script.ts
257360
- import { spawn as spawn3 } from "node:child_process";
257422
+ import { spawn as spawn4 } from "node:child_process";
257361
257423
  import { copyFileSync, writeFileSync as writeFileSync2 } from "node:fs";
257362
257424
  async function runScript(options8) {
257363
257425
  const { appId, code: code2 } = options8;
@@ -257376,7 +257438,7 @@ async function runScript(options8) {
257376
257438
  copyFileSync(getExecWrapperPath(), tempWrapper.path);
257377
257439
  try {
257378
257440
  const exitCode = await new Promise((resolvePromise) => {
257379
- const child = spawn3("deno", ["run", "--allow-all", "--node-modules-dir=auto", tempWrapper.path], {
257441
+ const child = spawn4("deno", ["run", "--allow-all", "--node-modules-dir=auto", tempWrapper.path], {
257380
257442
  env: {
257381
257443
  ...process.env,
257382
257444
  SCRIPT_PATH: scriptPath,
@@ -257409,10 +257471,7 @@ function readStdin2() {
257409
257471
  process.stdin.on("error", reject);
257410
257472
  });
257411
257473
  }
257412
- async function execAction({
257413
- app,
257414
- isNonInteractive
257415
- }) {
257474
+ async function execAction(isNonInteractive) {
257416
257475
  const noInputError = new InvalidInputError("No input provided. Pipe a script to stdin.", {
257417
257476
  hints: [
257418
257477
  { message: "File: cat ./script.ts | base44 exec" },
@@ -257428,7 +257487,7 @@ async function execAction({
257428
257487
  if (!code2.trim()) {
257429
257488
  throw noInputError;
257430
257489
  }
257431
- const { exitCode } = await runScript({ appId: app.id, code: code2 });
257490
+ const { exitCode } = await runScript({ appId: getAppContext().id, code: code2 });
257432
257491
  if (exitCode !== 0) {
257433
257492
  process.exitCode = exitCode;
257434
257493
  }
@@ -257441,26 +257500,18 @@ Examples:
257441
257500
  $ cat ./script.ts | base44 exec
257442
257501
 
257443
257502
  Inline script:
257444
- $ echo "const users = await base44.entities.User.list()" | base44 exec`).action(async (ctx) => {
257445
- return await execAction(ctx);
257503
+ $ echo "const users = await base44.entities.User.list()" | base44 exec`).action(async ({ isNonInteractive }) => {
257504
+ return await execAction(isNonInteractive);
257446
257505
  });
257447
257506
  }
257448
257507
 
257449
257508
  // src/cli/commands/project/eject.ts
257450
257509
  import { resolve as resolve12 } from "node:path";
257451
257510
  var import_kebabCase2 = __toESM(require_kebabCase(), 1);
257452
- async function eject(ctx, options8, command2) {
257511
+ async function eject(ctx, options8) {
257453
257512
  const { log, runTask: runTask2, isNonInteractive } = ctx;
257454
- const {
257455
- appId,
257456
- legacyProjectId,
257457
- value: selectedAppId
257458
- } = readExplicitAppId(command2);
257459
- if (appId && legacyProjectId) {
257460
- throw new InvalidInputError("--app-id and --project-id cannot be used together");
257461
- }
257462
- if (isNonInteractive && !selectedAppId) {
257463
- throw new InvalidInputError("--app-id is required in non-interactive mode");
257513
+ if (isNonInteractive && !options8.projectId) {
257514
+ throw new InvalidInputError("--project-id is required in non-interactive mode");
257464
257515
  }
257465
257516
  if (isNonInteractive && !options8.path) {
257466
257517
  throw new InvalidInputError("--path is required in non-interactive mode");
@@ -257468,13 +257519,13 @@ async function eject(ctx, options8, command2) {
257468
257519
  const projects = await listProjects();
257469
257520
  const ejectableProjects = projects.filter((p4) => p4.isManagedSourceCode !== false);
257470
257521
  let selectedProject;
257471
- if (selectedAppId) {
257472
- const foundProject = ejectableProjects.find((p4) => p4.id === selectedAppId);
257522
+ if (options8.projectId) {
257523
+ const foundProject = ejectableProjects.find((p4) => p4.id === options8.projectId);
257473
257524
  if (!foundProject) {
257474
- throw new InvalidInputError(`App with ID "${selectedAppId}" not found or not ejectable`, {
257525
+ throw new InvalidInputError(`Project with ID "${options8.projectId}" not found or not ejectable`, {
257475
257526
  hints: [
257476
257527
  {
257477
- message: "Run 'base44 eject' without --app-id to see available projects"
257528
+ message: "Run 'base44 eject' without --project-id to see available projects"
257478
257529
  }
257479
257530
  ]
257480
257531
  });
@@ -257550,15 +257601,13 @@ async function eject(ctx, options8, command2) {
257550
257601
  return { outroMessage: "Your new project is set and ready to use" };
257551
257602
  }
257552
257603
  function getEjectCommand() {
257553
- return new Base44Command("eject", {
257554
- requireAppContext: false
257555
- }).description("Download the code for an existing Base44 project").configureHelp({ showGlobalOptions: true }).option("-p, --path <path>", "Path where to write the project").option("-y, --yes", "Skip confirmation prompts").addOption(new Option("--project-id <id>", "Project ID to eject (skips interactive selection)").hideHelp()).action(eject);
257604
+ return new Base44Command("eject", { requireAppContext: false }).description("Download the code for an existing Base44 project").option("-p, --path <path>", "Path where to write the project").option("--project-id <id>", "Project ID to eject (skips interactive selection)").option("-y, --yes", "Skip confirmation prompts").action(eject);
257556
257605
  }
257557
257606
 
257558
257607
  // src/cli/program.ts
257559
257608
  function createProgram(context) {
257560
257609
  const program2 = new Command;
257561
- program2.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(package_default.version).addOption(new Option("--app-id <id>", "Base44 app ID to use").env(BASE44_APP_ID_ENV_VAR));
257610
+ program2.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(package_default.version);
257562
257611
  program2.configureHelp({
257563
257612
  sortSubcommands: true
257564
257613
  });
@@ -261832,4 +261881,4 @@ export {
261832
261881
  CLIExitError
261833
261882
  };
261834
261883
 
261835
- //# debugId=8E6F4E37112CE9D564756E2164756E21
261884
+ //# debugId=C265208687575E5664756E2164756E21