@gilbert_oliveira/commit-wizard 1.0.26 → 1.1.0
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/README.md +208 -35
- package/dist/ai-service.d.ts +36 -0
- package/dist/ai-service.js +156 -0
- package/dist/ai-service.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.js +84 -0
- package/dist/config.js.map +1 -0
- package/dist/diff-processor.d.ts +39 -0
- package/dist/diff-processor.js +156 -0
- package/dist/diff-processor.js.map +1 -0
- package/dist/git-utils.d.ts +52 -0
- package/dist/git-utils.js +156 -0
- package/dist/git-utils.js.map +1 -0
- package/dist/index.d.ts +2 -16
- package/dist/index.js +322 -207
- package/dist/index.js.map +1 -1
- package/package.json +40 -4
- package/src/index.ts +0 -279
- package/tsconfig.json +0 -24
package/README.md
CHANGED
|
@@ -1,80 +1,253 @@
|
|
|
1
|
-
# Commit Wizard
|
|
1
|
+
# 🧙♂️ Commit Wizard
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/%40gilbert_oliveira%2Fcommit-wizard)
|
|
4
|
+
[](https://github.com/gilbert-oliveira/commit-wizard/actions/workflows/ci.yml)
|
|
5
|
+
[](https://codecov.io/gh/gilbert-oliveira/commit-wizard)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
2
7
|
|
|
3
8
|
Gere mensagens de commit convencionais automaticamente com base nas alterações no código usando a API da OpenAI.
|
|
4
9
|
|
|
5
|
-
## ✨
|
|
10
|
+
## ✨ Funcionalidades
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
- 🤖 **Geração inteligente de commits** usando GPT-4o/GPT-4o Mini
|
|
13
|
+
- 📝 **Convenção de Conventional Commits** automática
|
|
14
|
+
- 🌍 **Suporte multilíngue** (Português e Inglês)
|
|
15
|
+
- ⚙️ **Configuração flexível** (local e global)
|
|
16
|
+
- 📊 **Análise de complexidade** do diff
|
|
17
|
+
- 🚀 **Auto commit** opcional
|
|
18
|
+
- 😀 **Emojis** opcionais nas mensagens
|
|
19
|
+
- 🔄 **Regeneração** de mensagens
|
|
20
|
+
- 📋 **Cópia para clipboard**
|
|
21
|
+
- 🎯 **Detecção de breaking changes**
|
|
22
|
+
- 🧪 **Cobertura de testes** completa
|
|
8
23
|
|
|
9
24
|
## 🚀 Instalação
|
|
10
25
|
|
|
26
|
+
### Global (Recomendado)
|
|
11
27
|
```bash
|
|
12
|
-
npm install -g commit-wizard
|
|
28
|
+
npm install -g @gilbert_oliveira/commit-wizard
|
|
13
29
|
```
|
|
14
30
|
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
### Local
|
|
17
32
|
```bash
|
|
18
|
-
npm install
|
|
33
|
+
npm install @gilbert_oliveira/commit-wizard
|
|
19
34
|
```
|
|
20
35
|
|
|
21
36
|
## ⚙️ Configuração
|
|
22
37
|
|
|
23
|
-
|
|
38
|
+
### 1. API Key da OpenAI
|
|
39
|
+
Defina sua chave da OpenAI como variável de ambiente:
|
|
24
40
|
|
|
25
41
|
```bash
|
|
26
42
|
export OPENAI_API_KEY=sk-...
|
|
27
43
|
```
|
|
28
44
|
|
|
29
|
-
|
|
45
|
+
Adicione isso no seu `.bashrc`, `.zshrc` ou arquivo de ambiente equivalente.
|
|
46
|
+
|
|
47
|
+
### 2. Configuração do Wizard
|
|
48
|
+
Execute o comando de configuração para personalizar o comportamento:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
commit-wizard --config
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Ou crie um arquivo `.commit-wizard.json` no seu projeto ou diretório home:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"model": "gpt-4o",
|
|
59
|
+
"temperature": 0.2,
|
|
60
|
+
"maxTokens": 1000,
|
|
61
|
+
"language": "pt",
|
|
62
|
+
"autoCommit": false,
|
|
63
|
+
"excludePatterns": ["*.lock*", "*.log", "node_modules/**"],
|
|
64
|
+
"includeEmoji": true
|
|
65
|
+
}
|
|
66
|
+
```
|
|
30
67
|
|
|
31
68
|
## 🧠 Como Funciona
|
|
32
69
|
|
|
33
|
-
1.
|
|
34
|
-
2.
|
|
35
|
-
3.
|
|
36
|
-
4.
|
|
70
|
+
1. **Análise**: Lê os arquivos staged (`git diff --cached`)
|
|
71
|
+
2. **Processamento**: Divide diff grandes em chunks menores
|
|
72
|
+
3. **IA**: Envia para OpenAI com prompts otimizados
|
|
73
|
+
4. **Geração**: Cria mensagem seguindo Conventional Commits
|
|
74
|
+
5. **Interação**: Permite edição, regeneração ou cópia
|
|
75
|
+
6. **Commit**: Executa git commit com a mensagem final
|
|
76
|
+
|
|
77
|
+
## 📝 Exemplos de Uso
|
|
78
|
+
|
|
79
|
+
### Uso Básico
|
|
80
|
+
```bash
|
|
81
|
+
# Adicione arquivos ao stage
|
|
82
|
+
git add .
|
|
83
|
+
|
|
84
|
+
# Execute o wizard
|
|
85
|
+
commit-wizard
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Comandos Disponíveis
|
|
89
|
+
```bash
|
|
90
|
+
commit-wizard # Gerar commit normal
|
|
91
|
+
commit-wizard --config # Configurar o wizard
|
|
92
|
+
commit-wizard --info # Ver informações do sistema
|
|
93
|
+
commit-wizard --help # Mostrar ajuda
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Exemplo de Output
|
|
97
|
+
```
|
|
98
|
+
📈 Análise do Diff:
|
|
99
|
+
• Arquivos alterados: 3
|
|
100
|
+
• Linhas adicionadas: +45
|
|
101
|
+
• Linhas removidas: -12
|
|
102
|
+
• Tokens estimados: 850
|
|
103
|
+
• Complexidade: 🟡 Moderada
|
|
104
|
+
|
|
105
|
+
✨ Mensagem de commit gerada:
|
|
106
|
+
feat(auth): adiciona autenticação OAuth2 com Google
|
|
107
|
+
|
|
108
|
+
💰 Tokens utilizados: 1,234 (prompt: 987, resposta: 247)
|
|
109
|
+
|
|
110
|
+
O que deseja fazer com a mensagem de commit?
|
|
111
|
+
❯ 📌 Confirmar e commitar
|
|
112
|
+
📝 Editar a mensagem antes de commitar
|
|
113
|
+
🔄 Regenerar mensagem
|
|
114
|
+
📋 Copiar para clipboard
|
|
115
|
+
🚫 Cancelar o commit
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 🛠 Modelos Suportados
|
|
119
|
+
|
|
120
|
+
- **GPT-4o** (padrão) - Mais recente e eficiente
|
|
121
|
+
- **GPT-4o Mini** - Mais rápido e econômico
|
|
122
|
+
- **GPT-4 Turbo** - Versão anterior robusta
|
|
123
|
+
- **GPT-3.5 Turbo** - Opção econômica
|
|
37
124
|
|
|
38
|
-
##
|
|
125
|
+
## 🧪 Scripts de Desenvolvimento
|
|
39
126
|
|
|
40
127
|
```bash
|
|
41
|
-
|
|
128
|
+
npm run build # Compilar TypeScript
|
|
129
|
+
npm run dev # Modo desenvolvimento
|
|
130
|
+
npm run test # Executar testes
|
|
131
|
+
npm run test:watch # Testes em modo watch
|
|
132
|
+
npm run test:coverage # Testes com cobertura
|
|
133
|
+
npm run lint # Verificar lint
|
|
134
|
+
npm run lint:fix # Corrigir lint automaticamente
|
|
135
|
+
npm run format # Formatar código
|
|
136
|
+
npm run format:check # Verificar formatação
|
|
137
|
+
npm run clean # Limpar arquivos build
|
|
42
138
|
```
|
|
43
139
|
|
|
44
|
-
|
|
140
|
+
## 📊 Conventional Commits Suportados
|
|
141
|
+
|
|
142
|
+
O wizard gera mensagens seguindo a [especificação Conventional Commits](https://www.conventionalcommits.org/):
|
|
143
|
+
|
|
144
|
+
- `feat:` - Novas funcionalidades
|
|
145
|
+
- `fix:` - Correções de bugs
|
|
146
|
+
- `docs:` - Mudanças na documentação
|
|
147
|
+
- `style:` - Formatação, ponto e vírgula, etc.
|
|
148
|
+
- `refactor:` - Mudanças que não alteram funcionalidade
|
|
149
|
+
- `perf:` - Melhorias de performance
|
|
150
|
+
- `test:` - Adição ou correção de testes
|
|
151
|
+
- `chore:` - Mudanças em ferramentas, configs, etc.
|
|
152
|
+
- `ci:` - Mudanças no CI/CD
|
|
45
153
|
|
|
154
|
+
### Breaking Changes
|
|
155
|
+
Para alterações que quebram compatibilidade:
|
|
46
156
|
```
|
|
47
|
-
|
|
48
|
-
|
|
157
|
+
feat!(auth): reestruturar API de login
|
|
158
|
+
|
|
159
|
+
BREAKING CHANGE: A API de login foi alterada e não é compatível com versões anteriores.
|
|
49
160
|
```
|
|
50
161
|
|
|
51
|
-
##
|
|
162
|
+
## 🎯 Configurações Avançadas
|
|
163
|
+
|
|
164
|
+
### Padrões de Exclusão
|
|
165
|
+
Customize quais arquivos ignorar:
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"excludePatterns": [
|
|
169
|
+
"*.lock*",
|
|
170
|
+
"*.log",
|
|
171
|
+
"node_modules/**",
|
|
172
|
+
"dist/**",
|
|
173
|
+
"coverage/**"
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
52
177
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
178
|
+
### Auto Commit
|
|
179
|
+
Para fluxos automatizados:
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"autoCommit": true
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Multilíngue
|
|
187
|
+
Suporte para português e inglês:
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"language": "en"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
58
193
|
|
|
59
|
-
##
|
|
194
|
+
## 🚨 Tratamento de Erros
|
|
60
195
|
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
196
|
+
O wizard trata graciosamente:
|
|
197
|
+
- ❌ API key não configurada
|
|
198
|
+
- ❌ Não é repositório Git
|
|
199
|
+
- ❌ Sem arquivos staged
|
|
200
|
+
- ❌ Erros da API OpenAI
|
|
201
|
+
- ❌ Problemas de conectividade
|
|
202
|
+
- ❌ Arquivos de configuração inválidos
|
|
64
203
|
|
|
65
|
-
##
|
|
204
|
+
## 💡 Dicas de Uso
|
|
66
205
|
|
|
67
|
-
|
|
206
|
+
1. **Stage seletivo**: Use `git add -p` para adicionar mudanças específicas
|
|
207
|
+
2. **Configuração por projeto**: Crie `.commit-wizard.json` no projeto
|
|
208
|
+
3. **Temperatura baixa**: Use 0.1-0.3 para mensagens mais consistentes
|
|
209
|
+
4. **Exclude patterns**: Configure para ignorar arquivos irrelevantes
|
|
210
|
+
5. **Auto commit**: Ative apenas em ambientes confiáveis
|
|
68
211
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
212
|
+
## 🤝 Contribuindo
|
|
213
|
+
|
|
214
|
+
1. Fork o projeto
|
|
215
|
+
2. Crie uma branch para sua feature (`git checkout -b feature/AmazingFeature`)
|
|
216
|
+
3. Commit suas mudanças (`git commit -m 'feat: add some AmazingFeature'`)
|
|
217
|
+
4. Push para a branch (`git push origin feature/AmazingFeature`)
|
|
218
|
+
5. Abra um Pull Request
|
|
219
|
+
|
|
220
|
+
### Executando Localmente
|
|
221
|
+
```bash
|
|
222
|
+
git clone https://github.com/gilbert-oliveira/commit-wizard.git
|
|
223
|
+
cd commit-wizard
|
|
224
|
+
npm install
|
|
225
|
+
npm run build
|
|
226
|
+
npm link
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## 📈 Roadmap
|
|
230
|
+
|
|
231
|
+
- [ ] Suporte a outros provedores de IA (Claude, Gemini)
|
|
232
|
+
- [ ] Integração com GitHub Actions
|
|
233
|
+
- [ ] Plugin para VS Code
|
|
234
|
+
- [ ] Templates de commit customizáveis
|
|
235
|
+
- [ ] Integração com Conventional Changelog
|
|
236
|
+
- [ ] Suporte a monorepos
|
|
237
|
+
- [ ] Cache de respostas IA
|
|
73
238
|
|
|
74
239
|
## 📄 Licença
|
|
75
240
|
|
|
76
241
|
Este projeto está licenciado sob a licença MIT. Veja o arquivo [LICENSE](LICENSE) para mais detalhes.
|
|
77
242
|
|
|
243
|
+
## 🙏 Agradecimentos
|
|
244
|
+
|
|
245
|
+
- [OpenAI](https://openai.com/) pela API GPT
|
|
246
|
+
- [Conventional Commits](https://www.conventionalcommits.org/) pela especificação
|
|
247
|
+
- Comunidade open source pelas bibliotecas utilizadas
|
|
248
|
+
|
|
78
249
|
---
|
|
79
250
|
|
|
80
|
-
|
|
251
|
+
<div align="center">
|
|
252
|
+
<sub>Feito com 💜 por <a href="https://github.com/gilbert-oliveira">Gilbert de Oliveira Santos</a></sub>
|
|
253
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Config } from './config.js';
|
|
2
|
+
export interface AIResponse {
|
|
3
|
+
content: string;
|
|
4
|
+
usage?: {
|
|
5
|
+
promptTokens: number;
|
|
6
|
+
completionTokens: number;
|
|
7
|
+
totalTokens: number;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Serviço para interação com APIs de IA
|
|
12
|
+
*/
|
|
13
|
+
export declare class AIService {
|
|
14
|
+
private config;
|
|
15
|
+
constructor(config: Config);
|
|
16
|
+
/**
|
|
17
|
+
* Gera prompt do sistema baseado no modo e linguagem
|
|
18
|
+
*/
|
|
19
|
+
private getSystemPrompt;
|
|
20
|
+
/**
|
|
21
|
+
* Gera prompt para mensagem de commit
|
|
22
|
+
*/
|
|
23
|
+
private getCommitPrompt;
|
|
24
|
+
/**
|
|
25
|
+
* Realiza chamada para a API da OpenAI
|
|
26
|
+
*/
|
|
27
|
+
callOpenAI(prompt: string, mode?: 'commit' | 'summary'): Promise<AIResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* Gera resumo de um chunk de diff
|
|
30
|
+
*/
|
|
31
|
+
generateSummary(chunk: string): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Gera mensagem de commit baseada no diff ou resumo
|
|
34
|
+
*/
|
|
35
|
+
generateCommitMessage(diffOrSummary: string): Promise<AIResponse>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serviço para interação com APIs de IA
|
|
3
|
+
*/
|
|
4
|
+
export class AIService {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Gera prompt do sistema baseado no modo e linguagem
|
|
10
|
+
*/
|
|
11
|
+
getSystemPrompt(mode) {
|
|
12
|
+
const isPortuguese = this.config.language === 'pt';
|
|
13
|
+
if (mode === 'commit') {
|
|
14
|
+
return isPortuguese
|
|
15
|
+
? 'Você é um assistente que gera mensagens de commit seguindo a convenção do Conventional Commits. Use linguagem imperativa em português.'
|
|
16
|
+
: 'You are an assistant that generates commit messages following the Conventional Commits convention. Use imperative language in English.';
|
|
17
|
+
}
|
|
18
|
+
return isPortuguese
|
|
19
|
+
? 'Você é um assistente que resume alterações de código de forma breve, usando linguagem imperativa em português.'
|
|
20
|
+
: 'You are an assistant that summarizes code changes briefly, using imperative language in English.';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gera prompt para mensagem de commit
|
|
24
|
+
*/
|
|
25
|
+
getCommitPrompt() {
|
|
26
|
+
const isPortuguese = this.config.language === 'pt';
|
|
27
|
+
if (isPortuguese) {
|
|
28
|
+
return `
|
|
29
|
+
Por favor, escreva a mensagem de commit para este diff usando a convenção de Conventional Commits.
|
|
30
|
+
A mensagem deve começar com um tipo de commit, como:
|
|
31
|
+
feat: para novas funcionalidades
|
|
32
|
+
fix: para correções de bugs
|
|
33
|
+
chore: para alterações que não afetam a funcionalidade
|
|
34
|
+
docs: para mudanças na documentação
|
|
35
|
+
style: para alterações no estilo do código (formatação)
|
|
36
|
+
refactor: para alterações no código que não alteram a funcionalidade
|
|
37
|
+
perf: para melhorias de desempenho
|
|
38
|
+
test: para alterações nos testes
|
|
39
|
+
ci: para mudanças no pipeline de integração contínua
|
|
40
|
+
|
|
41
|
+
${this.config.includeEmoji ? 'Inclua emojis apropriados no início da mensagem.' : 'Não inclua emojis na mensagem.'}
|
|
42
|
+
|
|
43
|
+
Para breaking changes, use "!" após o tipo: feat!(auth): reestruturar fluxo de login
|
|
44
|
+
|
|
45
|
+
Use sempre linguagem imperativa, como:
|
|
46
|
+
- "adiciona recurso"
|
|
47
|
+
- "corrige bug"
|
|
48
|
+
- "remove arquivo"
|
|
49
|
+
|
|
50
|
+
Mantenha a mensagem concisa mas informativa.
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
return `
|
|
54
|
+
Please write the commit message for this diff using the Conventional Commits convention.
|
|
55
|
+
The message should start with a commit type, such as:
|
|
56
|
+
feat: for new features
|
|
57
|
+
fix: for bug fixes
|
|
58
|
+
chore: for changes that don't affect functionality
|
|
59
|
+
docs: for documentation changes
|
|
60
|
+
style: for code style changes (formatting)
|
|
61
|
+
refactor: for code changes that don't alter functionality
|
|
62
|
+
perf: for performance improvements
|
|
63
|
+
test: for test changes
|
|
64
|
+
ci: for CI pipeline changes
|
|
65
|
+
|
|
66
|
+
${this.config.includeEmoji ? 'Include appropriate emojis at the beginning of the message.' : 'Do not include emojis in the message.'}
|
|
67
|
+
|
|
68
|
+
For breaking changes, use "!" after the type: feat!(auth): restructure login flow
|
|
69
|
+
|
|
70
|
+
Always use imperative language, such as:
|
|
71
|
+
- "add feature"
|
|
72
|
+
- "fix bug"
|
|
73
|
+
- "remove file"
|
|
74
|
+
|
|
75
|
+
Keep the message concise but informative.
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Realiza chamada para a API da OpenAI
|
|
80
|
+
*/
|
|
81
|
+
async callOpenAI(prompt, mode = 'commit') {
|
|
82
|
+
if (!this.config.apiKey) {
|
|
83
|
+
throw new Error('API key da OpenAI não configurada');
|
|
84
|
+
}
|
|
85
|
+
const url = 'https://api.openai.com/v1/chat/completions';
|
|
86
|
+
const systemPrompt = this.getSystemPrompt(mode);
|
|
87
|
+
const fullPrompt = mode === 'commit' ? `${this.getCommitPrompt()}\n\nDiff:\n\n${prompt}` : prompt;
|
|
88
|
+
const body = {
|
|
89
|
+
model: this.config.model,
|
|
90
|
+
messages: [
|
|
91
|
+
{ role: 'system', content: systemPrompt },
|
|
92
|
+
{ role: 'user', content: fullPrompt },
|
|
93
|
+
],
|
|
94
|
+
temperature: this.config.temperature,
|
|
95
|
+
max_tokens: 500, // Limite para mensagens de commit
|
|
96
|
+
};
|
|
97
|
+
try {
|
|
98
|
+
// Timeout de 30 segundos para evitar travamentos
|
|
99
|
+
const controller = new AbortController();
|
|
100
|
+
const timeoutId = globalThis.setTimeout(() => controller.abort(), 30000);
|
|
101
|
+
const response = await globalThis.fetch(url, {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify(body),
|
|
108
|
+
signal: controller.signal,
|
|
109
|
+
});
|
|
110
|
+
globalThis.clearTimeout(timeoutId);
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
const errorData = await response.json().catch(() => ({}));
|
|
113
|
+
throw new Error(`Erro na API OpenAI (${response.status}): ${errorData.error?.message || response.statusText}`);
|
|
114
|
+
}
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
return {
|
|
117
|
+
content: data.choices[0].message.content.trim().replace(/```/g, ''),
|
|
118
|
+
usage: data.usage
|
|
119
|
+
? {
|
|
120
|
+
promptTokens: data.usage.prompt_tokens,
|
|
121
|
+
completionTokens: data.usage.completion_tokens,
|
|
122
|
+
totalTokens: data.usage.total_tokens,
|
|
123
|
+
}
|
|
124
|
+
: undefined,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (error instanceof Error) {
|
|
129
|
+
if (error.name === 'AbortError') {
|
|
130
|
+
throw new Error('Timeout: A requisição demorou mais de 30 segundos. Tente reduzir o tamanho do diff ou verificar sua conexão.');
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
throw new Error(`Erro desconhecido ao chamar API: ${error}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Gera resumo de um chunk de diff
|
|
139
|
+
*/
|
|
140
|
+
async generateSummary(chunk) {
|
|
141
|
+
const isPortuguese = this.config.language === 'pt';
|
|
142
|
+
const summaryPrefix = isPortuguese
|
|
143
|
+
? 'A partir do diff abaixo, extraia um resumo breve das alterações (use linguagem imperativa):'
|
|
144
|
+
: 'From the diff below, extract a brief summary of the changes (use imperative language):';
|
|
145
|
+
const prompt = `${summaryPrefix}\n\n${chunk}`;
|
|
146
|
+
const response = await this.callOpenAI(prompt, 'summary');
|
|
147
|
+
return response.content;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Gera mensagem de commit baseada no diff ou resumo
|
|
151
|
+
*/
|
|
152
|
+
async generateCommitMessage(diffOrSummary) {
|
|
153
|
+
return this.callOpenAI(diffOrSummary, 'commit');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=ai-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-service.js","sourceRoot":"","sources":["../src/ai-service.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
apiKey?: string;
|
|
3
|
+
model: string;
|
|
4
|
+
temperature: number;
|
|
5
|
+
maxTokens: number;
|
|
6
|
+
language: 'pt' | 'en';
|
|
7
|
+
autoCommit: boolean;
|
|
8
|
+
excludePatterns: string[];
|
|
9
|
+
includeEmoji: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Carrega a configuração mesclando defaults com arquivo de config
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadConfig(): Config;
|
|
15
|
+
/**
|
|
16
|
+
* Salva a configuração no arquivo local ou global
|
|
17
|
+
*/
|
|
18
|
+
export declare function saveConfig(config: Partial<Config>, global?: boolean): void;
|
|
19
|
+
/**
|
|
20
|
+
* Cria um arquivo de configuração exemplo
|
|
21
|
+
*/
|
|
22
|
+
export declare function createConfigExample(): void;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
model: 'gpt-4o',
|
|
6
|
+
temperature: 0.2,
|
|
7
|
+
maxTokens: 1000,
|
|
8
|
+
language: 'pt',
|
|
9
|
+
autoCommit: false,
|
|
10
|
+
excludePatterns: ['*.lock*', '*.log', 'node_modules/**'],
|
|
11
|
+
includeEmoji: true,
|
|
12
|
+
};
|
|
13
|
+
const CONFIG_FILE_NAME = '.commit-wizard.json';
|
|
14
|
+
/**
|
|
15
|
+
* Busca o arquivo de configuração no diretório atual ou no home do usuário
|
|
16
|
+
*/
|
|
17
|
+
function findConfigFile() {
|
|
18
|
+
// Primeiro verifica no diretório atual
|
|
19
|
+
const localConfig = path.join(process.cwd(), CONFIG_FILE_NAME);
|
|
20
|
+
if (fs.existsSync(localConfig)) {
|
|
21
|
+
return localConfig;
|
|
22
|
+
}
|
|
23
|
+
// Depois verifica no home do usuário
|
|
24
|
+
const globalConfig = path.join(os.homedir(), CONFIG_FILE_NAME);
|
|
25
|
+
if (fs.existsSync(globalConfig)) {
|
|
26
|
+
return globalConfig;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Carrega a configuração mesclando defaults com arquivo de config
|
|
32
|
+
*/
|
|
33
|
+
export function loadConfig() {
|
|
34
|
+
const configFile = findConfigFile();
|
|
35
|
+
let userConfig = {};
|
|
36
|
+
if (configFile) {
|
|
37
|
+
try {
|
|
38
|
+
const configContent = fs.readFileSync(configFile, 'utf8');
|
|
39
|
+
userConfig = JSON.parse(configContent);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.warn(`⚠️ Erro ao ler arquivo de configuração ${configFile}:`, error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Mescla configuração padrão com configuração do usuário
|
|
46
|
+
const config = {
|
|
47
|
+
...DEFAULT_CONFIG,
|
|
48
|
+
...userConfig,
|
|
49
|
+
apiKey: userConfig.apiKey || process.env.OPENAI_API_KEY,
|
|
50
|
+
};
|
|
51
|
+
return config;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Salva a configuração no arquivo local ou global
|
|
55
|
+
*/
|
|
56
|
+
export function saveConfig(config, global = false) {
|
|
57
|
+
const configPath = global
|
|
58
|
+
? path.join(os.homedir(), CONFIG_FILE_NAME)
|
|
59
|
+
: path.join(process.cwd(), CONFIG_FILE_NAME);
|
|
60
|
+
try {
|
|
61
|
+
const existingConfig = global ? {} : loadConfig();
|
|
62
|
+
const newConfig = { ...existingConfig, ...config };
|
|
63
|
+
// Remove a apiKey do arquivo (deve ficar apenas em variável de ambiente)
|
|
64
|
+
delete newConfig.apiKey;
|
|
65
|
+
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2));
|
|
66
|
+
console.log(`✅ Configuração salva em ${configPath}`);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error('❌ Erro ao salvar configuração:', error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Cria um arquivo de configuração exemplo
|
|
74
|
+
*/
|
|
75
|
+
export function createConfigExample() {
|
|
76
|
+
const configPath = path.join(process.cwd(), `${CONFIG_FILE_NAME}.example`);
|
|
77
|
+
const exampleConfig = {
|
|
78
|
+
...DEFAULT_CONFIG,
|
|
79
|
+
apiKey: 'sk-your-openai-api-key-here',
|
|
80
|
+
};
|
|
81
|
+
fs.writeFileSync(configPath, JSON.stringify(exampleConfig, null, 2));
|
|
82
|
+
console.log(`📄 Arquivo de exemplo criado: ${configPath}`);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { AIService } from './ai-service.js';
|
|
2
|
+
/**
|
|
3
|
+
* Processador de diff para chunks e resumos
|
|
4
|
+
*/
|
|
5
|
+
export declare class DiffProcessor {
|
|
6
|
+
private aiService;
|
|
7
|
+
private maxTokens;
|
|
8
|
+
constructor(aiService: AIService, maxTokens?: number);
|
|
9
|
+
/**
|
|
10
|
+
* Divide o diff em chunks menores baseado na contagem de tokens
|
|
11
|
+
*/
|
|
12
|
+
chunkDiff(diff: string): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Processa diff grande gerando resumos dos chunks
|
|
15
|
+
*/
|
|
16
|
+
processLargeDiff(diff: string): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Analisa a complexidade do diff
|
|
19
|
+
*/
|
|
20
|
+
analyzeDiffComplexity(diff: string): {
|
|
21
|
+
tokenCount: number;
|
|
22
|
+
lineCount: number;
|
|
23
|
+
fileCount: number;
|
|
24
|
+
complexity: 'simple' | 'moderate' | 'complex';
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Extrai estatísticas do diff
|
|
28
|
+
*/
|
|
29
|
+
extractDiffStats(diff: string): {
|
|
30
|
+
additions: number;
|
|
31
|
+
deletions: number;
|
|
32
|
+
files: string[];
|
|
33
|
+
types: string[];
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Verifica se o diff contém breaking changes
|
|
37
|
+
*/
|
|
38
|
+
detectBreakingChanges(diff: string): boolean;
|
|
39
|
+
}
|