@nestbox-ai/cli 1.0.38 → 1.0.39

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 (35) hide show
  1. package/.github/workflows/test.yml +54 -0
  2. package/dist/commands/agent/apiUtils.d.ts +20 -0
  3. package/dist/commands/agent/apiUtils.js +75 -2
  4. package/dist/commands/agent/apiUtils.js.map +1 -1
  5. package/dist/commands/agent/create.d.ts +2 -29
  6. package/dist/commands/agent/create.js +123 -61
  7. package/dist/commands/agent/create.js.map +1 -1
  8. package/dist/commands/agent/deploy.js +183 -137
  9. package/dist/commands/agent/deploy.js.map +1 -1
  10. package/dist/commands/agent/index.d.ts +1 -2
  11. package/dist/commands/agent/index.js +3 -6
  12. package/dist/commands/agent/index.js.map +1 -1
  13. package/dist/commands/agent/yaml-schema.d.ts +72 -0
  14. package/dist/commands/agent/yaml-schema.js +61 -0
  15. package/dist/commands/agent/yaml-schema.js.map +1 -0
  16. package/dist/commands/agent.js +2 -2
  17. package/dist/commands/agent.js.map +1 -1
  18. package/dist/commands/generate/project.js +32 -28
  19. package/dist/commands/generate/project.js.map +1 -1
  20. package/dist/utils/agent.js +18 -20
  21. package/dist/utils/agent.js.map +1 -1
  22. package/package.json +3 -2
  23. package/src/commands/agent/apiUtils.ts +103 -14
  24. package/src/commands/agent/create.ts +266 -100
  25. package/src/commands/agent/deploy.ts +515 -264
  26. package/src/commands/agent/index.ts +1 -4
  27. package/src/commands/agent/yaml-schema.ts +57 -0
  28. package/src/commands/agent.ts +10 -10
  29. package/src/commands/generate/project.ts +179 -147
  30. package/src/utils/agent.ts +141 -125
  31. package/test/agent.test.ts +153 -124
  32. package/dist/commands/agent/createFromYaml.d.ts +0 -2
  33. package/dist/commands/agent/createFromYaml.js +0 -172
  34. package/dist/commands/agent/createFromYaml.js.map +0 -1
  35. package/src/commands/agent/createFromYaml.ts +0 -192
@@ -1,272 +1,523 @@
1
1
  import { Command } from "commander";
2
- import { withTokenRefresh } from "../../utils/error";
3
2
  import chalk from "chalk";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { getAuthToken } from "../../utils/auth";
6
+ import { withTokenRefresh } from "../../utils/error";
4
7
  import ora from "ora";
5
8
  import { resolveProject } from "../../utils/project";
6
- import fs from "fs";
7
9
  import {
8
- createZipFromDirectory,
9
- findProjectRoot,
10
- isTypeScriptProject,
11
- loadNestboxConfig,
12
- runPredeployScripts,
10
+ createZipFromDirectory,
11
+ isTypeScriptProject,
12
+ loadNestboxConfig,
13
+ runPredeployScripts,
13
14
  } from "../../utils/agent";
14
15
  import axios from "axios";
