@base44-preview/cli 0.0.16-pr.95.3b2ce0c → 0.0.17-pr.104.57e16fe

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 (28) hide show
  1. package/README.md +47 -156
  2. package/bin/dev.js +12 -0
  3. package/bin/run.js +12 -0
  4. package/dist/{cli/index.js → index.js} +942 -153
  5. package/package.json +7 -8
  6. /package/dist/{cli/templates → templates}/backend-and-client/.nvmrc +0 -0
  7. /package/dist/{cli/templates → templates}/backend-and-client/README.md +0 -0
  8. /package/dist/{cli/templates → templates}/backend-and-client/base44/app.jsonc.ejs +0 -0
  9. /package/dist/{cli/templates → templates}/backend-and-client/base44/config.jsonc.ejs +0 -0
  10. /package/dist/{cli/templates → templates}/backend-and-client/base44/entities/task.jsonc +0 -0
  11. /package/dist/{cli/templates → templates}/backend-and-client/components.json +0 -0
  12. /package/dist/{cli/templates → templates}/backend-and-client/index.html +0 -0
  13. /package/dist/{cli/templates → templates}/backend-and-client/jsconfig.json +0 -0
  14. /package/dist/{cli/templates → templates}/backend-and-client/package.json +0 -0
  15. /package/dist/{cli/templates → templates}/backend-and-client/postcss.config.js +0 -0
  16. /package/dist/{cli/templates → templates}/backend-and-client/src/App.jsx +0 -0
  17. /package/dist/{cli/templates → templates}/backend-and-client/src/api/base44Client.js.ejs +0 -0
  18. /package/dist/{cli/templates → templates}/backend-and-client/src/components/Base44Logo.jsx +0 -0
  19. /package/dist/{cli/templates → templates}/backend-and-client/src/components/ui/button.jsx +0 -0
  20. /package/dist/{cli/templates → templates}/backend-and-client/src/components/ui/checkbox.jsx +0 -0
  21. /package/dist/{cli/templates → templates}/backend-and-client/src/components/ui/input.jsx +0 -0
  22. /package/dist/{cli/templates → templates}/backend-and-client/src/index.css +0 -0
  23. /package/dist/{cli/templates → templates}/backend-and-client/src/main.jsx +0 -0
  24. /package/dist/{cli/templates → templates}/backend-and-client/tailwind.config.js +0 -0
  25. /package/dist/{cli/templates → templates}/backend-and-client/vite.config.js +0 -0
  26. /package/dist/{cli/templates → templates}/backend-only/base44/app.jsonc.ejs +0 -0
  27. /package/dist/{cli/templates → templates}/backend-only/base44/config.jsonc.ejs +0 -0
  28. /package/dist/{cli/templates → templates}/templates.json +0 -0
@@ -1,10 +1,9 @@
1
- #!/usr/bin/env node
2
1
  import { createRequire } from "node:module";
3
2
  import { EventEmitter, addAbortListener, on, once, setMaxListeners } from "node:events";
