|
| 1 | +const chalk = require('chalk'); |
| 2 | +const axios = require('axios'); |
| 3 | +const spawn = require('cross-spawn'); |
| 4 | +const { Command } = require('commander'); |
| 5 | +const fs = require('fs'); |
| 6 | +const path = require('path'); |
| 7 | +const inquirer = require('inquirer'); |
| 8 | +const yaml = require('js-yaml'); |
| 9 | +const { v4: uuidv4 } = require('uuid'); |
| 10 | + |
| 11 | +const { checkUserAuth, getUserData } = require('./userData'); |
| 12 | + |
| 13 | +async function askForActions(actionsData, parsedYaml) { |
| 14 | + console.log(chalk.yellow(`\n------------------------------Action Steps-----------------------------------------\n`)); |
| 15 | + console.log(chalk.green("Actions are the functionality that your Agent provides to the user. These are like functionality shortcuts that the user can invoke using \\ command.\n")); |
| 16 | + |
| 17 | + const initialPrompt = [ |
| 18 | + { |
| 19 | + type: 'confirm', |
| 20 | + name: 'addActions', |
| 21 | + message: 'Do you want to add actions?', |
| 22 | + default: true, |
| 23 | + } |
| 24 | + ]; |
| 25 | + |
| 26 | + const initialRes = await inquirer.prompt(initialPrompt); |
| 27 | + let addMoreActions = initialRes.addActions; |
| 28 | + |
| 29 | + while (addMoreActions) { |
| 30 | + const actionPrompt = [ |
| 31 | + { |
| 32 | + type: 'input', |
| 33 | + name: 'actionName', |
| 34 | + message: 'Please Enter Action Name:', |
| 35 | + default: parsedYaml.actions[0].name |
| 36 | + }, |
| 37 | + { |
| 38 | + type: 'input', |
| 39 | + name: 'description', |
| 40 | + message: 'Please Enter Action Description:', |
| 41 | + default: parsedYaml.actions[0].description |
| 42 | + }, |
| 43 | + { |
| 44 | + type: 'input', |
| 45 | + name: 'detailDescription', |
| 46 | + message: 'Please Enter Detail Description (optional):', |
| 47 | + default: parsedYaml.actions[0].detailDescription, |
| 48 | + }, |
| 49 | + { |
| 50 | + type: 'input', |
| 51 | + name: 'actionPrompt', |
| 52 | + message: 'Please Enter Action Prompt (optional):', |
| 53 | + default: parsedYaml.actions[0].actionPrompt, |
| 54 | + }, |
| 55 | + { |
| 56 | + type: 'confirm', |
| 57 | + name: 'addMoreActions', |
| 58 | + message: 'Do you want to add more actions?', |
| 59 | + default: false, |
| 60 | + } |
| 61 | + ]; |
| 62 | + |
| 63 | + const actionRes = await inquirer.prompt(actionPrompt); |
| 64 | + actionsData.push({ |
| 65 | + name: actionRes.actionName, |
| 66 | + description: actionRes.description, |
| 67 | + detailDescription: actionRes.detailDescription, |
| 68 | + actionPrompt: actionRes.actionPrompt, |
| 69 | + }); |
| 70 | + addMoreActions = actionRes.addMoreActions; |
| 71 | + } |
| 72 | + return actionsData; |
| 73 | + } |
| 74 | + |
| 75 | +async function askForInstructions(sdlc, parsedYaml) { |
| 76 | + let addMoreInstructions = true; |
| 77 | + console.log(chalk.yellow(`\n------------------------------SDLC Steps-----------------------------------------\n`)); |
| 78 | + console.log(chalk.green("SDLC Steps are the software development steps that your Agent will handle like code generation, deployment, testing etc. \n These are used by Universal Agent Router to route the user request to the correct Agent Invocation.\n Also add sample Instructions that the user should give to invoke that SLDC Step functionality.\n")); |
| 79 | + |
| 80 | + |
| 81 | + while (addMoreInstructions) { |
| 82 | + // Prompt for SDLC step name |
| 83 | + const stepPrompt = [ |
| 84 | + { |
| 85 | + type: 'list', |
| 86 | + name: 'name', |
| 87 | + message: 'Please Enter SDLC Step Name:', |
| 88 | + choices: parsedYaml.metadata.sdlc_steps_managed.map(item => item.name), |
| 89 | + } |
| 90 | + ]; |
| 91 | + |
| 92 | + const stepRes = await inquirer.prompt(stepPrompt); |
| 93 | + |
| 94 | + let instructions = []; |
| 95 | + |
| 96 | + // Prompt for multiple instructions |
| 97 | + let addMoreExamples = true; |
| 98 | + while (addMoreExamples) { |
| 99 | + const instructionPrompt = [ |
| 100 | + { |
| 101 | + type: 'input', |
| 102 | + name: 'example_instruction', |
| 103 | + message: 'Please Enter Instruction Description:', |
| 104 | + default: 'Generate a new React component', |
| 105 | + }, |
| 106 | + { |
| 107 | + type: 'confirm', |
| 108 | + name: 'addMoreExamples', |
| 109 | + message: 'Do you want to add another instruction?', |
| 110 | + default: false, |
| 111 | + } |
| 112 | + ]; |
| 113 | + |
| 114 | + const instructionRes = await inquirer.prompt(instructionPrompt); |
| 115 | + |
| 116 | + instructions.push(instructionRes.example_instruction); |
| 117 | + addMoreExamples = instructionRes.addMoreExamples; |
| 118 | + } |
| 119 | + |
| 120 | + sdlc.push({ |
| 121 | + name: stepRes.name, |
| 122 | + example_instructions: instructions, |
| 123 | + }); |
| 124 | + |
| 125 | + const addMoreStepsPrompt = [ |
| 126 | + { |
| 127 | + type: 'confirm', |
| 128 | + name: 'addMoreInstructions', |
| 129 | + message: 'Do you want to add more SDLC steps?', |
| 130 | + default: false, |
| 131 | + } |
| 132 | + ]; |
| 133 | + |
| 134 | + const addMoreStepsRes = await inquirer.prompt(addMoreStepsPrompt); |
| 135 | + addMoreInstructions = addMoreStepsRes.addMoreInstructions; |
| 136 | + } |
| 137 | + |
| 138 | + return sdlc; |
| 139 | +} |
| 140 | + |
| 141 | +function createProject(projectName, installPath, selectedTemplate, answers, parsedYaml ) { |
| 142 | + |
| 143 | + const projectDir = path.resolve(installPath); |
| 144 | + fs.mkdirSync(projectDir, { recursive: true }); |
| 145 | + |
| 146 | + // Copy the selected template to the project directory |
| 147 | + const templateDir = path.resolve(__dirname,'..', 'template'); |
| 148 | + const templatePath = path.join(templateDir, selectedTemplate); |
| 149 | + fs.cpSync(templatePath, projectDir, { recursive: true }); |
| 150 | + |
| 151 | + fs.renameSync( |
| 152 | + path.join(projectDir, 'gitignore'), |
| 153 | + path.join(projectDir, '.gitignore') |
| 154 | + ); |
| 155 | + |
| 156 | + const agentYamlPath = path.join(projectDir, 'codeboltagent.yaml'); |
| 157 | + let agentYaml = fs.readFileSync(agentYamlPath, 'utf8'); |
| 158 | + |
| 159 | + let agentYamlObj = yaml.load(agentYaml); |
| 160 | + agentYamlObj.title = projectName; |
| 161 | + agentYamlObj.description = answers.agentDescription; |
| 162 | + agentYamlObj.tags = answers.tags.split(',').map(tag => tag.trim()); |
| 163 | + agentYamlObj.unique_id = answers.unique_id |
| 164 | + agentYamlObj.metadata.agent_routing = { |
| 165 | + worksonblankcode: answers.worksonblankcode, |
| 166 | + worksonexistingcode: answers.worksonexistingcode, |
| 167 | + supportedlanguages: answers.supportedlanguages, |
| 168 | + supportedframeworks: answers.supportedframeworks, |
| 169 | + }; |
| 170 | + |
| 171 | + agentYamlObj.metadata.sdlc_steps_managed = answers.sdlc_steps_managed.map(step => ({ |
| 172 | + name: step.name, |
| 173 | + example_instructions: step.example_instructions, |
| 174 | + })); |
| 175 | + |
| 176 | + agentYamlObj.actions = parsedYaml.actions.map(action => ({ |
| 177 | + name: action.name, |
| 178 | + description: action.description, |
| 179 | + detailDescription: action.detailDescription, |
| 180 | + actionPrompt: action.actionPrompt, |
| 181 | + })); |
| 182 | + |
| 183 | + agentYaml = yaml.dump(agentYamlObj); |
| 184 | + |
| 185 | + fs.writeFileSync(agentYamlPath, agentYaml, 'utf8'); |
| 186 | + |
| 187 | + const projectPackageJson = require(path.join(projectDir, 'package.json')); |
| 188 | + |
| 189 | + // Update the project's package.json with the new project name |
| 190 | + projectPackageJson.name = projectName; |
| 191 | + |
| 192 | + fs.writeFileSync( |
| 193 | + path.join(projectDir, 'package.json'), |
| 194 | + JSON.stringify(projectPackageJson, null, 2) |
| 195 | + ); |
| 196 | + |
| 197 | + // Run `npm install` in the project directory to install |
| 198 | + // the dependencies. We are using a third-party library |
| 199 | + // called `cross-spawn` for cross-platform support. |
| 200 | + // (Node has issues spawning child processes in Windows). |
| 201 | + spawn.sync('npm', ['install'], { stdio: 'inherit', cwd: installPath }); |
| 202 | + |
| 203 | + spawn.sync('git', ['init'], { stdio: 'inherit', cwd: installPath }); |
| 204 | + |
| 205 | + console.log('Success! Your new project is ready.'); |
| 206 | + console.log(`Created ${projectName} at ${projectDir}`); |
| 207 | +} |
| 208 | + |
| 209 | +function getPrompts(projectName, quickEnabled, parsedYaml){ |
| 210 | + |
| 211 | + const prompts = []; |
| 212 | + |
| 213 | + const currentPath = process.cwd(); |
| 214 | + |
| 215 | + const templateDir = path.resolve(__dirname,'..', 'template'); |
| 216 | + const templates = fs.readdirSync(templateDir).filter(file => fs.statSync(path.join(templateDir, file)).isDirectory()); |
| 217 | + |
| 218 | + |
| 219 | + |
| 220 | + if (!quickEnabled) { |
| 221 | + prompts.push({ |
| 222 | + type: 'input', |
| 223 | + name: 'projectName', |
| 224 | + message: 'Please Enter the name of your Agent:', |
| 225 | + default: projectName, |
| 226 | + }); |
| 227 | + |
| 228 | + prompts.push({ |
| 229 | + type: 'input', |
| 230 | + name: 'unique_id', |
| 231 | + message: 'Please enter the unique_id:', |
| 232 | + default: projectName.replace(/[^a-zA-Z0-9]/g, ''), |
| 233 | + validate: function (input) { |
| 234 | + if (/\s/.test(input)) { |
| 235 | + return 'unique_id should not contain any spaces'; |
| 236 | + } |
| 237 | + return true; |
| 238 | + } |
| 239 | + }); |
| 240 | + |
| 241 | + prompts.push({ |
| 242 | + type: 'input', |
| 243 | + name: 'installPath', |
| 244 | + message: 'Please enter the path to install the application:', |
| 245 | + default: (answers) => path.join(currentPath, answers.projectName || 'defaultProjectName'), |
| 246 | + }); |
| 247 | + |
| 248 | + prompts.push({ |
| 249 | + type: 'list', |
| 250 | + name: 'template', |
| 251 | + message: 'Please select a template for your application:', |
| 252 | + choices: templates, |
| 253 | + }); |
| 254 | + |
| 255 | + prompts.push({ |
| 256 | + type: 'input', |
| 257 | + name: 'agentDescription', |
| 258 | + message: 'Please enter a description for your agent:', |
| 259 | + default: 'My Codebolt Agent', |
| 260 | + }); |
| 261 | + |
| 262 | + prompts.push({ |
| 263 | + type: 'input', |
| 264 | + name: 'tags', |
| 265 | + message: 'Please Enter agent tags by comma separated:', |
| 266 | + default: 'test', |
| 267 | + }); |
| 268 | + |
| 269 | + prompts.push({ |
| 270 | + type: 'confirm', |
| 271 | + name: 'worksonblankcode', |
| 272 | + message: 'Works on blank code:', |
| 273 | + default: parsedYaml.metadata.agent_routing.worksonblankcode, |
| 274 | + }); |
| 275 | + |
| 276 | + prompts.push({ |
| 277 | + type: 'confirm', |
| 278 | + name: 'worksonexistingcode', |
| 279 | + message: 'Works on existing code:', |
| 280 | + default: parsedYaml.metadata.agent_routing.worksonexistingcode, |
| 281 | + }); |
| 282 | + |
| 283 | + prompts.push({ |
| 284 | + type: 'checkbox', |
| 285 | + name: 'supportedlanguages', |
| 286 | + message: 'Supported Languages:', |
| 287 | + choices: parsedYaml.metadata.agent_routing.supportedlanguages, |
| 288 | + validate: function (input) { |
| 289 | + if (input.length === 0) { |
| 290 | + return 'You must select at least one language'; |
| 291 | + } |
| 292 | + return true; |
| 293 | + } |
| 294 | + }); |
| 295 | + |
| 296 | + prompts.push({ |
| 297 | + type: 'checkbox', |
| 298 | + name: 'supportedframeworks', |
| 299 | + message: 'Supported Frameworks:', |
| 300 | + choices: parsedYaml.metadata.agent_routing.supportedframeworks, |
| 301 | + validate: function (input) { |
| 302 | + if (input.length === 0) { |
| 303 | + return 'You must select at least one framework'; |
| 304 | + } |
| 305 | + return true; |
| 306 | + } |
| 307 | + }); |
| 308 | + } |
| 309 | + |
| 310 | + |
| 311 | + |
| 312 | + |
| 313 | + return prompts; |
| 314 | +} |
| 315 | + |
| 316 | +const createagent = async (options) => { |
| 317 | + console.log(options) |
| 318 | + let projectName = options.name || process.argv[3]; |
| 319 | + const quickEnabled = options.quick || false; |
| 320 | + |
| 321 | + const agentymlpath = path.join(__dirname, '..','template/basic', 'codeboltagent.yaml'); |
| 322 | + let agentYamlData = fs.readFileSync(agentymlpath, 'utf8'); |
| 323 | + const parsedYaml = yaml.load(agentYamlData); |
| 324 | + const prompts = getPrompts(projectName, quickEnabled, parsedYaml) |
| 325 | + |
| 326 | + |
| 327 | + |
| 328 | + console.log(chalk.blue( |
| 329 | + " _____ _ _ _ _ \n"+ |
| 330 | + " / __ \\ | | | | | | | \n"+ |
| 331 | + " | / \\/ ___ __| | ___| |__ ___ | | |_ \n"+ |
| 332 | + " | | / _ \\ / _` |/ _ \\ '_ \\ / _ \\| | __| \n"+ |
| 333 | + " | \\__/\\ (_) | (_| | __/ |_) | (_) | | |_ \n"+ |
| 334 | + " \\____/\\___/ \\__,_|\\___|_.__/ \\___/|_|\\__| \n")); |
| 335 | + |
| 336 | + inquirer.prompt(prompts).then(async answers => { |
| 337 | + let sdlc = []; |
| 338 | + let actionsData = []; |
| 339 | + |
| 340 | + let sdlcInstruction = await askForInstructions(sdlc, parsedYaml) |
| 341 | + let actions = await askForActions(actionsData, parsedYaml) |
| 342 | + |
| 343 | + projectName = answers.projectName.trim(); |
| 344 | + const installPath = answers.installPath.trim() === '.' ? process.cwd() : path.resolve(process.cwd(), answers.installPath.trim()); |
| 345 | + const selectedTemplate = answers.template; |
| 346 | + answers.sdlc_steps_managed = sdlcInstruction |
| 347 | + answers.actions = actions |
| 348 | + createProject(projectName, installPath, selectedTemplate, answers, parsedYaml); |
| 349 | + }); |
| 350 | +}; |
| 351 | + |
| 352 | + |
| 353 | +module.exports = { createagent }; |
0 commit comments