@nestbox-ai/cli 1.0.23 → 1.0.25

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 (61) hide show
  1. package/dist/commands/agent/apiUtils.d.ts +10 -0
  2. package/dist/commands/agent/apiUtils.js +20 -0
  3. package/dist/commands/agent/apiUtils.js.map +1 -0
  4. package/dist/commands/agent/create.d.ts +29 -0
  5. package/dist/commands/agent/create.js +88 -0
  6. package/dist/commands/agent/create.js.map +1 -0
  7. package/dist/commands/agent/createFromYaml.d.ts +2 -0
  8. package/dist/commands/agent/createFromYaml.js +172 -0
  9. package/dist/commands/agent/createFromYaml.js.map +1 -0
  10. package/dist/commands/agent/deploy.d.ts +2 -0
  11. package/dist/commands/agent/deploy.js +243 -0
  12. package/dist/commands/agent/deploy.js.map +1 -0
  13. package/dist/commands/agent/generate.d.ts +2 -0
  14. package/dist/commands/agent/generate.js +141 -0
  15. package/dist/commands/agent/generate.js.map +1 -0
  16. package/dist/commands/agent/index.d.ts +7 -0
  17. package/dist/commands/agent/index.js +21 -0
  18. package/dist/commands/agent/index.js.map +1 -0
  19. package/dist/commands/agent/list.d.ts +2 -0
  20. package/dist/commands/agent/list.js +94 -0
  21. package/dist/commands/agent/list.js.map +1 -0
  22. package/dist/commands/agent/remove.d.ts +2 -0
  23. package/dist/commands/agent/remove.js +85 -0
  24. package/dist/commands/agent/remove.js.map +1 -0
  25. package/dist/commands/agent.d.ts +4 -0
  26. package/dist/commands/agent.js +16 -731
  27. package/dist/commands/agent.js.map +1 -1
  28. package/dist/commands/compute/apiUtils.d.ts +11 -0
  29. package/dist/commands/compute/apiUtils.js +22 -0
  30. package/dist/commands/compute/apiUtils.js.map +1 -0
  31. package/dist/commands/compute/create.d.ts +2 -0
  32. package/dist/commands/compute/create.js +183 -0
  33. package/dist/commands/compute/create.js.map +1 -0
  34. package/dist/commands/compute/delete.d.ts +2 -0
  35. package/dist/commands/compute/delete.js +145 -0
  36. package/dist/commands/compute/delete.js.map +1 -0
  37. package/dist/commands/compute/index.d.ts +4 -0
  38. package/dist/commands/compute/index.js +14 -0
  39. package/dist/commands/compute/index.js.map +1 -0
  40. package/dist/commands/compute/list.d.ts +2 -0
  41. package/dist/commands/compute/list.js +128 -0
  42. package/dist/commands/compute/list.js.map +1 -0
  43. package/dist/commands/compute.d.ts +3 -0
  44. package/dist/commands/compute.js +10 -400
  45. package/dist/commands/compute.js.map +1 -1
  46. package/package.json +1 -1
  47. package/src/commands/agent/apiUtils.ts +24 -0
  48. package/src/commands/agent/create.ts +105 -0
  49. package/src/commands/agent/createFromYaml.ts +192 -0
  50. package/src/commands/agent/deploy.ts +272 -0
  51. package/src/commands/agent/generate.ts +151 -0
  52. package/src/commands/agent/index.ts +12 -0
  53. package/src/commands/agent/list.ts +104 -0
  54. package/src/commands/agent/remove.ts +103 -0
  55. package/src/commands/agent.ts +15 -909
  56. package/src/commands/compute/apiUtils.ts +28 -0
  57. package/src/commands/compute/create.ts +195 -0
  58. package/src/commands/compute/delete.ts +147 -0
  59. package/src/commands/compute/index.ts +7 -0
  60. package/src/commands/compute/list.ts +125 -0
  61. package/src/commands/compute.ts +16 -449