4
3
  import childProcess, { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
5
4
  import path, { basename, dirname, join, posix, resolve, win32 } from "node:path";
6
5
  import fs, { appendFileSync, createReadStream, createWriteStream, readFileSync, statSync, writeFileSync } from "node:fs";
7
- import y, { execArgv, execPath, hrtime, platform, stdin, stdout } from "node:process";
6
+ import process$1, { execArgv, execPath, hrtime, platform, stdin, stdout } from "node:process";
8
7
  import { aborted, callbackify, debuglog, inspect, promisify, stripVTControlCharacters } from "node:util";
9
8
  import * as g from "node:readline";
10
9
  import O from "node:readline";
@@ -894,7 +893,7 @@ var require_command = /* @__PURE__ */ __commonJSMin(((exports) => {
894
893
  const childProcess$1 = __require("node:child_process");
895
894
  const path$15 = __require("node:path");
896
895
  const fs$10 = __require("node:fs");
897
- const process$3 = __require("node:process");
896
+ const process$4 = __require("node:process");
898
897
  const { Argument, humanReadableArgName } = require_argument();
899
898
  const { CommanderError } = require_error$1();
900
899
  const { Help } = require_help();
@@ -945,10 +944,10 @@ var require_command = /* @__PURE__ */ __commonJSMin(((exports) => {
945
944
  this._showHelpAfterError = false;
946
945
  this._showSuggestionAfterError = true;
947
946
  this._outputConfiguration = {
948
- writeOut: (str) => process$3.stdout.write(str),
949
- writeErr: (str) => process$3.stderr.write(str),
950
- getOutHelpWidth: () => process$3.stdout.isTTY ? process$3.stdout.columns : void 0,
951
- getErrHelpWidth: () => process$3.stderr.isTTY ? process$3.stderr.columns : void 0,
947
+ writeOut: (str) => process$4.stdout.write(str),
948
+ writeErr: (str) => process$4.stderr.write(str),
949
+ getOutHelpWidth: () => process$4.stdout.isTTY ? process$4.stdout.columns : void 0,
950
+ getErrHelpWidth: () => process$4.stderr.isTTY ? process$4.stderr.columns : void 0,
952
951
  outputError: (str, write) => write(str)
953
952
  };
954
953
  this._hidden = false;
@@ -1302,7 +1301,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1302
1301
  */
1303
1302
  _exit(exitCode, code$1, message) {
1304
1303
  if (this._exitCallback) this._exitCallback(new CommanderError(exitCode, code$1, message));
1305
- process$3.exit(exitCode);
1304
+ process$4.exit(exitCode);
1306
1305
  }
1307
1306
  /**
1308
1307
  * Register callback `fn` for the command.
@@ -1641,11 +1640,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1641
1640
  if (argv !== void 0 && !Array.isArray(argv)) throw new Error("first parameter to parse must be array or undefined");
1642
1641
  parseOptions = parseOptions || {};
1643
1642
  if (argv === void 0 && parseOptions.from === void 0) {
1644
- if (process$3.versions?.electron) parseOptions.from = "electron";
1645
- const execArgv$1 = process$3.execArgv ?? [];
1643
+ if (process$4.versions?.electron) parseOptions.from = "electron";
1644
+ const execArgv$1 = process$4.execArgv ?? [];
1646
1645
  if (execArgv$1.includes("-e") || execArgv$1.includes("--eval") || execArgv$1.includes("-p") || execArgv$1.includes("--print")) parseOptions.from = "eval";
1647
1646
  }
1648
- if (argv === void 0) argv = process$3.argv;
1647
+ if (argv === void 0) argv = process$4.argv;
1649
1648
  this.rawArgs = argv.slice();
1650
1649
  let userArgs;
1651
1650
  switch (parseOptions.from) {
@@ -1655,7 +1654,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1655
1654
  userArgs = argv.slice(2);
1656
1655
  break;
1657
1656
  case "electron":
1658
- if (process$3.defaultApp) {
1657
+ if (process$4.defaultApp) {
1659
1658
  this._scriptPath = argv[1];
1660
1659
  userArgs = argv.slice(2);
1661
1660
  } else userArgs = argv.slice(1);
@@ -1769,15 +1768,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
1769
1768
  }
1770
1769
  launchWithNode = sourceExt.includes(path$15.extname(executableFile));
1771
1770
  let proc$1;
1772
- if (process$3.platform !== "win32") if (launchWithNode) {
1771
+ if (process$4.platform !== "win32") if (launchWithNode) {
1773
1772
  args.unshift(executableFile);
1774
- args = incrementNodeInspectorPort(process$3.execArgv).concat(args);
1775
- proc$1 = childProcess$1.spawn(process$3.argv[0], args, { stdio: "inherit" });
1773
+ args = incrementNodeInspectorPort(process$4.execArgv).concat(args);
1774
+ proc$1 = childProcess$1.spawn(process$4.argv[0], args, { stdio: "inherit" });
1776
1775
  } else proc$1 = childProcess$1.spawn(executableFile, args, { stdio: "inherit" });
1777
1776
  else {
1778
1777
  args.unshift(executableFile);
1779
- args = incrementNodeInspectorPort(process$3.execArgv).concat(args);
1780
- proc$1 = childProcess$1.spawn(process$3.execPath, args, { stdio: "inherit" });
1778
+ args = incrementNodeInspectorPort(process$4.execArgv).concat(args);
1779
+ proc$1 = childProcess$1.spawn(process$4.execPath, args, { stdio: "inherit" });
1781
1780
  }
1782
1781
  if (!proc$1.killed) [
1783
1782
  "SIGUSR1",
@@ -1786,14 +1785,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
1786
1785
  "SIGINT",
1787
1786
  "SIGHUP"
1788
1787
  ].forEach((signal) => {
1789
- process$3.on(signal, () => {
1788
+ process$4.on(signal, () => {
1790
1789
  if (proc$1.killed === false && proc$1.exitCode === null) proc$1.kill(signal);
1791
1790
  });
1792
1791
  });
1793
1792
  const exitCallback = this._exitCallback;
1794
1793
  proc$1.on("close", (code$1) => {
1795
1794
  code$1 = code$1 ?? 1;
1796
- if (!exitCallback) process$3.exit(code$1);
1795
+ if (!exitCallback) process$4.exit(code$1);
1797
1796
  else exitCallback(new CommanderError(code$1, "commander.executeSubCommandAsync", "(close)"));
1798
1797
  });
1799
1798
  proc$1.on("error", (err) => {
@@ -1805,7 +1804,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1805
1804
  - ${executableDirMessage}`;
1806
1805
  throw new Error(executableMissing);
1807
1806
  } else if (err.code === "EACCES") throw new Error(`'${executableFile}' not executable`);
1808
- if (!exitCallback) process$3.exit(1);
1807
+ if (!exitCallback) process$4.exit(1);
1809
1808
  else {
1810
1809
  const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)");
1811
1810
  wrappedError.nestedError = err;
@@ -2211,13 +2210,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2211
2210
  */
2212
2211
  _parseOptionsEnv() {
2213
2212
  this.options.forEach((option) => {
2214
- if (option.envVar && option.envVar in process$3.env) {
2213
+ if (option.envVar && option.envVar in process$4.env) {
2215
2214
  const optionKey = option.attributeName();
2216
2215
  if (this.getOptionValue(optionKey) === void 0 || [
2217
2216
  "default",
2218
2217
  "config",
2219
2218
  "env"
2220
- ].includes(this.getOptionValueSource(optionKey))) if (option.required || option.optional) this.emit(`optionEnv:${option.name()}`, process$3.env[option.envVar]);
2219
+ ].includes(this.getOptionValueSource(optionKey))) if (option.required || option.optional) this.emit(`optionEnv:${option.name()}`, process$4.env[option.envVar]);
2221
2220
  else this.emit(`optionEnv:${option.name()}`);
2222
2221
  }
2223
2222
  });
@@ -2596,7 +2595,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2596
2595
  */
2597
2596
  help(contextOptions) {
2598
2597
  this.outputHelp(contextOptions);
2599
- let exitCode = process$3.exitCode || 0;
2598
+ let exitCode = process$4.exitCode || 0;
2600
2599
  if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) exitCode = 1;
2601
2600
  this._exit(exitCode, "commander.help", "(outputHelp)");
2602
2601
  }
@@ -2712,16 +2711,16 @@ var require_src = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2712
2711
  const CSI = `${ESC}[`;
2713
2712
  const beep = "\x07";
2714
2713
  const cursor = {
2715
- to(x$2, y$2) {
2716
- if (!y$2) return `${CSI}${x$2 + 1}G`;
2717
- return `${CSI}${y$2 + 1};${x$2 + 1}H`;
2714
+ to(x$2, y$1) {
2715
+ if (!y$1) return `${CSI}${x$2 + 1}G`;
2716
+ return `${CSI}${y$1 + 1};${x$2 + 1}H`;
2718
2717
  },
2719
- move(x$2, y$2) {
2718
+ move(x$2, y$1) {
2720
2719
  let ret = "";
2721
2720
  if (x$2 < 0) ret += `${CSI}${-x$2}D`;
2722
2721
  else if (x$2 > 0) ret += `${CSI}${x$2}C`;
2723
- if (y$2 < 0) ret += `${CSI}${-y$2}A`;
2724
- else if (y$2 > 0) ret += `${CSI}${y$2}B`;
2722
+ if (y$1 < 0) ret += `${CSI}${-y$1}A`;
2723
+ else if (y$1 > 0) ret += `${CSI}${y$1}B`;
2725
2724
  return ret;
2726
2725
  },
2727
2726
  up: (count$1 = 1) => `${CSI}${count$1}A`,
@@ -3031,13 +3030,13 @@ function rD() {
3031
3030
  }
3032
3031
  }), r;
3033
3032
  }
3034
- const ED = rD(), d$1 = new Set(["\x1B", "›"]), oD = 39, y$1 = "\x07", V$1 = "[", nD = "]", G$1 = "m", _$1 = `${nD}8;;`, z = (e$1) => `${d$1.values().next().value}${V$1}${e$1}${G$1}`, K$1 = (e$1) => `${d$1.values().next().value}${_$1}${e$1}${y$1}`, aD = (e$1) => e$1.split(" ").map((u$2) => p(u$2)), k$1 = (e$1, u$2, t) => {
3033
+ const ED = rD(), d$1 = new Set(["\x1B", "›"]), oD = 39, y = "\x07", V$1 = "[", nD = "]", G$1 = "m", _$1 = `${nD}8;;`, z = (e$1) => `${d$1.values().next().value}${V$1}${e$1}${G$1}`, K$1 = (e$1) => `${d$1.values().next().value}${_$1}${e$1}${y}`, aD = (e$1) => e$1.split(" ").map((u$2) => p(u$2)), k$1 = (e$1, u$2, t) => {
3035
3034
  const F$1 = [...u$2];
3036
3035
  let s = !1, i$1 = !1, D$1 = p(P$1(e$1[e$1.length - 1]));
3037
3036
  for (const [C$1, n$1] of F$1.entries()) {
3038
3037
  const E = p(n$1);
3039
3038
  if (D$1 + E <= t ? e$1[e$1.length - 1] += n$1 : (e$1.push(n$1), D$1 = 0), d$1.has(n$1) && (s = !0, i$1 = F$1.slice(C$1 + 1).join("").startsWith(_$1)), s) {
3040
- i$1 ? n$1 === y$1 && (s = !1, i$1 = !1) : n$1 === G$1 && (s = !1);
3039
+ i$1 ? n$1 === y && (s = !1, i$1 = !1) : n$1 === G$1 && (s = !1);
3041
3040
  continue;
3042
3041
  }
3043
3042
  D$1 += E, D$1 === t && C$1 < F$1.length - 1 && (e$1.push(""), D$1 = 0);
@@ -3079,7 +3078,7 @@ const ED = rD(), d$1 = new Set(["\x1B", "›"]), oD = 39, y$1 = "\x07", V$1 = "["
3079
3078
  `)];
3080
3079
  for (const [E, a$1] of n$1.entries()) {
3081
3080
  if (F$1 += a$1, d$1.has(a$1)) {
3082
- const { groups: c$1 } = (/* @__PURE__ */ new RegExp(`(?:\\${V$1}(?<code>\\d+)m|\\${_$1}(?<uri>.*)${y$1})`)).exec(n$1.slice(E).join("")) || { groups: {} };
3081
+ const { groups: c$1 } = (/* @__PURE__ */ new RegExp(`(?:\\${V$1}(?<code>\\d+)m|\\${_$1}(?<uri>.*)${y})`)).exec(n$1.slice(E).join("")) || { groups: {} };
3083
3082
  if (c$1.code !== void 0) {
3084
3083
  const f = Number.parseFloat(c$1.code);
3085
3084
  s = f === oD ? void 0 : f;
@@ -3480,7 +3479,7 @@ var RD = class extends x$1 {
3480
3479
  //#endregion
3481
3480
  //#region node_modules/@clack/prompts/dist/index.mjs
3482
3481
  function ce() {
3483
- return y.platform !== "win32" ? y.env.TERM !== "linux" : !!y.env.CI || !!y.env.WT_SESSION || !!y.env.TERMINUS_SUBLIME || y.env.ConEmuTask === "{cmd::Cmder}" || y.env.TERM_PROGRAM === "Terminus-Sublime" || y.env.TERM_PROGRAM === "vscode" || y.env.TERM === "xterm-256color" || y.env.TERM === "alacritty" || y.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
3482
+ return process$1.platform !== "win32" ? process$1.env.TERM !== "linux" : !!process$1.env.CI || !!process$1.env.WT_SESSION || !!process$1.env.TERMINUS_SUBLIME || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
3484
3483
  }
3485
3484
  const V = ce(), u$1 = (t, n$1) => V ? t : n$1, le = u$1("◆", "*"), L = u$1("■", "x"), W = u$1("▲", "x"), C = u$1("◇", "o"), ue = u$1("┌", "T"), o$1 = u$1("│", "|"), d = u$1("└", "—"), k = u$1("●", ">"), P = u$1("○", " "), A = u$1("◻", "[•]"), T = u$1("◼", "[+]"), F = u$1("◻", "[ ]"), $e = u$1("▪", "•"), _ = u$1("─", "-"), me = u$1("╮", "+"), de = u$1("├", "+"), pe = u$1("╯", "+"), q = u$1("●", "•"), D = u$1("◆", "*"), U = u$1("▲", "!"), K = u$1("■", "x"), b = (t) => {
3486
3485
  switch (t) {
@@ -5819,6 +5818,97 @@ function handleTupleResult(result, final, index) {
5819
5818
  if (result.issues.length) final.issues.push(...prefixIssues(index, result.issues));
5820
5819
  final.value[index] = result.value;
5821
5820
  }
5821
+ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
5822
+ $ZodType.init(inst, def);
5823
+ inst._zod.parse = (payload, ctx) => {
5824
+ const input = payload.value;
5825
+ if (!isPlainObject$1(input)) {
5826
+ payload.issues.push({
5827
+ expected: "record",
5828
+ code: "invalid_type",
5829
+ input,
5830
+ inst
5831
+ });
5832
+ return payload;
5833
+ }
5834
+ const proms = [];
5835
+ const values = def.keyType._zod.values;
5836
+ if (values) {
5837
+ payload.value = {};
5838
+ const recordKeys = /* @__PURE__ */ new Set();
5839
+ for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
5840
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
5841
+ const result = def.valueType._zod.run({
5842
+ value: input[key],
5843
+ issues: []
5844
+ }, ctx);
5845
+ if (result instanceof Promise) proms.push(result.then((result$1) => {
5846
+ if (result$1.issues.length) payload.issues.push(...prefixIssues(key, result$1.issues));
5847
+ payload.value[key] = result$1.value;
5848
+ }));
5849
+ else {
5850
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
5851
+ payload.value[key] = result.value;
5852
+ }
5853
+ }
5854
+ let unrecognized;
5855
+ for (const key in input) if (!recordKeys.has(key)) {
5856
+ unrecognized = unrecognized ?? [];
5857
+ unrecognized.push(key);
5858
+ }
5859
+ if (unrecognized && unrecognized.length > 0) payload.issues.push({
5860
+ code: "unrecognized_keys",
5861
+ input,
5862
+ inst,
5863
+ keys: unrecognized
5864
+ });
5865
+ } else {
5866
+ payload.value = {};
5867
+ for (const key of Reflect.ownKeys(input)) {
5868
+ if (key === "__proto__") continue;
5869
+ let keyResult = def.keyType._zod.run({
5870
+ value: key,
5871
+ issues: []
5872
+ }, ctx);
5873
+ if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
5874
+ if (typeof key === "string" && number$1.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number")) {
5875
+ const retryResult = def.keyType._zod.run({
5876
+ value: Number(key),
5877
+ issues: []
5878
+ }, ctx);
5879
+ if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
5880
+ if (retryResult.issues.length === 0) keyResult = retryResult;
5881
+ }
5882
+ if (keyResult.issues.length) {
5883
+ if (def.mode === "loose") payload.value[key] = input[key];
5884
+ else payload.issues.push({
5885
+ code: "invalid_key",
5886
+ origin: "record",
5887
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
5888
+ input: key,
5889
+ path: [key],
5890
+ inst
5891
+ });
5892
+ continue;
5893
+ }
5894
+ const result = def.valueType._zod.run({
5895
+ value: input[key],
5896
+ issues: []
5897
+ }, ctx);
5898
+ if (result instanceof Promise) proms.push(result.then((result$1) => {
5899
+ if (result$1.issues.length) payload.issues.push(...prefixIssues(key, result$1.issues));
5900
+ payload.value[keyResult.value] = result$1.value;
5901
+ }));
5902
+ else {
5903
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
5904
+ payload.value[keyResult.value] = result.value;
5905
+ }
5906
+ }
5907
+ }
5908
+ if (proms.length) return Promise.all(proms).then(() => payload);
5909
+ return payload;
5910
+ };
5911
+ });
5822
5912
  const $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
5823
5913
  $ZodType.init(inst, def);
5824
5914
  const values = getEnumValues(def.entries);
@@ -6654,7 +6744,7 @@ function initializeContext(params) {
6654
6744
  external: params?.external ?? void 0
6655
6745
  };
6656
6746
  }
6657
- function process$2(schema, ctx, _params = {
6747
+ function process$3(schema, ctx, _params = {
6658
6748
  path: [],
6659
6749
  schemaPath: []
6660
6750
  }) {
@@ -6691,7 +6781,7 @@ function process$2(schema, ctx, _params = {
6691
6781
  const parent = schema._zod.parent;
6692
6782
  if (parent) {
6693
6783
  if (!result.ref) result.ref = parent;
6694
- process$2(parent, ctx, params);
6784
+ process$3(parent, ctx, params);
6695
6785
  ctx.seen.get(parent).isParent = true;
6696
6786
  }
6697
6787
  }
@@ -6903,7 +6993,7 @@ const createToJSONSchemaMethod = (schema, processors = {}) => (params) => {
6903
6993
  ...params,
6904
6994
  processors
6905
6995
  });
6906
- process$2(schema, ctx);
6996
+ process$3(schema, ctx);
6907
6997
  extractDefs(ctx, schema);
6908
6998
  return finalize(ctx, schema);
6909
6999
  };
@@ -6915,7 +7005,7 @@ const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params)
6915
7005
  io,
6916
7006
  processors
6917
7007
  });
6918
- process$2(schema, ctx);
7008
+ process$3(schema, ctx);
6919
7009
  extractDefs(ctx, schema);
6920
7010
  return finalize(ctx, schema);
6921
7011
  };
@@ -7002,7 +7092,7 @@ const arrayProcessor = (schema, ctx, _json, params) => {
7002
7092
  if (typeof minimum === "number") json.minItems = minimum;
7003
7093
  if (typeof maximum === "number") json.maxItems = maximum;
7004
7094
  json.type = "array";
7005
- json.items = process$2(def.element, ctx, {
7095
+ json.items = process$3(def.element, ctx, {
7006
7096
  ...params,
7007
7097
  path: [...params.path, "items"]
7008
7098
  });
@@ -7013,7 +7103,7 @@ const objectProcessor = (schema, ctx, _json, params) => {
7013
7103
  json.type = "object";
7014
7104
  json.properties = {};
7015
7105
  const shape = def.shape;
7016
- for (const key in shape) json.properties[key] = process$2(shape[key], ctx, {
7106
+ for (const key in shape) json.properties[key] = process$3(shape[key], ctx, {
7017
7107
  ...params,
7018
7108
  path: [
7019
7109
  ...params.path,
@@ -7031,7 +7121,7 @@ const objectProcessor = (schema, ctx, _json, params) => {
7031
7121
  if (def.catchall?._zod.def.type === "never") json.additionalProperties = false;
7032
7122
  else if (!def.catchall) {
7033
7123
  if (ctx.io === "output") json.additionalProperties = false;
7034
- } else if (def.catchall) json.additionalProperties = process$2(def.catchall, ctx, {
7124
+ } else if (def.catchall) json.additionalProperties = process$3(def.catchall, ctx, {
7035
7125
  ...params,
7036
7126
  path: [...params.path, "additionalProperties"]
7037
7127
  });
@@ -7039,7 +7129,7 @@ const objectProcessor = (schema, ctx, _json, params) => {
7039
7129
  const unionProcessor = (schema, ctx, json, params) => {
7040
7130
  const def = schema._zod.def;
7041
7131
  const isExclusive = def.inclusive === false;
7042
- const options = def.options.map((x$2, i$1) => process$2(x$2, ctx, {
7132
+ const options = def.options.map((x$2, i$1) => process$3(x$2, ctx, {
7043
7133
  ...params,
7044
7134
  path: [
7045
7135
  ...params.path,
@@ -7052,7 +7142,7 @@ const unionProcessor = (schema, ctx, json, params) => {
7052
7142
  };
7053
7143
  const intersectionProcessor = (schema, ctx, json, params) => {
7054
7144
  const def = schema._zod.def;
7055
- const a$1 = process$2(def.left, ctx, {
7145
+ const a$1 = process$3(def.left, ctx, {
7056
7146
  ...params,
7057
7147
  path: [
7058
7148
  ...params.path,
@@ -7060,7 +7150,7 @@ const intersectionProcessor = (schema, ctx, json, params) => {
7060
7150
  0
7061
7151
  ]
7062
7152
  });
7063
- const b$2 = process$2(def.right, ctx, {
7153
+ const b$2 = process$3(def.right, ctx, {
7064
7154
  ...params,
7065
7155
  path: [
7066
7156
  ...params.path,
@@ -7077,7 +7167,7 @@ const tupleProcessor = (schema, ctx, _json, params) => {
7077
7167
  json.type = "array";
7078
7168
  const prefixPath$1 = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
7079
7169
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
7080
- const prefixItems = def.items.map((x$2, i$1) => process$2(x$2, ctx, {
7170
+ const prefixItems = def.items.map((x$2, i$1) => process$3(x$2, ctx, {
7081
7171
  ...params,
7082
7172
  path: [
7083
7173
  ...params.path,
@@ -7085,7 +7175,7 @@ const tupleProcessor = (schema, ctx, _json, params) => {
7085
7175
  i$1
7086
7176
  ]
7087
7177
  }));
7088
- const rest = def.rest ? process$2(def.rest, ctx, {
7178
+ const rest = def.rest ? process$3(def.rest, ctx, {
7089
7179
  ...params,
7090
7180
  path: [
7091
7181
  ...params.path,
@@ -7109,9 +7199,42 @@ const tupleProcessor = (schema, ctx, _json, params) => {
7109
7199
  if (typeof minimum === "number") json.minItems = minimum;
7110
7200
  if (typeof maximum === "number") json.maxItems = maximum;
7111
7201
  };
7202
+ const recordProcessor = (schema, ctx, _json, params) => {
7203
+ const json = _json;
7204
+ const def = schema._zod.def;
7205
+ json.type = "object";
7206
+ const keyType = def.keyType;
7207
+ const patterns = keyType._zod.bag?.patterns;
7208
+ if (def.mode === "loose" && patterns && patterns.size > 0) {
7209
+ const valueSchema = process$3(def.valueType, ctx, {
7210
+ ...params,
7211
+ path: [
7212
+ ...params.path,
7213
+ "patternProperties",
7214
+ "*"
7215
+ ]
7216
+ });
7217
+ json.patternProperties = {};
7218
+ for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema;
7219
+ } else {
7220
+ if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process$3(def.keyType, ctx, {
7221
+ ...params,
7222
+ path: [...params.path, "propertyNames"]
7223
+ });
7224
+ json.additionalProperties = process$3(def.valueType, ctx, {
7225
+ ...params,
7226
+ path: [...params.path, "additionalProperties"]
7227
+ });
7228
+ }
7229
+ const keyValues = keyType._zod.values;
7230
+ if (keyValues) {
7231
+ const validKeyValues = [...keyValues].filter((v$1) => typeof v$1 === "string" || typeof v$1 === "number");
7232
+ if (validKeyValues.length > 0) json.required = validKeyValues;
7233
+ }
7234
+ };
7112
7235
  const nullableProcessor = (schema, ctx, json, params) => {
7113
7236
  const def = schema._zod.def;
7114
- const inner = process$2(def.innerType, ctx, params);
7237
+ const inner = process$3(def.innerType, ctx, params);
7115
7238
  const seen = ctx.seen.get(schema);
7116
7239
  if (ctx.target === "openapi-3.0") {
7117
7240
  seen.ref = def.innerType;
@@ -7120,27 +7243,27 @@ const nullableProcessor = (schema, ctx, json, params) => {
7120
7243
  };
7121
7244
  const nonoptionalProcessor = (schema, ctx, _json, params) => {
7122
7245
  const def = schema._zod.def;
7123
- process$2(def.innerType, ctx, params);
7246
+ process$3(def.innerType, ctx, params);
7124
7247
  const seen = ctx.seen.get(schema);
7125
7248
  seen.ref = def.innerType;
7126
7249
  };
7127
7250
  const defaultProcessor = (schema, ctx, json, params) => {
7128
7251
  const def = schema._zod.def;
7129
- process$2(def.innerType, ctx, params);
7252
+ process$3(def.innerType, ctx, params);
7130
7253
  const seen = ctx.seen.get(schema);
7131
7254
  seen.ref = def.innerType;
7132
7255
  json.default = JSON.parse(JSON.stringify(def.defaultValue));
7133
7256
  };
7134
7257
  const prefaultProcessor = (schema, ctx, json, params) => {
7135
7258
  const def = schema._zod.def;
7136
- process$2(def.innerType, ctx, params);
7259
+ process$3(def.innerType, ctx, params);
7137
7260
  const seen = ctx.seen.get(schema);
7138
7261
  seen.ref = def.innerType;
7139
7262
  if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue));
7140
7263
  };
7141
7264
  const catchProcessor = (schema, ctx, json, params) => {
7142
7265
  const def = schema._zod.def;
7143
- process$2(def.innerType, ctx, params);
7266
+ process$3(def.innerType, ctx, params);
7144
7267
  const seen = ctx.seen.get(schema);
7145
7268
  seen.ref = def.innerType;
7146
7269
  let catchValue;
@@ -7154,20 +7277,20 @@ const catchProcessor = (schema, ctx, json, params) => {
7154
7277
  const pipeProcessor = (schema, ctx, _json, params) => {
7155
7278
  const def = schema._zod.def;
7156
7279
  const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
7157
- process$2(innerType, ctx, params);
7280
+ process$3(innerType, ctx, params);
7158
7281
  const seen = ctx.seen.get(schema);
7159
7282
  seen.ref = innerType;
7160
7283
  };
7161
7284
  const readonlyProcessor = (schema, ctx, json, params) => {
7162
7285
  const def = schema._zod.def;
7163
- process$2(def.innerType, ctx, params);
7286
+ process$3(def.innerType, ctx, params);
7164
7287
  const seen = ctx.seen.get(schema);
7165
7288
  seen.ref = def.innerType;
7166
7289
  json.readOnly = true;
7167
7290
  };
7168
7291
  const optionalProcessor = (schema, ctx, _json, params) => {
7169
7292
  const def = schema._zod.def;
7170
- process$2(def.innerType, ctx, params);
7293
+ process$3(def.innerType, ctx, params);
7171
7294
  const seen = ctx.seen.get(schema);
7172
7295
  seen.ref = def.innerType;
7173
7296
  };
@@ -7638,6 +7761,21 @@ function tuple(items, _paramsOrRest, _params) {
7638
7761
  ...normalizeParams(params)
7639
7762
  });
7640
7763
  }
7764
+ const ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
7765
+ $ZodRecord.init(inst, def);
7766
+ ZodType.init(inst, def);
7767
+ inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
7768
+ inst.keyType = def.keyType;
7769
+ inst.valueType = def.valueType;
7770
+ });
7771
+ function record(keyType, valueType, params) {
7772
+ return new ZodRecord({
7773
+ type: "record",
7774
+ keyType,
7775
+ valueType,
7776
+ ...normalizeParams(params)
7777
+ });
7778
+ }
7641
7779
  const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
7642
7780
  $ZodEnum.init(inst, def);
7643
7781
  ZodType.init(inst, def);
@@ -7900,6 +8038,19 @@ var AuthValidationError = class extends Error {
7900
8038
  this.name = "AuthValidationError";
7901
8039
  }
7902
8040
  };
8041
+ var ConnectorApiError = class extends Error {
8042
+ constructor(message, cause) {
8043
+ super(message);
8044
+ this.cause = cause;
8045
+ this.name = "ConnectorApiError";
8046
+ }
8047
+ };
8048
+ var ConnectorValidationError = class extends Error {
8049
+ constructor(message) {
8050
+ super(message);
8051
+ this.name = "ConnectorValidationError";
8052
+ }
8053
+ };
7903
8054
 
7904
8055
  //#endregion
7905
8056
  //#region src/core/consts.ts
@@ -16193,7 +16344,7 @@ const createIgnorePredicate = (patterns, cwd, baseDir) => {
16193
16344
  };
16194
16345
  const normalizeOptions$2 = (options = {}) => {
16195
16346
  const ignoreOption = options.ignore ? Array.isArray(options.ignore) ? options.ignore : [options.ignore] : [];
16196
- const cwd = toPath$1(options.cwd) ?? y.cwd();
16347
+ const cwd = toPath$1(options.cwd) ?? process$1.cwd();
16197
16348
  const deep = typeof options.deep === "number" ? Math.max(0, options.deep) + 1 : Number.POSITIVE_INFINITY;
16198
16349
  return {
16199
16350
  cwd,
@@ -16290,7 +16441,7 @@ const getDirectoryGlob = ({ directoryPath, files, extensions }) => {
16290
16441
  const extensionGlob = extensions?.length > 0 ? `.${extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0]}` : "";
16291
16442
  return files ? files.map((file) => path.posix.join(directoryPath, `**/${path.extname(file) ? file : `${file}${extensionGlob}`}`)) : [path.posix.join(directoryPath, `**${extensionGlob ? `/*${extensionGlob}` : ""}`)];
16292
16443
  };
16293
- const directoryToGlob = async (directoryPaths, { cwd = y.cwd(), files, extensions, fs: fsImplementation } = {}) => {
16444
+ const directoryToGlob = async (directoryPaths, { cwd = process$1.cwd(), files, extensions, fs: fsImplementation } = {}) => {
16294
16445
  return (await Promise.all(directoryPaths.map(async (directoryPath) => {
16295
16446
  if (shouldExpandGlobstarDirectory(isNegativePattern(directoryPath) ? directoryPath.slice(1) : directoryPath)) return getDirectoryGlob({
16296
16447
  directoryPath,
@@ -16304,7 +16455,7 @@ const directoryToGlob = async (directoryPaths, { cwd = y.cwd(), files, extension
16304
16455
  }) : directoryPath;
16305
16456
  }))).flat();
16306
16457
  };
16307
- const directoryToGlobSync = (directoryPaths, { cwd = y.cwd(), files, extensions, fs: fsImplementation } = {}) => directoryPaths.flatMap((directoryPath) => {
16458
+ const directoryToGlobSync = (directoryPaths, { cwd = process$1.cwd(), files, extensions, fs: fsImplementation } = {}) => directoryPaths.flatMap((directoryPath) => {
16308
16459
  if (shouldExpandGlobstarDirectory(isNegativePattern(directoryPath) ? directoryPath.slice(1) : directoryPath)) return getDirectoryGlob({
16309
16460
  directoryPath,
16310
16461
  files,
@@ -16400,7 +16551,7 @@ const applyIgnoreFilesAndGetFilterSync = (options) => {
16400
16551
  };
16401
16552
  const createFilterFunction = (isIgnored, cwd) => {
16402
16553
  const seen = /* @__PURE__ */ new Set();
16403
- const basePath = cwd || y.cwd();
16554
+ const basePath = cwd || process$1.cwd();
16404
16555
  const pathCache = /* @__PURE__ */ new Map();
16405
16556
  return (fastGlobResult) => {
16406
16557
  const pathKey$1 = path.normalize(fastGlobResult.path ?? fastGlobResult);
@@ -16697,10 +16848,13 @@ const SiteConfigSchema = object({
16697
16848
  outputDirectory: string().optional(),
16698
16849
  installCommand: string().optional()
16699
16850
  });
16851
+ const ConnectorConfigSchema = object({ scopes: array(string()).optional() });
16852
+ const ConnectorsConfigSchema = record(string(), ConnectorConfigSchema);
16700
16853
  const ProjectConfigSchema = object({
16701
16854
  name: string().min(1, "App name cannot be empty"),
16702
16855
  description: string().optional(),
16703
16856
  site: SiteConfigSchema.optional(),
16857
+ connectors: ConnectorsConfigSchema.optional(),
16704
16858
  entitiesDir: string().optional().default("entities"),
16705
16859
  functionsDir: string().optional().default("functions")
16706
16860
  });
@@ -16798,7 +16952,10 @@ async function createProject(projectName, description) {
16798
16952
  return { projectId: CreateProjectResponseSchema.parse(await response.json()).id };
16799
16953
  }
16800
16954
  async function listProjects() {
16801
- const response = await base44Client.get(`api/apps?sort=-updated_date&fields=id,name,user_description,is_managed_source_code`);
16955
+ const response = await base44Client.get(`api/apps`, { searchParams: {
16956
+ "sort": "-updated_date",
16957
+ "fields": "id,name,user_description,is_managed_source_code"
16958
+ } });
16802
16959
  return ProjectsResponseSchema.parse(await response.json());
16803
16960
  }
16804
16961
 
@@ -30583,6 +30740,21 @@ async function getUserInfo(accessToken) {
30583
30740
  return result.data;
30584
30741
  }
30585
30742
 
30743
+ //#endregion
30744
+ //#region src/cli/errors.ts
30745
+ /**
30746
+ * Error thrown to signal a controlled CLI exit with a specific exit code.
30747
+ * This allows proper error propagation without calling process.exit() directly,
30748
+ * making the code more testable and maintaining a single exit point.
30749
+ */
30750
+ var CLIExitError = class extends Error {
30751
+ constructor(code$1) {
30752
+ super(`CLI exited with code ${code$1}`);
30753
+ this.code = code$1;
30754
+ this.name = "CLIExitError";
30755
+ }
30756
+ };
30757
+
30586
30758
  //#endregion
30587
30759
  //#region node_modules/chalk/source/vendor/ansi-styles/index.js
30588
30760
  const ANSI_BACKGROUND_OFFSET = 10;
@@ -30751,13 +30923,13 @@ var ansi_styles_default = ansiStyles;
30751
30923
 
30752
30924
  //#endregion
30753
30925
  //#region node_modules/chalk/source/vendor/supports-color/index.js
30754
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : y.argv) {
30926
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
30755
30927
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
30756
30928
  const position = argv.indexOf(prefix + flag);
30757
30929
  const terminatorPosition = argv.indexOf("--");
30758
30930
  return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
30759
30931
  }
30760
- const { env } = y;
30932
+ const { env } = process$1;
30761
30933
  let flagForceColor;
30762
30934
  if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
30763
30935
  else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
@@ -30790,7 +30962,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
30790
30962
  if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
30791
30963
  const min = forceColor || 0;
30792
30964
  if (env.TERM === "dumb") return min;
30793
- if (y.platform === "win32") {
30965
+ if (process$1.platform === "win32") {
30794
30966
  const osRelease = os.release().split(".");
30795
30967
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
30796
30968
  return 1;
@@ -31003,7 +31175,10 @@ const theme = {
31003
31175
  base44OrangeBackground: source_default.bgHex("#E86B3C"),
31004
31176
  shinyOrange: source_default.hex("#FFD700"),
31005
31177
  links: source_default.hex("#00D4FF"),
31006
- white: source_default.white
31178
+ white: source_default.white,
31179
+ success: source_default.green,
31180
+ warning: source_default.yellow,
31181
+ error: source_default.red
31007
31182
  },
31008
31183
  styles: {
31009
31184
  header: source_default.dim,
@@ -31149,7 +31324,7 @@ async function runCommand(commandFn, options) {
31149
31324
  } catch (e$1) {
31150
31325
  if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
31151
31326
  else M.error(String(e$1));
31152
- process.exit(1);
31327
+ throw new CLIExitError(1);
31153
31328
  }
31154
31329
  }
31155
31330
 
@@ -31529,9 +31704,9 @@ const getSubprocessResult = ({ stdout: stdout$1 }) => {
31529
31704
  //#region node_modules/execa/lib/utils/standard-stream.js
31530
31705
  const isStandardStream = (stream) => STANDARD_STREAMS.includes(stream);
31531
31706
  const STANDARD_STREAMS = [
31532
- y.stdin,
31533
- y.stdout,
31534
- y.stderr
31707
+ process$1.stdin,
31708
+ process$1.stdout,
31709
+ process$1.stderr
31535
31710
  ];
31536
31711
  const STANDARD_STREAMS_ALIASES = [
31537
31712
  "stdin",
@@ -31656,9 +31831,9 @@ const NO_ESCAPE_REGEXP = /^[\w./-]+$/;
31656
31831
  //#endregion
31657
31832
  //#region node_modules/is-unicode-supported/index.js
31658
31833
  function isUnicodeSupported() {
31659
- const { env: env$1 } = y;
31834
+ const { env: env$1 } = process$1;
31660
31835
  const { TERM, TERM_PROGRAM } = env$1;
31661
- if (y.platform !== "win32") return TERM !== "linux";
31836
+ if (process$1.platform !== "win32") return TERM !== "linux";
31662
31837
  return Boolean(env$1.WT_SESSION) || Boolean(env$1.TERMINUS_SUBLIME) || env$1.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env$1.TERMINAL_EMULATOR === "JetBrains-JediTerm";
31663
31838
  }
31664
31839
 
@@ -32585,7 +32760,7 @@ const TEN_MEGABYTES_IN_BYTES = 10 * 1024 * 1024;
32585
32760
 
32586
32761
  //#endregion
32587
32762
  //#region node_modules/npm-run-path/index.js
32588
- const npmRunPath = ({ cwd = y.cwd(), path: pathOption = y.env[pathKey()], preferLocal = true, execPath: execPath$1 = y.execPath, addExecPath = true } = {}) => {
32763
+ const npmRunPath = ({ cwd = process$1.cwd(), path: pathOption = process$1.env[pathKey()], preferLocal = true, execPath: execPath$1 = process$1.execPath, addExecPath = true } = {}) => {
32589
32764
  const cwdPath = path.resolve(toPath(cwd));
32590
32765
  const result = [];
32591
32766
  const pathParts = pathOption.split(path.delimiter);
@@ -32603,7 +32778,7 @@ const applyExecPath = (result, pathParts, execPath$1, cwdPath) => {
32603
32778
  const pathPart = path.resolve(cwdPath, toPath(execPath$1), "..");
32604
32779
  if (!pathParts.includes(pathPart)) result.push(pathPart);
32605
32780
  };
32606
- const npmRunPathEnv = ({ env: env$1 = y.env, ...options } = {}) => {
32781
+ const npmRunPathEnv = ({ env: env$1 = process$1.env, ...options } = {}) => {
32607
32782
  env$1 = { ...env$1 };
32608
32783
  const pathName = pathKey({ env: env$1 });
32609
32784
  options.path = env$1[pathName];
@@ -33738,7 +33913,7 @@ const normalizeCwd = (cwd = getDefaultCwd()) => {
33738
33913
  };
33739
33914
  const getDefaultCwd = () => {
33740
33915
  try {
33741
- return y.cwd();
33916
+ return process$1.cwd();
33742
33917
  } catch (error) {
33743
33918
  error.message = `The current directory does not exist.\n${error.message}`;
33744
33919
  throw error;
@@ -33773,7 +33948,7 @@ const normalizeOptions = (filePath, rawArguments, rawOptions) => {
33773
33948
  options.killSignal = normalizeKillSignal(options.killSignal);
33774
33949
  options.forceKillAfterDelay = normalizeForceKillAfterDelay(options.forceKillAfterDelay);
33775
33950
  options.lines = options.lines.map((lines, fdNumber) => lines && !BINARY_ENCODINGS.has(options.encoding) && options.buffer[fdNumber]);
33776
- if (y.platform === "win32" && path.basename(file, ".exe") === "cmd") commandArguments.unshift("/q");
33951
+ if (process$1.platform === "win32" && path.basename(file, ".exe") === "cmd") commandArguments.unshift("/q");
33777
33952
  return {
33778
33953
  file,
33779
33954
  commandArguments,
@@ -33800,7 +33975,7 @@ const addDefaultOptions = ({ extendEnv = true, preferLocal = false, cwd, localDi
33800
33975
  });
33801
33976
  const getEnv = ({ env: envOption, extendEnv, preferLocal, node, localDirectory, nodePath }) => {
33802
33977
  const env$1 = extendEnv ? {
33803
- ...y.env,
33978
+ ...process$1.env,
33804
33979
  ...envOption
33805
33980
  } : envOption;
33806
33981
  if (preferLocal || node) return npmRunPathEnv({
@@ -34800,12 +34975,12 @@ const guessStreamDirection = {
34800
34975
  }
34801
34976
  };
34802
34977
  const getStandardStreamDirection = (value) => {
34803
- if ([0, y.stdin].includes(value)) return "input";
34978
+ if ([0, process$1.stdin].includes(value)) return "input";
34804
34979
  if ([
34805
34980
  1,
34806
34981
  2,
34807
- y.stdout,
34808
- y.stderr
34982
+ process$1.stdout,
34983
+ process$1.stderr
34809
34984
  ].includes(value)) return "output";
34810
34985
  };
34811
34986
  const DEFAULT_DIRECTION = "output";
@@ -35869,9 +36044,9 @@ const addIpcMethods = (subprocess, { ipc }) => {
35869
36044
  Object.assign(subprocess, getIpcMethods(subprocess, false, ipc));
35870
36045
  };
35871
36046
  const getIpcExport = () => {
35872
- const anyProcess = y;
36047
+ const anyProcess = process$1;
35873
36048
  const isSubprocess = true;
35874
- const ipc = y.channel !== void 0;
36049
+ const ipc = process$1.channel !== void 0;
35875
36050
  return {
35876
36051
  ...getIpcMethods(anyProcess, isSubprocess, ipc),
35877
36052
  getCancelSignal: getCancelSignal$1.bind(void 0, {
@@ -36113,7 +36288,7 @@ if (process.platform === "linux") signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SI
36113
36288
 
36114
36289
  //#endregion
36115
36290
  //#region node_modules/signal-exit/dist/mjs/index.js
36116
- const processOk = (process$4) => !!process$4 && typeof process$4 === "object" && typeof process$4.removeListener === "function" && typeof process$4.emit === "function" && typeof process$4.reallyExit === "function" && typeof process$4.listeners === "function" && typeof process$4.kill === "function" && typeof process$4.pid === "number" && typeof process$4.on === "function";
36291
+ const processOk = (process$5) => !!process$5 && typeof process$5 === "object" && typeof process$5.removeListener === "function" && typeof process$5.emit === "function" && typeof process$5.reallyExit === "function" && typeof process$5.listeners === "function" && typeof process$5.kill === "function" && typeof process$5.pid === "number" && typeof process$5.on === "function";
36117
36292
  const kExitEmitter = Symbol.for("signal-exit emitter");
36118
36293
  const global$1 = globalThis;
36119
36294
  const ObjectDefineProperty = Object.defineProperty.bind(Object);
@@ -36181,7 +36356,7 @@ var SignalExitFallback = class extends SignalExitBase {
36181
36356
  };
36182
36357
  var SignalExit = class extends SignalExitBase {
36183
36358
  /* c8 ignore start */
36184
- #hupSig = process$1.platform === "win32" ? "SIGINT" : "SIGHUP";
36359
+ #hupSig = process$2.platform === "win32" ? "SIGINT" : "SIGHUP";
36185
36360
  /* c8 ignore stop */
36186
36361
  #emitter = new Emitter();
36187
36362
  #process;
@@ -36189,15 +36364,15 @@ var SignalExit = class extends SignalExitBase {
36189
36364
  #originalProcessReallyExit;
36190
36365
  #sigListeners = {};
36191
36366
  #loaded = false;
36192
- constructor(process$4) {
36367
+ constructor(process$5) {
36193
36368
  super();
36194
- this.#process = process$4;
36369
+ this.#process = process$5;
36195
36370
  this.#sigListeners = {};
36196
36371
  for (const sig of signals) this.#sigListeners[sig] = () => {
36197
36372
  const listeners = this.#process.listeners(sig);
36198
36373
  let { count: count$1 } = this.#emitter;
36199
36374
  /* c8 ignore start */
36200
- const p$1 = process$4;
36375
+ const p$1 = process$5;
36201
36376
  if (typeof p$1.__signal_exit_emitter__ === "object" && typeof p$1.__signal_exit_emitter__.count === "number") count$1 += p$1.__signal_exit_emitter__.count;
36202
36377
  /* c8 ignore stop */
36203
36378
  if (listeners.length === count$1) {
@@ -36205,11 +36380,11 @@ var SignalExit = class extends SignalExitBase {
36205
36380
  const ret = this.#emitter.emit("exit", null, sig);
36206
36381
  /* c8 ignore start */
36207
36382
  const s = sig === "SIGHUP" ? this.#hupSig : sig;
36208
- if (!ret) process$4.kill(process$4.pid, s);
36383
+ if (!ret) process$5.kill(process$5.pid, s);
36209
36384
  }
36210
36385
  };
36211
- this.#originalProcessReallyExit = process$4.reallyExit;
36212
- this.#originalProcessEmit = process$4.emit;
36386
+ this.#originalProcessReallyExit = process$5.reallyExit;
36387
+ this.#originalProcessEmit = process$5.emit;
36213
36388
  }
36214
36389
  onExit(cb, opts) {
36215
36390
  /* c8 ignore start */
@@ -36276,8 +36451,8 @@ var SignalExit = class extends SignalExitBase {
36276
36451
  } else return og.call(this.#process, ev, ...args);
36277
36452
  }
36278
36453
  };
36279
- const process$1 = globalThis.process;
36280
- const { onExit, load, unload } = signalExitWrap(processOk(process$1) ? new SignalExit(process$1) : new SignalExitFallback());
36454
+ const process$2 = globalThis.process;
36455
+ const { onExit, load, unload } = signalExitWrap(processOk(process$2) ? new SignalExit(process$2) : new SignalExitFallback());
36281
36456
 
36282
36457
  //#endregion
36283
36458
  //#region node_modules/execa/lib/terminate/cleanup.js
@@ -38028,13 +38203,6 @@ var require_lodash = /* @__PURE__ */ __commonJSMin(((exports, module) => {
38028
38203
  //#region src/cli/commands/project/create.ts
38029
38204
  var import_lodash = /* @__PURE__ */ __toESM(require_lodash(), 1);
38030
38205
  const DEFAULT_TEMPLATE_ID = "backend-only";
38031
- const SUPPORTED_AGENTS = [{
38032
- value: "cursor",
38033
- label: "Cursor"
38034
- }, {
38035
- value: "claude-code",
38036
- label: "Claude Code"
38037
- }];
38038
38206
  async function getTemplateById(templateId) {
38039
38207
  const templates = await listTemplates();
38040
38208
  const template = templates.find((t) => t.id === templateId);
@@ -38097,7 +38265,6 @@ async function createInteractive(options) {
38097
38265
  description: result.description || void 0,
38098
38266
  projectPath: result.projectPath,
38099
38267
  deploy: options.deploy,
38100
- skills: options.skills,
38101
38268
  isInteractive: true
38102
38269
  });
38103
38270
  }
@@ -38108,11 +38275,10 @@ async function createNonInteractive(options) {
38108
38275
  description: options.description,
38109
38276
  projectPath: options.path,
38110
38277
  deploy: options.deploy,
38111
- skills: options.skills,
38112
38278
  isInteractive: false
38113
38279
  });
38114
38280
  }
38115
- async function executeCreate({ template, name: rawName, description, projectPath, deploy, skills, isInteractive }) {
38281
+ async function executeCreate({ template, name: rawName, description, projectPath, deploy, isInteractive }) {
38116
38282
  const name$1 = rawName.trim();
38117
38283
  const resolvedPath = resolve(projectPath);
38118
38284
  const { projectId } = await runTask("Setting up your project...", async () => {
@@ -38172,45 +38338,12 @@ async function executeCreate({ template, name: rawName, description, projectPath
38172
38338
  finalAppUrl = appUrl;
38173
38339
  }
38174
38340
  }
38175
- let selectedAgents = [];
38176
- if (isInteractive) {
38177
- const result = await fe({
38178
- message: "Add AI agent skills? (Select agents to configure)",
38179
- options: SUPPORTED_AGENTS,
38180
- initialValues: SUPPORTED_AGENTS.map((agent) => agent.value),
38181
- required: false
38182
- });
38183
- if (!pD(result)) selectedAgents = result;
38184
- } else if (skills) selectedAgents = SUPPORTED_AGENTS.map((agent) => agent.value);
38185
- if (selectedAgents.length > 0) {
38186
- const agentArgs = selectedAgents.flatMap((agent) => ["-a", agent]);
38187
- M.step("Installing skills for: " + selectedAgents.join(", "));
38188
- await runTask("Installing skills for: " + selectedAgents.join(", "), async () => {
38189
- await execa("npx", [
38190
- "-y",
38191
- "add-skill",
38192
- "base44/skills",
38193
- "-y",
38194
- "-s",
38195
- "base44-cli",
38196
- "-s",
38197
- "base44-sdk",
38198
- ...agentArgs
38199
- ], {
38200
- cwd: resolvedPath,
38201
- stdio: "inherit"
38202
- });
38203
- }, {
38204
- successMessage: theme.colors.base44Orange("AI agent skills added successfully"),
38205
- errorMessage: "Failed to add AI agent skills - you can add them later with: npx add-skill base44/skills"
38206
- });
38207
- }
38208
38341
  M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38209
38342
  M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl(projectId))}`);
38210
38343
  if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38211
38344
  return { outroMessage: "Your project is set up and ready to use" };
38212
38345
  }
38213
- 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").option("--skills", "Add AI agent skills (Cursor, Claude Code)").hook("preAction", validateNonInteractiveFlags$1).action(async (options) => {
38346
+ 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) => {
38214
38347
  await chooseCreate(options);
38215
38348
  });
38216
38349
 
@@ -38256,7 +38389,7 @@ function isInsideContainer() {
38256
38389
  //#endregion
38257
38390
  //#region node_modules/is-wsl/index.js
38258
38391
  const isWsl = () => {
38259
- if (y.platform !== "linux") return false;
38392
+ if (process$1.platform !== "linux") return false;
38260
38393
  if (os.release().toLowerCase().includes("microsoft")) {
38261
38394
  if (isInsideContainer()) return false;
38262
38395
  return true;
@@ -38267,12 +38400,12 @@ const isWsl = () => {
38267
38400
  return false;
38268
38401
  }
38269
38402
  };
38270
- var is_wsl_default = y.env.__IS_WSL_TEST__ ? isWsl : isWsl();
38403
+ var is_wsl_default = process$1.env.__IS_WSL_TEST__ ? isWsl : isWsl();
38271
38404
 
38272
38405
  //#endregion
38273
38406
  //#region node_modules/powershell-utils/index.js
38274
38407
  const execFile$2 = promisify(childProcess.execFile);
38275
- const powerShellPath$1 = () => `${y.env.SYSTEMROOT || y.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
38408
+ const powerShellPath$1 = () => `${process$1.env.SYSTEMROOT || process$1.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
38276
38409
  const executePowerShell = async (command, options = {}) => {
38277
38410
  const { powerShellPath: psPath, ...execFileOptions } = options;
38278
38411
  const encodedCommand = executePowerShell.encodeCommand(command);
@@ -38383,7 +38516,7 @@ function defineLazyProperty(object$1, propertyName, valueGetter) {
38383
38516
  //#region node_modules/default-browser-id/index.js
38384
38517
  const execFileAsync$3 = promisify(execFile);
38385
38518
  async function defaultBrowserId() {
38386
- if (y.platform !== "darwin") throw new Error("macOS only");
38519
+ if (process$1.platform !== "darwin") throw new Error("macOS only");
38387
38520
  const { stdout: stdout$1 } = await execFileAsync$3("defaults", [
38388
38521
  "read",
38389
38522
  "com.apple.LaunchServices/com.apple.launchservices.secure",
@@ -38398,7 +38531,7 @@ async function defaultBrowserId() {
38398
38531
  //#region node_modules/run-applescript/index.js
38399
38532
  const execFileAsync$2 = promisify(execFile);
38400
38533
  async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
38401
- if (y.platform !== "darwin") throw new Error("macOS only");
38534
+ if (process$1.platform !== "darwin") throw new Error("macOS only");
38402
38535
  const outputArguments = humanReadableOutput ? [] : ["-ss"];
38403
38536
  const execOptions = {};
38404
38537
  if (signal) execOptions.signal = signal;
@@ -38507,14 +38640,14 @@ async function defaultBrowser$1(_execFileAsync = execFileAsync$1) {
38507
38640
  const execFileAsync = promisify(execFile);
38508
38641
  const titleize = (string$2) => string$2.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x$2) => x$2.toUpperCase());
38509
38642
  async function defaultBrowser() {
38510
- if (y.platform === "darwin") {
38643
+ if (process$1.platform === "darwin") {
38511
38644
  const id = await defaultBrowserId();
38512
38645
  return {
38513
38646
  name: await bundleName(id),
38514
38647
  id
38515
38648
  };
38516
38649
  }
38517
- if (y.platform === "linux") {
38650
+ if (process$1.platform === "linux") {
38518
38651
  const { stdout: stdout$1 } = await execFileAsync("xdg-mime", [
38519
38652
  "query",
38520
38653
  "default",
@@ -38526,13 +38659,13 @@ async function defaultBrowser() {
38526
38659
  id
38527
38660
  };
38528
38661
  }
38529
- if (y.platform === "win32") return defaultBrowser$1();
38662
+ if (process$1.platform === "win32") return defaultBrowser$1();
38530
38663
  throw new Error("Only macOS, Linux, and Windows are supported");
38531
38664
  }
38532
38665
 
38533
38666
  //#endregion
38534
38667
  //#region node_modules/is-in-ssh/index.js
38535
- const isInSsh = Boolean(y.env.SSH_CONNECTION || y.env.SSH_CLIENT || y.env.SSH_TTY);
38668
+ const isInSsh = Boolean(process$1.env.SSH_CONNECTION || process$1.env.SSH_CLIENT || process$1.env.SSH_TTY);
38536
38669
  var is_in_ssh_default = isInSsh;
38537
38670
 
38538
38671
  //#endregion
@@ -38540,7 +38673,7 @@ var is_in_ssh_default = isInSsh;
38540
38673
  const fallbackAttemptSymbol = Symbol("fallbackAttempt");
38541
38674
  const __dirname = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : "";
38542
38675
  const localXdgOpenPath = path.join(__dirname, "xdg-open");
38543
- const { platform: platform$1, arch } = y;
38676
+ const { platform: platform$1, arch } = process$1;
38544
38677
  const tryEachApp = async (apps$1, opener) => {
38545
38678
  if (apps$1.length === 0) return;
38546
38679
  const errors = [];
@@ -38653,7 +38786,7 @@ const baseOpen = async (options) => {
38653
38786
  await fs$1.access(localXdgOpenPath, constants$1.X_OK);
38654
38787
  exeLocalXdgOpen = true;
38655
38788
  } catch {}
38656
- command = y.versions.electron ?? (platform$1 === "android" || isBundled || !exeLocalXdgOpen) ? "xdg-open" : localXdgOpenPath;
38789
+ command = process$1.versions.electron ?? (platform$1 === "android" || isBundled || !exeLocalXdgOpen) ? "xdg-open" : localXdgOpenPath;
38657
38790
  }
38658
38791
  if (appArguments.length > 0) cliArguments.push(...appArguments);
38659
38792
  if (!options.wait) {
@@ -38796,9 +38929,8 @@ const deployCommand = new Command("deploy").description("Deploy all project reso
38796
38929
  //#endregion
38797
38930
  //#region src/cli/commands/project/link.ts
38798
38931
  function validateNonInteractiveFlags(command) {
38799
- const { create: create$1, name: name$1, existing, projectId } = command.opts();
38800
- if (create$1 && existing) command.error("--create and --existing cannot be used together");
38801
- if (existing && !projectId) command.error("--projectId is required when using --existing");
38932
+ const { create: create$1, name: name$1, projectId } = command.opts();
38933
+ if (create$1 && projectId) command.error("--create and --projectId cannot be used together");
38802
38934
  if (create$1 && !name$1) command.error("--name is required when using --create");
38803
38935
  }
38804
38936
  async function promptForLinkAction() {
@@ -38862,14 +38994,18 @@ async function link(options) {
38862
38994
  if (!projectRoot) throw new Error("No Base44 project found. Run this command from a project directory with a config.jsonc file.");
38863
38995
  if (await appConfigExists(projectRoot.root)) throw new Error("Project is already linked. An .app.jsonc file with the appId already exists.");
38864
38996
  let finalProjectId;
38865
- const action = options.existing ? "choose" : options.create ? "create" : await promptForLinkAction();
38997
+ const action = options.projectId ? "choose" : options.create ? "create" : await promptForLinkAction();
38866
38998
  if (action === "choose") {
38867
38999
  const linkableProjects = (await runTask("Fetching projects...", async () => listProjects(), {
38868
39000
  successMessage: "Projects fetched",
38869
39001
  errorMessage: "Failed to fetch projects"
38870
39002
  })).filter((p$1) => p$1.isManagedSourceCode !== true);
38871
39003
  if (!linkableProjects.length) return { outroMessage: "No projects available for linking" };
38872
- const { id: projectId } = options.existing ? { id: options.projectId } : await promptForExistingProject(linkableProjects);
39004
+ let projectId;
39005
+ if (options.projectId) {
39006
+ if (!linkableProjects.find((p$1) => p$1.id === options.projectId)) throw new Error(`Project with ID "${options.projectId}" not found or not available for linking.`);
39007
+ projectId = options.projectId;
39008
+ } else projectId = (await promptForExistingProject(linkableProjects)).id;
38873
39009
  await runTask("Linking project...", async () => {
38874
39010
  await writeAppConfig(projectRoot.root, projectId);
38875
39011
  setAppConfig({
@@ -38903,7 +39039,7 @@ async function link(options) {
38903
39039
  M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(getDashboardUrl(finalProjectId))}`);
38904
39040
  return { outroMessage: "Project linked" };
38905
39041
  }
38906
- const linkCommand = new Command("link").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("-e, --existing", "Link to an existing project (skip selection prompt)").option("-p, --projectId <id>", "Project ID (required when --existing is used)").hook("preAction", validateNonInteractiveFlags).action(async (options) => {
39042
+ const linkCommand = new Command("link").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", validateNonInteractiveFlags).action(async (options) => {
38907
39043
  await runCommand(() => link(options), {
38908
39044
  requireAuth: true,
38909
39045
  requireAppConfig: false
@@ -38931,12 +39067,665 @@ const siteDeployCommand = new Command("site").description("Manage site deploymen
38931
39067
  await runCommand(() => deployAction(options), { requireAuth: true });
38932
39068
  }));
38933
39069
 
39070
+ //#endregion
39071
+ //#region src/core/connectors/schema.ts
39072
+ /**
39073
+ * Response from POST /api/apps/{app_id}/external-auth/initiate
39074
+ */
39075
+ const InitiateResponseSchema = object({
39076
+ redirect_url: string().nullish(),
39077
+ connection_id: string().nullish(),
39078
+ already_authorized: boolean().nullish(),
39079
+ other_user_email: string().nullish(),
39080
+ error: string().nullish()
39081
+ });
39082
+ /**
39083
+ * Response from GET /api/apps/{app_id}/external-auth/status
39084
+ */
39085
+ const StatusResponseSchema = object({
39086
+ status: _enum([
39087
+ "ACTIVE",
39088
+ "PENDING",
39089
+ "FAILED"
39090
+ ]),
39091
+ account_email: string().nullish(),
39092
+ error: string().nullish()
39093
+ }).transform((data) => ({
39094
+ status: data.status,
39095
+ accountEmail: data.account_email,
39096
+ error: data.error
39097
+ }));
39098
+ /**
39099
+ * A connected integration from the list endpoint
39100
+ */
39101
+ const ConnectorSchema = object({
39102
+ integration_type: string(),
39103
+ status: string(),
39104
+ connected_at: string().nullish(),
39105
+ account_info: object({
39106
+ email: string().nullish(),
39107
+ name: string().nullish()
39108
+ }).nullish()
39109
+ }).transform((data) => ({
39110
+ integrationType: data.integration_type,
39111
+ status: data.status,
39112
+ connectedAt: data.connected_at,
39113
+ accountInfo: data.account_info
39114
+ }));
39115
+ /**
39116
+ * Response from GET /api/apps/{app_id}/external-auth/list
39117
+ */
39118
+ const ListResponseSchema = object({ integrations: array(ConnectorSchema) });
39119
+ /**
39120
+ * Generic API error response
39121
+ */
39122
+ const ApiErrorSchema = object({
39123
+ error: string(),
39124
+ detail: string().nullish()
39125
+ });
39126
+
39127
+ //#endregion
39128
+ //#region src/core/connectors/api.ts
39129
+ /**
39130
+ * Initiates OAuth flow for a connector integration.
39131
+ * Returns a redirect URL to open in the browser.
39132
+ */
39133
+ async function initiateOAuth(integrationType, scopes = null) {
39134
+ const response = await getAppClient().post("external-auth/initiate", {
39135
+ json: {
39136
+ integration_type: integrationType,
39137
+ scopes
39138
+ },
39139
+ throwHttpErrors: false
39140
+ });
39141
+ const json = await response.json();
39142
+ if (!response.ok) {
39143
+ const errorResult = ApiErrorSchema.safeParse(json);
39144
+ if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
39145
+ throw new ConnectorApiError(`Failed to initiate OAuth: ${response.status} ${response.statusText}`);
39146
+ }
39147
+ const result = InitiateResponseSchema.safeParse(json);
39148
+ if (!result.success) throw new ConnectorValidationError(`Invalid initiate response from server: ${result.error.message}`);
39149
+ return result.data;
39150
+ }
39151
+ /**
39152
+ * Checks the status of an OAuth connection attempt.
39153
+ */
39154
+ async function checkOAuthStatus(integrationType, connectionId) {
39155
+ const response = await getAppClient().get("external-auth/status", {
39156
+ searchParams: {
39157
+ integration_type: integrationType,
39158
+ connection_id: connectionId
39159
+ },
39160
+ throwHttpErrors: false
39161
+ });
39162
+ const json = await response.json();
39163
+ if (!response.ok) {
39164
+ const errorResult = ApiErrorSchema.safeParse(json);
39165
+ if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
39166
+ throw new ConnectorApiError(`Failed to check OAuth status: ${response.status} ${response.statusText}`);
39167
+ }
39168
+ const result = StatusResponseSchema.safeParse(json);
39169
+ if (!result.success) throw new ConnectorValidationError(`Invalid status response from server: ${result.error.message}`);
39170
+ return result.data;
39171
+ }
39172
+ /**
39173
+ * Lists all connected integrations for the current app.
39174
+ */
39175
+ async function listConnectors() {
39176
+ const response = await getAppClient().get("external-auth/list", { throwHttpErrors: false });
39177
+ const json = await response.json();
39178
+ if (!response.ok) {
39179
+ const errorResult = ApiErrorSchema.safeParse(json);
39180
+ if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
39181
+ throw new ConnectorApiError(`Failed to list connectors: ${response.status} ${response.statusText}`);
39182
+ }
39183
+ const result = ListResponseSchema.safeParse(json);
39184
+ if (!result.success) throw new ConnectorValidationError(`Invalid list response from server: ${result.error.message}`);
39185
+ return result.data.integrations;
39186
+ }
39187
+ /**
39188
+ * Disconnects (soft delete) a connector integration.
39189
+ */
39190
+ async function disconnectConnector(integrationType) {
39191
+ const response = await getAppClient().delete(`external-auth/integrations/${integrationType}`, { throwHttpErrors: false });
39192
+ if (!response.ok) {
39193
+ const json = await response.json();
39194
+ const errorResult = ApiErrorSchema.safeParse(json);
39195
+ if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
39196
+ throw new ConnectorApiError(`Failed to disconnect connector: ${response.status} ${response.statusText}`);
39197
+ }
39198
+ }
39199
+ /**
39200
+ * Removes (hard delete) a connector integration.
39201
+ * This permanently removes the connector and cannot be undone.
39202
+ */
39203
+ async function removeConnector(integrationType) {
39204
+ const response = await getAppClient().delete(`external-auth/integrations/${integrationType}/remove`, { throwHttpErrors: false });
39205
+ if (!response.ok) {
39206
+ const json = await response.json();
39207
+ const errorResult = ApiErrorSchema.safeParse(json);
39208
+ if (errorResult.success) throw new ConnectorApiError(errorResult.data.error);
39209
+ throw new ConnectorApiError(`Failed to remove connector: ${response.status} ${response.statusText}`);
39210
+ }
39211
+ }
39212
+
39213
+ //#endregion
39214
+ //#region src/core/connectors/constants.ts
39215
+ /**
39216
+ * OAuth polling configuration
39217
+ */
39218
+ const OAUTH_POLL_INTERVAL_MS = 2e3;
39219
+ const OAUTH_POLL_TIMEOUT_MS = 300 * 1e3;
39220
+ /**
39221
+ * Supported OAuth connector integrations.
39222
+ * Based on apper/backend/app/external_auth/models/constants.py
39223
+ */
39224
+ const SUPPORTED_INTEGRATIONS = [
39225
+ "googlecalendar",
39226
+ "googledrive",
39227
+ "gmail",
39228
+ "googlesheets",
39229
+ "googledocs",
39230
+ "googleslides",
39231
+ "slack",
39232
+ "notion",
39233
+ "salesforce",
39234
+ "hubspot",
39235
+ "linkedin",
39236
+ "tiktok"
39237
+ ];
39238
+ /**
39239
+ * Display names for integrations (for CLI output)
39240
+ */
39241
+ const INTEGRATION_DISPLAY_NAMES = {
39242
+ googlecalendar: "Google Calendar",
39243
+ googledrive: "Google Drive",
39244
+ gmail: "Gmail",
39245
+ googlesheets: "Google Sheets",
39246
+ googledocs: "Google Docs",
39247
+ googleslides: "Google Slides",
39248
+ slack: "Slack",
39249
+ notion: "Notion",
39250
+ salesforce: "Salesforce",
39251
+ hubspot: "HubSpot",
39252
+ linkedin: "LinkedIn",
39253
+ tiktok: "TikTok"
39254
+ };
39255
+ function isValidIntegration(type) {
39256
+ return SUPPORTED_INTEGRATIONS.includes(type);
39257
+ }
39258
+ function getIntegrationDisplayName(type) {
39259
+ if (isValidIntegration(type)) return INTEGRATION_DISPLAY_NAMES[type];
39260
+ return type;
39261
+ }
39262
+
39263
+ //#endregion
39264
+ //#region src/core/connectors/oauth.ts
39265
+ /**
39266
+ * Polls for OAuth completion status.
39267
+ * Returns when status becomes ACTIVE or FAILED, or times out.
39268
+ */
39269
+ async function waitForOAuthCompletion(integrationType, connectionId, options) {
39270
+ let accountEmail;
39271
+ let error;
39272
+ try {
39273
+ await pWaitFor(async () => {
39274
+ const status = await checkOAuthStatus(integrationType, connectionId);
39275
+ if (status.status === "ACTIVE") {
39276
+ accountEmail = status.accountEmail ?? void 0;
39277
+ return true;
39278
+ }
39279
+ if (status.status === "FAILED") {
39280
+ error = status.error || "Authorization failed";
39281
+ throw new Error(error);
39282
+ }
39283
+ options?.onPending?.();
39284
+ return false;
39285
+ }, {
39286
+ interval: OAUTH_POLL_INTERVAL_MS,
39287
+ timeout: OAUTH_POLL_TIMEOUT_MS
39288
+ });
39289
+ return {
39290
+ success: true,
39291
+ accountEmail
39292
+ };
39293
+ } catch (err) {
39294
+ if (err instanceof Error && err.message.includes("timed out")) return {
39295
+ success: false,
39296
+ error: "Authorization timed out. Please try again."
39297
+ };
39298
+ return {
39299
+ success: false,
39300
+ error: error || (err instanceof Error ? err.message : "Unknown error")
39301
+ };
39302
+ }
39303
+ }
39304
+
39305
+ //#endregion
39306
+ //#region src/core/connectors/config.ts
39307
+ /**
39308
+ * Read all connectors from the project config file
39309
+ */
39310
+ async function readLocalConnectors(projectRoot) {
39311
+ const found = await findProjectRoot(projectRoot);
39312
+ if (!found) return [];
39313
+ const connectorsData = (await readJsonFile(found.configPath)).connectors;
39314
+ if (!connectorsData) return [];
39315
+ const connectors = [];
39316
+ for (const [type, config$1] of Object.entries(connectorsData)) {
39317
+ if (!isValidIntegration(type)) throw new Error(`Unknown connector type: ${type}`);
39318
+ connectors.push({
39319
+ type,
39320
+ scopes: config$1.scopes
39321
+ });
39322
+ }
39323
+ return connectors;
39324
+ }
39325
+ /**
39326
+ * Write connectors to the project config file
39327
+ */
39328
+ async function writeLocalConnectors(connectors, projectRoot) {
39329
+ const found = await findProjectRoot(projectRoot);
39330
+ if (!found) throw new Error("Project config not found. Run this command from a Base44 project directory.");
39331
+ const existingConfig = await readJsonFile(found.configPath);
39332
+ const connectorsData = {};
39333
+ for (const connector of connectors) connectorsData[connector.type] = { ...connector.scopes && { scopes: connector.scopes } };
39334
+ const updatedConfig = {
39335
+ ...existingConfig,
39336
+ connectors: Object.keys(connectorsData).length > 0 ? connectorsData : void 0
39337
+ };
39338
+ if (!updatedConfig.connectors) delete updatedConfig.connectors;
39339
+ await writeJsonFile(found.configPath, updatedConfig);
39340
+ return found.configPath;
39341
+ }
39342
+ /**
39343
+ * Add a connector to the project config file
39344
+ */
39345
+ async function addLocalConnector(type, scopes, projectRoot) {
39346
+ const connectors = await readLocalConnectors(projectRoot);
39347
+ const existing = connectors.find((c$1) => c$1.type === type);
39348
+ if (existing) {
39349
+ if (scopes) existing.scopes = scopes;
39350
+ } else connectors.push({
39351
+ type,
39352
+ scopes
39353
+ });
39354
+ return await writeLocalConnectors(connectors, projectRoot);
39355
+ }
39356
+ /**
39357
+ * Remove a connector from the project config file
39358
+ */
39359
+ async function removeLocalConnector(type, projectRoot) {
39360
+ const connectors = await readLocalConnectors(projectRoot);
39361
+ const filtered = connectors.filter((c$1) => c$1.type !== type);
39362
+ if (filtered.length === connectors.length) return null;
39363
+ return await writeLocalConnectors(filtered, projectRoot);
39364
+ }
39365
+
39366
+ //#endregion
39367
+ //#region src/core/connectors/state.ts
39368
+ /**
39369
+ * Fetches both local config and backend connectors in parallel.
39370
+ * Gracefully handles failures by returning empty arrays.
39371
+ */
39372
+ async function fetchConnectorState() {
39373
+ const [local, backend] = await Promise.all([readLocalConnectors().catch(() => []), listConnectors().catch(() => [])]);
39374
+ return {
39375
+ local,
39376
+ backend
39377
+ };
39378
+ }
39379
+
39380
+ //#endregion
39381
+ //#region src/cli/commands/connectors/add.ts
39382
+ function validateIntegrationType(type) {
39383
+ if (!isValidIntegration(type)) {
39384
+ const supportedList = SUPPORTED_INTEGRATIONS.join(", ");
39385
+ throw new Error(`Unsupported connector: ${type}\nSupported connectors: ${supportedList}`);
39386
+ }
39387
+ return type;
39388
+ }
39389
+ async function promptForIntegrationType() {
39390
+ const selected = await ve({
39391
+ message: "Select an integration to connect:",
39392
+ options: SUPPORTED_INTEGRATIONS.map((type) => ({
39393
+ value: type,
39394
+ label: getIntegrationDisplayName(type)
39395
+ }))
39396
+ });
39397
+ if (pD(selected)) {
39398
+ xe("Operation cancelled.");
39399
+ process.exit(0);
39400
+ }
39401
+ return selected;
39402
+ }
39403
+ async function pollForOAuthCompletion(integrationType, connectionId) {
39404
+ return await runTask("Waiting for authorization...", async () => {
39405
+ return await waitForOAuthCompletion(integrationType, connectionId);
39406
+ }, {
39407
+ successMessage: "Authorization completed!",
39408
+ errorMessage: "Authorization failed"
39409
+ });
39410
+ }
39411
+ async function addConnector(integrationType) {
39412
+ const selectedType = integrationType ? validateIntegrationType(integrationType) : await promptForIntegrationType();
39413
+ const displayName = getIntegrationDisplayName(selectedType);
39414
+ const initiateResponse = await runTask(`Initiating ${displayName} connection...`, async () => {
39415
+ return await initiateOAuth(selectedType);
39416
+ }, {
39417
+ successMessage: `${displayName} OAuth initiated`,
39418
+ errorMessage: `Failed to initiate ${displayName} connection`
39419
+ });
39420
+ if (initiateResponse.already_authorized) {
39421
+ await addLocalConnector(selectedType);
39422
+ return { outroMessage: `Already connected to ${theme.styles.bold(displayName)} (added to config)` };
39423
+ }
39424
+ if (initiateResponse.error === "different_user" && initiateResponse.other_user_email) throw new Error(`This app is already connected to ${displayName} by ${initiateResponse.other_user_email}`);
39425
+ if (!initiateResponse.redirect_url || !initiateResponse.connection_id) throw new Error("Invalid response from server: missing redirect URL or connection ID");
39426
+ M.info(`Please authorize ${displayName} at:\n${theme.colors.links(initiateResponse.redirect_url)}`);
39427
+ const result = await pollForOAuthCompletion(selectedType, initiateResponse.connection_id);
39428
+ if (!result.success) throw new Error(result.error || "Authorization failed");
39429
+ await addLocalConnector(selectedType);
39430
+ const accountInfo = result.accountEmail ? ` as ${theme.styles.bold(result.accountEmail)}` : "";
39431
+ return { outroMessage: `Successfully connected to ${theme.styles.bold(displayName)}${accountInfo}` };
39432
+ }
39433
+ const connectorsAddCommand = new Command("add").argument("[type]", "Integration type (e.g., slack, notion, googlecalendar)").description("Connect an OAuth integration").action(async (type) => {
39434
+ await runCommand(() => addConnector(type), {
39435
+ requireAuth: true,
39436
+ requireAppConfig: true
39437
+ });
39438
+ });
39439
+
39440
+ //#endregion
39441
+ //#region src/cli/commands/connectors/list.ts
39442
+ function mergeConnectors(local, backend) {
39443
+ const merged = /* @__PURE__ */ new Map();
39444
+ for (const connector of local) merged.set(connector.type, {
39445
+ type: connector.type,
39446
+ displayName: getIntegrationDisplayName(connector.type),
39447
+ inLocal: true,
39448
+ inBackend: false
39449
+ });
39450
+ for (const connector of backend) {
39451
+ const existing = merged.get(connector.integrationType);
39452
+ const accountEmail = (connector.accountInfo?.email || connector.accountInfo?.name) ?? void 0;
39453
+ if (existing) {
39454
+ existing.inBackend = true;
39455
+ existing.status = connector.status;
39456
+ existing.accountEmail = accountEmail;
39457
+ } else merged.set(connector.integrationType, {
39458
+ type: connector.integrationType,
39459
+ displayName: getIntegrationDisplayName(connector.integrationType),
39460
+ inLocal: false,
39461
+ inBackend: true,
39462
+ status: connector.status,
39463
+ accountEmail
39464
+ });
39465
+ }
39466
+ return Array.from(merged.values());
39467
+ }
39468
+ function formatConnectorLine(connector) {
39469
+ const { displayName, inLocal, inBackend, status, accountEmail } = connector;
39470
+ const isConnected$1 = inBackend && status?.toLowerCase() === "active";
39471
+ const isPending = inLocal && !inBackend;
39472
+ const isOrphaned = inBackend && !inLocal;
39473
+ let bullet;
39474
+ let statusText = "";
39475
+ if (isConnected$1) {
39476
+ bullet = theme.colors.success("●");
39477
+ if (accountEmail) statusText = ` - ${accountEmail}`;
39478
+ } else if (isPending) {
39479
+ bullet = theme.colors.warning("○");
39480
+ statusText = theme.styles.dim(" (not connected)");
39481
+ } else if (isOrphaned) {
39482
+ bullet = theme.colors.error("○");
39483
+ statusText = theme.styles.dim(" (not in local config)");
39484
+ } else {
39485
+ bullet = theme.colors.error("○");
39486
+ statusText = theme.styles.dim(` (${status || "disconnected"})`);
39487
+ }
39488
+ return `${bullet} ${displayName}${statusText}`;
39489
+ }
39490
+ async function listConnectorsCommand() {
39491
+ const { local: localConnectors, backend: backendConnectors } = await runTask("Fetching connectors...", fetchConnectorState, {
39492
+ successMessage: "Connectors loaded",
39493
+ errorMessage: "Failed to fetch connectors"
39494
+ });
39495
+ const merged = mergeConnectors(localConnectors, backendConnectors);
39496
+ if (merged.length === 0) {
39497
+ M.info("No connectors configured for this app.");
39498
+ M.info(`Run ${theme.styles.bold("base44 connectors add")} to connect an integration.`);
39499
+ return { outroMessage: "" };
39500
+ }
39501
+ console.log();
39502
+ for (const connector of merged) console.log(formatConnectorLine(connector));
39503
+ console.log();
39504
+ const connected = merged.filter((c$1) => c$1.inBackend && c$1.status?.toLowerCase() === "active").length;
39505
+ const pending = merged.filter((c$1) => c$1.inLocal && !c$1.inBackend).length;
39506
+ let summary = `${connected} connected`;
39507
+ if (pending > 0) {
39508
+ summary += `, ${pending} pending`;
39509
+ M.info(`Run ${theme.styles.bold("base44 connectors push")} to connect pending integrations.`);
39510
+ }
39511
+ return { outroMessage: summary };
39512
+ }
39513
+ const connectorsListCommand = new Command("list").description("List all connected OAuth integrations").action(async () => {
39514
+ await runCommand(listConnectorsCommand, {
39515
+ requireAuth: true,
39516
+ requireAppConfig: true
39517
+ });
39518
+ });
39519
+
39520
+ //#endregion
39521
+ //#region src/cli/commands/connectors/push.ts
39522
+ function findPendingConnectors(local, backend) {
39523
+ const connectedTypes = new Set(backend.filter((c$1) => c$1.status.toLowerCase() === "active").map((c$1) => c$1.integrationType));
39524
+ return local.filter((c$1) => !connectedTypes.has(c$1.type)).map((c$1) => ({
39525
+ type: c$1.type,
39526
+ displayName: getIntegrationDisplayName(c$1.type),
39527
+ scopes: c$1.scopes
39528
+ }));
39529
+ }
39530
+ function findOrphanedConnectors(local, backend) {
39531
+ const localTypes = new Set(local.map((c$1) => c$1.type));
39532
+ return backend.filter((c$1) => c$1.status.toLowerCase() === "active").filter((c$1) => !localTypes.has(c$1.integrationType)).filter((c$1) => isValidIntegration(c$1.integrationType)).map((c$1) => ({
39533
+ type: c$1.integrationType,
39534
+ displayName: getIntegrationDisplayName(c$1.integrationType),
39535
+ accountEmail: (c$1.accountInfo?.email || c$1.accountInfo?.name) ?? void 0
39536
+ }));
39537
+ }
39538
+ async function connectSingleConnector(connector) {
39539
+ const { type, displayName, scopes } = connector;
39540
+ const initiateResponse = await initiateOAuth(type, scopes || null);
39541
+ if (initiateResponse.already_authorized) return { success: true };
39542
+ if (initiateResponse.error === "different_user") return {
39543
+ success: false,
39544
+ error: `Already connected by ${initiateResponse.other_user_email}`
39545
+ };
39546
+ if (!initiateResponse.redirect_url || !initiateResponse.connection_id) return {
39547
+ success: false,
39548
+ error: "Invalid response from server"
39549
+ };
39550
+ M.info(`Please authorize ${displayName} at:\n${theme.colors.links(initiateResponse.redirect_url)}`);
39551
+ return await runTask("Waiting for authorization...", async () => {
39552
+ return await waitForOAuthCompletion(type, initiateResponse.connection_id);
39553
+ }, {
39554
+ successMessage: "Authorization completed!",
39555
+ errorMessage: "Authorization failed"
39556
+ });
39557
+ }
39558
+ async function pushConnectorsCommand() {
39559
+ const { local: localConnectors, backend: backendConnectors } = await runTask("Checking connector status...", fetchConnectorState, {
39560
+ successMessage: "Status checked",
39561
+ errorMessage: "Failed to check status"
39562
+ });
39563
+ const pending = findPendingConnectors(localConnectors, backendConnectors);
39564
+ const orphaned = findOrphanedConnectors(localConnectors, backendConnectors);
39565
+ if (pending.length === 0 && orphaned.length === 0) return { outroMessage: "All connectors are in sync" };
39566
+ console.log();
39567
+ if (pending.length > 0) {
39568
+ M.info(`${pending.length} connector${pending.length === 1 ? "" : "s"} to connect:`);
39569
+ for (const c$1 of pending) console.log(` ${theme.colors.success("+")} ${c$1.displayName}`);
39570
+ }
39571
+ if (orphaned.length > 0) {
39572
+ M.info(`${orphaned.length} connector${orphaned.length === 1 ? "" : "s"} to remove:`);
39573
+ for (const c$1 of orphaned) {
39574
+ const accountInfo = c$1.accountEmail ? ` (${c$1.accountEmail})` : "";
39575
+ console.log(` ${theme.colors.error("-")} ${c$1.displayName}${accountInfo}`);
39576
+ }
39577
+ }
39578
+ console.log();
39579
+ const totalChanges = pending.length + orphaned.length;
39580
+ const shouldProceed = await ye({
39581
+ message: `Apply ${totalChanges} change${totalChanges === 1 ? "" : "s"}?`,
39582
+ initialValue: true
39583
+ });
39584
+ if (pD(shouldProceed) || !shouldProceed) return { outroMessage: "Cancelled" };
39585
+ let connected = 0;
39586
+ let removed = 0;
39587
+ let failed = 0;
39588
+ for (const connector of orphaned) try {
39589
+ await disconnectConnector(connector.type);
39590
+ M.success(`Removed ${connector.displayName}`);
39591
+ removed++;
39592
+ } catch (err) {
39593
+ M.error(`Failed to remove ${connector.displayName}: ${err instanceof Error ? err.message : "Unknown error"}`);
39594
+ failed++;
39595
+ }
39596
+ for (const connector of pending) {
39597
+ console.log();
39598
+ M.info(`Connecting ${theme.styles.bold(connector.displayName)}...`);
39599
+ const result = await connectSingleConnector(connector);
39600
+ if (result.success) {
39601
+ const accountInfo = result.accountEmail ? ` as ${result.accountEmail}` : "";
39602
+ M.success(`${connector.displayName} connected${accountInfo}`);
39603
+ connected++;
39604
+ } else {
39605
+ M.error(`${connector.displayName} failed: ${result.error}`);
39606
+ failed++;
39607
+ }
39608
+ }
39609
+ console.log();
39610
+ const parts = [];
39611
+ if (connected > 0) parts.push(`${connected} connected`);
39612
+ if (removed > 0) parts.push(`${removed} removed`);
39613
+ if (failed > 0) parts.push(`${failed} failed`);
39614
+ return { outroMessage: parts.join(", ") };
39615
+ }
39616
+ const connectorsPushCommand = new Command("push").description("Sync connectors with backend (connect new, remove missing)").action(async () => {
39617
+ await runCommand(pushConnectorsCommand, {
39618
+ requireAuth: true,
39619
+ requireAppConfig: true
39620
+ });
39621
+ });
39622
+
39623
+ //#endregion
39624
+ //#region src/cli/commands/connectors/remove.ts
39625
+ function mergeConnectorsForRemoval(local, backend) {
39626
+ const merged = /* @__PURE__ */ new Map();
39627
+ for (const connector of local) merged.set(connector.type, {
39628
+ type: connector.type,
39629
+ displayName: getIntegrationDisplayName(connector.type),
39630
+ inLocal: true,
39631
+ inBackend: false
39632
+ });
39633
+ for (const connector of backend) {
39634
+ if (!isValidIntegration(connector.integrationType)) continue;
39635
+ const existing = merged.get(connector.integrationType);
39636
+ const accountEmail = (connector.accountInfo?.email || connector.accountInfo?.name) ?? void 0;
39637
+ if (existing) {
39638
+ existing.inBackend = true;
39639
+ existing.accountEmail = accountEmail;
39640
+ } else merged.set(connector.integrationType, {
39641
+ type: connector.integrationType,
39642
+ displayName: getIntegrationDisplayName(connector.integrationType),
39643
+ inLocal: false,
39644
+ inBackend: true,
39645
+ accountEmail
39646
+ });
39647
+ }
39648
+ return Array.from(merged.values());
39649
+ }
39650
+ function validateConnectorType(type, merged) {
39651
+ if (!isValidIntegration(type)) throw new Error(`Invalid connector type: ${type}`);
39652
+ const connector = merged.find((c$1) => c$1.type === type);
39653
+ if (!connector) throw new Error(`No ${getIntegrationDisplayName(type)} connector found`);
39654
+ return {
39655
+ type,
39656
+ connector
39657
+ };
39658
+ }
39659
+ async function promptForConnectorToRemove(connectors) {
39660
+ const selected = await ve({
39661
+ message: "Select a connector to remove:",
39662
+ options: connectors.map((c$1) => {
39663
+ let label = c$1.displayName;
39664
+ if (c$1.accountEmail) label += ` (${c$1.accountEmail})`;
39665
+ else if (c$1.inLocal && !c$1.inBackend) label += " (not connected)";
39666
+ return {
39667
+ value: c$1.type,
39668
+ label
39669
+ };
39670
+ })
39671
+ });
39672
+ if (pD(selected)) {
39673
+ xe("Operation cancelled.");
39674
+ process.exit(0);
39675
+ }
39676
+ return {
39677
+ type: selected,
39678
+ connector: connectors.find((c$1) => c$1.type === selected)
39679
+ };
39680
+ }
39681
+ async function removeConnectorCommand(integrationType, options = {}) {
39682
+ const isHardDelete = options.hard === true;
39683
+ const { local: localConnectors, backend: backendConnectors } = await runTask("Fetching connectors...", fetchConnectorState, {
39684
+ successMessage: "Connectors loaded",
39685
+ errorMessage: "Failed to fetch connectors"
39686
+ });
39687
+ const merged = mergeConnectorsForRemoval(localConnectors, backendConnectors);
39688
+ if (merged.length === 0) return { outroMessage: "No connectors to remove" };
39689
+ const { type: selectedType, connector: selectedConnector } = integrationType ? validateConnectorType(integrationType, merged) : await promptForConnectorToRemove(merged);
39690
+ const displayName = getIntegrationDisplayName(selectedType);
39691
+ const accountInfo = selectedConnector.accountEmail ? ` (${selectedConnector.accountEmail})` : "";
39692
+ if (!options.yes) {
39693
+ const shouldRemove = await ye({
39694
+ message: `${isHardDelete ? "Permanently remove" : "Remove"} ${displayName}${accountInfo}?`,
39695
+ initialValue: false
39696
+ });
39697
+ if (pD(shouldRemove) || !shouldRemove) {
39698
+ xe("Operation cancelled.");
39699
+ process.exit(0);
39700
+ }
39701
+ }
39702
+ await runTask(`Removing ${displayName}...`, async () => {
39703
+ if (selectedConnector.inBackend) if (isHardDelete) await removeConnector(selectedType);
39704
+ else await disconnectConnector(selectedType);
39705
+ await removeLocalConnector(selectedType);
39706
+ }, {
39707
+ successMessage: `${displayName} removed`,
39708
+ errorMessage: `Failed to remove ${displayName}`
39709
+ });
39710
+ return { outroMessage: `Successfully removed ${theme.styles.bold(displayName)}` };
39711
+ }
39712
+ const connectorsRemoveCommand = new Command("remove").argument("[type]", "Integration type to remove (e.g., slack, notion)").option("--hard", "Permanently remove the connector (cannot be undone)").option("-y, --yes", "Skip confirmation prompt").description("Remove an OAuth integration").action(async (type, options) => {
39713
+ await runCommand(() => removeConnectorCommand(type, options), {
39714
+ requireAuth: true,
39715
+ requireAppConfig: true
39716
+ });
39717
+ });
39718
+
39719
+ //#endregion
39720
+ //#region src/cli/commands/connectors/index.ts
39721
+ const connectorsCommand = new Command("connectors").description("Manage OAuth connectors").addCommand(connectorsAddCommand).addCommand(connectorsListCommand).addCommand(connectorsPushCommand).addCommand(connectorsRemoveCommand);
39722
+
38934
39723
  //#endregion
38935
39724
  //#region package.json
38936
- var version = "0.0.16";
39725
+ var version = "0.0.17";
38937
39726
 
38938
39727
  //#endregion
38939
- //#region src/cli/index.ts
39728
+ //#region src/cli/program.ts
38940
39729
  const program = new Command();
38941
39730
  program.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version);
38942
39731
  program.configureHelp({ sortSubcommands: true });
@@ -38950,7 +39739,7 @@ program.addCommand(linkCommand);
38950
39739
  program.addCommand(entitiesPushCommand);
38951
39740
  program.addCommand(functionsDeployCommand);
38952
39741
  program.addCommand(siteDeployCommand);
38953
- program.parse();
39742
+ program.addCommand(connectorsCommand);
38954
39743
 
38955
39744
  //#endregion
38956
- export { };
39745
+ export { CLIExitError, program };