@base44-preview/cli 0.0.19-pr.124.a7f34a6 → 0.0.21-pr.112.b9c226a

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 (2) hide show
  1. package/dist/index.js +174 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15,6 +15,8 @@ import { finished } from "node:stream/promises";
15
15
  import path$1, { dirname as dirname$1, parse } from "path";
16
16
  import EE, { EventEmitter as EventEmitter$1 } from "events";
17
17
  import fs$2 from "fs";
18
+ import { getAppClient } from "@core/clients/index.js";
19
+ import { formatApiError } from "@core/errors.js";
18
20
  import { Buffer as Buffer$1 } from "buffer";
19
21
  import { randomBytes, randomUUID } from "node:crypto";
20
22
  import { StringDecoder } from "node:string_decoder";
@@ -23,6 +25,8 @@ import * as realZlib$1 from "zlib";
23
25
  import realZlib from "zlib";
24
26
  import assert$1 from "node:assert";
25
27
  import tty from "node:tty";
28
+ import { fetchAgents, pushAgents, writeAgents } from "@core/resources/agent/index.js";
29
+ import { readProjectConfig } from "@core/index.js";
26
30
  import { scheduler, setImmediate as setImmediate$1, setTimeout as setTimeout$1 } from "node:timers/promises";
27
31
  import { serialize } from "node:v8";
28
32
  import { Buffer as Buffer$2 } from "node:buffer";
@@ -7899,6 +7903,15 @@ var AuthValidationError = class extends Error {
7899
7903
  this.name = "AuthValidationError";
7900
7904
  }
7901
7905
  };
7906
+ /**
7907
+ * Formats an API error response into a human-readable string.
7908
+ * Prefers `message` (human-readable) over `detail`.
7909
+ */
7910
+ function formatApiError$1(errorJson) {
7911
+ const error = errorJson;
7912
+ const content = error?.message ?? error?.detail ?? errorJson;
7913
+ return typeof content === "string" ? content : JSON.stringify(content, null, 2);
7914
+ }
7902
7915
 
7903
7916
  //#endregion
7904
7917
  //#region src/core/consts.ts