@@ -0,0 +1,192 @@
1
+ import { Command } from "commander";
2
+ import { withTokenRefresh } from "../../utils/error";
3
+ import chalk from "chalk";
4
+ import ora from "ora";
5
+ import Table from "cli-table3";
6
+ import fs from "fs";
7
+ import yaml from 'js-yaml';
8
+ import { AgentYamlConfig } from "../../types/agentYaml";
9
+ import { userData } from "../../utils/user";
10
+ import { createAgent } from "./create";
11
+ import { createApis } from "./apiUtils";
12
+
13
+ export function registerCreateFromYamlCommand(agentCommand: Command): void {
14
+ agentCommand
15
+ .command("create [firstArg] [secondArg]")
16
+ .description("Create multiple agents from a YAML configuration file")
17
+ .option("--project <projectId>", "Project ID (defaults to the current project)")
18
+ .action(async (firstArg: string, secondArg: any, options: any) => {
19
+ try {
20
+ let apis = createApis();
21
+
22
+ // Determine which argument is the YAML file path
23
+ let yamlFilePath: string;
24
+
25
+ if (firstArg === 'file' && secondArg) {
26
+ yamlFilePath = secondArg;
27
+ } else if (firstArg) {
28
+ yamlFilePath = firstArg;
29
+ if (typeof secondArg === 'object' && !options) {
30
+ options = secondArg;
31
+ }
32
+ } else {
33
+ console.error(chalk.red("Missing YAML file path. Usage: nestbox agent create <yamlFile> OR nestbox agent create file <yamlFile>"));
34
+ return;
35
+ }
36
+
37
+ // Check if file exists
38
+ if (!fs.existsSync(yamlFilePath)) {
39
+ console.error(chalk.red(`YAML file not found: ${yamlFilePath}`));
40
+ return;
41
+ }
42
+
43
+ // Read and parse the YAML file
44
+ const spinner = ora(`Reading agents configuration from ${yamlFilePath}...`).start();
45
+
46
+ try {
47
+ const fileContents = fs.readFileSync(yamlFilePath, 'utf8');
48
+ const config = yaml.load(fileContents) as AgentYamlConfig;
49
+
50
+ if (!config || !config.agents || !Array.isArray(config.agents)) {
51
+ spinner.fail("Invalid YAML configuration: Missing 'agents' array");
52
+ console.error(chalk.red("The YAML file should contain an 'agents' array with agent configurations"));
53
+ return;
54
+ }
55
+
56
+ spinner.succeed(`Found ${config.agents.length} agents in configuration file`);
57
+
58
+ // Process each agent with token refresh support
59
+ const results = {
60
+ success: 0,
61
+ failed: 0,
62
+ agents: [] as Array<{name: string; success: boolean; message: string}>
63
+ };
64
+
65
+ // Get user data once
66
+ const user = await userData();
67
+
68
+ for (const agent of config.agents) {
69
+ if (!agent.name) {
70
+ console.log(chalk.yellow("Skipping agent with no name defined"));
71
+ results.failed++;
72
+ results.agents.push({
73
+ name: "unnamed",
74
+ success: false,
75
+ message: "Name is required"
76
+ });
77
+ continue;
78
+ }
79
+
80
+ let agentType = agent.type || "CHAT";
81
+ const resourceType = agentType === "AGENT" ? "Agent" : "Chatbot";
82
+
83
+ const agentSpinner = ora(`Creating ${resourceType.toLowerCase()} '${agent.name}'...`).start();
84
+
85
+ try {
86
+ // Create agent with token refresh support
87
+ await withTokenRefresh(
88
+ async () => {
89
+ // Map YAML config to createAgent options
90
+ const createOptions = {
91
+ ...options,
92
+ goal: agent.goal || "No goal specified",
93
+ modelBaseId: agent.modelBaseId || "",
94
+ instanceIP: agent.instanceIP || "localhost",
95
+ machineInstanceId: agent.machineInstanceId || 1,
96
+ machineManifestId: agent.machineManifestId || "default",
97
+ machineName: agent.machineName || `agent-${agent.name.toLowerCase()}`,
98
+ type: agentType,
99
+ userId: user.id,
100
+ parameters: agent.parameters ? agent.parameters.map((p: any) => {
101
+ return {
102
+ name: p.name || "unnamed",
103
+ description: p.description || "",
104
+ default: p.default || "",
105
+ isUserParam: p.isUserParam !== undefined ? p.isUserParam : true
106
+ };
107
+ }) : []
108
+ };
109
+
110
+ await createAgent(agent.name, createOptions, apis.agentsApi, apis.projectsApi);
111
+ },
112
+ () => {
113
+ apis = createApis();
114
+ }
115
+ );
116
+
117
+ agentSpinner.stop();
118
+
119
+ results.success++;
120
+ results.agents.push({
121
+ name: agent.name,
122
+ success: true,
123
+ message: `Created successfully`
124
+ });
125
+ } catch (error: any) {
126
+ agentSpinner.fail(`Failed to create ${resourceType.toLowerCase()} '${agent.name}'`);
127
+ console.error(chalk.red(`Error: ${error.message}`));
128
+ results.failed++;
129
+ results.agents.push({
130
+ name: agent.name,
131
+ success: false,
132
+ message: error.message
133
+ });
134
+ }
135
+ }
136
+
137
+ // Final summary
138
+ console.log(chalk.blue("\nResource creation summary:"));
139
+ const table = new Table({
140
+ head: [
141
+ chalk.white.bold("Name"),
142
+ chalk.white.bold("Type"),
143
+ chalk.white.bold("Status"),
144
+ chalk.white.bold("Message"),
145
+ ],
146
+ style: {
147
+ head: [],
148
+ border: [],
149
+ },
150
+ });
151
+
152
+ results.agents.forEach((agent, index) => {
153
+ const agentConfig = config.agents.find(a => a.name === agent.name) || config.agents[index];
154
+ const agentType = agentConfig?.type || "CHAT";
155
+ const resourceType = agentType === "AGENT" ? "Agent" : "Chatbot";
156
+
157
+ table.push([
158
+ agent.name,
159
+ resourceType,
160
+ agent.success ? chalk.green("Success") : chalk.red("Failed"),
161
+ agent.message
162
+ ]);
163
+ });
164
+
165
+ console.log(table.toString());
166
+ console.log(`\nTotal: ${results.success + results.failed}, Successful: ${results.success}, Failed: ${results.failed}`);
167
+
168
+ } catch (error: any) {
169
+ spinner.fail("Failed to process YAML file");
170
+ if (error.code === 'ENOENT') {
171
+ console.error(chalk.red(`File not found: ${yamlFilePath}`));
172
+ } else if (error.name === 'YAMLException') {
173
+ console.error(chalk.red(`Invalid YAML format: ${error.message}`));
174
+ } else {
175
+ console.error(
176
+ chalk.red("Error:"),
177
+ error.message || "Unknown error"
178
+ );
179
+ }
180
+ }
181
+ } catch (error: any) {
182
+ if (error.message && error.message.includes('Authentication')) {
183
+ console.error(chalk.red(error.message));
184
+ } else {
185
+ console.error(
186
+ chalk.red("Error:"),
187
+ error instanceof Error ? error.message : "Unknown error"
188
+ );
189
+ }
190
+ }
191
+ });
192
+ }
@@ -0,0 +1,272 @@
1
+ import { Command } from "commander";
2
+ import { withTokenRefresh } from "../../utils/error";
3
+ import chalk from "chalk";
4
+ import ora from "ora";
5
+ import { resolveProject } from "../../utils/project";
6
+ import fs from "fs";
7
+ import {
8
+ createZipFromDirectory,
9
+ findProjectRoot,
10
+ isTypeScriptProject,
11
+ loadNestboxConfig,
12
+ runPredeployScripts,
13
+ } from "../../utils/agent";
14
+ 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 = `Sending API request to deploy ${resourceType.toLowerCase()}...`;
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
+ });
272
+ }
@@ -0,0 +1,151 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import fs from "fs";
5
+ import {
6
+ createNestboxConfig,
7
+ extractZip,
8
+ } from "../../utils/agent";
9
+ import inquirer from "inquirer";
10
+ import path from "path";
11
+
12
+ export function registerGenerateCommand(agentCommand: Command): void {
13
+ agentCommand
14
+ .command("generate <folder>")
15
+ .description("Generate a new project from templates")
16
+ .option("--lang <language>", "Project language (ts|js)")
17
+ .option("--template <type>", "Template type (agent|chatbot)")
18
+ .option("--project <projectId>", "Project ID")
19
+ .action(async (folder, options) => {
20
+ try {
21
+ const spinner = ora("Initializing project generation...").start();
22
+
23
+ // Ensure target folder doesn't exist
24
+ if (fs.existsSync(folder)) {
25
+ spinner.fail(`Folder ${folder} already exists`);
26
+ return;
27
+ }
28
+
29
+ let selectedLang = options.lang;
30
+ let selectedTemplate = options.template;
31
+
32
+ // Interactive selection if not provided
33
+ if (!selectedLang || !selectedTemplate) {
34
+ spinner.stop();
35
+
36
+ const answers = await inquirer.prompt([
37
+ {
38
+ type: 'list',
39
+ name: 'lang',
40
+ message: 'Select project language:',
41
+ choices: [
42
+ { name: 'TypeScript', value: 'ts' },
43
+ { name: 'JavaScript', value: 'js' }
44
+ ],
45
+ when: () => !selectedLang
46
+ },
47
+ {
48
+ type: 'list',
49
+ name: 'template',
50
+ message: 'Select template type:',
51
+ choices: [
52
+ { name: 'Agent', value: 'agent' },
53
+ { name: 'Chatbot', value: 'chatbot' }
54
+ ],
55
+ when: () => !selectedTemplate
56
+ }
57
+ ]);
58
+
59
+ selectedLang = selectedLang || answers.lang;
60
+ selectedTemplate = selectedTemplate || answers.template;
61
+
62
+ spinner.start("Generating project...");
63
+ }
64
+
65
+ // Find matching template in local templates folder
66
+ const templateMapping: Record<string, string> = {
67
+ 'agent': 'base',
68
+ 'chatbot': 'chatbot'
69
+ };
70
+ const mappedTemplateType = templateMapping[selectedTemplate] || selectedTemplate;
71
+ const templateKey = `template-${mappedTemplateType}-${selectedLang}.zip`;
72
+
73
+ // Try process.cwd() first, then __dirname fallback
74
+ let templatePath = path.resolve(process.cwd(), 'templates', templateKey);
75
+ if (!fs.existsSync(templatePath)) {
76
+ // fallback to __dirname
77
+ templatePath = path.resolve(__dirname, '../../../templates', templateKey);
78
+ }
79
+
80
+ if (!fs.existsSync(templatePath)) {
81
+ spinner.fail(`Template not found: ${templatePath}`);
82
+ // Show available templates in both locations
83
+ const cwdTemplates = path.resolve(process.cwd(), 'templates');
84
+ const dirTemplates = path.resolve(__dirname, '../../../templates');
85
+ let shown = false;
86
+
87
+ if (fs.existsSync(cwdTemplates)) {
88
+ console.log(chalk.yellow('Available templates in ./templates:'));
89
+ fs.readdirSync(cwdTemplates).forEach(file => {
90
+ console.log(chalk.yellow(` - ${file}`));
91
+ });
92
+ shown = true;
93
+ }
94
+
95
+ if (fs.existsSync(dirTemplates)) {
96
+ console.log(chalk.yellow('Available templates in templates:'));
97
+ fs.readdirSync(dirTemplates).forEach(file => {
98
+ console.log(chalk.yellow(` - ${file}`));
99
+ });
100
+ shown = true;
101
+ }
102
+
103
+ if (!shown) {
104
+ console.log(chalk.red('No templates directory found. Please add your templates.'));
105
+ }
106
+ return;
107
+ }
108
+
109
+ spinner.text = `Extracting template to ${folder}...`;
110
+
111
+ try {
112
+ // Extract template to target folder
113
+ extractZip(templatePath, folder);
114
+
115
+ // Create nestbox.config.json for TypeScript projects
116
+ createNestboxConfig(folder, selectedLang === 'ts');
117
+
118
+ // Update package.json with project name if it exists
119
+ const packageJsonPath = path.join(folder, 'package.json');
120
+ if (fs.existsSync(packageJsonPath)) {
121
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
122
+ packageJson.name = path.basename(folder);
123
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
124
+ }
125
+
126
+ spinner.succeed(`Successfully generated ${mappedTemplateType} project in ${folder}`);
127
+
128
+ console.log(chalk.green("\nNext steps:"));
129
+ console.log(chalk.yellow(` cd ${folder}`));
130
+ console.log(chalk.yellow(" npm install"));
131
+ if (selectedLang === 'ts') {
132
+ console.log(chalk.yellow(" npm run build"));
133
+ }
134
+ console.log(chalk.yellow(" nestbox agent deploy --agent <agent-name> --instance <instance-name>"));
135
+
136
+ } catch (error) {
137
+ // Clean up on error
138
+ if (fs.existsSync(folder)) {
139
+ fs.rmSync(folder, { recursive: true, force: true });
140
+ }
141
+ throw error;
142
+ }
143
+
144
+ } catch (error: any) {
145
+ console.error(
146
+ chalk.red("Error:"),
147
+ error.message || "Failed to generate project"
148
+ );
149
+ }
150
+ });
151
+ }
@@ -0,0 +1,12 @@
1
+ // Main agent command exports
2
+ export { createAgent, type CreateAgentOptions } from "./create";
3
+
4
+ // Individual command exports for direct usage if needed
5
+ export { registerListCommand } from "./list";
6
+ export { registerRemoveCommand } from "./remove";
7
+ export { registerDeployCommand } from "./deploy";
8
+ export { registerGenerateCommand } from "./generate";
9
+ export { registerCreateFromYamlCommand } from "./createFromYaml";
10
+
11
+ // API utilities
12
+ export { createApis, type ApiInstances } from "./apiUtils";