85 lines
2.1 KiB
TypeScript
85 lines
2.1 KiB
TypeScript
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 | undefined,
|
|
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({
|
|
OPENAI_KEY: process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY,
|
|
generate: generate?.toString(),
|
|
});
|
|
|
|
const s = spinner();
|
|
s.start('The AI is analyzing your changes');
|
|
const messages = await generateCommitMessage(
|
|
config.OPENAI_KEY,
|
|
config.locale,
|
|
staged.diff,
|
|
config.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);
|
|
});
|