import { execa } from 'execa'; import { black, dim, green, red, bgCyan, } from 'kolorist'; import { intro, outro, spinner, select, confirm, isCancel, } from '@clack/prompts'; import { assertGitRepo, getStagedDiff, getDetectedMessage, } from '../utils/git.js'; import { getConfig } from '../utils/config.js'; import { generateCommitMessage } from '../utils/openai.js'; import { KnownError, handleCliError } from '../utils/error.js'; export default async ( generate: number, rawArgv: string[], ) => (async () => { intro(bgCyan(black(' aicommits '))); await assertGitRepo(); const detectingFiles = spinner(); detectingFiles.start('Detecting staged files'); const staged = await getStagedDiff(); if (!staged) { throw new KnownError('No staged changes found. Make sure to stage your changes with `git add`.'); } detectingFiles.stop(`${getDetectedMessage(staged.files)}:\n${ staged.files.map(file => ` ${file}`).join('\n') }`); const config = await getConfig(); const OPENAI_KEY = process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY ?? config.OPENAI_KEY; if (!OPENAI_KEY) { throw new KnownError('Please set your OpenAI API key via `aicommits config set OPENAI_KEY=`'); } const s = spinner(); s.start('The AI is analyzing your changes'); const messages = await generateCommitMessage( OPENAI_KEY, staged.diff, generate, ); s.stop('Changes analyzed'); let message: string; if (messages.length === 1) { [message] = messages; const confirmed = await confirm({ message: `Use this commit message?\n\n ${message}\n`, }); if (!confirmed || isCancel(confirmed)) { outro('Commit cancelled'); return; } } 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; } message = selected; } await execa('git', ['commit', '-m', message, ...rawArgv]); outro(`${green('✔')} Successfully committed!`); })().catch((error) => { outro(`${red('✖')} ${error.message}`); handleCliError(error); process.exit(1); });