UNPKG

@bxav/code-artisan

Version:

An AI-driven CLI tool for code refactoring across various programming languages.

1,287 lines (1,172 loc) 46.7 kB
#!/usr/bin/env node /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ([ /* 0 */, /* 1 */ /***/ ((module) => { module.exports = require("dotenv/config"); /***/ }), /* 2 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AppModule = void 0; const tslib_1 = __webpack_require__(3); const config_1 = __webpack_require__(4); const common_1 = __webpack_require__(5); const smart_corrector_command_1 = __webpack_require__(6); const init_command_1 = __webpack_require__(30); const build_expert_questions_1 = __webpack_require__(32); const cli_utils_1 = __webpack_require__(9); const cli_config_service_1 = __webpack_require__(24); const smart_corrector_service_1 = __webpack_require__(26); const code_linter_agent_service_1 = __webpack_require__(33); const code_linter_alpha_command_1 = __webpack_require__(37); let AppModule = class AppModule { }; exports.AppModule = AppModule; exports.AppModule = AppModule = tslib_1.__decorate([ (0, common_1.Module)({ imports: [config_1.ConfigModule.forRoot(), cli_utils_1.CliUtilsModule], providers: [ cli_config_service_1.CliConfigService, smart_corrector_service_1.SmartCorrectorService, code_linter_agent_service_1.CodeLinterAgentService, smart_corrector_command_1.SmartCorrectorCommand, code_linter_alpha_command_1.CodeLinterAlphaCommand, init_command_1.InitCommand, build_expert_questions_1.AskBuildExpertQuestions, ], }) ], AppModule); /***/ }), /* 3 */ /***/ ((module) => { module.exports = require("tslib"); /***/ }), /* 4 */ /***/ ((module) => { module.exports = require("@nestjs/config"); /***/ }), /* 5 */ /***/ ((module) => { module.exports = require("@nestjs/common"); /***/ }), /* 6 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { var _a, _b, _c, _d, _e; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SmartCorrectorCommand = void 0; const tslib_1 = __webpack_require__(3); const fs = tslib_1.__importStar(__webpack_require__(7)); const nest_commander_1 = __webpack_require__(8); const cli_utils_1 = __webpack_require__(9); const cli_config_service_1 = __webpack_require__(24); const smart_corrector_service_1 = __webpack_require__(26); let SmartCorrectorCommand = class SmartCorrectorCommand extends nest_commander_1.CommandRunner { constructor(configService, smartCorrectorService, modelBuilderService, fileManager, loaderService) { super(); this.configService = configService; this.smartCorrectorService = smartCorrectorService; this.modelBuilderService = modelBuilderService; this.fileManager = fileManager; this.loaderService = loaderService; } async run(_params, options) { const config = await this.configService.loadConfig(options.config); if (!config) { console.warn('Failed to load configuration.\nPlease run `code-artisan init` to initialize CodeArtisan.'); return; } if (!this.configService.validate(config)) { console.error('Fix your configuration file.'); return; } if (Object.keys(config.experts).length === 0) { console.error('No experts configured.'); return; } const expertName = options.expert || Object.keys(config.experts)[0]; const expertConfig = config.experts[expertName]; if (!expertConfig) { console.error(`Expert '${expertName}' not found.`); return; } console.log(`Processing files with '${expertName}' expert configurations...`); const prompt = this.configService.loadPrompt(); const codingStyles = await this.configService.loadCodingStyles(expertConfig); const examples = await this.configService.loadExamples(expertConfig); let filePaths = _params; if (!filePaths.length) { filePaths = await (0, cli_utils_1.getChangedFiles)(options.commitDiff || undefined); } else { filePaths = await this.fileManager.getFiles(filePaths); } filePaths = filePaths.filter((filePath) => expertConfig.pattern .split(',') .some((p) => filePath.endsWith(p.trim()))); const fileContents = await this.loadFilesContent(filePaths); const modelConfig = config.model || { type: 'OpenAI', name: 'gpt-4-1106-preview', options: { temperature: 0, }, }; const model = await this.modelBuilderService.buildModel(modelConfig.type, modelConfig.name, modelConfig.options); const load = this.loaderService.createLoader({ text: 'Refactoring...' }); const newFileContents = await this.smartCorrectorService.refactorFiles(model, fileContents, { prompt, role: expertConfig.role, codingStyles: codingStyles.join('\n'), examples: examples.join('\n'), }); await this.writeNewContents(newFileContents); load.stop(); } async loadFilesContent(filePaths) { const contents = {}; for (const filePath of filePaths) { contents[filePath] = await (0, cli_utils_1.loadTextFile)(filePath); } return contents; } async writeNewContents(newFileContents) { for (const [filePath, content] of Object.entries(newFileContents)) { fs.writeFileSync(filePath, content.replace(/^```.*\n/, '').replace(/\n```$/, '\n')); } } parseCommitDiff(val) { return val; } parseConfig(val) { return val; } parseExpert(val) { return val; } }; exports.SmartCorrectorCommand = SmartCorrectorCommand; tslib_1.__decorate([ (0, nest_commander_1.Option)({ flags: '-c, --commit-diff [commitDiff]', description: 'The commit diff to use for the refactor', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], SmartCorrectorCommand.prototype, "parseCommitDiff", null); tslib_1.__decorate([ (0, nest_commander_1.Option)({ flags: '--config [path]', description: 'Path to a custom CodeArtisan configuration file', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], SmartCorrectorCommand.prototype, "parseConfig", null); tslib_1.__decorate([ (0, nest_commander_1.Option)({ flags: '--expert [name]', description: 'Specify the expert to use for linting', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], SmartCorrectorCommand.prototype, "parseExpert", null); exports.SmartCorrectorCommand = SmartCorrectorCommand = tslib_1.__decorate([ (0, nest_commander_1.Command)({ name: 'smart-corrector', description: 'Smart corrector' }), tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof cli_config_service_1.CliConfigService !== "undefined" && cli_config_service_1.CliConfigService) === "function" ? _a : Object, typeof (_b = typeof smart_corrector_service_1.SmartCorrectorService !== "undefined" && smart_corrector_service_1.SmartCorrectorService) === "function" ? _b : Object, typeof (_c = typeof cli_utils_1.ModelBuilderService !== "undefined" && cli_utils_1.ModelBuilderService) === "function" ? _c : Object, typeof (_d = typeof cli_utils_1.FileManagerService !== "undefined" && cli_utils_1.FileManagerService) === "function" ? _d : Object, typeof (_e = typeof cli_utils_1.LoaderService !== "undefined" && cli_utils_1.LoaderService) === "function" ? _e : Object]) ], SmartCorrectorCommand); /***/ }), /* 7 */ /***/ ((module) => { module.exports = require("fs"); /***/ }), /* 8 */ /***/ ((module) => { module.exports = require("nest-commander"); /***/ }), /* 9 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); const tslib_1 = __webpack_require__(3); tslib_1.__exportStar(__webpack_require__(10), exports); tslib_1.__exportStar(__webpack_require__(12), exports); tslib_1.__exportStar(__webpack_require__(15), exports); tslib_1.__exportStar(__webpack_require__(16), exports); tslib_1.__exportStar(__webpack_require__(18), exports); tslib_1.__exportStar(__webpack_require__(22), exports); /***/ }), /* 10 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getChangedFiles = void 0; const child_process_1 = __webpack_require__(11); function getChangedFiles(ref = 'HEAD~1 HEAD') { return new Promise((resolve, reject) => { (0, child_process_1.exec)(`git diff --name-only ${ref}`, (error, stdout, stderr) => { if (error) { if (error.message.includes('not a git repository')) { console.error('Git is not initialized in this directory.'); reject(new Error('Git is not initialized in this directory.')); } else { console.error(`exec error: ${error}`); reject(error); } return; } if (stderr) { console.error(`stderr: ${stderr}`); reject(new Error(stderr)); return; } // Split the stdout by newline to get an array of file paths const filePaths = stdout.split('\n'); resolve(filePaths); }); }); } exports.getChangedFiles = getChangedFiles; /***/ }), /* 11 */ /***/ ((module) => { module.exports = require("child_process"); /***/ }), /* 12 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.loadConfig = exports.loadTextFile = exports.loadMarkdown = exports.loadJSON = exports.loadYaml = void 0; const tslib_1 = __webpack_require__(3); const fs = tslib_1.__importStar(__webpack_require__(7)); const path = tslib_1.__importStar(__webpack_require__(13)); const yaml = tslib_1.__importStar(__webpack_require__(14)); function loadYaml(filePath) { try { const fileContent = yaml.load(fs.readFileSync(filePath, 'utf8')); return fileContent; } catch (error) { console.error('Error reading or parsing YAML file:', error); } } exports.loadYaml = loadYaml; function loadJSON(filePath) { try { const fileContent = fs.readFileSync(filePath, 'utf8'); const data = JSON.parse(fileContent); return data; } catch (error) { console.error('Error reading or parsing JSON file:', error); } } exports.loadJSON = loadJSON; function loadMarkdown(filePath) { try { const fileContent = fs.readFileSync(filePath, 'utf8'); return fileContent; } catch (error) { console.error('Error reading or parsing Markdown file:', error); } } exports.loadMarkdown = loadMarkdown; function loadTextFile(filePath) { try { const fileContent = fs.readFileSync(filePath, 'utf8'); return fileContent; } catch (error) { console.error('Error reading or parsing Markdown file:', error); } } exports.loadTextFile = loadTextFile; function loadConfig(filePath) { const ext = path.extname(filePath); switch (ext.toLowerCase()) { case '.yaml': case '.yml': return loadYaml(filePath); case '.json': return loadJSON(filePath); case '.md': return loadMarkdown(filePath); default: console.error('Unsupported file format:', ext); } } exports.loadConfig = loadConfig; /***/ }), /* 13 */ /***/ ((module) => { module.exports = require("path"); /***/ }), /* 14 */ /***/ ((module) => { module.exports = require("js-yaml"); /***/ }), /* 15 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FileManagerService = void 0; const tslib_1 = __webpack_require__(3); const common_1 = __webpack_require__(5); const fs_1 = __webpack_require__(7); const path = tslib_1.__importStar(__webpack_require__(13)); let FileManagerService = class FileManagerService { async ensureDirectory(path) { try { await fs_1.promises.access(path); } catch { await fs_1.promises.mkdir(path, { recursive: true }); console.log(`Directory created at ${path}`); } } async writeFile(path, content) { await fs_1.promises.writeFile(path, content); } async getFilesRecursively(directory) { const files = await fs_1.promises.readdir(directory); const results = files.map(async (file) => { const filePath = path.join(directory, file); const stat = (0, fs_1.statSync)(filePath); if (stat.isDirectory()) { return this.getFilesRecursively(filePath); } else { return [filePath]; } }); return (await Promise.all(results)).flat(); } async getFiles(filePaths) { const allFilesPromises = filePaths.map(async (path) => { if ((0, fs_1.statSync)(path).isDirectory()) { return this.getFilesRecursively(path); } else { return [path]; } }); const allFilesArrays = await Promise.all(allFilesPromises); filePaths = allFilesArrays.flat(); return filePaths; } }; exports.FileManagerService = FileManagerService; exports.FileManagerService = FileManagerService = tslib_1.__decorate([ (0, common_1.Injectable)() ], FileManagerService); /***/ }), /* 16 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.LoaderService = void 0; const tslib_1 = __webpack_require__(3); const common_1 = __webpack_require__(5); const loading = __webpack_require__(17); const pongFrames = [ '▐⠂ ▌', '▐⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂▌', '▐ ⠈▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐ ⠈ ▌', '▐ ⠂ ▌', '▐ ⠠ ▌', '▐ ⡀ ▌', '▐ ⠠ ▌', '▐ ⠂ ▌', '▐⠈ ▌', '▐⠂ ▌', ]; let LoaderService = class LoaderService { createLoader({ text }) { return loading({ text, color: 'yellow', interval: 80, stream: process.stdout, frames: pongFrames, }).start(); } }; exports.LoaderService = LoaderService; exports.LoaderService = LoaderService = tslib_1.__decorate([ (0, common_1.Injectable)() ], LoaderService); /***/ }), /* 17 */ /***/ ((module) => { module.exports = require("loading-cli"); /***/ }), /* 18 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { var _a; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ModelBuilderService = void 0; const tslib_1 = __webpack_require__(3); const openai_1 = __webpack_require__(19); const mistralai_1 = __webpack_require__(20); const ollama_1 = __webpack_require__(21); const common_1 = __webpack_require__(5); const nest_commander_1 = __webpack_require__(8); let ModelBuilderService = class ModelBuilderService { constructor(inquirer) { this.inquirer = inquirer; } async buildModel(modelType, modelName, options) { switch (modelType) { case 'OpenAI': return new openai_1.ChatOpenAI({ modelName, openAIApiKey: process.env['OPENAI_API_KEY'] || (await this.promptForOpenaiKey()), ...options, }); case 'Mistral': return new mistralai_1.ChatMistralAI({ apiKey: process.env['MISTRAL_API_KEY'], modelName, }); case 'Ollama': return new ollama_1.Ollama({ baseUrl: process.env['OLLAMA_BASE_URL'] || 'http://localhost:11434', model: modelName, }); default: throw new Error(`Unsupported model type: ${modelType}`); } } async promptForOpenaiKey() { const { openaiKey } = await this.inquirer.ask('ask-openai-key-questions', undefined); return openaiKey; } }; exports.ModelBuilderService = ModelBuilderService; exports.ModelBuilderService = ModelBuilderService = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof nest_commander_1.InquirerService !== "undefined" && nest_commander_1.InquirerService) === "function" ? _a : Object]) ], ModelBuilderService); /***/ }), /* 19 */ /***/ ((module) => { module.exports = require("@langchain/openai"); /***/ }), /* 20 */ /***/ ((module) => { module.exports = require("@langchain/mistralai"); /***/ }), /* 21 */ /***/ ((module) => { module.exports = require("@langchain/community/llms/ollama"); /***/ }), /* 22 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CliUtilsModule = void 0; const tslib_1 = __webpack_require__(3); const common_1 = __webpack_require__(5); const model_builder_service_1 = __webpack_require__(18); const ask_openai_key_questions_1 = __webpack_require__(23); const file_manager_service_1 = __webpack_require__(15); const loader_service_1 = __webpack_require__(16); let CliUtilsModule = class CliUtilsModule { }; exports.CliUtilsModule = CliUtilsModule; exports.CliUtilsModule = CliUtilsModule = tslib_1.__decorate([ (0, common_1.Module)({ providers: [ file_manager_service_1.FileManagerService, loader_service_1.LoaderService, model_builder_service_1.ModelBuilderService, ask_openai_key_questions_1.AskOpenaiKeyQuestions, ], exports: [file_manager_service_1.FileManagerService, loader_service_1.LoaderService, model_builder_service_1.ModelBuilderService], }) ], CliUtilsModule); /***/ }), /* 23 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AskOpenaiKeyQuestions = void 0; const tslib_1 = __webpack_require__(3); const nest_commander_1 = __webpack_require__(8); let AskOpenaiKeyQuestions = class AskOpenaiKeyQuestions { parseOpenaiKey(val) { return val; } }; exports.AskOpenaiKeyQuestions = AskOpenaiKeyQuestions; tslib_1.__decorate([ (0, nest_commander_1.Question)({ message: 'What is your openai key? (You can also set OPENAI_API_KEY environment variable)', name: 'openaiKey', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], AskOpenaiKeyQuestions.prototype, "parseOpenaiKey", null); exports.AskOpenaiKeyQuestions = AskOpenaiKeyQuestions = tslib_1.__decorate([ (0, nest_commander_1.QuestionSet)({ name: 'ask-openai-key-questions' }) ], AskOpenaiKeyQuestions); /***/ }), /* 24 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CliConfigService = void 0; const tslib_1 = __webpack_require__(3); const fs_1 = __webpack_require__(7); const path = tslib_1.__importStar(__webpack_require__(13)); const yaml = tslib_1.__importStar(__webpack_require__(14)); const cli_utils_1 = __webpack_require__(9); const common_1 = __webpack_require__(5); const zod_1 = __webpack_require__(25); const modelSchema = zod_1.z.object({ type: zod_1.z.string(), name: zod_1.z.string(), options: zod_1.z .object({ temperature: zod_1.z.number(), }) .optional(), }); const expertSchema = zod_1.z.object({ pattern: zod_1.z.string(), role: zod_1.z.string(), codingStyles: zod_1.z .array(zod_1.z.object({ path: zod_1.z.string(), })) .optional(), examples: zod_1.z .array(zod_1.z.object({ path: zod_1.z.string(), })) .optional(), }); const expertsSchema = zod_1.z.record(expertSchema); const mainSchema = zod_1.z.object({ model: modelSchema.optional(), experts: expertsSchema, }); let CliConfigService = class CliConfigService { constructor() { } validate(parsedYaml) { const result = mainSchema.safeParse(parsedYaml); if (result.success === false && result.error instanceof zod_1.z.ZodError) { console.error('YAML validation failed with the following errors:'); result.error.errors.forEach((err) => { console.log(`Path: ${err.path.join('.')}, Message: ${err.message}`); }); } return result.success; } async loadConfig(customConfigPath) { try { const configPath = customConfigPath || path.join(process.cwd(), '.codeartisan', 'config.yml'); const configFile = await fs_1.promises.readFile(configPath, 'utf8'); return yaml.load(configFile); } catch (error) { return null; } } async loadExamples(expertConfig) { if (!expertConfig.examples || expertConfig.examples.length === 0) { console.log('No examples configured for this expert.'); return []; } const examples = await Promise.all(expertConfig.examples.map(async (example) => this.loadFileContent(path.join(process.cwd(), example.path)))); return examples.filter(Boolean); } async loadCodingStyles(expertConfig) { if (!expertConfig.codingStyles || expertConfig.codingStyles.length === 0) { console.log('No coding styles configured for this expert.'); return []; } const codingStyles = await Promise.all(expertConfig.codingStyles.map(async (stylePath) => this.loadFileContent(path.join(process.cwd(), stylePath.path)))); return codingStyles.filter(Boolean); } async loadFileContent(filePath) { try { return await fs_1.promises.readFile(filePath, 'utf8'); } catch (error) { console.error(`File not found: ${filePath}`, error); return null; } } loadPrompt() { return (0, cli_utils_1.loadConfig)(path.join(__dirname, 'assets', 'expert-prompt.md')); } }; exports.CliConfigService = CliConfigService; exports.CliConfigService = CliConfigService = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__metadata("design:paramtypes", []) ], CliConfigService); /***/ }), /* 25 */ /***/ ((module) => { module.exports = require("zod"); /***/ }), /* 26 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SmartCorrectorService = void 0; const tslib_1 = __webpack_require__(3); const prompts_1 = __webpack_require__(27); const runnables_1 = __webpack_require__(28); const output_parsers_1 = __webpack_require__(29); const prompts_2 = __webpack_require__(27); const common_1 = __webpack_require__(5); let SmartCorrectorService = class SmartCorrectorService { constructor() { } async refactorFiles(model, fileContents, { prompt, role, codingStyles, examples, }) { const template = prompts_1.ChatPromptTemplate.fromMessages([ prompts_2.SystemMessagePromptTemplate.fromTemplate(prompt), prompts_2.HumanMessagePromptTemplate.fromTemplate(`Please, refactor the following code and respond directly to this message with the refactored code without adding markdown around. Here is the code to refactor:`), prompts_2.HumanMessagePromptTemplate.fromTemplate('{input}'), ]); const outputParser = new output_parsers_1.StringOutputParser(); const chain = runnables_1.RunnableSequence.from([template, model, outputParser]); const newFileContents = await chain.batch(Object.entries(fileContents).map(([filePath, content]) => ({ codingStyles, examples, role, input: content, })), { maxConcurrency: 5, }); return Object.keys(fileContents).reduce((acc, filePath, index) => { acc[filePath] = newFileContents[index]; return acc; }, {}); } }; exports.SmartCorrectorService = SmartCorrectorService; exports.SmartCorrectorService = SmartCorrectorService = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__metadata("design:paramtypes", []) ], SmartCorrectorService); /***/ }), /* 27 */ /***/ ((module) => { module.exports = require("@langchain/core/prompts"); /***/ }), /* 28 */ /***/ ((module) => { module.exports = require("@langchain/core/runnables"); /***/ }), /* 29 */ /***/ ((module) => { module.exports = require("@langchain/core/output_parsers"); /***/ }), /* 30 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { var _a, _b; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.InitCommand = void 0; const tslib_1 = __webpack_require__(3); const nest_commander_1 = __webpack_require__(8); const fs_1 = __webpack_require__(7); const path = tslib_1.__importStar(__webpack_require__(13)); const axios_1 = tslib_1.__importDefault(__webpack_require__(31)); const cli_utils_1 = __webpack_require__(9); const BASE_CODE_ARTISAN_DIR = '.codeartisan'; const CONFIG_FILE_NAME = 'config.yml'; const CODING_STYLES_FILE_NAME = 'coding-styles.md'; const EXAMPLES_FILE_NAME = 'examples.md'; const EXAMPLES_DIR_NAME = 'examples'; const CODING_STYLES_URL = 'https://raw.githubusercontent.com/bxav/ai-atelier/main/apps/code-artisan-cli/examples'; const CONFIG_CONTENT_TEMPLATE = `# OpenAI API model: type: OpenAI name: gpt-4-1106-preview # gpt-4-1106-preview, ... options: temperature: 0.5 # # Mistral API # model: # type: Mistral # name: mistral-small # # Local LLM # model: # type: Ollama # name: mistral # codellama:13b, ... commands: # lint: nx lint # test: nx test # build: nx build experts: {{expertType}}: pattern: {{expertFilePattern}} role: {{expertRole}} codingStyles: - path: ./${BASE_CODE_ARTISAN_DIR}/{{expertType}}/coding-styles.md examples: - path: ./${BASE_CODE_ARTISAN_DIR}/{{expertType}}/examples/examples.md`; let InitCommand = class InitCommand extends nest_commander_1.CommandRunner { constructor(inquirer, fileManager) { super(); this.inquirer = inquirer; this.fileManager = fileManager; } async run() { const { expertType, expertRole, expertFilePattern } = await this.inquirer.ask('ask-build-expert-questions', undefined); console.log('Initializing CodeArtisan for', expertType, '...'); const codeArtisanDir = path.join(process.cwd(), BASE_CODE_ARTISAN_DIR); await this.fileManager.ensureDirectory(codeArtisanDir); const expertDir = path.join(codeArtisanDir, expertType); const examplesDir = path.join(expertDir, EXAMPLES_DIR_NAME); await this.fileManager.ensureDirectory(examplesDir); await this.fetchAndSaveFile(`${CODING_STYLES_URL}/${expertType}/${CODING_STYLES_FILE_NAME}`, expertDir, CODING_STYLES_FILE_NAME); await this.fetchAndSaveFile(`${CODING_STYLES_URL}/${expertType}/${EXAMPLES_FILE_NAME}`, examplesDir, EXAMPLES_FILE_NAME); const configPath = path.join(codeArtisanDir, CONFIG_FILE_NAME); const configContent = this.generateConfigContent(expertType, expertRole, expertFilePattern); await fs_1.promises.writeFile(configPath, configContent); console.log('Created config.yml with React expert setup'); } async fetchAndSaveFile(url, directory, filename) { try { const response = await axios_1.default.get(url); const filePath = path.join(directory, filename); await this.fileManager.writeFile(filePath, response.data); console.log(`Fetched and saved ${filename}`); } catch (error) { console.error(`Failed to fetch and save ${filename}:`, error); } } generateConfigContent(expertType, expertRole, expertFilePattern) { return CONFIG_CONTENT_TEMPLATE.replace(/{{expertType}}/g, expertType) .replace('{{expertFilePattern}}', expertFilePattern) .replace('{{expertRole}}', expertRole); } }; exports.InitCommand = InitCommand; exports.InitCommand = InitCommand = tslib_1.__decorate([ (0, nest_commander_1.Command)({ name: 'init', description: 'Initialize CodeArtisan in your project', }), tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof nest_commander_1.InquirerService !== "undefined" && nest_commander_1.InquirerService) === "function" ? _a : Object, typeof (_b = typeof cli_utils_1.FileManagerService !== "undefined" && cli_utils_1.FileManagerService) === "function" ? _b : Object]) ], InitCommand); /***/ }), /* 31 */ /***/ ((module) => { module.exports = require("axios"); /***/ }), /* 32 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AskBuildExpertQuestions = void 0; const tslib_1 = __webpack_require__(3); const nest_commander_1 = __webpack_require__(8); const filePatterns = { next: '.tsx, .jsx', nestjs: '.service.ts, .module.ts, .controller.ts', 'c++': '.c, .cpp', python: '.py', }; let AskBuildExpertQuestions = class AskBuildExpertQuestions { parseExpertType(type) { return type; } parseExpertRole(role) { return role; } parseFilePattern(pattern) { return pattern; } }; exports.AskBuildExpertQuestions = AskBuildExpertQuestions; tslib_1.__decorate([ (0, nest_commander_1.Question)({ message: 'What example would you like to load? You can update this later in the .codeartisan/config.yml file.', name: 'expertType', choices: ['next', 'nestjs', 'c++', 'python'], default: 'next', type: 'list', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", String) ], AskBuildExpertQuestions.prototype, "parseExpertType", null); tslib_1.__decorate([ (0, nest_commander_1.Question)({ name: 'expertRole', message: 'Give a role to your expert', default: (v) => { return `Senior ${v.expertType.charAt(0).toUpperCase() + v.expertType.slice(1)} Engineer`; }, }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], AskBuildExpertQuestions.prototype, "parseExpertRole", null); tslib_1.__decorate([ (0, nest_commander_1.Question)({ name: 'expertFilePattern', message: 'Give a file pattern to your expert', default: (v) => { return filePatterns[v.expertType]; }, }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], AskBuildExpertQuestions.prototype, "parseFilePattern", null); exports.AskBuildExpertQuestions = AskBuildExpertQuestions = tslib_1.__decorate([ (0, nest_commander_1.QuestionSet)({ name: 'ask-build-expert-questions' }) ], AskBuildExpertQuestions); /***/ }), /* 33 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CodeLinterAgentService = void 0; const tslib_1 = __webpack_require__(3); const common_1 = __webpack_require__(5); const code_linter_agent_1 = __webpack_require__(34); let CodeLinterAgentService = class CodeLinterAgentService { constructor() { } async refactorFile(model, fileContents, { prompt, role, codingStyles, examples, }) { const agent = new code_linter_agent_1.CodeLinterAgent({ model, prompt, role, codingStyles, examples, }); return { [Object.keys(fileContents)[0]]: await agent.refactorFile(fileContents[Object.keys(fileContents)[0]]), }; } }; exports.CodeLinterAgentService = CodeLinterAgentService; exports.CodeLinterAgentService = CodeLinterAgentService = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__metadata("design:paramtypes", []) ], CodeLinterAgentService); /***/ }), /* 34 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CodeLinterAgent = void 0; const prompts_1 = __webpack_require__(27); const langgraph_1 = __webpack_require__(35); const messages_1 = __webpack_require__(36); const prompts_2 = __webpack_require__(27); const prompts_3 = __webpack_require__(27); class CodeLinterAgent { constructor({ model, prompt, role, codingStyles, examples }) { this.model = model; this.prompt = prompt; this.role = role; this.codingStyles = codingStyles; this.examples = examples; } async refactorFile(codeToRefactor) { const chain = this.buildRefactorPrompt().pipe(this.model); const reflect = this.buildReflectionPrompt().pipe(this.model); const workflow = this.composeWorkflow(chain, reflect); const agent = workflow.compile(); const initialMessages = this.constructInitialMessages(codeToRefactor); const messages = await agent.invoke(initialMessages); return messages.slice(-1)[0].content; } buildRefactorPrompt() { return prompts_1.ChatPromptTemplate.fromMessages([ prompts_3.SystemMessagePromptTemplate.fromTemplate(this.prompt), new prompts_2.MessagesPlaceholder('messages'), ]); } buildReflectionPrompt() { const reflectionMessage = `You are a senior developer reviewing a pull request. Provide detailed recommendations, including adherence to guidelines and ensuring no breaking changes.`; return prompts_1.ChatPromptTemplate.fromMessages([ prompts_3.HumanMessagePromptTemplate.fromTemplate(reflectionMessage), new prompts_2.MessagesPlaceholder('messages'), ]); } composeWorkflow(chain, reflect) { const workflow = new langgraph_1.MessageGraph(); workflow.addNode('generate', this.createGenerationNode(chain)); workflow.addNode('reflect', this.createReflectionNode(reflect)); workflow.setEntryPoint('generate'); workflow.addConditionalEdges('generate', this.determineContinuation); workflow.addEdge('reflect', 'generate'); return workflow; } createGenerationNode(chain) { return async (messages, config) => [ await chain.invoke({ messages, codingStyles: this.codingStyles, examples: this.examples, role: this.role, }, config), ]; } createReflectionNode(reflect) { return async (messages, config) => { const clsMap = { ai: messages_1.HumanMessage, human: messages_1.AIMessage }; const translated = messages.map((msg, i) => i === 0 ? msg : new clsMap[msg._getType()](msg.content)); const res = await reflect.invoke({ messages: translated }, config); return [new messages_1.HumanMessage(res.content)]; }; } determineContinuation(messages) { return messages.length > 6 ? langgraph_1.END : 'reflect'; } constructInitialMessages(codeToRefactor) { const initialMessageContent = `Refactor the following code and respond directly to this message with the refactored code without adding markdown around. Here is the code to refactor:`; return [ new messages_1.HumanMessage(initialMessageContent), new messages_1.HumanMessage(codeToRefactor), ]; } } exports.CodeLinterAgent = CodeLinterAgent; /***/ }), /* 35 */ /***/ ((module) => { module.exports = require("@langchain/langgraph"); /***/ }), /* 36 */ /***/ ((module) => { module.exports = require("@langchain/core/messages"); /***/ }), /* 37 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { var _a, _b, _c, _d, _e; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CodeLinterAlphaCommand = void 0; const tslib_1 = __webpack_require__(3); const fs = tslib_1.__importStar(__webpack_require__(7)); const nest_commander_1 = __webpack_require__(8); const cli_utils_1 = __webpack_require__(9); const cli_config_service_1 = __webpack_require__(24); const code_linter_agent_service_1 = __webpack_require__(33); let CodeLinterAlphaCommand = class CodeLinterAlphaCommand extends nest_commander_1.CommandRunner { constructor(configService, codeLinterAgent, modelBuilderService, fileManager, loaderService) { super(); this.configService = configService; this.codeLinterAgent = codeLinterAgent; this.modelBuilderService = modelBuilderService; this.fileManager = fileManager; this.loaderService = loaderService; } async run(_params, options) { const config = await this.configService.loadConfig(options.config); if (!config) { console.warn('Failed to load configuration.\nPlease run `code-artisan init` to initialize CodeArtisan.'); return; } if (!this.configService.validate(config)) { console.error('Fix your configuration file.'); return; } if (Object.keys(config.experts).length === 0) { console.error('No experts configured.'); return; } const expertName = options.expert || Object.keys(config.experts)[0]; const expertConfig = config.experts[expertName]; if (!expertConfig) { console.error(`Expert '${expertName}' not found.`); return; } console.log(`Processing files with '${expertName}' expert configurations...`); const prompt = this.configService.loadPrompt(); const codingStyles = await this.configService.loadCodingStyles(expertConfig); const examples = await this.configService.loadExamples(expertConfig); let filePaths = _params; if (!filePaths.length) { filePaths = await (0, cli_utils_1.getChangedFiles)(options.commitDiff || undefined); } else { filePaths = await this.fileManager.getFiles(filePaths); } filePaths = filePaths.filter((filePath) => expertConfig.pattern .split(',') .some((p) => filePath.endsWith(p.trim()))); const fileContents = await this.loadFilesContent(filePaths); if (Object.keys(fileContents).length !== 1) { console.error('Please provide a single file to refactor.'); return; } const modelConfig = config.model || { type: 'OpenAI', name: 'gpt-4-1106-preview', options: { temperature: 0, }, }; const model = await this.modelBuilderService.buildModel(modelConfig.type, modelConfig.name, modelConfig.options); const load = this.loaderService.createLoader({ text: 'Refactoring...' }); const newFileContents = await this.codeLinterAgent.refactorFile(model, fileContents, { prompt, role: expertConfig.role, codingStyles: codingStyles.join('\n'), examples: examples.join('\n'), }); await this.writeNewContents(newFileContents); load.stop(); } async loadFilesContent(filePaths) { const contents = {}; for (const filePath of filePaths) { contents[filePath] = await (0, cli_utils_1.loadTextFile)(filePath); } return contents; } async writeNewContents(newFileContents) { for (const [filePath, content] of Object.entries(newFileContents)) { fs.writeFileSync(filePath, content.replace(/^```.*\n/, '').replace(/\n```$/, '\n')); } } parseCommitDiff(val) { return val; } parseConfig(val) { return val; } parseExpert(val) { return val; } }; exports.CodeLinterAlphaCommand = CodeLinterAlphaCommand; tslib_1.__decorate([ (0, nest_commander_1.Option)({ flags: '-c, --commit-diff [commitDiff]', description: 'The commit diff to use for the refactor', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], CodeLinterAlphaCommand.prototype, "parseCommitDiff", null); tslib_1.__decorate([ (0, nest_commander_1.Option)({ flags: '--config [path]', description: 'Path to a custom CodeArtisan configuration file', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], CodeLinterAlphaCommand.prototype, "parseConfig", null); tslib_1.__decorate([ (0, nest_commander_1.Option)({ flags: '--expert [name]', description: 'Specify the expert to use for linting', }), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], CodeLinterAlphaCommand.prototype, "parseExpert", null); exports.CodeLinterAlphaCommand = CodeLinterAlphaCommand = tslib_1.__decorate([ (0, nest_commander_1.Command)({ name: 'code-linter-alpha', description: 'Code Linter Alpha Command', }), tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof cli_config_service_1.CliConfigService !== "undefined" && cli_config_service_1.CliConfigService) === "function" ? _a : Object, typeof (_b = typeof code_linter_agent_service_1.CodeLinterAgentService !== "undefined" && code_linter_agent_service_1.CodeLinterAgentService) === "function" ? _b : Object, typeof (_c = typeof cli_utils_1.ModelBuilderService !== "undefined" && cli_utils_1.ModelBuilderService) === "function" ? _c : Object, typeof (_d = typeof cli_utils_1.FileManagerService !== "undefined" && cli_utils_1.FileManagerService) === "function" ? _d : Object, typeof (_e = typeof cli_utils_1.LoaderService !== "undefined" && cli_utils_1.LoaderService) === "function" ? _e : Object]) ], CodeLinterAlphaCommand); /***/ }) /******/ ]); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { var exports = __webpack_exports__; //#!/usr/bin/env node Object.defineProperty(exports, "__esModule", ({ value: true })); __webpack_require__(1); const app_module_1 = __webpack_require__(2); const nest_commander_1 = __webpack_require__(8); async function bootstrap() { await nest_commander_1.CommandFactory.run(app_module_1.AppModule); } bootstrap(); })(); var __webpack_export_target__ = exports; for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i]; if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true }); /******/ })() ;