@gilbert_oliveira/commit-wizard 2.13.0-canary.6 → 2.13.0-canary.7

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.
@@ -1,23 +1,23 @@
1
1
  #!/usr/bin/env node
2
- var Ze=Object.defineProperty;var S=(e,t)=>()=>(e&&(t=e(e=0)),t);var O=(e,t)=>{for(var i in t)Ze(e,i,{get:t[i],enumerable:!0})};import Pt from"path";import{fileURLToPath as It}from"url";var d=S(()=>{"use strict"});import{existsSync as be,readFileSync as ve}from"fs";import{join as Ce}from"path";function Se(e){let t;try{t=Ce(process.cwd(),".commit-wizardrc")}catch{t="/tmp/.commit-wizardrc"}let i=Ce(process.env.HOME||process.env.USERPROFILE||"/tmp",".commit-wizardrc"),o={...Xe};try{if(be(i)){let s=ve(i,"utf-8"),r=JSON.parse(s);o=xe(o,r)}}catch{console.warn("\u26A0\uFE0F Erro ao ler configura\xE7\xE3o global: Erro desconhecido")}let n=e||t;try{if(be(n)){let s=ve(n,"utf-8"),r=JSON.parse(s);o=xe(o,r)}}catch{console.warn("\u26A0\uFE0F Erro ao ler .commit-wizardrc: Erro desconhecido")}return o.openai.apiKey=process.env.OPENAI_API_KEY,process.env.COMMIT_WIZARD_DEBUG,process.env.COMMIT_WIZARD_DRY_RUN==="true"&&(o.dryRun=!0),o}function xe(e,t){return{...e,...t,openai:{...e.openai,...t.openai},smartSplit:{...e.smartSplit,...t.smartSplit},cache:{...e.cache,...t.cache},commitlint:{...e.commitlint,...t.commitlint}}}function we(e){let t=[];return e.openai.apiKey||t.push("OPENAI_API_KEY n\xE3o encontrada nas vari\xE1veis de ambiente"),(e.openai.maxTokens<10||e.openai.maxTokens>4e3)&&t.push("maxTokens deve estar entre 10 e 4000"),(e.openai.temperature<0||e.openai.temperature>2)&&t.push("temperature deve estar entre 0 e 2"),["pt","en","es","fr","de","it","ja","ko","zh"].includes(e.language)||t.push("language deve ser um idioma suportado (pt, en, es, fr, de, it, ja, ko, zh)"),["conventional","simple","detailed"].includes(e.commitStyle)||t.push("commitStyle deve ser conventional, simple ou detailed"),e.smartSplit.minGroupSize<1&&t.push("smartSplit.minGroupSize deve ser pelo menos 1"),(e.smartSplit.maxGroups<1||e.smartSplit.maxGroups>10)&&t.push("smartSplit.maxGroups deve estar entre 1 e 10"),(e.smartSplit.confidenceThreshold<0||e.smartSplit.confidenceThreshold>1)&&t.push("smartSplit.confidenceThreshold deve estar entre 0 e 1"),e.cache.ttl<1&&t.push("cache.ttl deve ser pelo menos 1 minuto"),e.cache.maxSize<1&&t.push("cache.maxSize deve ser pelo menos 1"),t}var Xe,$e=S(()=>{"use strict";d();Xe={openai:{model:"gpt-4o",maxTokens:150,temperature:.7,timeout:3e4,retries:2},language:"pt",commitStyle:"conventional",autoCommit:!1,splitCommits:!1,dryRun:!1,smartSplit:{enabled:!0,minGroupSize:1,maxGroups:5,confidenceThreshold:.7},cache:{enabled:!0,ttl:60,maxSize:100},commitlint:{enabled:!0}}});var j={};O(j,{escapeShellArg:()=>T,executeCommit:()=>M,executeFileCommit:()=>G,getDiffStats:()=>Y,getFileDiff:()=>et,getGitStatus:()=>K,isGitRepository:()=>B});import{execSync as E}from"child_process";function T(e){return`'${e.replace(/'/g,`'"'"'`)}'`}function B(){try{return E("git rev-parse --git-dir",{stdio:"ignore"}),!0}catch{return!1}}function K(){try{let t=E("git diff --cached --name-only",{encoding:"utf-8",stdio:"pipe"}).trim().split(`
3
- `).filter(o=>o.length>0),i=t.length>0?E("git diff --cached",{encoding:"utf-8",stdio:"pipe"}):"";return{hasStaged:t.length>0,stagedFiles:t,diff:i.trim()}}catch(e){throw new Error(`Erro ao obter status do Git: ${e instanceof Error?e.message:"Erro desconhecido"}`)}}function et(e){try{return E(`git diff --cached -- "${e}"`,{encoding:"utf-8",stdio:"pipe"})}catch(t){throw new Error(`Erro ao obter diff do arquivo ${e}: ${t instanceof Error?t.message:"Erro desconhecido"}`)}}function M(e){try{let t=T(e);return E(`git commit -m ${t}`,{stdio:"pipe"}),{success:!0,hash:E("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Erro desconhecido ao executar commit"}}}function G(e,t){try{let i=T(t),o=T(e);return E(`git commit ${o} -m ${i}`,{stdio:"pipe"}),{success:!0,hash:E("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:t}}catch(i){return{success:!1,error:i instanceof Error?i.message:"Erro desconhecido ao executar commit do arquivo"}}}function Y(){try{let t=E("git diff --cached --numstat",{encoding:"utf-8",stdio:"pipe"}).trim().split(`
4
- `).filter(n=>n.length>0),i=0,o=0;return t.forEach(n=>{let[s,r]=n.split(" ");s&&s!=="-"&&(i+=parseInt(s)||0),r&&r!=="-"&&(o+=parseInt(r)||0)}),{added:i,removed:o,files:t.length}}catch{return{added:0,removed:0,files:0}}}var w=S(()=>{"use strict";d()});var ze={};O(ze,{buildPrompt:()=>Ee,detectCommitType:()=>Re,extractCommitTypeFromMessage:()=>je,generateCommitMessage:()=>Fe,generateWithRetry:()=>D,processOpenAIMessage:()=>Me,smartFilterDiff:()=>Ae});function Ae(e,t){if(e.length<=t)return e;let i=[/^diff --git a\/package-lock\.json/m,/^diff --git a\/yarn\.lock/m,/^diff --git a\/pnpm-lock\.yaml/m,/^diff --git a\/composer\.lock/m,/^diff --git a\/Gemfile\.lock/m,/^diff --git a\/Cargo\.lock/m,/^diff --git a\/poetry\.lock/m,/^diff --git a\/go\.sum/m,/^diff --git a\/requirements(?:\.txt)?\.lock/m,/^diff --git a\/.*\.min\.js/m,/^diff --git a\/.*\.min\.css/m,/^diff --git a\/.*\.map/m,/^diff --git a\/dist\//m,/^diff --git a\/build\//m],o=e.split(/(?=^diff --git)/m).filter(a=>a.trim()),n=[],s=[];o.forEach(a=>{i.some(p=>p.test(a))?s.push(a):n.push(a)});let r="",l=t;for(let a of n)if(a.length<=l)r+=a,l-=a.length;else if(l>200){r+=a.substring(0,l-50),l=t-r.length;break}else break;if(!r&&s.length>0&&l>0)for(let a of s)if(a.length<=l)r+=a,l-=a.length;else if(l>200){r+=a.substring(0,l-50),l=t-r.length;break}else break;let m=`
5
- ... (diff otimizado para focar em mudan\xE7as principais)`;if(l>200&&s.length>0){let a=`
2
+ var Xe=Object.defineProperty;var S=(e,t)=>()=>(e&&(t=e(e=0)),t);var k=(e,t)=>{for(var i in t)Xe(e,i,{get:t[i],enumerable:!0})};import Pt from"path";import{fileURLToPath as kt}from"url";var f=S(()=>{"use strict"});import{existsSync as be,readFileSync as Ce}from"fs";import{join as ve}from"path";function Se(e){let t;try{t=ve(process.cwd(),".commit-wizardrc")}catch{t="/tmp/.commit-wizardrc"}let i=ve(process.env.HOME||process.env.USERPROFILE||"/tmp",".commit-wizardrc"),o={...et};try{if(be(i)){let s=Ce(i,"utf-8"),r=JSON.parse(s);o=xe(o,r)}}catch{console.warn("\u26A0\uFE0F Erro ao ler configura\xE7\xE3o global: Erro desconhecido")}let n=e||t;try{if(be(n)){let s=Ce(n,"utf-8"),r=JSON.parse(s);o=xe(o,r)}}catch{console.warn("\u26A0\uFE0F Erro ao ler .commit-wizardrc: Erro desconhecido")}return o.openai.apiKey=process.env.OPENAI_API_KEY,process.env.COMMIT_WIZARD_DEBUG,process.env.COMMIT_WIZARD_DRY_RUN==="true"&&(o.dryRun=!0),o}function xe(e,t){return{...e,...t,openai:{...e.openai,...t.openai},smartSplit:{...e.smartSplit,...t.smartSplit},cache:{...e.cache,...t.cache},commitlint:{...e.commitlint,...t.commitlint}}}function we(e){let t=[];return e.openai.apiKey||t.push("OPENAI_API_KEY n\xE3o encontrada nas vari\xE1veis de ambiente"),(e.openai.maxTokens<10||e.openai.maxTokens>4e3)&&t.push("maxTokens deve estar entre 10 e 4000"),(e.openai.temperature<0||e.openai.temperature>2)&&t.push("temperature deve estar entre 0 e 2"),["pt","en","es","fr","de","it","ja","ko","zh"].includes(e.language)||t.push("language deve ser um idioma suportado (pt, en, es, fr, de, it, ja, ko, zh)"),["conventional","simple","detailed"].includes(e.commitStyle)||t.push("commitStyle deve ser conventional, simple ou detailed"),e.smartSplit.minGroupSize<1&&t.push("smartSplit.minGroupSize deve ser pelo menos 1"),(e.smartSplit.maxGroups<1||e.smartSplit.maxGroups>10)&&t.push("smartSplit.maxGroups deve estar entre 1 e 10"),(e.smartSplit.confidenceThreshold<0||e.smartSplit.confidenceThreshold>1)&&t.push("smartSplit.confidenceThreshold deve estar entre 0 e 1"),e.cache.ttl<1&&t.push("cache.ttl deve ser pelo menos 1 minuto"),e.cache.maxSize<1&&t.push("cache.maxSize deve ser pelo menos 1"),t}var et,$e=S(()=>{"use strict";f();et={openai:{model:"gpt-4o",maxTokens:150,temperature:.7,timeout:3e4,retries:2},language:"pt",commitStyle:"conventional",autoCommit:!1,splitCommits:!1,dryRun:!1,smartSplit:{enabled:!0,minGroupSize:1,maxGroups:5,confidenceThreshold:.7},cache:{enabled:!0,ttl:60,maxSize:100},commitlint:{enabled:!0}}});var j={};k(j,{escapeShellArg:()=>L,executeCommit:()=>R,executeFileCommit:()=>T,getDiffStats:()=>Q,getFileDiff:()=>tt,getGitStatus:()=>Y,isGitRepository:()=>K});import{execSync as A}from"child_process";function L(e){return`'${e.replace(/'/g,`'"'"'`)}'`}function K(){try{return A("git rev-parse --git-dir",{stdio:"ignore"}),!0}catch{return!1}}function Y(){try{let t=A("git diff --cached --name-only",{encoding:"utf-8",stdio:"pipe"}).trim().split(`
3
+ `).filter(o=>o.length>0),i=t.length>0?A("git diff --cached",{encoding:"utf-8",stdio:"pipe"}):"";return{hasStaged:t.length>0,stagedFiles:t,diff:i.trim()}}catch(e){throw new Error(`Erro ao obter status do Git: ${e instanceof Error?e.message:"Erro desconhecido"}`)}}function tt(e){try{return A(`git diff --cached -- "${e}"`,{encoding:"utf-8",stdio:"pipe"})}catch(t){throw new Error(`Erro ao obter diff do arquivo ${e}: ${t instanceof Error?t.message:"Erro desconhecido"}`)}}function R(e){try{let t=L(e);return A(`git commit -m ${t}`,{stdio:"pipe"}),{success:!0,hash:A("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Erro desconhecido ao executar commit"}}}function T(e,t){try{let i=L(t),o=L(e);return A(`git commit ${o} -m ${i}`,{stdio:"pipe"}),{success:!0,hash:A("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:t}}catch(i){return{success:!1,error:i instanceof Error?i.message:"Erro desconhecido ao executar commit do arquivo"}}}function Q(){try{let t=A("git diff --cached --numstat",{encoding:"utf-8",stdio:"pipe"}).trim().split(`
4
+ `).filter(n=>n.length>0),i=0,o=0;return t.forEach(n=>{let[s,r]=n.split(" ");s&&s!=="-"&&(i+=parseInt(s)||0),r&&r!=="-"&&(o+=parseInt(r)||0)}),{added:i,removed:o,files:t.length}}catch{return{added:0,removed:0,files:0}}}var w=S(()=>{"use strict";f()});var ze={};k(ze,{buildPrompt:()=>Ae,buildSystemMessage:()=>Fe,detectCommitType:()=>Me,extractCommitTypeFromMessage:()=>je,generateCommitMessage:()=>Ie,generateWithRetry:()=>N,processOpenAIMessage:()=>Re,smartFilterDiff:()=>Ee});function Ee(e,t){if(e.length<=t)return e;let i=[/^diff --git a\/package-lock\.json/m,/^diff --git a\/yarn\.lock/m,/^diff --git a\/pnpm-lock\.yaml/m,/^diff --git a\/composer\.lock/m,/^diff --git a\/Gemfile\.lock/m,/^diff --git a\/Cargo\.lock/m,/^diff --git a\/poetry\.lock/m,/^diff --git a\/go\.sum/m,/^diff --git a\/requirements(?:\.txt)?\.lock/m,/^diff --git a\/.*\.min\.js/m,/^diff --git a\/.*\.min\.css/m,/^diff --git a\/.*\.map/m,/^diff --git a\/dist\//m,/^diff --git a\/build\//m],o=e.split(/(?=^diff --git)/m).filter(a=>a.trim()),n=[],s=[];o.forEach(a=>{i.some(d=>d.test(a))?s.push(a):n.push(a)});let r="",m=t;for(let a of n)if(a.length<=m)r+=a,m-=a.length;else if(m>200){r+=a.substring(0,m-50),m=t-r.length;break}else break;if(!r&&s.length>0&&m>0)for(let a of s)if(a.length<=m)r+=a,m-=a.length;else if(m>200){r+=a.substring(0,m-50),m=t-r.length;break}else break;let l=`
5
+ ... (diff otimizado para focar em mudan\xE7as principais)`;if(m>200&&s.length>0){let a=`
6
6
 
7
- ... (${s.length} arquivo(s) de depend\xEAncias/build omitido(s): ${s.map(p=>{let y=p.match(/^diff --git a\/(.*?) b\//);return y?y[1]:""}).filter(Boolean).join(", ")})`,u=l-m.length;a.length<u&&(r+=a)}return r.trim()!==e.trim()?r+m:r}function Ee(e,t,i,o){let n=t.language==="pt"?"portugu\xEAs":"english",s=o!=null?tt(t.commitStyle,t.language,o):it(t.commitStyle,t.language),l=Ae(e,6e3),m=i.length>10?`${i.length} arquivos: ${i.slice(0,5).join(", ")}...`:i.join(", ");return`Gere mensagem de commit em ${n} (${t.commitStyle}).
7
+ ... (${s.length} arquivo(s) de depend\xEAncias/build omitido(s): ${s.map(d=>{let y=d.match(/^diff --git a\/(.*?) b\//);return y?y[1]:""}).filter(Boolean).join(", ")})`,u=m-l.length;a.length<u&&(r+=a)}return r.trim()!==e.trim()?r+l:r}function Ae(e,t,i,o){let n=t.language==="pt"?"portugu\xEAs":"english",s=o!=null?it(t.commitStyle,t.language,o):ot(t.commitStyle,t.language),m=Ee(e,6e3),l=i.length>10?`${i.length} arquivos: ${i.slice(0,5).join(", ")}...`:i.join(", ");return`Gere mensagem de commit em ${n} (${t.commitStyle}).
8
8
 
9
- Arquivos: ${m}
9
+ Arquivos: ${l}
10
10
 
11
11
  ${s}
12
12
 
13
13
  Diff:
14
14
  \`\`\`
15
- ${l}
15
+ ${m}
16
16
  \`\`\`
17
17
 
18
- Mensagem:`}function tt(e,t,i){let o=t==="pt",n=[];if(e==="conventional"){n.push(o?"- Use formato: tipo(escopo): descri\xE7\xE3o":"- Use format: type(scope): description");let s=i.typeEnum?.join(", ")??Q;n.push(o?`- Tipos v\xE1lidos: ${s}`:`- Valid types: ${s}`);let r=i.headerMaxLength??72;n.push(o?`- Mantenha a primeira linha com at\xE9 ${r} caracteres`:`- Keep first line under ${r} characters`);let l=i.typeEnum?.[0]??"feat",m=`${l}(auth): adicionar valida\xE7\xE3o de email`,c=`${l}(auth): add email validation`;if(o&&m.length<=r?n.push(`- Exemplo: "${m}"`):!o&&c.length<=r&&n.push(`- Example: "${c}"`),i.subjectCase){let{condition:a,cases:u}=i.subjectCase,p=u.join(", ");a==="never"?n.push(o?`- Subject nunca em: ${p}`:`- Subject must never be: ${p}`):a==="always"&&n.push(o?`- Subject deve estar em: ${p}`:`- Subject must be in: ${p}`)}if(i.subjectFullStop){let{condition:a,value:u}=i.subjectFullStop,p=u??".";a==="never"?n.push(o?`- N\xE3o termine o subject com "${p}"`:`- Do not end subject with "${p}"`):a==="always"&&n.push(o?`- Termine o subject com "${p}"`:`- End subject with "${p}"`)}i.bodyLeadingBlank===!0&&n.push(o?"- Adicione uma linha em branco entre o header e o body":"- Add a blank line between header and body"),i.scopeEnum&&i.scopeEnum.length>0&&n.push(o?`- Escopos permitidos: ${i.scopeEnum.join(", ")}`:`- Allowed scopes: ${i.scopeEnum.join(", ")}`)}else if(e==="simple"){let s=i.headerMaxLength??50;o?(n.push("- Use formato simples e direto"),n.push("- Comece com verbo no infinitivo"),n.push('- Exemplo: "corrigir valida\xE7\xE3o de formul\xE1rio"'),n.push(`- M\xE1ximo ${s} caracteres`)):(n.push("- Use simple and direct format"),n.push("- Start with imperative verb"),n.push('- Example: "fix form validation"'),n.push(`- Maximum ${s} characters`))}else{let s=i.headerMaxLength??72;o?(n.push(`- Primeira linha: resumo em at\xE9 ${s} caracteres`),n.push("- Se necess\xE1rio, adicione corpo explicativo"),n.push("- Use presente do indicativo"),n.push("- Seja descritivo mas conciso")):(n.push(`- First line: summary under ${s} characters`),n.push("- Add explanatory body if needed"),n.push("- Use imperative mood"),n.push("- Be descriptive but concise"))}return n.join(`
19
- `)}function it(e,t){let i={pt:{conventional:`- Use formato: tipo(escopo): descri\xE7\xE3o
20
- - Tipos v\xE1lidos: ${Q}
18
+ Mensagem:`}function it(e,t,i){let o=t==="pt",n=[];if(e==="conventional"){n.push(o?"- Use formato: tipo(escopo): descri\xE7\xE3o":"- Use format: type(scope): description");let s=i.typeEnum?.join(", ")??D;n.push(o?`- Tipos v\xE1lidos: ${s}`:`- Valid types: ${s}`);let r=i.headerMaxLength??72;n.push(o?`- OBRIGAT\xD3RIO: primeira linha deve ter no m\xE1ximo ${r} caracteres (regra header-max-length do commitlint)`:`- REQUIRED: first line must not exceed ${r} characters (commitlint header-max-length rule)`);let m=i.typeEnum?.[0]??"feat",l=`${m}(auth): adicionar valida\xE7\xE3o de email`,c=`${m}(auth): add email validation`;if(o&&l.length<=r?n.push(`- Exemplo: "${l}"`):!o&&c.length<=r&&n.push(`- Example: "${c}"`),i.subjectCase){let{condition:a,cases:u}=i.subjectCase,d=u.join(", ");a==="never"?n.push(o?`- Subject nunca em: ${d}`:`- Subject must never be: ${d}`):a==="always"&&n.push(o?`- Subject deve estar em: ${d}`:`- Subject must be in: ${d}`)}if(i.subjectFullStop){let{condition:a,value:u}=i.subjectFullStop,d=u??".";a==="never"?n.push(o?`- N\xE3o termine o subject com "${d}"`:`- Do not end subject with "${d}"`):a==="always"&&n.push(o?`- Termine o subject com "${d}"`:`- End subject with "${d}"`)}i.bodyLeadingBlank===!0&&n.push(o?"- Adicione uma linha em branco entre o header e o body":"- Add a blank line between header and body"),i.scopeEnum&&i.scopeEnum.length>0&&n.push(o?`- Escopos permitidos: ${i.scopeEnum.join(", ")}`:`- Allowed scopes: ${i.scopeEnum.join(", ")}`)}else if(e==="simple"){let s=i.headerMaxLength??50;o?(n.push("- Use formato simples e direto"),n.push("- Comece com verbo no infinitivo"),n.push('- Exemplo: "corrigir valida\xE7\xE3o de formul\xE1rio"'),n.push(`- M\xE1ximo ${s} caracteres`)):(n.push("- Use simple and direct format"),n.push("- Start with imperative verb"),n.push('- Example: "fix form validation"'),n.push(`- Maximum ${s} characters`))}else{let s=i.headerMaxLength??72;o?(n.push(`- Primeira linha: resumo em at\xE9 ${s} caracteres`),n.push("- Se necess\xE1rio, adicione corpo explicativo"),n.push("- Use presente do indicativo"),n.push("- Seja descritivo mas conciso")):(n.push(`- First line: summary under ${s} characters`),n.push("- Add explanatory body if needed"),n.push("- Use imperative mood"),n.push("- Be descriptive but concise"))}return n.join(`
19
+ `)}function ot(e,t){let i={pt:{conventional:`- Use formato: tipo(escopo): descri\xE7\xE3o
20
+ - Tipos v\xE1lidos: ${D}
21
21
  - Exemplo: "feat(auth): adicionar valida\xE7\xE3o de email"
22
22
  - Mantenha a primeira linha com at\xE9 50 caracteres`,simple:`- Use formato simples e direto
23
23
  - Comece com verbo no infinitivo
@@ -26,7 +26,7 @@ Mensagem:`}function tt(e,t,i){let o=t==="pt",n=[];if(e==="conventional"){n.push(
26
26
  - Se necess\xE1rio, adicione corpo explicativo
27
27
  - Use presente do indicativo
28
28
  - Seja descritivo mas conciso`},en:{conventional:`- Use format: type(scope): description
29
- - Valid types: ${Q}
29
+ - Valid types: ${D}
30
30
  - Example: "feat(auth): add email validation"
31
31
  - Keep first line under 50 characters`,simple:`- Use simple and direct format
32
32
  - Start with imperative verb
@@ -34,20 +34,23 @@ Mensagem:`}function tt(e,t,i){let o=t==="pt",n=[];if(e==="conventional"){n.push(
34
34
  - Maximum 50 characters`,detailed:`- First line: summary under 50 characters
35
35
  - Add explanatory body if needed
36
36
  - Use imperative mood
37
- - Be descriptive but concise`}},o=t==="pt"?"pt":"en";return i[o][e]||i[o].conventional}function je(e){let t={feat:/^(feat|feature)(\([^)]+\))?:/i,fix:/^(fix|bugfix)(\([^)]+\))?:/i,docs:/^(docs|documentation)(\([^)]+\))?:/i,style:/^(style|format)(\([^)]+\))?:/i,refactor:/^(refactor|refactoring)(\([^)]+\))?:/i,test:/^(test|testing)(\([^)]+\))?:/i,chore:/^(chore|maintenance)(\([^)]+\))?:/i,build:/^(build|ci)(\([^)]+\))?:/i,ci:/^(ci|continuous-integration)(\([^)]+\))?:/i};for(let[i,o]of Object.entries(t))if(o.test(e))return i;return null}function Re(e,t){let i=e.toLowerCase(),o=t.join(" ").toLowerCase();return o.includes("test")||o.includes("spec")||i.includes("test(")?"test":o.includes("readme")||o.includes(".md")||o.includes("docs")?"docs":o.includes("package.json")||o.includes("dockerfile")||o.includes(".yml")||o.includes(".yaml")||o.includes("webpack")||o.includes("tsconfig")?"build":o.includes(".css")||o.includes(".scss")||i.includes("style")||i.includes("format")?"style":i.includes("fix")||i.includes("bug")||i.includes("error")||i.includes("issue")?"fix":i.includes("add")||i.includes("new")||i.includes("create")||i.includes("implement")?"feat":i.includes("refactor")||i.includes("restructure")||i.includes("rename")?"refactor":"chore"}function Me(e){if(e.startsWith("```")){let t=e.match(/^```[^\n`]*\n([\s\S]*?)\n\s*```([\s\S]*)$/);if(t){let i=t[1].trim(),o=t[2].trim();e=o?`${i}
37
+ - Be descriptive but concise`}},o=t==="pt"?"pt":"en";return i[o][e]||i[o].conventional}function je(e){let t={feat:/^(feat|feature)(\([^)]+\))?:/i,fix:/^(fix|bugfix)(\([^)]+\))?:/i,docs:/^(docs|documentation)(\([^)]+\))?:/i,style:/^(style|format)(\([^)]+\))?:/i,refactor:/^(refactor|refactoring)(\([^)]+\))?:/i,test:/^(test|testing)(\([^)]+\))?:/i,chore:/^(chore|maintenance)(\([^)]+\))?:/i,build:/^(build|ci)(\([^)]+\))?:/i,ci:/^(ci|continuous-integration)(\([^)]+\))?:/i};for(let[i,o]of Object.entries(t))if(o.test(e))return i;return null}function Me(e,t){let i=e.toLowerCase(),o=t.join(" ").toLowerCase();return o.includes("test")||o.includes("spec")||i.includes("test(")?"test":o.includes("readme")||o.includes(".md")||o.includes("docs")?"docs":o.includes("package.json")||o.includes("dockerfile")||o.includes(".yml")||o.includes(".yaml")||o.includes("webpack")||o.includes("tsconfig")?"build":o.includes(".css")||o.includes(".scss")||i.includes("style")||i.includes("format")?"style":i.includes("fix")||i.includes("bug")||i.includes("error")||i.includes("issue")?"fix":i.includes("add")||i.includes("new")||i.includes("create")||i.includes("implement")?"feat":i.includes("refactor")||i.includes("restructure")||i.includes("rename")?"refactor":"chore"}function Re(e){if(e.startsWith("```")){let t=e.match(/^```[^\n`]*\n([\s\S]*?)\n\s*```([\s\S]*)$/);if(t){let i=t[1].trim(),o=t[2].trim();e=o?`${i}
38
38
 
39
- ${o}`:i}else e.match(/^```[\s\S]*```$/)&&(e=e.replace(/^```(?:plaintext|javascript|typescript|python|java|html|css|json|xml|yaml|yml|bash|shell|text)?\s*/,"").replace(/\s*```$/,""))}return e=e.trim(),e}async function Fe(e,t,i,o){try{if(!t.openai.apiKey)return{success:!1,error:"Chave da OpenAI n\xE3o encontrada. Configure OPENAI_API_KEY nas vari\xE1veis de ambiente."};let n=Ee(e,t,i,o),s=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{Authorization:`Bearer ${t.openai.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:t.openai.model,messages:[{role:"user",content:n}],max_tokens:Math.min(t.openai.maxTokens,150),temperature:t.openai.temperature})});if(!s.ok){let a=await s.json().catch(()=>({}));return{success:!1,error:`Erro da OpenAI (${s.status}): ${a.error?.message||"Erro desconhecido"}`}}let l=(await s.json()).choices?.[0]?.message?.content?.trim();if(!l)return{success:!1,error:"OpenAI retornou resposta vazia"};l=Me(l);let m=je(l),c=Re(e,i);return{success:!0,suggestion:{message:l,type:m||c,confidence:.8}}}catch(n){return{success:!1,error:`Erro ao conectar com OpenAI: ${n instanceof Error?n.message:"Erro desconhecido"}`}}}async function D(e,t,i,o=3,n){let s="";for(let r=0;r<o;r++){let l=await Fe(e,t,i,n);if(l.success)return l;s=l.error||"Erro desconhecido",r<o-1&&await new Promise(m=>setTimeout(m,Math.pow(2,r)*1e3))}return{success:!1,error:`Falha ap\xF3s ${o} tentativas. \xDAltimo erro: ${s}`}}var Q,Z=S(()=>{"use strict";d();Q="feat, fix, docs, style, refactor, test, chore, build, ci"});var te={};O(te,{askContinueCommits:()=>ee,confirmCommit:()=>at,copyToClipboard:()=>_,editCommitMessage:()=>U,selectFilesForCommit:()=>X,showCancellation:()=>P,showCommitPreview:()=>N,showCommitResult:()=>v});import{text as ot,select as nt,confirm as q,log as F,note as Pe,cancel as st,isCancel as z}from"@clack/prompts";import rt from"clipboardy";async function N(e){Pe(`Tipo: ${e.type}
40
- Mensagem: "${e.message}"`,"\u{1F4AD} Sugest\xE3o de Commit");let t=await nt({message:"O que voc\xEA gostaria de fazer?",options:[{value:"commit",label:"\u2705 Fazer commit com esta mensagem",hint:"Executar git commit imediatamente"},{value:"edit",label:"\u270F\uFE0F Editar mensagem",hint:"Modificar a mensagem antes de commitar"},{value:"copy",label:"\u{1F4CB} Copiar para clipboard",hint:"Copiar mensagem e sair sem commitar"},{value:"cancel",label:"\u274C Cancelar",hint:"Sair sem fazer nada"}]});return z(t)?{action:"cancel"}:{action:t}}async function U(e){let t=await ot({message:"Edite a mensagem do commit:",initialValue:e,placeholder:"Digite a mensagem do commit...",validate:o=>{if(!o||o.trim().length===0)return"A mensagem n\xE3o pode estar vazia";if(o.trim().length>72)return"A mensagem est\xE1 muito longa (m\xE1ximo 72 caracteres recomendado)"}});if(z(t))return{action:"cancel"};let i=await q({message:`Confirma a mensagem editada: "${t}"?`});return z(i)||!i?{action:"cancel"}:{action:"commit",message:t}}async function _(e){try{return await rt.write(e),F.success("\u2705 Mensagem copiada para a \xE1rea de transfer\xEAncia!"),!0}catch(t){return F.error(`\u274C Erro ao copiar: ${t instanceof Error?t.message:"Erro desconhecido"}`),!1}}async function at(e){Pe(`"${e}"`,"\u{1F680} Confirmar Commit");let t=await q({message:"Executar o commit agora?"});return z(t)?!1:t}function v(e,t,i){e&&t?(F.success("\u2705 Commit realizado com sucesso!"),F.info(`\u{1F517} Hash: ${t.substring(0,8)}`)):F.error(`\u274C Erro ao realizar commit: ${i||"Erro desconhecido"}`)}async function X(e){F.info("\u{1F4CB} Modo Split: Selecione os arquivos para este commit");let t=[];for(let i of e){let o=await q({message:`Incluir "${i}" neste commit?`});if(z(o))break;o&&t.push(i)}return t}async function ee(e){if(e.length===0)return!1;F.info(`\u{1F4C4} Arquivos restantes: ${e.join(", ")}`);let t=await q({message:"Gerar commit para os arquivos restantes?"});return z(t)?!1:t}function P(){st("Opera\xE7\xE3o cancelada pelo usu\xE1rio")}var L=S(()=>{"use strict";d()});var Ge={};O(Ge,{chooseSplitMode:()=>oe,confirmGroupCommit:()=>lt,showSmartSplitGroups:()=>mt,showSmartSplitProgress:()=>ut});import{select as Ie,confirm as ct,log as ke,note as Oe,isCancel as ie}from"@clack/prompts";async function oe(){let e=await Ie({message:"Como voc\xEA gostaria de organizar os commits?",options:[{value:"smart",label:"\u{1F9E0} Smart Split (Recomendado)",hint:"IA analisa contexto e agrupa automaticamente"},{value:"manual",label:"\u270B Split Manual",hint:"Voc\xEA escolhe arquivos manualmente"},{value:"cancel",label:"\u274C Cancelar",hint:"Voltar ao modo normal"}]});return ie(e)?{action:"cancel"}:e==="manual"?{action:"manual"}:e==="smart"?{action:"proceed"}:{action:"cancel"}}async function mt(e){Oe(`Identificamos ${e.length} grupo(s) l\xF3gico(s) para seus commits:
39
+ ${o}`:i}else e.match(/^```[\s\S]*```$/)&&(e=e.replace(/^```(?:plaintext|javascript|typescript|python|java|html|css|json|xml|yaml|yml|bash|shell|text)?\s*/,"").replace(/\s*```$/,""))}return e=e.trim(),e}function Fe(e,t){if(!t)return null;let i=e.language==="pt",o=[];if(e.commitStyle==="conventional"){let s=t.typeEnum?.join(", ")??D;o.push(i?"- Formato: tipo(escopo): descri\xE7\xE3o":"- Format: type(scope): description"),o.push(i?`- Tipos permitidos: ${s}`:`- Allowed types: ${s}`)}if(t.headerMaxLength!=null){let s=t.headerMaxLength;o.push(i?`- CR\xCDTICO: o header (primeira linha) N\xC3O PODE exceder ${s} caracteres. Conte os caracteres antes de responder.`:`- CRITICAL: the header (first line) MUST NOT exceed ${s} characters. Count characters before responding.`)}if(t.scopeEnum&&t.scopeEnum.length>0&&o.push(i?`- Escopos permitidos: ${t.scopeEnum.join(", ")}`:`- Allowed scopes: ${t.scopeEnum.join(", ")}`),t.subjectCase){let{condition:s,cases:r}=t.subjectCase,m=r.join(", ");s==="never"?o.push(i?`- Subject nunca em: ${m}`:`- Subject must never be: ${m}`):s==="always"&&o.push(i?`- Subject deve estar em: ${m}`:`- Subject must be in: ${m}`)}if(t.subjectFullStop){let{condition:s,value:r}=t.subjectFullStop,m=r??".";s==="never"&&o.push(i?`- N\xE3o termine o subject com "${m}"`:`- Do not end subject with "${m}"`)}return o.length===0?null:`${i?"Voc\xEA \xE9 um gerador de mensagens de commit. Siga ESTRITAMENTE as seguintes regras do commitlint do projeto. Responda APENAS com a mensagem de commit, sem explica\xE7\xF5es adicionais.":"You are a commit message generator. STRICTLY follow the project commitlint rules below. Respond with ONLY the commit message, no additional explanation."}
40
+
41
+ ${o.join(`
42
+ `)}`}async function Ie(e,t,i,o){try{if(!t.openai.apiKey)return{success:!1,error:"Chave da OpenAI n\xE3o encontrada. Configure OPENAI_API_KEY nas vari\xE1veis de ambiente."};let n=Ae(e,t,i,o),s=Fe(t,o),r=[];s&&r.push({role:"system",content:s}),r.push({role:"user",content:n});let m=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{Authorization:`Bearer ${t.openai.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:t.openai.model,messages:r,max_tokens:Math.min(t.openai.maxTokens,150),temperature:t.openai.temperature})});if(!m.ok){let d=await m.json().catch(()=>({}));return{success:!1,error:`Erro da OpenAI (${m.status}): ${d.error?.message||"Erro desconhecido"}`}}let c=(await m.json()).choices?.[0]?.message?.content?.trim();if(!c)return{success:!1,error:"OpenAI retornou resposta vazia"};c=Re(c);let a=je(c),u=Me(e,i);return{success:!0,suggestion:{message:c,type:a||u,confidence:.8}}}catch(n){return{success:!1,error:`Erro ao conectar com OpenAI: ${n instanceof Error?n.message:"Erro desconhecido"}`}}}async function N(e,t,i,o=3,n){let s="";for(let r=0;r<o;r++){let m=await Ie(e,t,i,n);if(m.success)return m;s=m.error||"Erro desconhecido",r<o-1&&await new Promise(l=>setTimeout(l,Math.pow(2,r)*1e3))}return{success:!1,error:`Falha ap\xF3s ${o} tentativas. \xDAltimo erro: ${s}`}}var D,Z=S(()=>{"use strict";f();D="feat, fix, docs, style, refactor, test, chore, build, ci"});var te={};k(te,{askContinueCommits:()=>ee,confirmCommit:()=>ct,copyToClipboard:()=>J,editCommitMessage:()=>_,selectFilesForCommit:()=>X,showCancellation:()=>z,showCommitPreview:()=>U,showCommitResult:()=>C});import{text as nt,select as st,confirm as q,log as F,note as Pe,cancel as rt,isCancel as I}from"@clack/prompts";import at from"clipboardy";async function U(e){Pe(`Tipo: ${e.type}
43
+ Mensagem: "${e.message}"`,"\u{1F4AD} Sugest\xE3o de Commit");let t=await st({message:"O que voc\xEA gostaria de fazer?",options:[{value:"commit",label:"\u2705 Fazer commit com esta mensagem",hint:"Executar git commit imediatamente"},{value:"edit",label:"\u270F\uFE0F Editar mensagem",hint:"Modificar a mensagem antes de commitar"},{value:"copy",label:"\u{1F4CB} Copiar para clipboard",hint:"Copiar mensagem e sair sem commitar"},{value:"cancel",label:"\u274C Cancelar",hint:"Sair sem fazer nada"}]});return I(t)?{action:"cancel"}:{action:t}}async function _(e){let t=await nt({message:"Edite a mensagem do commit:",initialValue:e,placeholder:"Digite a mensagem do commit...",validate:o=>{if(!o||o.trim().length===0)return"A mensagem n\xE3o pode estar vazia";if(o.trim().length>72)return"A mensagem est\xE1 muito longa (m\xE1ximo 72 caracteres recomendado)"}});if(I(t))return{action:"cancel"};let i=await q({message:`Confirma a mensagem editada: "${t}"?`});return I(i)||!i?{action:"cancel"}:{action:"commit",message:t}}async function J(e){try{return await at.write(e),F.success("\u2705 Mensagem copiada para a \xE1rea de transfer\xEAncia!"),!0}catch(t){return F.error(`\u274C Erro ao copiar: ${t instanceof Error?t.message:"Erro desconhecido"}`),!1}}async function ct(e){Pe(`"${e}"`,"\u{1F680} Confirmar Commit");let t=await q({message:"Executar o commit agora?"});return I(t)?!1:t}function C(e,t,i){e&&t?(F.success("\u2705 Commit realizado com sucesso!"),F.info(`\u{1F517} Hash: ${t.substring(0,8)}`)):F.error(`\u274C Erro ao realizar commit: ${i||"Erro desconhecido"}`)}async function X(e){F.info("\u{1F4CB} Modo Split: Selecione os arquivos para este commit");let t=[];for(let i of e){let o=await q({message:`Incluir "${i}" neste commit?`});if(I(o))break;o&&t.push(i)}return t}async function ee(e){if(e.length===0)return!1;F.info(`\u{1F4C4} Arquivos restantes: ${e.join(", ")}`);let t=await q({message:"Gerar commit para os arquivos restantes?"});return I(t)?!1:t}function z(){rt("Opera\xE7\xE3o cancelada pelo usu\xE1rio")}var G=S(()=>{"use strict";f()});var Ge={};k(Ge,{chooseSplitMode:()=>oe,confirmGroupCommit:()=>ut,showSmartSplitGroups:()=>lt,showSmartSplitProgress:()=>pt});import{select as ke,confirm as mt,log as Oe,note as Te,isCancel as ie}from"@clack/prompts";async function oe(){let e=await ke({message:"Como voc\xEA gostaria de organizar os commits?",options:[{value:"smart",label:"\u{1F9E0} Smart Split (Recomendado)",hint:"IA analisa contexto e agrupa automaticamente"},{value:"manual",label:"\u270B Split Manual",hint:"Voc\xEA escolhe arquivos manualmente"},{value:"cancel",label:"\u274C Cancelar",hint:"Voltar ao modo normal"}]});return ie(e)?{action:"cancel"}:e==="manual"?{action:"manual"}:e==="smart"?{action:"proceed"}:{action:"cancel"}}async function lt(e){Te(`Identificamos ${e.length} grupo(s) l\xF3gico(s) para seus commits:
41
44
 
42
45
  `+e.map((i,o)=>`${o+1}. **${i.name}**
43
46
  \u{1F4C4} ${i.files.join(", ")}
44
47
  \u{1F4A1} ${i.description}
45
48
  \u{1F3AF} Confian\xE7a: ${Math.round(i.confidence*100)}%`).join(`
46
49
 
47
- `),"\u{1F9E0} An\xE1lise de Contexto");let t=await Ie({message:"O que voc\xEA gostaria de fazer?",options:[{value:"proceed",label:"\u2705 Prosseguir com esta organiza\xE7\xE3o",hint:"Usar os grupos como sugeridos pela IA"},{value:"manual",label:"\u270B Fazer split manual",hint:"Escolher arquivos manualmente"},{value:"cancel",label:"\u274C Cancelar",hint:"Voltar ao modo normal"}]});return ie(t)?{action:"cancel"}:t==="proceed"?{action:"proceed",groups:e}:{action:t}}async function lt(e,t){Oe(`**Grupo:** ${e.name}
50
+ `),"\u{1F9E0} An\xE1lise de Contexto");let t=await ke({message:"O que voc\xEA gostaria de fazer?",options:[{value:"proceed",label:"\u2705 Prosseguir com esta organiza\xE7\xE3o",hint:"Usar os grupos como sugeridos pela IA"},{value:"manual",label:"\u270B Fazer split manual",hint:"Escolher arquivos manualmente"},{value:"cancel",label:"\u274C Cancelar",hint:"Voltar ao modo normal"}]});return ie(t)?{action:"cancel"}:t==="proceed"?{action:"proceed",groups:e}:{action:t}}async function ut(e,t){Te(`**Grupo:** ${e.name}
48
51
  **Arquivos:** ${e.files.join(", ")}
49
- **Mensagem:** "${t}"`,"\u{1F680} Confirmar Commit do Grupo");let i=await ct({message:`Fazer commit para "${e.name}"?`});return ie(i)?!1:i}function ut(e,t,i){let o=Math.round(e/t*100),n="\u2588".repeat(Math.floor(o/10))+"\u2591".repeat(10-Math.floor(o/10));ke.info(`\u{1F504} Progresso: [${n}] ${o}% (${e}/${t})`),ke.info(`\u{1F4CB} Processando: ${i}`)}var ne=S(()=>{"use strict";d()});import ft from"crypto";function Te(e){Le=new se(e)}function De(){return Le}function qe(e,t){let i=De();return i?i.get(e,t):{hit:!1}}function Ne(e,t,i){let o=De();o&&o.set(e,t,i)}var se,Le,re=S(()=>{"use strict";d();se=class{cache=new Map;config;constructor(t){this.config=t}generateHash(t,i){let o={files:t.sort(),diff:i.substring(0,1e3),model:this.config.openai.model,temperature:this.config.openai.temperature};return ft.createHash("md5").update(JSON.stringify(o)).digest("hex")}get(t,i){if(!this.config.cache.enabled)return{hit:!1};let o=this.generateHash(t,i),n=this.cache.get(o);if(!n)return{hit:!1};let s=Date.now(),r=this.config.cache.ttl*60*1e3;return s-n.timestamp>r?(this.cache.delete(o),{hit:!1}):{hit:!0,groups:n.groups}}set(t,i,o){if(!this.config.cache.enabled||(this.cache.size>=this.config.cache.maxSize&&this.cleanup(),this.cache.size>=this.config.cache.maxSize))return;let n=this.generateHash(t,i),s={groups:o,timestamp:Date.now(),hash:n};this.cache.set(n,s)}cleanup(){let t=Date.now(),i=this.config.cache.ttl*60*1e3;for(let[o,n]of this.cache.entries())t-n.timestamp>i&&this.cache.delete(o);if(this.cache.size>=this.config.cache.maxSize){let n=Array.from(this.cache.entries()).sort((s,r)=>s[1].timestamp-r[1].timestamp).slice(0,Math.ceil(this.config.cache.maxSize*.5));for(let[s]of n)this.cache.delete(s)}}clear(){this.cache.clear()}getStats(){return{size:this.cache.size,maxSize:this.config.cache.maxSize,enabled:this.config.cache.enabled}}},Le=null});import{log as h}from"@clack/prompts";function pt(e,t){let o=t.length>8e3?t.substring(0,8e3)+`
50
- ... (diff truncado)`:t,n=e.length,s=e.reduce((l,m)=>{let c=m.split(".").pop()||"sem-extensao";return l[c]=(l[c]||0)+1,l},{}),r=Object.entries(s).map(([l,m])=>`${l}: ${m}`).join(", ");return`Analise os arquivos modificados e agrupe em commits l\xF3gicos.
52
+ **Mensagem:** "${t}"`,"\u{1F680} Confirmar Commit do Grupo");let i=await mt({message:`Fazer commit para "${e.name}"?`});return ie(i)?!1:i}function pt(e,t,i){let o=Math.round(e/t*100),n="\u2588".repeat(Math.floor(o/10))+"\u2591".repeat(10-Math.floor(o/10));Oe.info(`\u{1F504} Progresso: [${n}] ${o}% (${e}/${t})`),Oe.info(`\u{1F4CB} Processando: ${i}`)}var ne=S(()=>{"use strict";f()});import dt from"crypto";function De(e){Le=new se(e)}function Ne(){return Le}function qe(e,t){let i=Ne();return i?i.get(e,t):{hit:!1}}function Ue(e,t,i){let o=Ne();o&&o.set(e,t,i)}var se,Le,re=S(()=>{"use strict";f();se=class{cache=new Map;config;constructor(t){this.config=t}generateHash(t,i){let o={files:t.sort(),diff:i.substring(0,1e3),model:this.config.openai.model,temperature:this.config.openai.temperature};return dt.createHash("md5").update(JSON.stringify(o)).digest("hex")}get(t,i){if(!this.config.cache.enabled)return{hit:!1};let o=this.generateHash(t,i),n=this.cache.get(o);if(!n)return{hit:!1};let s=Date.now(),r=this.config.cache.ttl*60*1e3;return s-n.timestamp>r?(this.cache.delete(o),{hit:!1}):{hit:!0,groups:n.groups}}set(t,i,o){if(!this.config.cache.enabled||(this.cache.size>=this.config.cache.maxSize&&this.cleanup(),this.cache.size>=this.config.cache.maxSize))return;let n=this.generateHash(t,i),s={groups:o,timestamp:Date.now(),hash:n};this.cache.set(n,s)}cleanup(){let t=Date.now(),i=this.config.cache.ttl*60*1e3;for(let[o,n]of this.cache.entries())t-n.timestamp>i&&this.cache.delete(o);if(this.cache.size>=this.config.cache.maxSize){let n=Array.from(this.cache.entries()).sort((s,r)=>s[1].timestamp-r[1].timestamp).slice(0,Math.ceil(this.config.cache.maxSize*.5));for(let[s]of n)this.cache.delete(s)}}clear(){this.cache.clear()}getStats(){return{size:this.cache.size,maxSize:this.config.cache.maxSize,enabled:this.config.cache.enabled}}},Le=null});import{log as h}from"@clack/prompts";function ft(e,t){let o=t.length>8e3?t.substring(0,8e3)+`
53
+ ... (diff truncado)`:t,n=e.length,s=e.reduce((m,l)=>{let c=l.split(".").pop()||"sem-extensao";return m[c]=(m[c]||0)+1,m},{}),r=Object.entries(s).map(([m,l])=>`${m}: ${l}`).join(", ");return`Analise os arquivos modificados e agrupe em commits l\xF3gicos.
51
54
 
52
55
  ARQUIVOS (${n}): ${e.join(", ")}
53
56
  TIPOS: ${r}
@@ -68,7 +71,7 @@ Agrupe arquivos relacionados. M\xE1ximo 5 grupos. Responda em JSON:
68
71
  "confidence": 0.8
69
72
  }
70
73
  ]
71
- }`}function dt(e){let t=e.reduce((o,n)=>{let s=n.split("/").slice(0,-1).join("/")||"root";return o[s]||(o[s]=[]),o[s].push(n),o},{});return`Agrupe estes arquivos em commits l\xF3gicos baseado nos diret\xF3rios:
74
+ }`}function gt(e){let t=e.reduce((o,n)=>{let s=n.split("/").slice(0,-1).join("/")||"root";return o[s]||(o[s]=[]),o[s].push(n),o},{});return`Agrupe estes arquivos em commits l\xF3gicos baseado nos diret\xF3rios:
72
75
 
73
76
  ARQUIVOS POR DIRET\xD3RIO:
74
77
  ${Object.entries(t).map(([o,n])=>`${o}: ${n.length} arquivo(s)`).join(`
@@ -87,40 +90,40 @@ Agrupe por funcionalidade relacionada. M\xE1ximo 5 grupos. JSON:
87
90
  "confidence": 0.7
88
91
  }
89
92
  ]
90
- }`}async function gt(e,t,i){try{if(!i.openai.apiKey)return{success:!1,error:"Chave da OpenAI n\xE3o encontrada"};let o=qe(e,t);if(o.hit&&o.groups)return{success:!0,groups:o.groups};let s=t.length>6e3,r=s?dt(e):pt(e,t);s&&console.warn(`\u26A0\uFE0F Diff muito grande (${t.length} chars), usando an\xE1lise baseada em nomes de arquivos`);let l=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{Authorization:`Bearer ${i.openai.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:i.openai.model,messages:[{role:"user",content:r}],max_tokens:800,temperature:.3})});if(!l.ok){let g=await l.json().catch(()=>({}));return{success:!1,error:`Erro da OpenAI (${l.status}): ${g.error?.message||"Erro desconhecido"}`}}let c=(await l.json()).choices?.[0]?.message?.content?.trim();if(!c)return{success:!1,error:"OpenAI retornou resposta vazia"};let a=c.match(/\{[\s\S]*\}/);if(!a)return{success:!1,error:"Resposta da OpenAI n\xE3o cont\xE9m JSON v\xE1lido"};let u=JSON.parse(a[0]);if(!u.groups||!Array.isArray(u.groups))return{success:!1,error:"Formato de resposta inv\xE1lido da OpenAI"};let p=u.groups.flatMap(g=>g.files||[]),y=e.filter(g=>!p.includes(g));y.length>0&&(u.groups[0].files=[...u.groups[0].files||[],...y]);let R=u.groups.map(g=>({id:g.id||`group-${Math.random().toString(36).substr(2,9)}`,name:g.name||"Grupo sem nome",description:g.description||"Sem descri\xE7\xE3o",files:g.files||[],diff:"",confidence:g.confidence||.5}));return Ne(e,t,R),{success:!0,groups:R}}catch(o){return{success:!1,error:`Erro ao analisar contexto: ${o instanceof Error?o.message:"Erro desconhecido"}`}}}async function ht(e){let{getFileDiff:t}=await Promise.resolve().then(()=>(w(),j)),i=e.files.map(s=>{try{let r=t(s),l=4e3;return r.length>l?r.substring(0,l)+`
91
- ... (diff truncado)`:r}catch{return""}}).filter(s=>s.length>0);if(i.length===0&&e.files.length>0){let{execSync:s}=await import("child_process"),r=e.files.filter(m=>{try{return s(`test -f "${m}"`,{stdio:"ignore"}),s(`git status --porcelain -- "${m}"`,{encoding:"utf-8",stdio:"pipe"}).trim().startsWith("??")}catch{return!1}});if(r.length>0)return r.map(m=>{try{let c=s(`cat "${m}"`,{encoding:"utf-8",stdio:"pipe"}),a=2e3,u=c.length>a?c.substring(0,a)+`
92
- ... (conte\xFAdo truncado)`:c;return`diff --git a/${m} b/${m}
93
+ }`}async function ht(e,t,i){try{if(!i.openai.apiKey)return{success:!1,error:"Chave da OpenAI n\xE3o encontrada"};let o=qe(e,t);if(o.hit&&o.groups)return{success:!0,groups:o.groups};let s=t.length>6e3,r=s?gt(e):ft(e,t);s&&console.warn(`\u26A0\uFE0F Diff muito grande (${t.length} chars), usando an\xE1lise baseada em nomes de arquivos`);let m=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{Authorization:`Bearer ${i.openai.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:i.openai.model,messages:[{role:"user",content:r}],max_tokens:800,temperature:.3})});if(!m.ok){let g=await m.json().catch(()=>({}));return{success:!1,error:`Erro da OpenAI (${m.status}): ${g.error?.message||"Erro desconhecido"}`}}let c=(await m.json()).choices?.[0]?.message?.content?.trim();if(!c)return{success:!1,error:"OpenAI retornou resposta vazia"};let a=c.match(/\{[\s\S]*\}/);if(!a)return{success:!1,error:"Resposta da OpenAI n\xE3o cont\xE9m JSON v\xE1lido"};let u=JSON.parse(a[0]);if(!u.groups||!Array.isArray(u.groups))return{success:!1,error:"Formato de resposta inv\xE1lido da OpenAI"};let d=u.groups.flatMap(g=>g.files||[]),y=e.filter(g=>!d.includes(g));y.length>0&&(u.groups[0].files=[...u.groups[0].files||[],...y]);let M=u.groups.map(g=>({id:g.id||`group-${Math.random().toString(36).substr(2,9)}`,name:g.name||"Grupo sem nome",description:g.description||"Sem descri\xE7\xE3o",files:g.files||[],diff:"",confidence:g.confidence||.5}));return Ue(e,t,M),{success:!0,groups:M}}catch(o){return{success:!1,error:`Erro ao analisar contexto: ${o instanceof Error?o.message:"Erro desconhecido"}`}}}async function yt(e){let{getFileDiff:t}=await Promise.resolve().then(()=>(w(),j)),i=e.files.map(s=>{try{let r=t(s),m=4e3;return r.length>m?r.substring(0,m)+`
94
+ ... (diff truncado)`:r}catch{return""}}).filter(s=>s.length>0);if(i.length===0&&e.files.length>0){let{execSync:s}=await import("child_process"),r=e.files.filter(l=>{try{return s(`test -f "${l}"`,{stdio:"ignore"}),s(`git status --porcelain -- "${l}"`,{encoding:"utf-8",stdio:"pipe"}).trim().startsWith("??")}catch{return!1}});if(r.length>0)return r.map(l=>{try{let c=s(`cat "${l}"`,{encoding:"utf-8",stdio:"pipe"}),a=2e3,u=c.length>a?c.substring(0,a)+`
95
+ ... (conte\xFAdo truncado)`:c;return`diff --git a/${l} b/${l}
93
96
  new file mode 100644
94
97
  index 0000000..${Math.random().toString(36).substr(2,7)}
95
98
  --- /dev/null
96
- +++ b/${m}
99
+ +++ b/${l}
97
100
  @@ -0,0 +1,${u.split(`
98
101
  `).length} @@
99
102
  ${u.split(`
100
- `).map(p=>`+${p}`).join(`
101
- `)}`}catch{return""}}).filter(m=>m.length>0).join(`
102
- `);let l=e.files.filter(m=>{try{return s(`test -f "${m}"`,{stdio:"ignore"}),s("git diff --cached --name-only",{encoding:"utf-8",stdio:"pipe"}).trim().split(`
103
- `).includes(m)}catch{return!1}});if(l.length>0)return l.map(m=>{try{let c=s(`cat "${m}"`,{encoding:"utf-8",stdio:"pipe"}),a=2e3,u=c.length>a?c.substring(0,a)+`
104
- ... (conte\xFAdo truncado)`:c;return`diff --git a/${m} b/${m}
103
+ `).map(d=>`+${d}`).join(`
104
+ `)}`}catch{return""}}).filter(l=>l.length>0).join(`
105
+ `);let m=e.files.filter(l=>{try{return s(`test -f "${l}"`,{stdio:"ignore"}),s("git diff --cached --name-only",{encoding:"utf-8",stdio:"pipe"}).trim().split(`
106
+ `).includes(l)}catch{return!1}});if(m.length>0)return m.map(l=>{try{let c=s(`cat "${l}"`,{encoding:"utf-8",stdio:"pipe"}),a=2e3,u=c.length>a?c.substring(0,a)+`
107
+ ... (conte\xFAdo truncado)`:c;return`diff --git a/${l} b/${l}
105
108
  index 0000000..${Math.random().toString(36).substr(2,7)} 100644
106
- --- a/${m}
107
- +++ b/${m}
109
+ --- a/${l}
110
+ +++ b/${l}
108
111
  @@ -1 +1,${u.split(`
109
112
  `).length} @@
110
113
  ${u.split(`
111
- `).map(p=>`+${p}`).join(`
112
- `)}`}catch{return""}}).filter(m=>m.length>0).join(`
114
+ `).map(d=>`+${d}`).join(`
115
+ `)}`}catch{return""}}).filter(l=>l.length>0).join(`
113
116
  `)}let o=i.join(`
114
117
  `),n=8e3;return o.length>n?o.substring(0,n)+`
115
- ... (diff total truncado)`:o}async function ae(e,t,i,o){i.silent||h.info("\u{1F9E0} Modo Smart Split ativado - Agrupando arquivos por contexto"),i.silent||h.info("\u{1F916} Analisando contexto das mudan\xE7as...");let n=await gt(e.stagedFiles,e.diff,t);if(!n.success){i.silent||h.error(`\u274C Erro na an\xE1lise de contexto: ${n.error}`);return}if(!n.groups||n.groups.length===0){i.silent||h.error("\u274C Nenhum grupo foi criado pela an\xE1lise");return}if(i.silent||(h.success(`\u2705 ${n.groups.length} grupo(s) identificado(s):`),n.groups.forEach((s,r)=>{h.info(` ${r+1}. ${s.name} (${s.files.length} arquivo(s))`),h.info(` \u{1F4C4} ${s.files.join(", ")}`)})),!i.yes&&!i.silent){let{showSmartSplitGroups:s}=await Promise.resolve().then(()=>(ne(),Ge)),r=await s(n.groups);if(r.action==="cancel"){i.silent||h.info("\u274C Opera\xE7\xE3o cancelada pelo usu\xE1rio");return}if(r.action==="manual"){let l={...i,split:!0,smartSplit:!1},{main:m}=await Promise.resolve().then(()=>(ce(),_e));await m(l);return}}for(let s=0;s<n.groups.length;s++){let r=n.groups[s];if(!r){i.silent||h.error(`\u274C Grupo ${s+1} \xE9 undefined`);continue}i.silent||h.info(`
116
- \u{1F504} Processando grupo ${s+1}/${n.groups.length}: ${r.name}`);let l=await ht(r);if(!l){i.silent||(h.warn(`\u26A0\uFE0F Nenhum diff encontrado para o grupo: ${r.name}`),h.info(` \u{1F4C4} Arquivos: ${r.files.join(", ")}`),h.info(" \u{1F4A1} Poss\xEDvel causa: arquivos novos, deletados/recriados, ou sem mudan\xE7as"));continue}i.silent||h.info(`\u{1F916} Gerando commit para: ${r.name}`);let{generateWithRetry:m}=await Promise.resolve().then(()=>(Z(),ze)),c=await m(l,t,r.files,3,o);if(!c.success){i.silent||h.error(`\u274C Erro ao gerar commit para ${r.name}: ${c.error}`);continue}if(!c.suggestion){i.silent||h.error(`\u274C Nenhuma sugest\xE3o gerada para ${r.name}`);continue}if(t.dryRun){i.silent||(h.info(`\u{1F50D} Dry Run - Grupo: ${r.name}`),h.info(`\u{1F4C4} Arquivos: ${r.files.join(", ")}`),h.info(`\u{1F4AD} Mensagem: "${c.suggestion.message}"`));continue}if(i.yes){let{executeFileCommit:a}=await Promise.resolve().then(()=>(w(),j)),u;if(r.files.length===1&&r.files[0])u=a(r.files[0],c.suggestion.message||"");else{let{execSync:p}=await import("child_process"),{escapeShellArg:y}=await Promise.resolve().then(()=>(w(),j));try{let R=r.files.map(b=>y(b)).join(" "),g=y(c.suggestion.message||"");p(`git commit ${R} -m ${g}`,{stdio:"pipe"}),u={success:!0,hash:p("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:c.suggestion.message||""}}catch(R){u={success:!1,error:R instanceof Error?R.message:"Erro desconhecido ao executar commit"}}}v(u.success,u.hash,u.error)}else{let{showCommitPreview:a,editCommitMessage:u,copyToClipboard:p,showCancellation:y}=await Promise.resolve().then(()=>(L(),te));switch((await a(c.suggestion)).action){case"commit":{let{executeFileCommit:g}=await Promise.resolve().then(()=>(w(),j)),$,b=c.suggestion.message||"Atualiza\xE7\xE3o de arquivos";if(r.files.length===1&&r.files[0])$=g(r.files[0],b);else{let{execSync:k}=await import("child_process"),{escapeShellArg:I}=await Promise.resolve().then(()=>(w(),j));try{let A=r.files.map(H=>I(H)).join(" "),W=I(b);k(`git commit ${A} -m ${W}`,{stdio:"pipe"}),$={success:!0,hash:k("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:b}}catch(A){$={success:!1,error:A instanceof Error?A.message:"Erro desconhecido ao executar commit"}}}v($.success,$.hash,$.error);break}case"edit":{let g=await u(c.suggestion.message);if(g.action==="commit"&&g.message){let{executeFileCommit:$}=await Promise.resolve().then(()=>(w(),j)),b;if(r.files.length===1&&r.files[0])b=$(r.files[0],g.message||"");else{let{execSync:k}=await import("child_process"),{escapeShellArg:I}=await Promise.resolve().then(()=>(w(),j));try{let A=r.files.map(H=>I(H)).join(" "),W=I(g.message||"");k(`git commit ${A} -m ${W}`,{stdio:"pipe"}),b={success:!0,hash:k("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:g.message||""}}catch(A){b={success:!1,error:A instanceof Error?A.message:"Erro desconhecido ao executar commit"}}}v(b.success,b.hash,b.error)}break}case"copy":{await p(c.suggestion.message),i.silent||h.info("\u{1F3AF} Mensagem copiada para clipboard");break}case"cancel":{y();return}}}if(s<n.groups.length-1&&!i.yes){let{askContinueCommits:a}=await Promise.resolve().then(()=>(L(),te)),u=n.groups.slice(s+1).filter(y=>y!==void 0).map(y=>y.name);if(!await a(u))break}}i.silent||h.success("\u2705 Smart Split conclu\xEDdo!")}var Ue=S(()=>{"use strict";d();re();L()});import{existsSync as ue,writeFileSync as yt,readFileSync as bt}from"fs";import{join as J,extname as vt,basename as Ct}from"path";import{spawnSync as le}from"child_process";function me(e){let t={},i=e?.rules??{},o=i["type-enum"];Array.isArray(o)&&Array.isArray(o[2])&&(t.typeEnum=o[2]);let n=i["header-max-length"];Array.isArray(n)&&typeof n[2]=="number"&&(t.headerMaxLength=n[2]);let s=i["subject-case"];if(Array.isArray(s)){let[c,a,u]=s;Array.isArray(u)?t.subjectCase={severity:c,condition:a,cases:u}:typeof u=="string"&&(t.subjectCase={severity:c,condition:a,cases:[u]})}let r=i["subject-full-stop"];if(Array.isArray(r)){let[c,a,u]=r;t.subjectFullStop={severity:c,condition:a,value:u??"."}}let l=i["body-leading-blank"];Array.isArray(l)&&(t.bodyLeadingBlank=l[1]==="always");let m=i["scope-enum"];return Array.isArray(m)&&Array.isArray(m[2])&&(t.scopeEnum=m[2]),t}function Je(e){try{let t=vt(e).toLowerCase(),i=Ct(e);if(t===".json"||t===""&&i===".commitlintrc")try{let o=bt(e,"utf-8"),n=JSON.parse(o);return me(n)}catch{return null}if(t===".js"||t===".mjs"||t===".cjs"){let o=["import { pathToFileURL } from 'url';",`const mod = await import(pathToFileURL(${JSON.stringify(e)}).href);`,"const cfg = mod.default ?? mod;","process.stdout.write(JSON.stringify(cfg));"].join(`
117
- `),n=le(process.execPath,["--input-type=module"],{input:o,encoding:"utf-8",timeout:5e3});if(n.status===0&&n.stdout)try{let l=JSON.parse(n.stdout);return me(l)}catch{}let s=["try {",` const c = require(${JSON.stringify(e)});`," process.stdout.write(JSON.stringify(c.default ?? c));","} catch (e) {"," process.exit(1);","}"].join(`
118
- `),r=le(process.execPath,["-e",s],{encoding:"utf-8",timeout:5e3});if(r.status===0&&r.stdout)try{let l=JSON.parse(r.stdout);return me(l)}catch{}}return null}catch{return null}}function fe(e){let t=e||process.cwd();for(let i of xt){let o=J(t,i);if(ue(o))return o}return null}function pe(e){let t=e||process.cwd(),i=J(t,"node_modules",".bin","commitlint");return ue(i)}function Ve(e,t){let i=t||process.cwd(),o=J(i,"node_modules",".bin","commitlint"),n=le(o,[],{input:e,encoding:"utf-8",cwd:i});if(n.status===0)return{valid:!0,errors:[],warnings:[]};let r=((n.stdout||"")+(n.stderr||"")).split(`
119
- `),l=[],m=[];for(let c of r){let a=c.trim();a&&(a.startsWith("\u2716")||a.includes("[error]")?l.push(a):(a.startsWith("\u26A0")||a.includes("[warning]"))&&m.push(a))}if(l.length===0&&n.status!==0){let c=r.map(a=>a.trim()).filter(a=>!(!a.length||a.startsWith("\u29D7")||a.startsWith("\u2714")||a.startsWith("at ")||a.startsWith("file:///")||a.match(/^[^:]+\.(?:js|ts|mjs|cjs):\d+$/)||a==="^"||a==="throw err;"||a.startsWith("Node.js v")));l.push(...c)}return{valid:!1,errors:l,warnings:m}}function We(e){let t=e||process.cwd(),i=J(t,"commitlint.config.js");if(ue(i))throw new Error("commitlint.config.js j\xE1 existe neste diret\xF3rio. Remova-o antes de continuar.");yt(i,`export default {
118
+ ... (diff total truncado)`:o}async function ae(e,t,i,o){i.silent||h.info("\u{1F9E0} Modo Smart Split ativado - Agrupando arquivos por contexto"),i.silent||h.info("\u{1F916} Analisando contexto das mudan\xE7as...");let n=await ht(e.stagedFiles,e.diff,t);if(!n.success){i.silent||h.error(`\u274C Erro na an\xE1lise de contexto: ${n.error}`);return}if(!n.groups||n.groups.length===0){i.silent||h.error("\u274C Nenhum grupo foi criado pela an\xE1lise");return}if(i.silent||(h.success(`\u2705 ${n.groups.length} grupo(s) identificado(s):`),n.groups.forEach((s,r)=>{h.info(` ${r+1}. ${s.name} (${s.files.length} arquivo(s))`),h.info(` \u{1F4C4} ${s.files.join(", ")}`)})),!i.yes&&!i.silent){let{showSmartSplitGroups:s}=await Promise.resolve().then(()=>(ne(),Ge)),r=await s(n.groups);if(r.action==="cancel"){i.silent||h.info("\u274C Opera\xE7\xE3o cancelada pelo usu\xE1rio");return}if(r.action==="manual"){let m={...i,split:!0,smartSplit:!1},{main:l}=await Promise.resolve().then(()=>(ce(),Je));await l(m);return}}for(let s=0;s<n.groups.length;s++){let r=n.groups[s];if(!r){i.silent||h.error(`\u274C Grupo ${s+1} \xE9 undefined`);continue}i.silent||h.info(`
119
+ \u{1F504} Processando grupo ${s+1}/${n.groups.length}: ${r.name}`);let m=await yt(r);if(!m){i.silent||(h.warn(`\u26A0\uFE0F Nenhum diff encontrado para o grupo: ${r.name}`),h.info(` \u{1F4C4} Arquivos: ${r.files.join(", ")}`),h.info(" \u{1F4A1} Poss\xEDvel causa: arquivos novos, deletados/recriados, ou sem mudan\xE7as"));continue}i.silent||h.info(`\u{1F916} Gerando commit para: ${r.name}`);let{generateWithRetry:l}=await Promise.resolve().then(()=>(Z(),ze)),c=await l(m,t,r.files,3,o);if(!c.success){i.silent||h.error(`\u274C Erro ao gerar commit para ${r.name}: ${c.error}`);continue}if(!c.suggestion){i.silent||h.error(`\u274C Nenhuma sugest\xE3o gerada para ${r.name}`);continue}if(t.dryRun){i.silent||(h.info(`\u{1F50D} Dry Run - Grupo: ${r.name}`),h.info(`\u{1F4C4} Arquivos: ${r.files.join(", ")}`),h.info(`\u{1F4AD} Mensagem: "${c.suggestion.message}"`));continue}if(i.yes){let{executeFileCommit:a}=await Promise.resolve().then(()=>(w(),j)),u;if(r.files.length===1&&r.files[0])u=a(r.files[0],c.suggestion.message||"");else{let{execSync:d}=await import("child_process"),{escapeShellArg:y}=await Promise.resolve().then(()=>(w(),j));try{let M=r.files.map(b=>y(b)).join(" "),g=y(c.suggestion.message||"");d(`git commit ${M} -m ${g}`,{stdio:"pipe"}),u={success:!0,hash:d("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:c.suggestion.message||""}}catch(M){u={success:!1,error:M instanceof Error?M.message:"Erro desconhecido ao executar commit"}}}C(u.success,u.hash,u.error)}else{let{showCommitPreview:a,editCommitMessage:u,copyToClipboard:d,showCancellation:y}=await Promise.resolve().then(()=>(G(),te));switch((await a(c.suggestion)).action){case"commit":{let{executeFileCommit:g}=await Promise.resolve().then(()=>(w(),j)),$,b=c.suggestion.message||"Atualiza\xE7\xE3o de arquivos";if(r.files.length===1&&r.files[0])$=g(r.files[0],b);else{let{execSync:P}=await import("child_process"),{escapeShellArg:O}=await Promise.resolve().then(()=>(w(),j));try{let E=r.files.map(B=>O(B)).join(" "),H=O(b);P(`git commit ${E} -m ${H}`,{stdio:"pipe"}),$={success:!0,hash:P("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:b}}catch(E){$={success:!1,error:E instanceof Error?E.message:"Erro desconhecido ao executar commit"}}}C($.success,$.hash,$.error);break}case"edit":{let g=await u(c.suggestion.message);if(g.action==="commit"&&g.message){let{executeFileCommit:$}=await Promise.resolve().then(()=>(w(),j)),b;if(r.files.length===1&&r.files[0])b=$(r.files[0],g.message||"");else{let{execSync:P}=await import("child_process"),{escapeShellArg:O}=await Promise.resolve().then(()=>(w(),j));try{let E=r.files.map(B=>O(B)).join(" "),H=O(g.message||"");P(`git commit ${E} -m ${H}`,{stdio:"pipe"}),b={success:!0,hash:P("git rev-parse HEAD",{encoding:"utf-8",stdio:"pipe"}).trim(),message:g.message||""}}catch(E){b={success:!1,error:E instanceof Error?E.message:"Erro desconhecido ao executar commit"}}}C(b.success,b.hash,b.error)}break}case"copy":{await d(c.suggestion.message),i.silent||h.info("\u{1F3AF} Mensagem copiada para clipboard");break}case"cancel":{y();return}}}if(s<n.groups.length-1&&!i.yes){let{askContinueCommits:a}=await Promise.resolve().then(()=>(G(),te)),u=n.groups.slice(s+1).filter(y=>y!==void 0).map(y=>y.name);if(!await a(u))break}}i.silent||h.success("\u2705 Smart Split conclu\xEDdo!")}var _e=S(()=>{"use strict";f();re();G()});import{existsSync as ue,writeFileSync as bt,readFileSync as Ct}from"fs";import{join as V,extname as vt,basename as xt}from"path";import{spawnSync as le}from"child_process";function me(e){let t={},i=e?.rules??{},o=i["type-enum"];Array.isArray(o)&&Array.isArray(o[2])&&(t.typeEnum=o[2]);let n=i["header-max-length"];Array.isArray(n)&&typeof n[2]=="number"&&(t.headerMaxLength=n[2]);let s=i["subject-case"];if(Array.isArray(s)){let[c,a,u]=s;Array.isArray(u)?t.subjectCase={severity:c,condition:a,cases:u}:typeof u=="string"&&(t.subjectCase={severity:c,condition:a,cases:[u]})}let r=i["subject-full-stop"];if(Array.isArray(r)){let[c,a,u]=r;t.subjectFullStop={severity:c,condition:a,value:u??"."}}let m=i["body-leading-blank"];Array.isArray(m)&&(t.bodyLeadingBlank=m[1]==="always");let l=i["scope-enum"];return Array.isArray(l)&&Array.isArray(l[2])&&(t.scopeEnum=l[2]),t}function Ve(e){try{let t=vt(e).toLowerCase(),i=xt(e);if(t===".json"||t===""&&i===".commitlintrc")try{let o=Ct(e,"utf-8"),n=JSON.parse(o);return me(n)}catch{return null}if(t===".js"||t===".mjs"||t===".cjs"){let o=["import { pathToFileURL } from 'url';",`const mod = await import(pathToFileURL(${JSON.stringify(e)}).href);`,"const cfg = mod.default ?? mod;","process.stdout.write(JSON.stringify(cfg));"].join(`
120
+ `),n=le(process.execPath,["--input-type=module"],{input:o,encoding:"utf-8",timeout:5e3});if(n.status===0&&n.stdout)try{let m=JSON.parse(n.stdout);return me(m)}catch{}let s=["try {",` const c = require(${JSON.stringify(e)});`," process.stdout.write(JSON.stringify(c.default ?? c));","} catch (e) {"," process.exit(1);","}"].join(`
121
+ `),r=le(process.execPath,["-e",s],{encoding:"utf-8",timeout:5e3});if(r.status===0&&r.stdout)try{let m=JSON.parse(r.stdout);return me(m)}catch{}}return null}catch{return null}}function pe(e){let t=e||process.cwd();for(let i of St){let o=V(t,i);if(ue(o))return o}return null}function de(e){let t=e||process.cwd(),i=V(t,"node_modules",".bin","commitlint");return ue(i)}function We(e,t){let i=t||process.cwd(),o=V(i,"node_modules",".bin","commitlint"),n=le(o,[],{input:e,encoding:"utf-8",cwd:i});if(n.status===0)return{valid:!0,errors:[],warnings:[]};let r=((n.stdout||"")+(n.stderr||"")).split(`
122
+ `),m=[],l=[];for(let c of r){let a=c.trim();a&&(a.startsWith("\u2716")||a.includes("[error]")?m.push(a):(a.startsWith("\u26A0")||a.includes("[warning]"))&&l.push(a))}if(m.length===0&&n.status!==0){let c=r.map(a=>a.trim()).filter(a=>!(!a.length||a.startsWith("\u29D7")||a.startsWith("\u2714")||a.startsWith("at ")||a.startsWith("file:///")||a.match(/^[^:]+\.(?:js|ts|mjs|cjs):\d+$/)||a==="^"||a==="throw err;"||a.startsWith("Node.js v")));m.push(...c)}return{valid:!1,errors:m,warnings:l}}function He(e){let t=e||process.cwd(),i=V(t,"commitlint.config.js");if(ue(i))throw new Error("commitlint.config.js j\xE1 existe neste diret\xF3rio. Remova-o antes de continuar.");bt(i,`export default {
120
123
  extends: ['@commitlint/config-conventional'],
121
124
  };
122
- `,"utf-8")}var xt,de=S(()=>{"use strict";d();xt=["commitlint.config.js","commitlint.config.ts","commitlint.config.mjs","commitlint.config.cjs",".commitlintrc",".commitlintrc.js",".commitlintrc.json",".commitlintrc.yml",".commitlintrc.yaml"]});var _e={};O(_e,{main:()=>he});import{log as f}from"@clack/prompts";function St(e,t){return!t.commitlint.enabled||!pe()?!1:e.validate?!0:fe()!==null}function ge(e,t){let i=Ve(e);return i.valid?(t||f.success("\u2705 Mensagem validada pelo commitlint!"),!0):(f.error("\u274C A mensagem n\xE3o passou na valida\xE7\xE3o do commitlint:"),i.errors.forEach(o=>f.error(` ${o}`)),i.warnings.length>0&&i.warnings.forEach(o=>f.info(` \u26A0\uFE0F ${o}`)),!1)}async function he(e={silent:!1,yes:!1,auto:!1,split:!1,smartSplit:!1,dryRun:!1,help:!1,version:!1,validate:!1,initCommitlint:!1}){e.silent||f.info("\u{1F680} Commit Wizard iniciado!"),B()||(f.error("\u274C N\xE3o foi encontrado um reposit\xF3rio Git neste diret\xF3rio."),e.silent||f.info("\u{1F4A1} Execute o comando em um diret\xF3rio com reposit\xF3rio Git inicializado."),process.exit(1)),e.silent||f.info("\u2699\uFE0F Carregando configura\xE7\xE3o...");let t=Se();Te(t),e.split&&(t.splitCommits=!0),e.dryRun&&(t.dryRun=!0);let i=we(t);i.length>0&&(f.error("\u274C Erros na configura\xE7\xE3o:"),i.forEach(c=>f.error(` \u2022 ${c}`)),process.exit(1)),e.silent||f.success(`\u2705 Configura\xE7\xE3o carregada (modelo: ${t.openai.model}, idioma: ${t.language})`);let o=St(e,t);e.silent||(e.validate&&!pe()?f.info("\u26A0\uFE0F --validate especificado mas commitlint n\xE3o est\xE1 instalado. Valida\xE7\xE3o ignorada."):o&&f.info("\u{1F50D} Valida\xE7\xE3o commitlint ativa"));let n=fe(),s=n?Je(n):null;e.silent||f.info("\u{1F4CB} Verificando arquivos staged...");let r=K();r.hasStaged||(f.warn("\u26A0\uFE0F Nenhum arquivo foi encontrado no stage."),e.silent||f.info("\u{1F4A1} Use `git add <arquivo>` para adicionar arquivos ao stage antes de gerar o commit."),process.exit(0));let l=Y();if(e.silent||(f.success(`\u2705 Encontrados ${r.stagedFiles.length} arquivo(s) staged:`),r.stagedFiles.forEach(c=>f.info(` \u{1F4C4} ${c}`)),f.info(`\u{1F4CA} Estat\xEDsticas: +${l.added} -${l.removed} linhas`)),t.splitCommits||e.smartSplit){if(e.yes)return await ae(r,t,e,s);switch((await oe()).action){case"proceed":return await ae(r,t,e,s);case"manual":return await wt(r,t,e,s);case"cancel":P();return}}e.silent||f.info("\u{1F916} Gerando mensagem de commit com IA...");let m=await D(r.diff,t,r.stagedFiles,3,s);if(m.success||(f.error(`\u274C Erro ao gerar commit: ${m.error}`),process.exit(1)),m.suggestion||(f.error("\u274C Nenhuma sugest\xE3o foi gerada"),process.exit(1)),e.silent||f.success("\u2728 Mensagem de commit gerada!"),t.dryRun){f.info("\u{1F50D} Modo Dry Run - Mensagem gerada:"),f.info(`"${m.suggestion.message}"`),f.info("\u{1F4A1} Execute sem --dry-run para fazer o commit");return}if(e.yes){o&&(ge(m.suggestion.message,e.silent)||process.exit(1));let c=M(m.suggestion.message);v(c.success,c.hash,c.error);return}for(;;)switch((await N(m.suggestion)).action){case"commit":{if(o&&!ge(m.suggestion.message,e.silent))break;let a=M(m.suggestion.message);v(a.success,a.hash,a.error);return}case"edit":{let a=await U(m.suggestion.message);if(a.action==="cancel"){P();return}if(a.action==="commit"&&a.message){if(o&&!ge(a.message,e.silent))break;let u=M(a.message);v(u.success,u.hash,u.error);return}break}case"copy":{await _(m.suggestion.message),e.silent||f.info('\u{1F3AF} Voc\xEA pode usar a mensagem copiada com: git commit -m "mensagem"');return}case"cancel":{P();return}}}async function wt(e,t,i,o){i.silent||f.info("\u{1F504} Modo Split ativado - Commits separados por arquivo");let n=[...e.stagedFiles];for(;n.length>0;){let s=i.yes?[n[0]]:await X(n);if(s.length===0){i.silent||f.info("\u274C Nenhum arquivo selecionado");break}let{getFileDiff:r}=await Promise.resolve().then(()=>(w(),j)),l=s.filter(c=>c!==void 0).map(c=>{try{return r(c)}catch(a){return f.error(`\u274C Erro ao obter diff do arquivo ${c}: ${a instanceof Error?a.message:"Erro desconhecido"}`),""}}).filter(c=>c.length>0).join(`
123
- `);if(!l){i.silent||f.warn("\u26A0\uFE0F Nenhum diff encontrado para os arquivos selecionados"),n=n.filter(c=>!s.includes(c));continue}i.silent||f.info(`\u{1F916} Gerando commit para: ${s.join(", ")}`);let m=await D(l,t,s.filter(c=>c!==void 0),3,o);if(!m.success){f.error(`\u274C Erro ao gerar commit: ${m.error}`),n=n.filter(c=>!s.includes(c));continue}if(!m.suggestion){f.error("\u274C Nenhuma sugest\xE3o foi gerada"),n=n.filter(c=>!s.includes(c));continue}if(t.dryRun){f.info(`\u{1F50D} Dry Run - Mensagem para ${s.join(", ")}:`),f.info(`"${m.suggestion.message}"`),n=n.filter(c=>!s.includes(c));continue}if(i.yes){let c=s.length===1&&s[0]?await G(s[0],m.suggestion.message):await M(m.suggestion.message);v(c.success,c.hash,c.error)}else{let c=await N(m.suggestion);if(c.action==="commit"){let a=s.length===1&&s[0]?await G(s[0],m.suggestion.message):await M(m.suggestion.message);v(a.success,a.hash,a.error)}else if(c.action==="edit"){let a=await U(m.suggestion.message);if(a.action==="commit"&&a.message){let u=s.length===1&&s[0]?await G(s[0],a.message):await M(a.message);v(u.success,u.hash,u.error)}}else if(c.action==="copy")await _(m.suggestion.message),i.silent||f.info("\u{1F3AF} Mensagem copiada para clipboard");else if(c.action==="cancel"){P();return}}if(n=n.filter(c=>!s.includes(c)),n.length>0&&!i.yes&&!await ee(n))break}i.silent||f.success("\u2705 Modo Split conclu\xEDdo!")}var ce=S(()=>{"use strict";d();$e();w();Z();L();ne();Ue();re();de()});d();ce();import{intro as jt,outro as Rt,log as V}from"@clack/prompts";d();d();import{readFileSync as $t}from"fs";import{join as ye,dirname as At}from"path";import{fileURLToPath as Et}from"url";function He(){try{let e=Et(import.meta.url),t=At(e),i=[ye(t,"..","package.json"),ye(t,"..","..","package.json"),ye(process.cwd(),"package.json")];for(let o of i)try{let n=$t(o,"utf-8"),s=JSON.parse(n);if(s.name==="@gilbert_oliveira/commit-wizard")return s.version}catch{continue}throw new Error("Package.json n\xE3o encontrado")}catch{return console.warn("\u26A0\uFE0F N\xE3o foi poss\xEDvel ler a vers\xE3o do package.json, usando vers\xE3o padr\xE3o"),"0.0.0"}}function Be(e){return{silent:e.includes("--silent")||e.includes("-s"),yes:e.includes("--yes")||e.includes("-y"),auto:e.includes("--auto")||e.includes("-a"),split:e.includes("--split"),smartSplit:e.includes("--smart-split"),dryRun:e.includes("--dry-run")||e.includes("-n"),help:e.includes("--help")||e.includes("-h"),version:e.includes("--version")||e.includes("-v"),validate:e.includes("--validate"),initCommitlint:e.includes("--init-commitlint")}}function Ke(){console.log(`
125
+ `,"utf-8")}var St,fe=S(()=>{"use strict";f();St=["commitlint.config.js","commitlint.config.ts","commitlint.config.mjs","commitlint.config.cjs",".commitlintrc",".commitlintrc.js",".commitlintrc.json",".commitlintrc.yml",".commitlintrc.yaml"]});var Je={};k(Je,{main:()=>he});import{log as p}from"@clack/prompts";function wt(e,t){return!t.commitlint.enabled||!de()?!1:e.validate?!0:pe()!==null}function ge(e,t){let i=We(e);return i.valid?(t||p.success("\u2705 Mensagem validada pelo commitlint!"),!0):(p.error("\u274C A mensagem n\xE3o passou na valida\xE7\xE3o do commitlint:"),i.errors.forEach(o=>p.error(` ${o}`)),i.warnings.length>0&&i.warnings.forEach(o=>p.info(` \u26A0\uFE0F ${o}`)),!1)}async function he(e={silent:!1,yes:!1,auto:!1,split:!1,smartSplit:!1,dryRun:!1,help:!1,version:!1,validate:!1,initCommitlint:!1}){e.silent||p.info("\u{1F680} Commit Wizard iniciado!"),K()||(p.error("\u274C N\xE3o foi encontrado um reposit\xF3rio Git neste diret\xF3rio."),e.silent||p.info("\u{1F4A1} Execute o comando em um diret\xF3rio com reposit\xF3rio Git inicializado."),process.exit(1)),e.silent||p.info("\u2699\uFE0F Carregando configura\xE7\xE3o...");let t=Se();De(t),e.split&&(t.splitCommits=!0),e.dryRun&&(t.dryRun=!0);let i=we(t);i.length>0&&(p.error("\u274C Erros na configura\xE7\xE3o:"),i.forEach(c=>p.error(` \u2022 ${c}`)),process.exit(1)),e.silent||p.success(`\u2705 Configura\xE7\xE3o carregada (modelo: ${t.openai.model}, idioma: ${t.language})`);let o=wt(e,t);e.silent||(e.validate&&!de()?p.info("\u26A0\uFE0F --validate especificado mas commitlint n\xE3o est\xE1 instalado. Valida\xE7\xE3o ignorada."):o&&p.info("\u{1F50D} Valida\xE7\xE3o commitlint ativa"));let n=pe(),s=n?Ve(n):null;e.silent||p.info("\u{1F4CB} Verificando arquivos staged...");let r=Y();r.hasStaged||(p.warn("\u26A0\uFE0F Nenhum arquivo foi encontrado no stage."),e.silent||p.info("\u{1F4A1} Use `git add <arquivo>` para adicionar arquivos ao stage antes de gerar o commit."),process.exit(0));let m=Q();if(e.silent||(p.success(`\u2705 Encontrados ${r.stagedFiles.length} arquivo(s) staged:`),r.stagedFiles.forEach(c=>p.info(` \u{1F4C4} ${c}`)),p.info(`\u{1F4CA} Estat\xEDsticas: +${m.added} -${m.removed} linhas`)),t.splitCommits||e.smartSplit){if(e.yes)return await ae(r,t,e,s);switch((await oe()).action){case"proceed":return await ae(r,t,e,s);case"manual":return await $t(r,t,e,s);case"cancel":z();return}}e.silent||p.info("\u{1F916} Gerando mensagem de commit com IA...");let l=await N(r.diff,t,r.stagedFiles,3,s);if(l.success||(p.error(`\u274C Erro ao gerar commit: ${l.error}`),process.exit(1)),l.suggestion||(p.error("\u274C Nenhuma sugest\xE3o foi gerada"),process.exit(1)),e.silent||p.success("\u2728 Mensagem de commit gerada!"),t.dryRun){p.info("\u{1F50D} Modo Dry Run - Mensagem gerada:"),p.info(`"${l.suggestion.message}"`),p.info("\u{1F4A1} Execute sem --dry-run para fazer o commit");return}if(e.yes){o&&(ge(l.suggestion.message,e.silent)||process.exit(1));let c=R(l.suggestion.message);C(c.success,c.hash,c.error);return}for(;;)switch((await U(l.suggestion)).action){case"commit":{if(o&&!ge(l.suggestion.message,e.silent))break;let a=R(l.suggestion.message);C(a.success,a.hash,a.error);return}case"edit":{let a=await _(l.suggestion.message);if(a.action==="cancel"){z();return}if(a.action==="commit"&&a.message){if(o&&!ge(a.message,e.silent))break;let u=R(a.message);C(u.success,u.hash,u.error);return}break}case"copy":{await J(l.suggestion.message),e.silent||p.info('\u{1F3AF} Voc\xEA pode usar a mensagem copiada com: git commit -m "mensagem"');return}case"cancel":{z();return}}}async function $t(e,t,i,o){i.silent||p.info("\u{1F504} Modo Split ativado - Commits separados por arquivo");let n=[...e.stagedFiles];for(;n.length>0;){let s=i.yes?[n[0]]:await X(n);if(s.length===0){i.silent||p.info("\u274C Nenhum arquivo selecionado");break}let{getFileDiff:r}=await Promise.resolve().then(()=>(w(),j)),m=s.filter(c=>c!==void 0).map(c=>{try{return r(c)}catch(a){return p.error(`\u274C Erro ao obter diff do arquivo ${c}: ${a instanceof Error?a.message:"Erro desconhecido"}`),""}}).filter(c=>c.length>0).join(`
126
+ `);if(!m){i.silent||p.warn("\u26A0\uFE0F Nenhum diff encontrado para os arquivos selecionados"),n=n.filter(c=>!s.includes(c));continue}i.silent||p.info(`\u{1F916} Gerando commit para: ${s.join(", ")}`);let l=await N(m,t,s.filter(c=>c!==void 0),3,o);if(!l.success){p.error(`\u274C Erro ao gerar commit: ${l.error}`),n=n.filter(c=>!s.includes(c));continue}if(!l.suggestion){p.error("\u274C Nenhuma sugest\xE3o foi gerada"),n=n.filter(c=>!s.includes(c));continue}if(t.dryRun){p.info(`\u{1F50D} Dry Run - Mensagem para ${s.join(", ")}:`),p.info(`"${l.suggestion.message}"`),n=n.filter(c=>!s.includes(c));continue}if(i.yes){let c=s.length===1&&s[0]?await T(s[0],l.suggestion.message):await R(l.suggestion.message);C(c.success,c.hash,c.error)}else{let c=await U(l.suggestion);if(c.action==="commit"){let a=s.length===1&&s[0]?await T(s[0],l.suggestion.message):await R(l.suggestion.message);C(a.success,a.hash,a.error)}else if(c.action==="edit"){let a=await _(l.suggestion.message);if(a.action==="commit"&&a.message){let u=s.length===1&&s[0]?await T(s[0],a.message):await R(a.message);C(u.success,u.hash,u.error)}}else if(c.action==="copy")await J(l.suggestion.message),i.silent||p.info("\u{1F3AF} Mensagem copiada para clipboard");else if(c.action==="cancel"){z();return}}if(n=n.filter(c=>!s.includes(c)),n.length>0&&!i.yes&&!await ee(n))break}i.silent||p.success("\u2705 Modo Split conclu\xEDdo!")}var ce=S(()=>{"use strict";f();$e();w();Z();G();ne();_e();re();fe()});f();ce();import{intro as Mt,outro as Rt,log as W}from"@clack/prompts";f();f();import{readFileSync as Et}from"fs";import{join as ye,dirname as At}from"path";import{fileURLToPath as jt}from"url";function Be(){try{let e=jt(import.meta.url),t=At(e),i=[ye(t,"..","package.json"),ye(t,"..","..","package.json"),ye(process.cwd(),"package.json")];for(let o of i)try{let n=Et(o,"utf-8"),s=JSON.parse(n);if(s.name==="@gilbert_oliveira/commit-wizard")return s.version}catch{continue}throw new Error("Package.json n\xE3o encontrado")}catch{return console.warn("\u26A0\uFE0F N\xE3o foi poss\xEDvel ler a vers\xE3o do package.json, usando vers\xE3o padr\xE3o"),"0.0.0"}}function Ke(e){return{silent:e.includes("--silent")||e.includes("-s"),yes:e.includes("--yes")||e.includes("-y"),auto:e.includes("--auto")||e.includes("-a"),split:e.includes("--split"),smartSplit:e.includes("--smart-split"),dryRun:e.includes("--dry-run")||e.includes("-n"),help:e.includes("--help")||e.includes("-h"),version:e.includes("--version")||e.includes("-v"),validate:e.includes("--validate"),initCommitlint:e.includes("--init-commitlint")}}function Ye(){console.log(`
124
127
  \u{1F9D9}\u200D\u2642\uFE0F Commit Wizard - Gerador inteligente de mensagens de commit
125
128
 
126
129
  USAGE:
@@ -149,4 +152,4 @@ EXAMPLES:
149
152
  commit-wizard --init-commitlint # Criar configura\xE7\xE3o padr\xE3o do commitlint
150
153
 
151
154
  Para mais informa\xE7\xF5es, visite: https://github.com/user/commit-wizard
152
- `)}function Ye(){let e=He();console.log(`commit-wizard v${e}`)}de();async function Mt(){try{let e=Be(process.argv.slice(2));if(e.help&&(Ke(),process.exit(0)),e.version&&(Ye(),process.exit(0)),e.initCommitlint){try{We(),V.success("\u2705 commitlint.config.js criado com sucesso!"),V.info("\u{1F4A1} Instale as depend\xEAncias necess\xE1rias: npm install --save-dev @commitlint/cli @commitlint/config-conventional")}catch(t){V.error(`\u274C ${t instanceof Error?t.message:"Erro ao criar configura\xE7\xE3o do commitlint"}`),process.exit(1)}process.exit(0)}e.auto&&(e.silent=!0,e.yes=!0),e.silent||jt("\u{1F9D9}\u200D\u2642\uFE0F Commit Wizard"),await he(e),e.silent||Rt("At\xE9 logo! \u2728")}catch(e){V.error(`Erro: ${e instanceof Error?e.message:"Erro desconhecido"}`),process.exit(1)}}Mt();
155
+ `)}function Qe(){let e=Be();console.log(`commit-wizard v${e}`)}fe();async function Ft(){try{let e=Ke(process.argv.slice(2));if(e.help&&(Ye(),process.exit(0)),e.version&&(Qe(),process.exit(0)),e.initCommitlint){try{He(),W.success("\u2705 commitlint.config.js criado com sucesso!"),W.info("\u{1F4A1} Instale as depend\xEAncias necess\xE1rias: npm install --save-dev @commitlint/cli @commitlint/config-conventional")}catch(t){W.error(`\u274C ${t instanceof Error?t.message:"Erro ao criar configura\xE7\xE3o do commitlint"}`),process.exit(1)}process.exit(0)}e.auto&&(e.silent=!0,e.yes=!0),e.silent||Mt("\u{1F9D9}\u200D\u2642\uFE0F Commit Wizard"),await he(e),e.silent||Rt("At\xE9 logo! \u2728")}catch(e){W.error(`Erro: ${e instanceof Error?e.message:"Erro desconhecido"}`),process.exit(1)}}Ft();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "displayName": "Commit Wizard",
4
4
  "publisher": "gilbert-oliveira",
5
5
  "description": "CLI inteligente para gerar mensagens de commit usando OpenAI",
6
- "version": "2.13.0-canary.6",
6
+ "version": "2.13.0-canary.7",
7
7
  "categories": [
8
8
  "Other",
9
9
  "SCM Providers"
@@ -202,8 +202,8 @@ function getStyleInstructionsFromRules(
202
202
  const maxLen = rules.headerMaxLength ?? 72;
203
203
  lines.push(
204
204
  isPt
205
- ? `- Mantenha a primeira linha com até ${maxLen} caracteres`
206
- : `- Keep first line under ${maxLen} characters`
205
+ ? `- OBRIGATÓRIO: primeira linha deve ter no máximo ${maxLen} caracteres (regra header-max-length do commitlint)`
206
+ : `- REQUIRED: first line must not exceed ${maxLen} characters (commitlint header-max-length rule)`
207
207
  );
208
208
 
209
209
  const exampleType = rules.typeEnum?.[0] ?? 'feat';
@@ -484,6 +484,70 @@ export function processOpenAIMessage(message: string): string {
484
484
  return message;
485
485
  }
486
486
 
487
+ /**
488
+ * Builds a system-role message for the OpenAI API call that strictly enforces
489
+ * commitlint rules. System messages carry higher precedence than user messages,
490
+ * making the AI more reliably follow hard constraints like header-max-length.
491
+ */
492
+ export function buildSystemMessage(
493
+ config: Config,
494
+ commitlintRules?: CommitlintRules | null
495
+ ): string | null {
496
+ if (!commitlintRules) return null;
497
+
498
+ const isPt = config.language === 'pt';
499
+ const rules: string[] = [];
500
+
501
+ if (config.commitStyle === 'conventional') {
502
+ const types = commitlintRules.typeEnum?.join(', ') ?? DEFAULT_COMMIT_TYPES;
503
+ rules.push(isPt ? `- Formato: tipo(escopo): descrição` : `- Format: type(scope): description`);
504
+ rules.push(isPt ? `- Tipos permitidos: ${types}` : `- Allowed types: ${types}`);
505
+ }
506
+
507
+ if (commitlintRules.headerMaxLength != null) {
508
+ const maxLen = commitlintRules.headerMaxLength;
509
+ rules.push(
510
+ isPt
511
+ ? `- CRÍTICO: o header (primeira linha) NÃO PODE exceder ${maxLen} caracteres. Conte os caracteres antes de responder.`
512
+ : `- CRITICAL: the header (first line) MUST NOT exceed ${maxLen} characters. Count characters before responding.`
513
+ );
514
+ }
515
+
516
+ if (commitlintRules.scopeEnum && commitlintRules.scopeEnum.length > 0) {
517
+ rules.push(
518
+ isPt
519
+ ? `- Escopos permitidos: ${commitlintRules.scopeEnum.join(', ')}`
520
+ : `- Allowed scopes: ${commitlintRules.scopeEnum.join(', ')}`
521
+ );
522
+ }
523
+
524
+ if (commitlintRules.subjectCase) {
525
+ const { condition, cases } = commitlintRules.subjectCase;
526
+ const caseList = cases.join(', ');
527
+ if (condition === 'never') {
528
+ rules.push(isPt ? `- Subject nunca em: ${caseList}` : `- Subject must never be: ${caseList}`);
529
+ } else if (condition === 'always') {
530
+ rules.push(isPt ? `- Subject deve estar em: ${caseList}` : `- Subject must be in: ${caseList}`);
531
+ }
532
+ }
533
+
534
+ if (commitlintRules.subjectFullStop) {
535
+ const { condition, value } = commitlintRules.subjectFullStop;
536
+ const char = value ?? '.';
537
+ if (condition === 'never') {
538
+ rules.push(isPt ? `- Não termine o subject com "${char}"` : `- Do not end subject with "${char}"`);
539
+ }
540
+ }
541
+
542
+ if (rules.length === 0) return null;
543
+
544
+ const intro = isPt
545
+ ? 'Você é um gerador de mensagens de commit. Siga ESTRITAMENTE as seguintes regras do commitlint do projeto. Responda APENAS com a mensagem de commit, sem explicações adicionais.'
546
+ : 'You are a commit message generator. STRICTLY follow the project commitlint rules below. Respond with ONLY the commit message, no additional explanation.';
547
+
548
+ return `${intro}\n\n${rules.join('\n')}`;
549
+ }
550
+
487
551
  /**
488
552
  * Consome a API da OpenAI para gerar mensagem de commit
489
553
  */
@@ -503,6 +567,13 @@ export async function generateCommitMessage(
503
567
  }
504
568
 
505
569
  const prompt = buildPrompt(diff, config, filenames, commitlintRules);
570
+ const systemMessage = buildSystemMessage(config, commitlintRules);
571
+
572
+ const messages: Array<{ role: string; content: string }> = [];
573
+ if (systemMessage) {
574
+ messages.push({ role: 'system', content: systemMessage });
575
+ }
576
+ messages.push({ role: 'user', content: prompt });
506
577
 
507
578
  const response = await fetch('https://api.openai.com/v1/chat/completions', {
508
579
  method: 'POST',
@@ -512,12 +583,7 @@ export async function generateCommitMessage(
512
583
  },
513
584
  body: JSON.stringify({
514
585
  model: config.openai.model,
515
- messages: [
516
- {
517
- role: 'user',
518
- content: prompt,
519
- },
520
- ],
586
+ messages,
521
587
  max_tokens: Math.min(config.openai.maxTokens, 150), // Limitar para economizar tokens
522
588
  temperature: config.openai.temperature,
523
589
  }),