UNPKG

@elsikora/commitizen-plugin-commitlint-ai

Version:
177 lines (172 loc) 8.17 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var chalk = require('chalk'); var commitConfirmation = require('./services/commitConfirmation.js'); var commitlintConfig = require('./services/commitlintConfig.js'); var commitlintValidator = require('./services/commitlintValidator.js'); var index = require('./services/llm/index.js'); var prompts = require('./store/prompts.js'); var config = require('./services/llm/config.js'); async function Process(rules, prompts$1, inquirer) { prompts.setPromptConfig(prompts$1); // First, ask for LLM provider and API key await index.selectLLMProvider(inquirer); // Extract context from commitlint config const promptContext = commitlintConfig.extractLLMPromptContext(rules, prompts$1); // Check if manual mode is enabled in config const config$1 = config.getLLMConfig(); // If manual mode is enabled, skip AI generation and go straight to manual entry if (config$1 && config$1.mode === "manual") { console.log(chalk.blue("Using manual commit entry mode...")); } else { try { console.log(chalk.blue("Generating commit message with AI...")); // Generate commit message using LLM const commitConfig = await index.generateCommitMessage(promptContext); // Validate the commit message with commitlint and fix if needed const validatedCommitMessage = await commitlintValidator.validateAndFixCommitMessage(commitConfig, promptContext); // If validation returned null, it means we should switch to manual mode if (validatedCommitMessage === null) { console.log(chalk.yellow("Switching to manual commit entry after failed validation attempts.")); } else { console.log(chalk.green("AI generated commit message successfully!")); // Show the generated message to the user console.log("\n" + chalk.yellow("Generated commit message:")); console.log(chalk.white("-----------------------------------")); console.log(chalk.white(validatedCommitMessage)); console.log(chalk.white("-----------------------------------\n")); // Ask for confirmation const { confirmCommit } = await inquirer.prompt([ { // eslint-disable-next-line @elsikora-typescript/naming-convention default: true, message: "Do you want to proceed with this commit message?", name: "confirmCommit", type: "confirm", }, ]); if (confirmCommit) { return validatedCommitMessage; } else { console.log(chalk.yellow("AI generated message rejected. Switching to commit edit mode.")); const confirmedCommitMessage = await commitConfirmation.commitConfirmation(promptContext, { ...commitConfig, scope: extractCommitScope(validatedCommitMessage) }); return confirmedCommitMessage; // If user rejects the generated message, fall through to the manual entry option } } } catch (error) { // Only show error for AI mode errors, not when manual mode is intentionally used if (config$1?.mode !== "manual") { console.error(chalk.red("Error generating commit with AI:"), error); console.log(chalk.yellow("Falling back to manual commit entry...")); } } } // Fallback to regular prompts if LLM fails or in manual mode const commitQuestions = [ { choices: promptContext.typeEnum?.map((type) => { const desc = promptContext.typeDescriptions?.[type]?.description ?? ""; const emoji = promptContext.typeDescriptions?.[type]?.emoji ?? ""; // Remove emoji from description if it already appears at the beginning let cleanDesc = desc; if (emoji && desc.startsWith(emoji)) { cleanDesc = desc.slice(emoji.length).trim(); } return { name: type + (emoji ? " " + emoji : "") + ": " + cleanDesc, value: type, }; }) ?? [], message: promptContext.typeDescription ?? "Select the type of change that you're committing:", name: "type", type: "list", }, { message: promptContext.scopeDescription ?? 'What is the scope of this change:\n - Use component, directory or area of codebase\n - Use comma-separated list for multiple areas\n - Type "global" for project-wide changes\n - Press enter to skip if scope is not applicable', name: "scope", type: "input", }, { message: promptContext.subject.description ?? "Write a short, imperative mood description of the change:", name: "subject", type: "input", // eslint-disable-next-line @elsikora-sonar/function-return-type validate: (input) => { if (!input) return "Subject is required"; return true; }, }, { message: promptContext.body?.description ?? "Provide a longer description of the change: (press enter to skip)", name: "body", type: "input", }, { // eslint-disable-next-line @elsikora-typescript/naming-convention default: false, message: "Are there any breaking changes?", name: "isBreaking", type: "confirm", }, { message: "Describe the breaking changes:", name: "breakingBody", type: "input", // eslint-disable-next-line @elsikora-typescript/no-unsafe-return when: (answers) => answers.isBreaking, }, ]; // First get all commit details // @ts-ignore const answers = await inquirer.prompt(commitQuestions); // Construct message from manual answers // eslint-disable-next-line @elsikora-typescript/no-unsafe-argument,@elsikora-typescript/restrict-plus-operands const header = "".concat(answers.type, answers.scope ? "(" + answers.scope + ")" : "", ": ", answers.subject); let body = ""; if (answers.isBreaking) { // eslint-disable-next-line @elsikora-typescript/restrict-template-expressions body = `BREAKING CHANGE: ${answers.breakingBody || "This commit introduces breaking changes."}\n\n`; } if (answers.body) { // eslint-disable-next-line @elsikora-typescript/restrict-plus-operands body += answers.body; } const commitMessage = [header, body].filter(Boolean).join("\n\n"); // Display the commit message to the user console.log("\n" + chalk.yellow("Your commit message:")); console.log(chalk.white("-----------------------------------")); console.log(chalk.white(commitMessage)); console.log(chalk.white("-----------------------------------\n")); // Now ask for confirmation const { confirmCommit } = await inquirer.prompt([ { // eslint-disable-next-line @elsikora-typescript/naming-convention default: true, message: "Are you sure you want to proceed with the commit above?", name: "confirmCommit", type: "confirm", }, ]); // Check confirmation if (!confirmCommit) { console.log(chalk.yellow("Commit canceled.")); throw new Error("User canceled the commit"); } return commitMessage; } function extractCommitScope(commitMessage) { const scopeRegex = /^[^(\n]+(\([^)\n]+\))?:/; const match = scopeRegex.exec(commitMessage); if (match?.[1]) { return match[1].slice(1, -1); } return ""; } exports.default = Process; //# sourceMappingURL=Process.js.map