@gilbert_oliveira/commit-wizard 2.12.3-canary.1 → 2.12.3-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/core/index.ts CHANGED
@@ -1,385 +1,3 @@
1
- import { log } from '@clack/prompts';
2
- import { loadConfig, validateConfig } from '../config/index';
3
- import {
4
- isGitRepository,
5
- getGitStatus,
6
- getDiffStats,
7
- executeCommit,
8
- executeFileCommit,
9
- } from '../git/index';
10
- import { generateWithRetry } from './openai';
11
- import {
12
- showCommitPreview,
13
- editCommitMessage,
14
- copyToClipboard,
15
- showCommitResult,
16
- showCancellation,
17
- selectFilesForCommit,
18
- askContinueCommits,
19
- } from '../ui/index';
20
- import { chooseSplitMode } from '../ui/smart-split';
21
- import { handleSmartSplitMode } from './smart-split';
22
- import { initializeCache } from './cache';
23
- import type { CLIArgs } from '../utils/args';
24
- import type { Config } from '../config/index';
25
-
26
- export async function main(
27
- args: CLIArgs = {
28
- silent: false,
29
- yes: false,
30
- auto: false,
31
- split: false,
32
- smartSplit: false,
33
- dryRun: false,
34
- help: false,
35
- version: false,
36
- }
37
- ) {
38
- if (!args.silent) {
39
- log.info('🚀 Commit Wizard iniciado!');
40
- }
41
-
42
- // Verificar se estamos em um repositório Git
43
- if (!isGitRepository()) {
44
- log.error('❌ Não foi encontrado um repositório Git neste diretório.');
45
- if (!args.silent) {
46
- log.info(
47
- '💡 Execute o comando em um diretório com repositório Git inicializado.'
48
- );
49
- }
50
- process.exit(1);
51
- }
52
-
53
- // Carregar e validar configuração
54
- if (!args.silent) {
55
- log.info('⚙️ Carregando configuração...');
56
- }
57
- const config = loadConfig();
58
-
59
- // Inicializar cache global
60
- initializeCache(config);
61
-
62
- // Sobrescrever configuração com argumentos CLI
63
- if (args.split) {
64
- config.splitCommits = true;
65
- }
66
- if (args.dryRun) {
67
- config.dryRun = true;
68
- }
69
-
70
- const configErrors = validateConfig(config);
71
-
72
- if (configErrors.length > 0) {
73
- log.error('❌ Erros na configuração:');
74
- configErrors.forEach((error) => log.error(` • ${error}`));
75
- process.exit(1);
76
- }
77
-
78
- if (!args.silent) {
79
- log.success(
80
- `✅ Configuração carregada (modelo: ${config.openai.model}, idioma: ${config.language})`
81
- );
82
- }
83
-
84
- // Verificar arquivos staged
85
- if (!args.silent) {
86
- log.info('📋 Verificando arquivos staged...');
87
- }
88
- const gitStatus = getGitStatus();
89
-
90
- if (!gitStatus.hasStaged) {
91
- log.warn('⚠️ Nenhum arquivo foi encontrado no stage.');
92
- if (!args.silent) {
93
- log.info(
94
- '💡 Use `git add <arquivo>` para adicionar arquivos ao stage antes de gerar o commit.'
95
- );
96
- }
97
- process.exit(0);
98
- }
99
-
100
- const diffStats = getDiffStats();
101
- if (!args.silent) {
102
- log.success(
103
- `✅ Encontrados ${gitStatus.stagedFiles.length} arquivo(s) staged:`
104
- );
105
- gitStatus.stagedFiles.forEach((file) => log.info(` 📄 ${file}`));
106
- log.info(
107
- `📊 Estatísticas: +${diffStats.added} -${diffStats.removed} linhas`
108
- );
109
- }
110
-
111
- // Modo Split: escolher entre smart split e split manual
112
- if (config.splitCommits || args.smartSplit) {
113
- if (args.yes) {
114
- // Modo automático: usar smart split
115
- return await handleSmartSplitMode(gitStatus, config, args);
116
- } else {
117
- // Modo interativo: perguntar qual tipo de split
118
- const splitAction = await chooseSplitMode();
119
-
120
- switch (splitAction.action) {
121
- case 'proceed':
122
- return await handleSmartSplitMode(gitStatus, config, args);
123
- case 'manual':
124
- return await handleSplitMode(gitStatus, config, args);
125
- case 'cancel':
126
- showCancellation();
127
- return;
128
- }
129
- }
130
- }
131
-
132
- // Gerar mensagem de commit com OpenAI
133
- if (!args.silent) {
134
- log.info('🤖 Gerando mensagem de commit com IA...');
135
- }
136
-
137
- const result = await generateWithRetry(
138
- gitStatus.diff,
139
- config,
140
- gitStatus.stagedFiles
141
- );
142
-
143
- if (!result.success) {
144
- log.error(`❌ Erro ao gerar commit: ${result.error}`);
145
- process.exit(1);
146
- }
147
-
148
- if (!result.suggestion) {
149
- log.error('❌ Nenhuma sugestão foi gerada');
150
- process.exit(1);
151
- }
152
-
153
- if (!args.silent) {
154
- log.success('✨ Mensagem de commit gerada!');
155
- }
156
-
157
- // Modo Dry Run: apenas mostrar mensagem
158
- if (config.dryRun) {
159
- log.info('🔍 Modo Dry Run - Mensagem gerada:');
160
- log.info(`"${result.suggestion.message}"`);
161
- log.info('💡 Execute sem --dry-run para fazer o commit');
162
- return;
163
- }
164
-
165
- // Modo automático: commit direto
166
- if (args.yes) {
167
- const commitResult = executeCommit(result.suggestion.message);
168
- showCommitResult(
169
- commitResult.success,
170
- commitResult.hash,
171
- commitResult.error
172
- );
173
- return;
174
- }
175
-
176
- // Interface interativa
177
- while (true) {
178
- const uiAction = await showCommitPreview(result.suggestion);
179
-
180
- switch (uiAction.action) {
181
- case 'commit': {
182
- // Commit direto com mensagem gerada
183
- const commitResult = executeCommit(result.suggestion.message);
184
- showCommitResult(
185
- commitResult.success,
186
- commitResult.hash,
187
- commitResult.error
188
- );
189
- return;
190
- }
191
- case 'edit': {
192
- // Editar mensagem
193
- const editAction = await editCommitMessage(result.suggestion.message);
194
- if (editAction.action === 'cancel') {
195
- showCancellation();
196
- return;
197
- }
198
- if (editAction.action === 'commit' && editAction.message) {
199
- const editCommitResult = executeCommit(editAction.message);
200
- showCommitResult(
201
- editCommitResult.success,
202
- editCommitResult.hash,
203
- editCommitResult.error
204
- );
205
- return;
206
- }
207
- break;
208
- }
209
- case 'copy': {
210
- // Copiar para clipboard
211
- await copyToClipboard(result.suggestion.message);
212
- if (!args.silent) {
213
- log.info(
214
- '🎯 Você pode usar a mensagem copiada com: git commit -m "mensagem"'
215
- );
216
- }
217
- return;
218
- }
219
- case 'cancel': {
220
- // Cancelar operação
221
- showCancellation();
222
- return;
223
- }
224
- }
225
- }
226
- }
227
-
228
- async function handleSplitMode(gitStatus: any, config: any, args: CLIArgs) {
229
- if (!args.silent) {
230
- log.info('🔄 Modo Split ativado - Commits separados por arquivo');
231
- }
232
-
233
- let remainingFiles = [
234
- ...(gitStatus as { stagedFiles: string[] }).stagedFiles,
235
- ];
236
-
237
- while (remainingFiles.length > 0) {
238
- // Selecionar arquivos para este commit
239
- const selectedFiles = args.yes
240
- ? [remainingFiles[0]] // Modo automático: um arquivo por vez
241
- : await selectFilesForCommit(remainingFiles);
242
-
243
- if (selectedFiles.length === 0) {
244
- if (!args.silent) {
245
- log.info('❌ Nenhum arquivo selecionado');
246
- }
247
- break;
248
- }
249
-
250
- // Gerar diff apenas dos arquivos selecionados
251
- const { getFileDiff } = await import('../git/index');
252
- const fileDiffs = selectedFiles
253
- .filter((file): file is string => file !== undefined)
254
- .map((file) => {
255
- try {
256
- return getFileDiff(file);
257
- } catch (error) {
258
- log.error(
259
- `❌ Erro ao obter diff do arquivo ${file}: ${error instanceof Error ? error.message : 'Erro desconhecido'}`
260
- );
261
- return '';
262
- }
263
- })
264
- .filter((diff) => diff.length > 0)
265
- .join('\n');
266
-
267
- if (!fileDiffs) {
268
- if (!args.silent) {
269
- log.warn('⚠️ Nenhum diff encontrado para os arquivos selecionados');
270
- }
271
- remainingFiles = remainingFiles.filter(
272
- (file) => !selectedFiles.includes(file)
273
- );
274
- continue;
275
- }
276
-
277
- if (!args.silent) {
278
- log.info(`🤖 Gerando commit para: ${selectedFiles.join(', ')}`);
279
- }
280
-
281
- const result = await generateWithRetry(
282
- fileDiffs,
283
- config,
284
- selectedFiles.filter((file): file is string => file !== undefined)
285
- );
286
-
287
- if (!result.success) {
288
- log.error(`❌ Erro ao gerar commit: ${result.error}`);
289
- remainingFiles = remainingFiles.filter(
290
- (file) => !selectedFiles.includes(file)
291
- );
292
- continue;
293
- }
294
-
295
- if (!result.suggestion) {
296
- log.error('❌ Nenhuma sugestão foi gerada');
297
- remainingFiles = remainingFiles.filter(
298
- (file) => !selectedFiles.includes(file)
299
- );
300
- continue;
301
- }
302
-
303
- // Modo Dry Run: apenas mostrar mensagem
304
- if ((config as Config).dryRun) {
305
- log.info(`🔍 Dry Run - Mensagem para ${selectedFiles.join(', ')}:`);
306
- log.info(`"${result.suggestion.message}"`);
307
- remainingFiles = remainingFiles.filter(
308
- (file) => !selectedFiles.includes(file)
309
- );
310
- continue;
311
- }
312
-
313
- // Modo automático: commit direto
314
- if (args.yes) {
315
- // Para múltiplos arquivos, usar commit normal
316
- // Para arquivo único, usar executeFileCommit
317
- const commitResult =
318
- selectedFiles.length === 1 && selectedFiles[0]
319
- ? await executeFileCommit(selectedFiles[0], result.suggestion.message)
320
- : await executeCommit(result.suggestion.message);
321
-
322
- showCommitResult(
323
- commitResult.success,
324
- commitResult.hash,
325
- commitResult.error
326
- );
327
- } else {
328
- // Interface interativa para este commit
329
- const uiAction = await showCommitPreview(result.suggestion);
330
-
331
- if (uiAction.action === 'commit') {
332
- const commitResult =
333
- selectedFiles.length === 1 && selectedFiles[0]
334
- ? await executeFileCommit(
335
- selectedFiles[0],
336
- result.suggestion.message
337
- )
338
- : await executeCommit(result.suggestion.message);
339
- showCommitResult(
340
- commitResult.success,
341
- commitResult.hash,
342
- commitResult.error
343
- );
344
- } else if (uiAction.action === 'edit') {
345
- const editAction = await editCommitMessage(result.suggestion.message);
346
- if (editAction.action === 'commit' && editAction.message) {
347
- const commitResult =
348
- selectedFiles.length === 1 && selectedFiles[0]
349
- ? await executeFileCommit(selectedFiles[0], editAction.message)
350
- : await executeCommit(editAction.message);
351
- showCommitResult(
352
- commitResult.success,
353
- commitResult.hash,
354
- commitResult.error
355
- );
356
- }
357
- } else if (uiAction.action === 'copy') {
358
- await copyToClipboard(result.suggestion.message);
359
- if (!args.silent) {
360
- log.info('🎯 Mensagem copiada para clipboard');
361
- }
362
- } else if (uiAction.action === 'cancel') {
363
- showCancellation();
364
- return;
365
- }
366
- }
367
-
368
- // Remover arquivos processados
369
- remainingFiles = remainingFiles.filter(
370
- (file) => !selectedFiles.includes(file)
371
- );
372
-
373
- // Perguntar se quer continuar (exceto em modo automático)
374
- if (remainingFiles.length > 0 && !args.yes) {
375
- const continueCommits = await askContinueCommits(remainingFiles);
376
- if (!continueCommits) {
377
- break;
378
- }
379
- }
380
- }
381
-
382
- if (!args.silent) {
383
- log.success('✅ Modo Split concluído!');
384
- }
385
- }
1
+ // Re-exports para compatibilidade retroativa.
2
+ // A lógica foi movida para src/commands/commit.ts na task 7.
3
+ export { runCommitCommand, main } from '../commands/commit';