@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
JavaScript
#!/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 });
/******/ })()
;