From 65da1dc30119ce2bb43ef5a4e4226812e6b796cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Thu, 28 Aug 2025 10:53:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9C=A8aicommits=E4=B8=AD=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=8F=90=E4=BA=A4=E3=80=81=E6=8E=A8=E9=80=81=E3=80=81?= =?UTF-8?q?=E9=87=8D=E5=86=99=E5=92=8C=E5=8F=96=E6=B6=88=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/aicommits.ts | 142 +++++++++++++++++++----- src/commands/prepare-commit-msg-hook.ts | 2 +- 2 files changed, 118 insertions(+), 26 deletions(-) diff --git a/src/commands/aicommits.ts b/src/commands/aicommits.ts index faf49fb..f7fae47 100644 --- a/src/commands/aicommits.ts +++ b/src/commands/aicommits.ts @@ -61,7 +61,7 @@ export default async ( }); const s = spinner(); - s.start('The AI is analyzing your changes'); + s.start('正在分析您的更改'); let messages: string[]; try { messages = await generateCommitMessage( @@ -84,34 +84,126 @@ export default async ( throw new KnownError('No commit messages were generated. Try again.'); } - let message: string; - if (messages.length === 1) { - [message] = messages; - const confirmed = await confirm({ - message: `Use this commit message?\n\n ${message}\n`, + // 处理单个或多个提交消息的函数 + const handleCommitAction = async (msg: string, isSingleMessage: boolean = true) => { + const action = await select({ + message: isSingleMessage ? `使用此提交消息?\n\n ${msg}\n` : '选择操作:', + options: [ + { label: '提交', value: 'commit' }, + { label: '提交并推送', value: 'commit-and-push' }, + { label: '重写', value: 'rewrite' }, + { label: '取消', value: 'cancel' }, + ], }); - - if (!confirmed || isCancel(confirmed)) { - outro('Commit cancelled'); - return; + + if (isCancel(action) || action === 'cancel') { + outro('提交已取消'); + return false; } - } else { - const selected = await select({ - message: `Pick a commit message to use: ${dim('(Ctrl+c to exit)')}`, - options: messages.map((value) => ({ label: value, value })), - }); - - if (isCancel(selected)) { - outro('Commit cancelled'); - return; + + if (action === 'rewrite') { + return 'rewrite'; + } + + if (action === 'commit') { + await execa('git', ['commit', '-m', msg, ...rawArgv]); + outro(`${green('✔')} 提交成功!`); + return true; + } else if (action === 'commit-and-push') { + await execa('git', ['commit', '-m', msg, ...rawArgv]); + const pushSpinner = spinner(); + pushSpinner.start('正在推送到远程仓库...'); + try { + await execa('git', ['push']); + pushSpinner.stop('推送成功'); + outro(`${green('✔')} 提交并推送成功!`); + return true; + } catch (error) { + pushSpinner.stop('推送失败'); + outro(`${red('✖')} 提交成功但推送失败: ${(error as Error).message}`); + return true; + } + } + return false; + }; + + // 重新生成提交消息的函数 + const regenerateMessages = async () => { + const s = spinner(); + s.start('正在重新生成提交消息...'); + try { + const config = await getConfig({ + OPENAI_KEY: env.OPENAI_KEY || env.OPENAI_API_KEY, + proxy: + env.https_proxy || env.HTTPS_PROXY || env.http_proxy || env.HTTP_PROXY, + generate: generate?.toString(), + type: commitType?.toString(), + }); + + const newMessages = await generateCommitMessage( + config.OPENAI_KEY, + config.model, + config.locale, + staged.diff, + config.generate, + config['max-length'], + config.type, + config.timeout, + config.proxy, + config.baseURL + ); + + s.stop('已重新生成提交消息'); + + if (newMessages.length === 0) { + throw new KnownError('没有重新生成提交消息。请重试。'); + } + + return newMessages; + } catch (error) { + s.stop('重新生成失败'); + throw error; + } + }; + + // 处理消息选择和提交的主循环 + let currentMessages = messages; + while (true) { + let message: string; + + if (currentMessages.length === 1) { + [message] = currentMessages; + const result = await handleCommitAction(message, true); + + if (result === 'rewrite') { + currentMessages = await regenerateMessages(); + continue; + } else if (result === true || result === false) { + return; + } + } else { + const selected = await select({ + message: `选择一个提交消息: ${dim('(Ctrl+c 退出)')}`, + options: currentMessages.map((value) => ({ label: value, value })), + }); + + if (isCancel(selected)) { + outro('提交已取消'); + return; + } + + message = selected as string; + const result = await handleCommitAction(message, false); + + if (result === 'rewrite') { + currentMessages = await regenerateMessages(); + continue; + } else if (result === true || result === false) { + return; + } } - - message = selected as string; } - - await execa('git', ['commit', '-m', message, ...rawArgv]); - - outro(`${green('✔')} Successfully committed!`); + })().catch((error) => { outro(`${red('✖')} ${error.message}`); handleCliError(error); diff --git a/src/commands/prepare-commit-msg-hook.ts b/src/commands/prepare-commit-msg-hook.ts index 234b687..6d8f5af 100644 --- a/src/commands/prepare-commit-msg-hook.ts +++ b/src/commands/prepare-commit-msg-hook.ts @@ -36,7 +36,7 @@ export default () => }); const s = spinner(); - s.start('The AI is analyzing your changes'); + s.start('正在分析您的更改'); let messages: string[]; try { messages = await generateCommitMessage(