15
- import { AgentType } from "../../types/agentType";
16
- import path from "path";
17
- import { getAuthToken } from "../../utils/auth";
18
- import { createApis } from "./apiUtils";
19
-
20
- export function registerDeployCommand(agentCommand: Command): void {
21
- agentCommand
22
- .command("deploy")
23
- .description("Deploy an AI agent to the Nestbox platform")
24
- .option("--agent <agentName>", "Agent name to deploy")
25
- .option("--chatbot <chatbotName>", "Chatbot name to deploy")
26
- .requiredOption("--instance <instanceName>", "Instance name")
27
- .option(
28
- "--zip <zipFileOrDirPath>",
29
- "Path to the zip file or directory to upload"
30
- )
31
- .option(
32
- "--project <projectName>",
33
- "Project name (defaults to the current project)"
34
- )
35
- .option("--entry <entryFunction>", "Entry function name")
36
- .option("--log", "Show detailed logs during deployment")
37
- .action(async (options) => {
38
- try {
39
- const {
40
- agent: agentName,
41
- chatbot: chatbotName,
42
- instance: instanceName,
43
- zip: customZipPath,
44
- entry,
45
- log,
46
- } = options;
47
-
48
- // Ensure either agent or chatbot is provided, but not both
49
- if ((!agentName && !chatbotName) || (agentName && chatbotName)) {
50
- console.error(
51
- chalk.red("Please provide either --agent OR --chatbot option, but not both.")
52
- );
53
- return;
54
- }
55
-
56
- let apis = createApis();
57
-
58
- // Find project root
59
- const projectRoot = await findProjectRoot();
60
- console.log(chalk.blue(`Project root detected at: ${projectRoot}`));
61
-
62
- // Main deployment logic with token refresh
63
- await withTokenRefresh(
64
- async () => {
65
- // Resolve project
66
- const projectData = await resolveProject(apis.projectsApi, options);
67
-
68
- // Determine if we're deploying an agent or chatbot
69
- const isAgent = !!agentName;
70
- const resourceName = isAgent ? agentName : chatbotName;
71
- const resourceType = isAgent ? "Agent" : "Chatbot";
72
- const agentType = isAgent ? AgentType.REGULAR : "CHAT";
73
-
74
- // Get agents data and find agent/chatbot by name
75
- const agentsData: any = await apis.agentsApi.machineAgentControllerGetMachineAgentByProjectId(
76
- projectData.id,
77
- 0,
78
- 10,
79
- agentType
80
- );
81
-
82
- const targetAgent = agentsData.data.machineAgents.find(
83
- (agent: any) => agent.agentName === resourceName
84
- );
85
-
86
- if (!targetAgent) {
87
- console.error(
88
- chalk.red(`${resourceType} with name "${resourceName}" not found in project "${projectData.name}".`)
89
- );
90
- console.log(chalk.yellow(`Available ${resourceType.toLowerCase()}s:`));
91
- agentsData.data.machineAgents.forEach((agent: any) => {
92
- console.log(chalk.yellow(` - ${agent.agentName} (ID: ${agent.id})`));
93
- });
94
- return;
95
- }
96
-
97
- // Get instance data and find instance by name
98
- const instanceData: any = await apis.instanceApi.machineInstancesControllerGetMachineInstanceByUserId(
99
- projectData.id,
100
- 0,
101
- 10
102
- );
103
-
104
- const targetInstance = instanceData.data.machineInstances.find(
105
- (instance: any) => instance.instanceName === instanceName
106
- );
107
-
108
- if (!targetInstance) {
109
- console.error(
110
- chalk.red(`Instance with name "${instanceName}" not found in project "${projectData.name}".`)
111
- );
112
- console.log(chalk.yellow("Available instances:"));
113
- instanceData.data.machineInstances.forEach((instance: any) => {
114
- console.log(chalk.yellow(` - ${instance.instanceName} (ID: ${instance.id})`));
115
- });
116
- return;
117
- }
118
-
119
- // Extract IDs
120
- const agentId = targetAgent.id;
121
- const resolvedEntry = entry || targetAgent.entryFunctionName || "main";
122
- const instanceId = targetInstance.id;
123
-
124
- // Load nestbox.config.json
125
- const config = loadNestboxConfig(projectRoot);
126
-
127
- // Start the deployment process
128
- const spinner = ora(
129
- `Preparing to deploy ${resourceType.toLowerCase()} ${agentId} to instance ${instanceId}...`
130
- ).start();
131
-
132
- try {
133
- let zipFilePath;
134
-
135
- if (customZipPath) {
136
- // Process custom zip path
137
- if (!fs.existsSync(customZipPath)) {
138
- spinner.fail(`Path not found: ${customZipPath}`);
139
- return;
140
- }
141
-
142
- const stats = fs.statSync(customZipPath);
143
-
144
- if (stats.isFile()) {
145
- if (!customZipPath.toLowerCase().endsWith(".zip")) {
146
- spinner.fail(`File is not a zip archive: ${customZipPath}`);
147
- return;
148
- }
149
- spinner.text = `Using provided zip file: ${customZipPath}`;
150
- zipFilePath = customZipPath;
151
- } else if (stats.isDirectory()) {
152
- // Process directory
153
- spinner.text = `Processing directory: ${customZipPath}`;
154
-
155
- const isTypeScript = isTypeScriptProject(customZipPath);
156
-
157
- if (isTypeScript && (config?.agent?.predeploy || config?.agents?.predeploy)) {
158
- const predeployScripts = config?.agent?.predeploy || config?.agents?.predeploy;
159
- spinner.text = `Running predeploy scripts on target directory...`;
160
- await runPredeployScripts(predeployScripts, customZipPath);
161
- }
162
-
163
- spinner.text = `Creating zip archive from directory ${customZipPath}...`;
164
- zipFilePath = createZipFromDirectory(customZipPath);
165
- spinner.text = `Directory zipped successfully to ${zipFilePath}`;
166
- }
167
- } else {
168
- // Use project root
169
- spinner.text = `Using project root: ${projectRoot}`;
170
-
171
- const isTypeScript = isTypeScriptProject(projectRoot);
172
-
173
- if (isTypeScript && (config?.agent?.predeploy || config?.agents?.predeploy)) {
174
- const predeployScripts = config?.agent?.predeploy || config?.agents?.predeploy;
175
- spinner.text = `Running predeploy scripts on project root...`;
176
- await runPredeployScripts(predeployScripts, projectRoot);
177
- }
178
-
179
- spinner.text = `Creating zip archive from project root ${projectRoot}...`;
180
- zipFilePath = createZipFromDirectory(projectRoot);
181
- spinner.text = `Directory zipped successfully to ${zipFilePath}`;
182
- }
183
-
184
- spinner.text = `Deploying ${resourceType.toLowerCase()} ${agentId} to instance ${instanceId}...`;
185
-
186
- // Prepare deployment
187
- const authToken = getAuthToken();
188
- const baseUrl = authToken?.serverUrl?.endsWith("/")
189
- ? authToken.serverUrl.slice(0, -1)
190
- : authToken?.serverUrl;
191
-
192
- const { default: FormData } = await import("form-data");
193
- const form = new FormData();
194
-
195
- form.append("file", fs.createReadStream(zipFilePath));
196
- form.append("machineAgentId", agentId.toString());
197
- form.append("instanceId", instanceId.toString());
198
- form.append("entryFunctionName", resolvedEntry);
199
- form.append("isSourceCodeUpdate", "true");
200
- form.append("projectId", projectData.id);
201
-
202
- if (log) {
203
- console.log(chalk.blue("Form Details "));
204
- console.log(chalk.blue(` - File: ${path.basename(zipFilePath)}`));
205
- console.log(chalk.blue(` - Agent ID: ${agentId}`));
206
- console.log(chalk.blue(` - Instance ID: ${instanceId}`));
207
- console.log(chalk.blue(` - Entry Function: ${resolvedEntry}`));
208
- console.log(chalk.blue(` - Project ID: ${projectData.id}`));
209
- }
210
-
211
- const axiosInstance = axios.create({
212
- baseURL: baseUrl,
213
- headers: {
214
- ...form.getHeaders(),
215
- Authorization: authToken?.token,
216
- },
217
- });
218
-
219
- const endpoint = `/projects/${projectData.id}/agents/${agentId}`;
220
-
221
- spinner.text = `Deploy ${resourceType.toLowerCase()} ${agentName}...`;
222
- const res = await axiosInstance.patch(endpoint, form);
223
-
224
- if (!customZipPath && zipFilePath && fs.existsSync(zipFilePath)) {
225
- fs.unlinkSync(zipFilePath);
226
- }
227
-
228
- if (log) {
229
- console.log(chalk.blue("\nDeployment request:"));
230
- console.log(chalk.blue(` URL: ${baseUrl}${endpoint}`));
231
- console.log(chalk.blue(` Method: PATCH`));
232
- console.log(chalk.blue(` File: ${path.basename(zipFilePath)}`));
233
- console.log(chalk.blue(` Response status: ${res.status} ${res.statusText}`));
234
- const lines = res.data.logEntries || [];
235
- console.log(chalk.blue(` Deployment log entries (${lines.length} lines):`));
236
- lines.forEach((line: any) => {
237
- console.log(chalk.blue(` - [${line.type} ${line.timestamp}] ${line.message} `));
238
- });
239
- }
240
- spinner.succeed("Successfully deployed");
241
- console.log(chalk.green(`${resourceType} deployed successfully!`));
242
- console.log(chalk.cyan(`📍 Instance: ${instanceName}`));
243
- console.log(chalk.cyan(`🤖 Agent: ${agentName} (${agentId})`));
244
- console.log(chalk.cyan(`⚙️ Entry: ${resolvedEntry}`));
245
- console.log(chalk.cyan(`🔄 Process: ${res.data.processName}`));
246
- } catch (error: any) {
247
- spinner.fail(`Failed to deploy ${resourceType.toLowerCase()}`);
248
- throw error;
249
- }
250
- },
251
- () => {
252
- apis = createApis();
253
- }
254
- );
255
- } catch (error: any) {
256
- if (error.message && error.message.includes('Authentication')) {
257
- console.error(chalk.red(error.message));
258
- } else if (error.response) {
259
- console.error(
260
- chalk.red(
261
- `API Error (${error.response.status}): ${error.response.data?.message || "Unknown error"}`
262
- )
263
- );
264
- if (error.response.data) {
265
- console.error(chalk.red(`Error Data: ${JSON.stringify(error.response.data, null, 2)}`));
266
- }
267
- } else {
268
- console.error(chalk.red("Error:"), error.message || "Unknown error");
269
- }
270
- }
271
- });
16
+ import {
17
+ createApis,
18
+ loadAgentFromYaml,
19
+ loadAllAgentNamesFromYaml,
20
+ } from "./apiUtils";
21
+ import inquirer from "inquirer";
22
+
23
+ type ManifestAgent = {
24
+ name: string;
25
+ goal: string;
26
+ entry: string;
27
+ inputSchema: any;
28
+ type: string;
29
+ };
30
+
31
+ type CreateAgentOptions = {
32
+ type?: string;
33
+ goal?: string;
34
+ inputSchema?: any;
35
+ machineManifestId?: string;
36
+ project?: string;
37
+ instance?: string;
38
+ machineInstanceId?: number;
39
+ instanceIP?: string;
40
+ entryFunctionName?: string;
41
+ modelBaseId?: string;
42
+ prefix?: string;
43
+ };
44
+
45
+ type DeployAgentOptions = {
46
+ agent: string; // agent name
47
+ description?: string;
48
+ inputSchema?: any;
49
+ instance: string;
50
+ project?: string;
51
+ type?: string;
52
+ prefix?: string;
53
+ all?: boolean;
54
+ entryFunction: string;
55
+ log?: boolean;
56
+ silent?: boolean;
57
+ };
58
+
59
+ type AgentCreateData = {
60
+ type: string;
61
+ agentName: string;
62
+ goal: string;
63
+ inputSchema: any;
64
+ machineManifestId: string;
65
+ projectId: string;
66
+ machineName: string;
67
+ machineInstanceId: number;
68
+ instanceIP: string;
69
+ userId: number;
70
+ entryFunctionName: string;
71
+ modelBaseId: string;
72
+ parameters: [{}];
73
+ };
74
+
75
+ type ConfigData = {
76
+ instance?: string;
77
+ };
78
+
79
+ type MachineInstanceData = {
80
+ machineId?: string;
81
+ id?: number;
82
+ internalIP?: string;
83
+ };
84
+
85
+ async function buildAgentData(
86
+ options: DeployAgentOptions,
87
+ machineInstanceData: MachineInstanceData = {}
88
+ ): Promise<AgentCreateData> {
89
+ const deployAgentData = {
90
+ agentName: "",
91
+ goal: "",
92
+ inputSchema: {},
93
+
94
+ machineManifestId: machineInstanceData.machineId,
95
+ machineName: options.instance,
96
+ machineInstanceId: machineInstanceData.id,
97
+ instanceIP: machineInstanceData.internalIP,
98
+
99
+ projectId: options.project,
100
+ type: options?.type || "REGULAR",
101
+ userId: 0,
102
+ modelBaseId: "",
103
+ entryFunctionName: "",
104
+ };
105
+
106
+ if (!options.agent) {
107
+ throw new Error("Missing required argument <agent>.");
108
+ }
109
+ deployAgentData.agentName = options.prefix
110
+ ? options.prefix + "-" + options.agent
111
+ : options.agent;
112
+
113
+ if (options.description || options.inputSchema || options.entryFunction) {
114
+ if (!options.description) {
115
+ throw new Error("Missing required argument <description>.");
116
+ }
117
+ if (!options.inputSchema) {
118
+ throw new Error("Missing required argument <inputSchema>.");
119
+ }
120
+ if (!options.entryFunction) {
121
+ throw new Error("Missing required argument <entryFunction>.");
122
+ }
123
+ deployAgentData.goal = options.description;
124
+ deployAgentData.inputSchema = JSON.parse(options.inputSchema);
125
+ deployAgentData.entryFunctionName = options.entryFunction;
126
+ } else {
127
+ const manifestAgent = await loadAgentFromYaml(options.agent);
128
+
129
+ if (!manifestAgent) {
130
+ throw new Error(
131
+ "Could not find a yaml file definition of an agent or agent not defined in yaml file."
132
+ );
133
+ }
134
+
135
+ deployAgentData.entryFunctionName = manifestAgent.entry;
136
+ deployAgentData.goal = manifestAgent.description;
137
+ deployAgentData.inputSchema = manifestAgent.inputSchema || {};
138
+ deployAgentData.type = options.type || manifestAgent?.type || "REGULAR";
139
+ }
140
+
141
+ return deployAgentData as AgentCreateData;
142
+ }
143
+
144
+ export function registerDeployCommand(agentCommand: Command) {
145
+ agentCommand
146
+ .command("deploy")
147
+ .description("Deploy an AI agent to the Nestbox platform")
148
+ .option(
149
+ "--prefix <prefix>",
150
+ "A prefix added to beginning of the agent name."
151
+ )
152
+ .option("--agent <agent>", "Agent name to deploy")
153
+ .option("--description <description>", "Goal/description of the agent")
154
+ .option("--inputSchema <inputSchema>", "Agent input schema")
155
+ .option(
156
+ "--project <project>",
157
+ "Project ID (defaults to current project)"
158
+ )
159
+ .option("--type <type>", "Agent type (e.g. CHAT, AGENT, REGULAR)")
160
+ .option("--entryFunction <entryFunction>", "Entry function name")
161
+ .option("--instance <instance>", "Machine name")
162
+ .option("--log", "Show detailed logs during deployment")
163
+ .option("--silent", "Disable automatic agent creation.")
164
+ .option("--all", "Deploy all agents defined in nestbox-agents.yaml")
165
+ .action(async (options): Promise<any> => {
166
+ try {
167
+ let apis = createApis();
168
+
169
+ await withTokenRefresh(
170
+ async () => {
171
+ let names: string[] = [];
172
+ if (options.all) {
173
+ names = await loadAllAgentNamesFromYaml();
174
+ if (!names.length) {
175
+ console.log(
176
+ chalk.yellow(
177
+ "No agents found in YAML manifest."
178
+ )
179
+ );
180
+ return;
181
+ }
182
+ } else {
183
+ if (!options?.agent) {
184
+ console.log(
185
+ chalk.red("Parameter <agent> not provided.")
186
+ );
187
+ return;
188
+ }
189
+ names = [options.agent];
190
+ }
191
+
192
+ const projectData = await resolveProject(
193
+ apis.projectsApi,
194
+ {
195
+ project: options.project,
196
+ instance: "",
197
+ ...options,
198
+ }
199
+ );
200
+
201
+ const projectRoot = process.cwd();
202
+ const config = loadNestboxConfig(projectRoot);
203
+
204
+ if (!options?.instance && !config?.instance) {
205
+ console.log(
206
+ chalk.red("Parameter <instance> not provided.")
207
+ );
208
+ return;
209
+ }
210
+
211
+ const machineName = options.instance || config.instance;
212
+
213
+ const instanceData: any =
214
+ await apis.instanceApi.machineInstancesControllerGetMachineInstanceByUserId(
215
+ projectData.id,
216
+ 0,
217
+ 10
218
+ );
219
+
220
+ const targetInstance =
221
+ instanceData.data.machineInstances.find(
222
+ (instance: any) =>
223
+ instance.instanceName === machineName
224
+ );
225
+
226
+ if (!targetInstance) {
227
+ console.error(
228
+ chalk.red(
229
+ `Instance with name "${machineName}" not found in project "${projectData.name}".`
230
+ )
231
+ );
232
+ console.log(chalk.yellow("Available instances:"));
233
+ instanceData.data.machineInstances.forEach(
234
+ (instance: any) => {
235
+ console.log(
236
+ chalk.yellow(
237
+ ` - ${instance.instanceName} (ID: ${instance.id})`
238
+ )
239
+ );
240
+ }
241
+ );
242
+ return;
243
+ }
244
+
245
+ for (const name of names) {
246
+ const data = await buildAgentData(
247
+ {
248
+ ...options,
249
+ project: projectData.id,
250
+ instance: machineName,
251
+ agent: name,
252
+ },
253
+ targetInstance
254
+ );
255
+
256
+ const agentsData: any =
257
+ await apis.agentsApi.machineAgentControllerGetMachineAgentByProjectId(
258
+ projectData.id,
259
+ 0,
260
+ 10,
261
+ data.type
262
+ );
263
+
264
+ let targetAgent =
265
+ agentsData.data.machineAgents.find(
266
+ (agent: any) =>
267
+ agent.agentName === data.agentName
268
+ );
269
+
270
+ if (!targetAgent && !options.silent) {
271
+ const { confirmCreation } =
272
+ await inquirer.prompt([
273
+ {
274
+ type: "confirm",
275
+ name: "confirmCreation",
276
+ message: chalk.red(
277
+ `No agent with specified name "${data.agentName}" found. Would you like to create one first before deployment?`
278
+ ),
279
+ default: false,
280
+ },
281
+ ]);
282
+
283
+ if (!confirmCreation) {
284
+ continue;
285
+ }
286
+ }
287
+
288
+ if (!targetAgent) {
289
+ const response =
290
+ await apis.agentsApi.machineAgentControllerCreateMachineAgent(
291
+ projectData.id,
292
+ { ...data }
293
+ );
294
+
295
+ targetAgent = response.data;
296
+
297
+ console.log(
298
+ chalk.green(
299
+ `Created agent ${data.agentName} before deploying.`
300
+ )
301
+ );
302
+ }
303
+
304
+ const agentId = targetAgent.id;
305
+ const resolvedEntry =
306
+ data.entryFunctionName ||
307
+ targetAgent.entryFunctionName ||
308
+ "main";
309
+ const instanceId = targetInstance.id;
310
+
311
+ const spinner = ora(
312
+ `Preparing to deploy ${data.agentName.toLowerCase()} ${agentId} to instance ${instanceId}...`
313
+ ).start();
314
+
315
+ try {
316
+ let zipFilePath;
317
+
318
+ spinner.text = `Using project root: ${projectRoot}`;
319
+
320
+ const isTypeScript =
321
+ isTypeScriptProject(projectRoot);
322
+
323
+ if (
324
+ isTypeScript &&
325
+ (config?.agent?.predeploy ||
326
+ config?.agents?.predeploy)
327
+ ) {
328
+ const predeployScripts =
329
+ config?.agent?.predeploy ||
330
+ config?.agents?.predeploy;
331
+ spinner.text = `Running predeploy scripts on project root...`;
332
+ await runPredeployScripts(
333
+ predeployScripts,
334
+ projectRoot
335
+ );
336
+ }
337
+
338
+ spinner.text = `Creating zip archive from project root ${projectRoot}...`;
339
+ zipFilePath =
340
+ createZipFromDirectory(projectRoot);
341
+ spinner.text = `Directory zipped successfully to ${zipFilePath}`;
342
+
343
+ spinner.text = `Deploying ${data.agentName.toLowerCase()} ${agentId} to instance ${instanceId}...`;
344
+
345
+ const authToken = getAuthToken();
346
+ const baseUrl = authToken?.serverUrl?.endsWith(
347
+ "/"
348
+ )
349
+ ? authToken.serverUrl.slice(0, -1)
350
+ : authToken?.serverUrl;
351
+
352
+ const { default: FormData } = await import(
353
+ "form-data"
354
+ );
355
+ const form = new FormData();
356
+
357
+ form.append(
358
+ "file",
359
+ fs.createReadStream(zipFilePath)
360
+ );
361
+ form.append(
362
+ "machineAgentId",
363
+ agentId.toString()
364
+ );
365
+ form.append(
366
+ "instanceId",
367
+ instanceId.toString()
368
+ );
369
+ form.append("entryFunctionName", resolvedEntry);
370
+ form.append("isSourceCodeUpdate", "true");
371
+ form.append("projectId", projectData.id);
372
+
373
+ if (options.log) {
374
+ console.log(chalk.blue("Form Details "));
375
+ console.log(
376
+ chalk.blue(
377
+ ` - File: ${path.basename(zipFilePath)}`
378
+ )
379
+ );
380
+ console.log(
381
+ chalk.blue(` - Agent ID: ${agentId}`)
382
+ );
383
+ console.log(
384
+ chalk.blue(
385
+ ` - Instance ID: ${instanceId}`
386
+ )
387
+ );
388
+ console.log(
389
+ chalk.blue(
390
+ ` - Entry Function: ${resolvedEntry}`
391
+ )
392
+ );
393
+ console.log(
394
+ chalk.blue(
395
+ ` - Project ID: ${projectData.id}`
396
+ )
397
+ );
398
+ }
399
+
400
+ const axiosInstance = axios.create({
401
+ baseURL: baseUrl,
402
+ headers: {
403
+ ...form.getHeaders(),
404
+ Authorization: authToken?.token,
405
+ },
406
+ });
407
+
408
+ const endpoint = `/projects/${projectData.id}/agents/${agentId}`;
409
+
410
+ spinner.text = `Deploy ${name}...`;
411
+ const res = await axiosInstance.patch(
412
+ endpoint,
413
+ form
414
+ );
415
+
416
+ await axios.patch(
417
+ baseUrl + endpoint,
418
+ {
419
+ projectId: data.projectId,
420
+ id: agentId,
421
+ agentName: data.agentName,
422
+ goal: data.goal,
423
+ inputSchema: data.inputSchema,
424
+ },
425
+ {
426
+ headers: {
427
+ Authorization: authToken?.token,
428
+ },
429
+ }
430
+ );
431
+
432
+ if (options.log) {
433
+ console.log(
434
+ chalk.blue("\nDeployment request:")
435
+ );
436
+ console.log(
437
+ chalk.blue(
438
+ ` URL: ${baseUrl}${endpoint}`
439
+ )
440
+ );
441
+ console.log(chalk.blue(` Method: PATCH`));
442
+ console.log(
443
+ chalk.blue(
444
+ ` File: ${path.basename(zipFilePath)}`
445
+ )
446
+ );
447
+ console.log(
448
+ chalk.blue(
449
+ ` Response status: ${res.status} ${res.statusText}`
450
+ )
451
+ );
452
+ const lines = res.data.logEntries || [];
453
+ console.log(
454
+ chalk.blue(
455
+ ` Deployment log entries (${lines.length} lines):`
456
+ )
457
+ );
458
+ lines.forEach((line: any) => {
459
+ console.log(
460
+ chalk.blue(
461
+ ` - [${line.type} ${line.timestamp}] ${line.message} `
462
+ )
463
+ );
464
+ });
465
+ }
466
+ spinner.succeed("Successfully deployed");
467
+ console.log(
468
+ chalk.green(
469
+ `${data.agentName} deployed successfully!`
470
+ )
471
+ );
472
+ console.log(
473
+ chalk.cyan(
474
+ `📍 Instance: ${data.machineName}`
475
+ )
476
+ );
477
+ console.log(
478
+ chalk.cyan(`🤖 Agent: ${name} (${agentId})`)
479
+ );
480
+ console.log(
481
+ chalk.cyan(`⚙️ Entry: ${resolvedEntry}`)
482
+ );
483
+ console.log(
484
+ chalk.cyan(
485
+ `🔄 Process: ${res.data.processName}`
486
+ )
487
+ );
488
+ } catch (error: any) {
489
+ spinner.fail(
490
+ `Failed to deploy ${data.agentName.toLowerCase()}`
491
+ );
492
+ }
493
+ }
494
+ },
495
+ () => {
496
+ apis = createApis();
497
+ }
498
+ );
499
+ } catch (error: any) {
500
+ if (error.message && error.message.includes("Authentication")) {
501
+ console.error(chalk.red(error.message));
502
+ } else if (error.response) {
503
+ console.error(
504
+ chalk.red(
505
+ `API Error (${error.response.status}): ${error.response.data?.message || "Unknown error"}`
506
+ )
507
+ );
508
+ if (error.response.data) {
509
+ console.error(
510
+ chalk.red(
511
+ `Error Data: ${JSON.stringify(error.response.data, null, 2)}`
512
+ )
513
+ );
514
+ }
515
+ } else {
516
+ console.error(
517
+ chalk.red("Error:"),
518
+ error.message || "Unknown error"
519
+ );
520
+ }
521
+ }
522
+ });
272
523
  }