diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 35f0d629..b1d32633 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -18,7 +18,7 @@ To get started, follow these steps: 1. Clone the project repository locally. 2. Install dependencies with `npm install`. 3. Run the project with `npm run dev`. -4. See [issues](https://github.com/di-sukharev/open-commit/issues) or [TODO.md](../TODO.md) to help the project. +4. See [issues](https://github.com/di-sukharev/opencommit/issues) or [TODO.md](../TODO.md) to help the project. ## Commit message guidelines @@ -30,7 +30,7 @@ If you encounter any issues while using the project, please report them on the G ## Contacts -If you have any questions about contributing to the project, please contact by [creating an issue](https://github.com/di-sukharev/open-commit/issues) on the GitHub issue tracker. +If you have any questions about contributing to the project, please contact by [creating an issue](https://github.com/di-sukharev/opencommit/issues) on the GitHub issue tracker. ## License diff --git a/out/cli.cjs b/out/cli.cjs index a4fe603b..8c67547c 100755 --- a/out/cli.cjs +++ b/out/cli.cjs @@ -44931,7 +44931,14 @@ var CONVENTIONAL_COMMIT_KEYWORDS = "Do not preface the commit with anything, exc var getCommitConvention = (fullGitMojiSpec) => config4.OCO_EMOJI ? fullGitMojiSpec ? FULL_GITMOJI_SPEC : GITMOJI_HELP : CONVENTIONAL_COMMIT_KEYWORDS; var getDescriptionInstruction = () => config4.OCO_DESCRIPTION ? `Add a short description of WHY the changes are done after the commit message. Don't start it with "This commit", just describe the changes.` : "Don't add any descriptions to the commit, only commit message."; var getOneLineCommitInstruction = () => config4.OCO_ONE_LINE_COMMIT ? "Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change." : ""; -var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec) => ({ +var userInputCodeContext = (context) => { + if (context !== "" && context !== " ") { + return `Additional context provided by the user: ${context} +Consider this context when generating the commit message, incorporating relevant information when appropriate.`; + } + return ""; +}; +var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec, context) => ({ role: "system", content: (() => { const commitConvention = fullGitMojiSpec ? "GitMoji specification" : "Conventional Commit Convention"; @@ -44941,12 +44948,14 @@ var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec) => ({ const descriptionGuideline = getDescriptionInstruction(); const oneLineCommitGuideline = getOneLineCommitInstruction(); const generalGuidelines = `Use the present tense. Lines must not be longer than 74 characters. Use ${language} for the commit message.`; + const userInputContext = userInputCodeContext(context); return `${missionStatement} ${diffInstruction} ${conventionGuidelines} ${descriptionGuideline} ${oneLineCommitGuideline} -${generalGuidelines}`; +${generalGuidelines} +${userInputContext}`; })() }); var INIT_DIFF_PROMPT = { @@ -44988,7 +44997,7 @@ var INIT_CONSISTENCY_PROMPT = (translation4) => ({ role: "assistant", content: getContent(translation4) }); -var getMainCommitPrompt = async (fullGitMojiSpec) => { +var getMainCommitPrompt = async (fullGitMojiSpec, context) => { switch (config4.OCO_PROMPT_MODULE) { case "@commitlint": if (!await commitlintLLMConfigExists()) { @@ -45010,7 +45019,7 @@ var getMainCommitPrompt = async (fullGitMojiSpec) => { ]; default: return [ - INIT_MAIN_PROMPT2(translation3.localLanguage, fullGitMojiSpec), + INIT_MAIN_PROMPT2(translation3.localLanguage, fullGitMojiSpec, context), INIT_DIFF_PROMPT, INIT_CONSISTENCY_PROMPT(translation3) ]; @@ -45037,8 +45046,8 @@ function mergeDiffs(arr, maxStringLength) { var config5 = getConfig(); var MAX_TOKENS_INPUT = config5.OCO_TOKENS_MAX_INPUT; var MAX_TOKENS_OUTPUT = config5.OCO_TOKENS_MAX_OUTPUT; -var generateCommitMessageChatCompletionPrompt = async (diff, fullGitMojiSpec) => { - const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec); +var generateCommitMessageChatCompletionPrompt = async (diff, fullGitMojiSpec, context) => { + const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context); const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT]; chatContextAsCompletionRequest.push({ role: "user", @@ -45054,9 +45063,12 @@ var GenerateCommitMessageErrorEnum = ((GenerateCommitMessageErrorEnum2) => { return GenerateCommitMessageErrorEnum2; })(GenerateCommitMessageErrorEnum || {}); var ADJUSTMENT_FACTOR = 20; -var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false) => { +var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false, context = "") => { try { - const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec); + const INIT_MESSAGES_PROMPT = await getMainCommitPrompt( + fullGitMojiSpec, + context + ); const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map( (msg) => tokenCount(msg.content) + 4 ).reduce((a4, b7) => a4 + b7, 0); @@ -45076,7 +45088,8 @@ var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false) => { } const messages = await generateCommitMessageChatCompletionPrompt( diff, - fullGitMojiSpec + fullGitMojiSpec, + context ); const engine = getEngine(); const commitMessage = await engine.generateCommitMessage(messages); @@ -45283,6 +45296,7 @@ var checkMessageTemplate = (extraArgs2) => { var generateCommitMessageFromGitDiff = async ({ diff, extraArgs: extraArgs2, + context = "", fullGitMojiSpec = false, skipCommitConfirmation = false }) => { @@ -45292,7 +45306,8 @@ var generateCommitMessageFromGitDiff = async ({ try { let commitMessage = await generateCommitMessageByDiff( diff, - fullGitMojiSpec + fullGitMojiSpec, + context ); const messageTemplate = checkMessageTemplate(extraArgs2); if (config6.OCO_MESSAGE_TEMPLATE_PLACEHOLDER && typeof messageTemplate === "string") { @@ -45402,7 +45417,7 @@ ${source_default.grey("\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2 process.exit(1); } }; -async function commit(extraArgs2 = [], isStageAllFlag = false, fullGitMojiSpec = false, skipCommitConfirmation = false) { +async function commit(extraArgs2 = [], context = "", isStageAllFlag = false, fullGitMojiSpec = false, skipCommitConfirmation = false) { if (isStageAllFlag) { const changedFiles2 = await getChangedFiles(); if (changedFiles2) @@ -45433,7 +45448,7 @@ async function commit(extraArgs2 = [], isStageAllFlag = false, fullGitMojiSpec = if (hD2(isStageAllAndCommitConfirmedByUser)) process.exit(1); if (isStageAllAndCommitConfirmedByUser) { - await commit(extraArgs2, true, fullGitMojiSpec); + await commit(extraArgs2, context, true, fullGitMojiSpec); process.exit(1); } if (stagedFiles.length === 0 && changedFiles.length > 0) { @@ -45448,7 +45463,7 @@ async function commit(extraArgs2 = [], isStageAllFlag = false, fullGitMojiSpec = process.exit(1); await gitAdd({ files }); } - await commit(extraArgs2, false, fullGitMojiSpec); + await commit(extraArgs2, context, false, fullGitMojiSpec); process.exit(1); } stagedFilesSpinner.stop( @@ -45459,6 +45474,7 @@ ${stagedFiles.map((file) => ` ${file}`).join("\n")}` generateCommitMessageFromGitDiff({ diff: await getDiff({ files: stagedFiles }), extraArgs: extraArgs2, + context, fullGitMojiSpec, skipCommitConfirmation }) @@ -45817,6 +45833,12 @@ Z2( commands: [configCommand, hookCommand, commitlintConfigCommand], flags: { fgm: Boolean, + context: { + type: String, + alias: "c", + description: "Additional user input context for the commit message", + default: "" + }, yes: { type: Boolean, alias: "y", @@ -45833,7 +45855,7 @@ Z2( if (await isHookCalled()) { prepareCommitMessageHook(); } else { - commit(extraArgs, false, flags.fgm, flags.yes); + commit(extraArgs, flags.context, false, flags.fgm, flags.yes); } }, extraArgs diff --git a/out/github-action.cjs b/out/github-action.cjs index 5acd5e08..5140c41b 100644 --- a/out/github-action.cjs +++ b/out/github-action.cjs @@ -63732,7 +63732,14 @@ var CONVENTIONAL_COMMIT_KEYWORDS = "Do not preface the commit with anything, exc var getCommitConvention = (fullGitMojiSpec) => config4.OCO_EMOJI ? fullGitMojiSpec ? FULL_GITMOJI_SPEC : GITMOJI_HELP : CONVENTIONAL_COMMIT_KEYWORDS; var getDescriptionInstruction = () => config4.OCO_DESCRIPTION ? `Add a short description of WHY the changes are done after the commit message. Don't start it with "This commit", just describe the changes.` : "Don't add any descriptions to the commit, only commit message."; var getOneLineCommitInstruction = () => config4.OCO_ONE_LINE_COMMIT ? "Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change." : ""; -var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec) => ({ +var userInputCodeContext = (context2) => { + if (context2 !== "" && context2 !== " ") { + return `Additional context provided by the user: ${context2} +Consider this context when generating the commit message, incorporating relevant information when appropriate.`; + } + return ""; +}; +var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec, context2) => ({ role: "system", content: (() => { const commitConvention = fullGitMojiSpec ? "GitMoji specification" : "Conventional Commit Convention"; @@ -63742,12 +63749,14 @@ var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec) => ({ const descriptionGuideline = getDescriptionInstruction(); const oneLineCommitGuideline = getOneLineCommitInstruction(); const generalGuidelines = `Use the present tense. Lines must not be longer than 74 characters. Use ${language} for the commit message.`; + const userInputContext = userInputCodeContext(context2); return `${missionStatement} ${diffInstruction} ${conventionGuidelines} ${descriptionGuideline} ${oneLineCommitGuideline} -${generalGuidelines}`; +${generalGuidelines} +${userInputContext}`; })() }); var INIT_DIFF_PROMPT = { @@ -63789,7 +63798,7 @@ var INIT_CONSISTENCY_PROMPT = (translation4) => ({ role: "assistant", content: getContent(translation4) }); -var getMainCommitPrompt = async (fullGitMojiSpec) => { +var getMainCommitPrompt = async (fullGitMojiSpec, context2) => { switch (config4.OCO_PROMPT_MODULE) { case "@commitlint": if (!await commitlintLLMConfigExists()) { @@ -63811,7 +63820,7 @@ var getMainCommitPrompt = async (fullGitMojiSpec) => { ]; default: return [ - INIT_MAIN_PROMPT2(translation3.localLanguage, fullGitMojiSpec), + INIT_MAIN_PROMPT2(translation3.localLanguage, fullGitMojiSpec, context2), INIT_DIFF_PROMPT, INIT_CONSISTENCY_PROMPT(translation3) ]; @@ -63838,8 +63847,8 @@ function mergeDiffs(arr, maxStringLength) { var config5 = getConfig(); var MAX_TOKENS_INPUT = config5.OCO_TOKENS_MAX_INPUT; var MAX_TOKENS_OUTPUT = config5.OCO_TOKENS_MAX_OUTPUT; -var generateCommitMessageChatCompletionPrompt = async (diff, fullGitMojiSpec) => { - const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec); +var generateCommitMessageChatCompletionPrompt = async (diff, fullGitMojiSpec, context2) => { + const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context2); const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT]; chatContextAsCompletionRequest.push({ role: "user", @@ -63855,9 +63864,12 @@ var GenerateCommitMessageErrorEnum = ((GenerateCommitMessageErrorEnum2) => { return GenerateCommitMessageErrorEnum2; })(GenerateCommitMessageErrorEnum || {}); var ADJUSTMENT_FACTOR = 20; -var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false) => { +var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false, context2 = "") => { try { - const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec); + const INIT_MESSAGES_PROMPT = await getMainCommitPrompt( + fullGitMojiSpec, + context2 + ); const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map( (msg) => tokenCount(msg.content) + 4 ).reduce((a3, b3) => a3 + b3, 0); @@ -63877,7 +63889,8 @@ var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false) => { } const messages = await generateCommitMessageChatCompletionPrompt( diff, - fullGitMojiSpec + fullGitMojiSpec, + context2 ); const engine = getEngine(); const commitMessage = await engine.generateCommitMessage(messages); diff --git a/src/cli.ts b/src/cli.ts index 7d731d9f..fd07a907 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -20,6 +20,12 @@ cli( commands: [configCommand, hookCommand, commitlintConfigCommand], flags: { fgm: Boolean, + context: { + type: String, + alias: 'c', + description: 'Additional user input context for the commit message', + default: '' + }, yes: { type: Boolean, alias: 'y', @@ -37,7 +43,7 @@ cli( if (await isHookCalled()) { prepareCommitMessageHook(); } else { - commit(extraArgs, false, flags.fgm, flags.yes); + commit(extraArgs, flags.context, false, flags.fgm, flags.yes); } }, extraArgs diff --git a/src/commands/commit.ts b/src/commands/commit.ts index a26df269..0707ea94 100644 --- a/src/commands/commit.ts +++ b/src/commands/commit.ts @@ -39,6 +39,7 @@ const checkMessageTemplate = (extraArgs: string[]): string | false => { interface GenerateCommitMessageFromGitDiffParams { diff: string; extraArgs: string[]; + context?: string; fullGitMojiSpec?: boolean; skipCommitConfirmation?: boolean; } @@ -46,6 +47,7 @@ interface GenerateCommitMessageFromGitDiffParams { const generateCommitMessageFromGitDiff = async ({ diff, extraArgs, + context = '', fullGitMojiSpec = false, skipCommitConfirmation = false }: GenerateCommitMessageFromGitDiffParams): Promise => { @@ -56,7 +58,8 @@ const generateCommitMessageFromGitDiff = async ({ try { let commitMessage = await generateCommitMessageByDiff( diff, - fullGitMojiSpec + fullGitMojiSpec, + context ); const messageTemplate = checkMessageTemplate(extraArgs); @@ -135,8 +138,7 @@ ${chalk.grey('——————————————————')}` ]); pushSpinner.stop( - `${chalk.green('✔')} Successfully pushed all commits to ${ - remotes[0] + `${chalk.green('✔')} Successfully pushed all commits to ${remotes[0] }` ); @@ -197,6 +199,7 @@ ${chalk.grey('——————————————————')}` export async function commit( extraArgs: string[] = [], + context: string = '', isStageAllFlag: Boolean = false, fullGitMojiSpec: boolean = false, skipCommitConfirmation: boolean = false @@ -238,7 +241,7 @@ export async function commit( if (isCancel(isStageAllAndCommitConfirmedByUser)) process.exit(1); if (isStageAllAndCommitConfirmedByUser) { - await commit(extraArgs, true, fullGitMojiSpec); + await commit(extraArgs, context, true, fullGitMojiSpec); process.exit(1); } @@ -256,7 +259,7 @@ export async function commit( await gitAdd({ files }); } - await commit(extraArgs, false, fullGitMojiSpec); + await commit(extraArgs, context, false, fullGitMojiSpec); process.exit(1); } @@ -270,6 +273,7 @@ export async function commit( generateCommitMessageFromGitDiff({ diff: await getDiff({ files: stagedFiles }), extraArgs, + context, fullGitMojiSpec, skipCommitConfirmation }) diff --git a/src/generateCommitMessageFromGitDiff.ts b/src/generateCommitMessageFromGitDiff.ts index 8ba87407..546de68a 100644 --- a/src/generateCommitMessageFromGitDiff.ts +++ b/src/generateCommitMessageFromGitDiff.ts @@ -11,9 +11,10 @@ const MAX_TOKENS_OUTPUT = config.OCO_TOKENS_MAX_OUTPUT; const generateCommitMessageChatCompletionPrompt = async ( diff: string, - fullGitMojiSpec: boolean + fullGitMojiSpec: boolean, + context: string ): Promise> => { - const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec); + const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context); const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT]; @@ -36,10 +37,14 @@ const ADJUSTMENT_FACTOR = 20; export const generateCommitMessageByDiff = async ( diff: string, - fullGitMojiSpec: boolean = false + fullGitMojiSpec: boolean = false, + context: string = "" ): Promise => { try { - const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec); + const INIT_MESSAGES_PROMPT = await getMainCommitPrompt( + fullGitMojiSpec, + context + ); const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map( (msg) => tokenCount(msg.content as string) + 4 @@ -69,7 +74,8 @@ export const generateCommitMessageByDiff = async ( const messages = await generateCommitMessageChatCompletionPrompt( diff, - fullGitMojiSpec + fullGitMojiSpec, + context, ); const engine = getEngine(); diff --git a/src/prompts.ts b/src/prompts.ts index 6cc64b9f..78a5ecd7 100644 --- a/src/prompts.ts +++ b/src/prompts.ts @@ -111,9 +111,24 @@ const getOneLineCommitInstruction = () => ? 'Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change.' : ''; +/** + * Get the context of the user input + * @param extraArgs - The arguments passed to the command line + * @example + * $ oco -- This is a context used to generate the commit message + * @returns - The context of the user input + */ +const userInputCodeContext = (context: string) => { + if (context !== '' && context !== ' ') { + return `Additional context provided by the user: ${context}\nConsider this context when generating the commit message, incorporating relevant information when appropriate.`; + } + return ''; +}; + const INIT_MAIN_PROMPT = ( language: string, - fullGitMojiSpec: boolean + fullGitMojiSpec: boolean, + context: string ): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({ role: 'system', content: (() => { @@ -127,15 +142,16 @@ const INIT_MAIN_PROMPT = ( const descriptionGuideline = getDescriptionInstruction(); const oneLineCommitGuideline = getOneLineCommitInstruction(); const generalGuidelines = `Use the present tense. Lines must not be longer than 74 characters. Use ${language} for the commit message.`; + const userInputContext = userInputCodeContext(context); - return `${missionStatement}\n${diffInstruction}\n${conventionGuidelines}\n${descriptionGuideline}\n${oneLineCommitGuideline}\n${generalGuidelines}`; + return `${missionStatement}\n${diffInstruction}\n${conventionGuidelines}\n${descriptionGuideline}\n${oneLineCommitGuideline}\n${generalGuidelines}\n${userInputContext}`; })() }); export const INIT_DIFF_PROMPT: OpenAI.Chat.Completions.ChatCompletionMessageParam = - { - role: 'user', - content: `diff --git a/src/server.ts b/src/server.ts +{ + role: 'user', + content: `diff --git a/src/server.ts b/src/server.ts index ad4db42..f3b18a9 100644 --- a/src/server.ts +++ b/src/server.ts @@ -159,7 +175,7 @@ export const INIT_DIFF_PROMPT: OpenAI.Chat.Completions.ChatCompletionMessagePara +app.listen(process.env.PORT || PORT, () => { + console.log(\`Server listening on port \${PORT}\`); });` - }; +}; const getContent = (translation: ConsistencyPrompt) => { const fix = config.OCO_EMOJI @@ -185,7 +201,8 @@ const INIT_CONSISTENCY_PROMPT = ( }); export const getMainCommitPrompt = async ( - fullGitMojiSpec: boolean + fullGitMojiSpec: boolean, + context: string ): Promise> => { switch (config.OCO_PROMPT_MODULE) { case '@commitlint': @@ -207,14 +224,14 @@ export const getMainCommitPrompt = async ( INIT_DIFF_PROMPT, INIT_CONSISTENCY_PROMPT( commitLintConfig.consistency[ - translation.localLanguage + translation.localLanguage ] as ConsistencyPrompt ) ]; default: return [ - INIT_MAIN_PROMPT(translation.localLanguage, fullGitMojiSpec), + INIT_MAIN_PROMPT(translation.localLanguage, fullGitMojiSpec, context), INIT_DIFF_PROMPT, INIT_CONSISTENCY_PROMPT(translation) ];