@@ -16553,7 +16566,7 @@ async function readAllEntities(entitiesDir) {
16553
16566
  //#endregion
16554
16567
  //#region src/core/resources/entity/api.ts
16555
16568
  async function syncEntities(entities) {
16556
- const appClient = getAppClient();
16569
+ const appClient = getAppClient$1();
16557
16570
  const schemaSyncPayload = Object.fromEntries(entities.map((entity) => [entity.name, entity]));
16558
16571
  const response = await appClient.put("entity-schemas", {
16559
16572
  json: { entityNameToSchema: schemaSyncPayload },
@@ -16561,8 +16574,8 @@ async function syncEntities(entities) {
16561
16574
  });
16562
16575
  if (!response.ok) {
16563
16576
  const errorJson = await response.json();
16564
- if (response.status === 428) throw new Error(`Failed to delete entity: ${errorJson.message}`);
16565
- throw new Error(`Error occurred while syncing entities ${errorJson.message}`);
16577
+ if (response.status === 428) throw new Error(`Failed to delete entity: ${formatApiError$1(errorJson)}`);
16578
+ throw new Error(`Error occurred while syncing entities: ${formatApiError$1(errorJson)}`);
16566
16579
  }
16567
16580
  return SyncEntitiesResponseSchema.parse(await response.json());
16568
16581
  }
@@ -16650,7 +16663,7 @@ function toDeployPayloadItem(fn) {
16650
16663
  };
16651
16664
  }
16652
16665
  async function deployFunctions(functions) {
16653
- const appClient = getAppClient();
16666
+ const appClient = getAppClient$1();
16654
16667
  const payload = { functions: functions.map(toDeployPayloadItem) };
16655
16668
  const response = await appClient.put("backend-functions", {
16656
16669
  json: payload,
@@ -16684,6 +16697,98 @@ const functionResource = {
16684
16697
  push: pushFunctions
16685
16698
  };
16686
16699
 
16700
+ //#endregion
16701
+ //#region src/core/resources/agent/schema.ts
16702
+ const EntityToolConfigSchema = object({
16703
+ entity_name: string().min(1),
16704
+ allowed_operations: array(_enum([
16705
+ "read",
16706
+ "create",
16707
+ "update",
16708
+ "delete"
16709
+ ])).default([])
16710
+ });
16711
+ const BackendFunctionToolConfigSchema = object({
16712
+ function_name: string().min(1),
16713
+ description: string().default("agent backend function")
16714
+ });
16715
+ const ToolConfigSchema = union([EntityToolConfigSchema, BackendFunctionToolConfigSchema]);
16716
+ const AgentConfigSchema = object({
16717
+ name: string().regex(/^[a-z0-9_]+$/, "Agent name must be lowercase alphanumeric with underscores").min(1).max(100),
16718
+ description: string().min(1, "Agent description cannot be empty"),
16719
+ instructions: string().min(1, "Agent instructions cannot be empty"),
16720
+ tool_configs: array(ToolConfigSchema).default([]),
16721
+ whatsapp_greeting: string().nullable().optional()
16722
+ });
16723
+ const SyncAgentsResponseSchema = object({
16724
+ created: array(string()),
16725
+ updated: array(string()),
16726
+ deleted: array(string())
16727
+ });
16728
+ const AgentConfigApiResponseSchema = object({
16729
+ name: string(),
16730
+ description: string(),
16731
+ instructions: string(),
16732
+ tool_configs: array(ToolConfigSchema).default([]),
16733
+ whatsapp_greeting: string().nullable().optional()
16734
+ });
16735
+ const ListAgentsResponseSchema = object({
16736
+ items: array(AgentConfigApiResponseSchema),
16737
+ total: number()
16738
+ });
16739
+
16740
+ //#endregion
16741
+ //#region src/core/resources/agent/config.ts
16742
+ async function readAgentFile(agentPath) {
16743
+ const parsed = await readJsonFile(agentPath);
16744
+ const result = AgentConfigSchema.safeParse(parsed);
16745
+ if (!result.success) throw new Error(`Invalid agent configuration in ${agentPath}: ${result.error.issues.map((e$1) => e$1.message).join(", ")}`);
16746
+ return result.data;
16747
+ }
16748
+ async function readAllAgents(agentsDir) {
16749
+ if (!await pathExists(agentsDir)) return [];
16750
+ const files = await globby(`*.${CONFIG_FILE_EXTENSION_GLOB}`, {
16751
+ cwd: agentsDir,
16752
+ absolute: true
16753
+ });
16754
+ const agents = await Promise.all(files.map((filePath) => readAgentFile(filePath)));
16755
+ const names = /* @__PURE__ */ new Set();
16756
+ for (const agent of agents) {
16757
+ if (names.has(agent.name)) throw new Error(`Duplicate agent name "${agent.name}"`);
16758
+ names.add(agent.name);
16759
+ }
16760
+ return agents;
16761
+ }
16762
+
16763
+ //#endregion
16764
+ //#region src/core/resources/agent/api.ts
16765
+ async function pushAgents$1(agents) {
16766
+ const appClient = getAppClient();
16767
+ const payload = agents.map((agent) => ({
16768
+ name: agent.name,
16769
+ description: agent.description,
16770
+ instructions: agent.instructions,
16771
+ tool_configs: agent.tool_configs,
16772
+ whatsapp_greeting: agent.whatsapp_greeting ?? null
16773
+ }));
16774
+ const response = await appClient.put("agent-configs", {
16775
+ json: payload,
16776
+ throwHttpErrors: false
16777
+ });
16778
+ if (!response.ok) {
16779
+ const errorJson = await response.json();
16780
+ throw new Error(`Error occurred while syncing agents: ${formatApiError(errorJson)}`);
16781
+ }
16782
+ return SyncAgentsResponseSchema.parse(await response.json());
16783
+ }
16784
+
16785
+ //#endregion
16786
+ //#region src/core/resources/agent/resource.ts
16787
+ const agentResource = {
16788
+ readAll: readAllAgents,
16789
+ push: pushAgents$1
16790
+ };
16791
+
16687
16792
  //#endregion
16688
16793
  //#region src/core/project/schema.ts
16689
16794
  const TemplateSchema = object({
@@ -16704,7 +16809,8 @@ const ProjectConfigSchema = object({
16704
16809
  description: string().optional(),
16705
16810
  site: SiteConfigSchema.optional(),
16706
16811
  entitiesDir: string().optional().default("entities"),
16707
- functionsDir: string().optional().default("functions")
16812
+ functionsDir: string().optional().default("functions"),
16813
+ agentsDir: string().optional().default("agents")
16708
16814
  });
16709
16815
  const AppConfigSchema = object({ id: string().min(1, "id cannot be empty") });
16710
16816
  const CreateProjectResponseSchema = looseObject({ id: string() });
@@ -16760,7 +16866,7 @@ async function findProjectRoot(startPath) {
16760
16866
  * @example
16761
16867
  * const { project, entities, functions } = await readProjectConfig();
16762
16868
  */
16763
- async function readProjectConfig(projectRoot) {
16869
+ async function readProjectConfig$1(projectRoot) {
16764
16870
  let found;
16765
16871
  if (projectRoot) {
16766
16872
  const configPath$1 = await findConfigInDir(projectRoot);
@@ -16776,7 +16882,11 @@ async function readProjectConfig(projectRoot) {
16776
16882
  if (!result.success) throw new Error(`Invalid project configuration: ${result.error.message}`);
16777
16883
  const project = result.data;
16778
16884
  const configDir = dirname(configPath);
16779
- const [entities, functions] = await Promise.all([entityResource.readAll(join(configDir, project.entitiesDir)), functionResource.readAll(join(configDir, project.functionsDir))]);
16885
+ const [entities, functions, agents] = await Promise.all([
16886
+ entityResource.readAll(join(configDir, project.entitiesDir)),
16887
+ functionResource.readAll(join(configDir, project.functionsDir)),
16888
+ agentResource.readAll(join(configDir, project.agentsDir))
16889
+ ]);
16780
16890
  return {
16781
16891
  project: {
16782
16892
  ...project,
@@ -16784,7 +16894,8 @@ async function readProjectConfig(projectRoot) {
16784
16894
  configPath
16785
16895
  },
16786
16896
  entities,
16787
- functions
16897
+ functions,
16898
+ agents
16788
16899
  };
16789
16900
  }
16790
16901
 
@@ -25412,7 +25523,7 @@ async function uploadSite(archivePath) {
25412
25523
  const blob = new Blob([archiveBuffer], { type: "application/gzip" });
25413
25524
  const formData = new FormData();
25414
25525
  formData.append("file", blob, "dist.tar.gz");
25415
- const response = await getAppClient().post("deploy-dist", { body: formData });
25526
+ const response = await getAppClient$1().post("deploy-dist", { body: formData });
25416
25527
  return DeployResponseSchema.parse(await response.json());
25417
25528
  }
25418
25529
 
@@ -30517,7 +30628,7 @@ const base44Client = distribution_default.create({
30517
30628
  * const appClient = getAppClient();
30518
30629
  * const response = await appClient.get("entities");
30519
30630
  */
30520
- function getAppClient() {
30631
+ function getAppClient$1() {
30521
30632
  const { id } = getAppConfig();
30522
30633
  return base44Client.extend({ prefixUrl: new URL(`/api/apps/${id}/`, getBase44ApiUrl()).href });
30523
30634
  }
@@ -31337,7 +31448,7 @@ const logoutCommand = new Command("logout").description("Logout from current dev
31337
31448
  //#endregion
31338
31449
  //#region src/cli/commands/entities/push.ts
31339
31450
  async function pushEntitiesAction() {
31340
- const { entities } = await readProjectConfig();
31451
+ const { entities } = await readProjectConfig$1();
31341
31452
  if (entities.length === 0) return { outroMessage: "No entities found in project" };
31342
31453
  M.info(`Found ${entities.length} entities to push`);
31343
31454
  const result = await runTask("Pushing entities to Base44", async () => {
@@ -31355,10 +31466,56 @@ const entitiesPushCommand = new Command("entities").description("Manage project
31355
31466
  await runCommand(pushEntitiesAction, { requireAuth: true });
31356
31467
  }));
31357
31468
 
31469
+ //#endregion
31470
+ //#region src/cli/commands/agents/pull.ts
31471
+ async function pullAgentsAction() {
31472
+ const { project } = await readProjectConfig();
31473
+ const agentsDir = join(dirname(project.configPath), project.agentsDir);
31474
+ const response = await runTask("Fetching agents from Base44", async () => {
31475
+ return await fetchAgents();
31476
+ }, {
31477
+ successMessage: "Agents fetched successfully",
31478
+ errorMessage: "Failed to fetch agents"
31479
+ });
31480
+ if (response.items.length === 0) return { outroMessage: "No agents found on Base44" };
31481
+ const { written, deleted } = await runTask("Writing agent files", async () => {
31482
+ return await writeAgents(agentsDir, response.items);
31483
+ }, {
31484
+ successMessage: "Agent files written successfully",
31485
+ errorMessage: "Failed to write agent files"
31486
+ });
31487
+ if (written.length > 0) M.success(`Written: ${written.join(", ")}`);
31488
+ if (deleted.length > 0) M.warn(`Deleted: ${deleted.join(", ")}`);
31489
+ return { outroMessage: `Pulled ${response.total} agents to ${agentsDir}` };
31490
+ }
31491
+ const agentsPullCommand = new Command("pull").description("Pull agents from Base44 to local files (replaces all local agent configs)").action(async () => {
31492
+ await runCommand(pullAgentsAction, { requireAuth: true });
31493
+ });
31494
+
31495
+ //#endregion
31496
+ //#region src/cli/commands/agents/push.ts
31497
+ async function pushAgentsAction() {
31498
+ const { agents } = await readProjectConfig();
31499
+ M.info(agents.length === 0 ? "No local agents found - this will delete all remote agents" : `Found ${agents.length} agents to push`);
31500
+ const result = await runTask("Pushing agents to Base44", async () => {
31501
+ return await pushAgents(agents);
31502
+ }, {
31503
+ successMessage: "Agents pushed successfully",
31504
+ errorMessage: "Failed to push agents"
31505
+ });
31506
+ if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31507
+ if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31508
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31509
+ return {};
31510
+ }
31511
+ const agentsCommand = new Command("agents").description("Manage project agents").addCommand(new Command("push").description("Push local agents to Base44 (replaces all remote agent configs)").action(async () => {
31512
+ await runCommand(pushAgentsAction, { requireAuth: true });
31513
+ })).addCommand(agentsPullCommand);
31514
+
31358
31515
  //#endregion
31359
31516
  //#region src/cli/commands/functions/deploy.ts
31360
31517
  async function deployFunctionsAction() {
31361
- const { functions } = await readProjectConfig();
31518
+ const { functions } = await readProjectConfig$1();
31362
31519
  if (functions.length === 0) return { outroMessage: "No functions found. Create functions in the 'functions' directory." };
31363
31520
  M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31364
31521
  const result = await runTask("Deploying functions to Base44", async () => {
@@ -38139,7 +38296,7 @@ async function executeCreate({ template, name: rawName, description, projectPath
38139
38296
  id: projectId,
38140
38297
  projectRoot: resolvedPath
38141
38298
  });
38142
- const { project, entities } = await readProjectConfig(resolvedPath);
38299
+ const { project, entities } = await readProjectConfig$1(resolvedPath);
38143
38300
  let finalAppUrl;
38144
38301
  if (entities.length > 0) {
38145
38302
  let shouldPushEntities;
@@ -38762,7 +38919,7 @@ const dashboardCommand = new Command("dashboard").description("Open the app dash
38762
38919
  //#endregion
38763
38920
  //#region src/cli/commands/project/deploy.ts
38764
38921
  async function deployAction$1(options) {
38765
- const projectData = await readProjectConfig();
38922
+ const projectData = await readProjectConfig$1();
38766
38923
  if (!hasResourcesToDeploy(projectData)) return { outroMessage: "No resources found to deploy" };
38767
38924
  const { project, entities, functions } = projectData;
38768
38925
  const summaryLines = [];
@@ -38911,7 +39068,7 @@ const linkCommand = new Command("link").description("Link a local project to a B
38911
39068
  //#endregion
38912
39069
  //#region src/cli/commands/site/deploy.ts
38913
39070
  async function deployAction(options) {
38914
- const { project } = await readProjectConfig();
39071
+ const { project } = await readProjectConfig$1();
38915
39072
  if (!project.site?.outputDirectory) throw new Error("No site configuration found. Please add 'site.outputDirectory' to your config.jsonc");
38916
39073
  const outputDir = resolve(project.root, project.site.outputDirectory);
38917
39074
  if (!options.yes) {
@@ -38931,7 +39088,7 @@ const siteDeployCommand = new Command("site").description("Manage site deploymen
38931
39088
 
38932
39089
  //#endregion
38933
39090
  //#region package.json
38934
- var version = "0.0.19";
39091
+ var version = "0.0.21";
38935
39092
 
38936
39093
  //#endregion
38937
39094
  //#region src/cli/program.ts
@@ -38946,6 +39103,7 @@ program.addCommand(dashboardCommand);
38946
39103
  program.addCommand(deployCommand);
38947
39104
  program.addCommand(linkCommand);
38948
39105
  program.addCommand(entitiesPushCommand);
39106
+ program.addCommand(agentsCommand);
38949
39107
  program.addCommand(functionsDeployCommand);
38950
39108
  program.addCommand(siteDeployCommand);
38951
39109
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.19-pr.124.a7f34a6",
3
+ "version": "0.0.21-pr.112.b9c226a",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "bin": {