aicommit2 1.9.5 → 1.9.6
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 +14 -7
- package/dist/cli.mjs +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,9 +115,7 @@ ollama run llama3 # model you want use. ex) codellama, deepseek-coder
|
|
|
115
115
|
3. Set the model and host
|
|
116
116
|
|
|
117
117
|
```sh
|
|
118
|
-
aicommit2 config set OLLAMA_MODEL=<your model>
|
|
119
|
-
aicommit2 config set OLLAMA_HOST=<host> # Optional. The default host for ollama is http://localhost:11434.
|
|
120
|
-
aicommit2 config set OLLAMA_TIMEOUT=<timout> # Optional. default is 100000ms (100s)
|
|
118
|
+
aicommit2 config set OLLAMA_MODEL=<your model>
|
|
121
119
|
```
|
|
122
120
|
|
|
123
121
|
> If you want to use ollama, you must set **OLLAMA_MODEL**.
|
|
@@ -313,13 +311,13 @@ aicommit2 config set OPENAI_KEY=<your-api-key> generate=3 locale=en
|
|
|
313
311
|
| `CLOVAX_COOKIE` | N/A | The Clova X Cookie string |
|
|
314
312
|
| `OLLAMA_MODEL` | N/A | The Ollama Model. It should be downloaded your local |
|
|
315
313
|
| `OLLAMA_HOST` | `http://localhost:11434` | The Ollama Host |
|
|
316
|
-
| `OLLAMA_TIMEOUT` | `
|
|
314
|
+
| `OLLAMA_TIMEOUT` | `100_000` ms | Request timeout for the Ollama |
|
|
317
315
|
| `OLLAMA_STREAM` | N/A | Whether to make stream requests (**experimental feature**) |
|
|
318
316
|
| `locale` | `en` | Locale for the generated commit messages |
|
|
319
317
|
| `generate` | `1` | Number of commit messages to generate |
|
|
320
318
|
| `type` | `conventional` | Type of commit message to generate |
|
|
321
319
|
| `proxy` | N/A | Set a HTTP/HTTPS proxy to use for requests(only **OpenAI**) |
|
|
322
|
-
| `timeout` | `
|
|
320
|
+
| `timeout` | `10_000` ms | Network request timeout |
|
|
323
321
|
| `max-length` | `50` | Maximum character length of the generated commit message |
|
|
324
322
|
| `max-tokens` | `200` | The maximum number of tokens that the AI models can generate (for **Open AI, Anthropic, Gemini, Mistral**) |
|
|
325
323
|
| `temperature` | `0.7` | The temperature (0.0-2.0) is used to control the randomness of the output (for **Open AI, Anthropic, Gemini, Mistral**) |
|
|
@@ -373,7 +371,7 @@ aicommit2 config set proxy=
|
|
|
373
371
|
|
|
374
372
|
The timeout for network requests to the OpenAI API in milliseconds.
|
|
375
373
|
|
|
376
|
-
Default: `
|
|
374
|
+
Default: `10_000` (10 seconds)
|
|
377
375
|
|
|
378
376
|
```sh
|
|
379
377
|
aicommit2 config set timeout=20000 # 20s
|
|
@@ -464,12 +462,21 @@ Default: `http://localhost:11434`
|
|
|
464
462
|
|
|
465
463
|
The Ollama host
|
|
466
464
|
|
|
465
|
+
```sh
|
|
466
|
+
aicommit2 config set OLLAMA_HOST=<host>
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
|
|
467
470
|
##### OLLAMA_TIMEOUT
|
|
468
471
|
|
|
469
|
-
Default: `
|
|
472
|
+
Default: `100_000` (100 seconds)
|
|
470
473
|
|
|
471
474
|
Request timeout for the Ollama. Default OLLAMA_TIMEOUT is **100 seconds** because it can take a long time to run locally.
|
|
472
475
|
|
|
476
|
+
```sh
|
|
477
|
+
aicommit2 config set OLLAMA_TIMEOUT=<timout>
|
|
478
|
+
```
|
|
479
|
+
|
|
473
480
|
##### OLLAMA_STREAM
|
|
474
481
|
|
|
475
482
|
<img src="https://github.com/tak-bro/aicommit2/blob/main/img/ollama_stream-min.gif?raw=true" alt="OLLAMA_STREAM" />
|
package/dist/cli.mjs
CHANGED
|
@@ -33,7 +33,7 @@ ${JSON.stringify({docs:"Documentation only changes",style:"Changes that do not a
|
|
|
33
33
|
${ie(n)}
|
|
34
34
|
Here are diff:
|
|
35
35
|
${r}`}sanitizeMessage(t,r,n){const s=t.split(`
|
|
36
|
-
`).map(o=>o.trim().replace(/^\d+\.\s/,"")).map(o=>o.replace(/[`'"*]/g,"")).filter(o=>{switch(r){case"conventional":return Hr(o);case"gitmoji":return Ur(o);default:return!0}}).map(o=>{if(r==="conventional"){const u=/: (\w)/;return o.replace(u,(a,i)=>`: ${i.toLowerCase()}`)}return o}).filter(o=>!!o);return s.length>n?s.slice(0,n):s}}var qr="1.9.
|
|
36
|
+
`).map(o=>o.trim().replace(/^\d+\.\s/,"")).map(o=>o.replace(/[`'"*]/g,"")).filter(o=>{switch(r){case"conventional":return Hr(o);case"gitmoji":return Ur(o);default:return!0}}).map(o=>{if(r==="conventional"){const u=/: (\w)/;return o.replace(u,(a,i)=>`: ${i.toLowerCase()}`)}return o}).filter(o=>!!o);return s.length>n?s.slice(0,n):s}}var qr="1.9.6",wi="A Reactive CLI that generates git commit messages with various AI";class b extends Error{}const ht=" ",he=e=>{e instanceof Error&&(e instanceof b||(e.stack&&console.error(g.dim(e.stack.split(`
|
|
37
37
|
`).slice(1).join(`
|
|
38
38
|
`))),console.error(`
|
|
39
39
|
${ht}${g.dim(`aicommit2 v${qr}`)}`),console.error(`
|
|
@@ -64,13 +64,13 @@ ${t}`)},Bi=(e,t)=>{const{year:r,month:n,day:s,hours:o,minutes:u,seconds:a}=xi(e)
|
|
|
64
64
|
|
|
65
65
|
${i}`),a.statusCode===500&&(l+=`
|
|
66
66
|
|
|
67
|
-
Check the API status: https://status.openai.com`),new b(l)}return JSON.parse(i)},an=e=>e.trim().replace(/[\n\r]/g,"").replace(/(\w)\.$/,"$1"),j=e=>Array.from(new Set(e)),sa=async(e,t,r,n,s,o,u,a,i,l,f,c,D,p,d)=>{try{const h=Q(s,a,i,D),m=await oa(e,t,r,{model:n,messages:[{role:"system",content:h},{role:"user",content:o}],temperature:c,top_p:1,frequency_penalty:0,presence_penalty:0,max_tokens:f,stream:!1,n:u},l,d),C=j(m.choices.filter(F=>F.message?.content).map(F=>an(F.message.content)).map(F=>{if(i==="conventional"){const P=/: (\w)/;return F.replace(P,(N,V)=>`: ${V.toLowerCase()}`)}return F}).filter(F=>{switch(i){case"gitmoji":return Ur(F);case"conventional":return Hr(F);case"":default:return!0}})),w=m.choices.filter(F=>F.message?.content).map(F=>an(F.message.content)).join();return p&&L("OPEN AI",o,h,w),C}catch(h){const m=h;throw m.code==="ENOTFOUND"?new b(`Error connecting to ${m.hostname} (${m.syscall})`):m}};class ua extends Y{constructor(t){super(t),this.params=t,this.handleError$=r=>{const n=r.error?.error?.message?.replace(/(\r\n|\n|\r)/gm,"")||"An error occurred";return G({name:`${this.errorPrefix} ${n}`,value:n,isError:!0,disabled:!0})},this.generateStreamChoice$=()=>{const r=this.params.stagedDiff.diff,{locale:n,generate:s,type:o,prompt:u}=this.params.config,a=this.params.config["max-length"],l=`${Q(n,a,o,u)}
|
|
67
|
+
Check the API status: https://status.openai.com`),new b(l)}return JSON.parse(i)},an=e=>e.trim().replace(/[\n\r]/g,"").replace(/(\w)\.$/,"$1"),j=e=>Array.from(new Set(e)),sa=async(e,t,r,n,s,o,u,a,i,l,f,c,D,p,d)=>{try{const h=Q(s,a,i,D),m=await oa(e,t,r,{model:n,messages:[{role:"system",content:h},{role:"user",content:`Here are diff: ${o}`}],temperature:c,top_p:1,frequency_penalty:0,presence_penalty:0,max_tokens:f,stream:!1,n:u},l,d),C=j(m.choices.filter(F=>F.message?.content).map(F=>an(F.message.content)).map(F=>{if(i==="conventional"){const P=/: (\w)/;return F.replace(P,(N,V)=>`: ${V.toLowerCase()}`)}return F}).filter(F=>{switch(i){case"gitmoji":return Ur(F);case"conventional":return Hr(F);case"":default:return!0}})),w=m.choices.filter(F=>F.message?.content).map(F=>an(F.message.content)).join();return p&&L("OPEN AI",o,h,w),C}catch(h){const m=h;throw m.code==="ENOTFOUND"?new b(`Error connecting to ${m.hostname} (${m.syscall})`):m}};class ua extends Y{constructor(t){super(t),this.params=t,this.handleError$=r=>{const n=r.error?.error?.message?.replace(/(\r\n|\n|\r)/gm,"")||"An error occurred";return G({name:`${this.errorPrefix} ${n}`,value:n,isError:!0,disabled:!0})},this.generateStreamChoice$=()=>{const r=this.params.stagedDiff.diff,{locale:n,generate:s,type:o,prompt:u}=this.params.config,a=this.params.config["max-length"],l=`${Q(n,a,o,u)}
|
|
68
68
|
${ie(s)}`,f={max_tokens:this.params.config["max-tokens"],temperature:this.params.config.temperature,system:l,messages:[{role:"user",content:r}],model:this.params.config.ANTHROPIC_MODEL,stream:!0},c=this.anthropic.messages.create(f);let D="";return S(Yr(c)).pipe(Ut(p=>["content_block_delta","message_stop"].includes(p.type)),I(p=>p),Kt(p=>{p.type==="content_block_delta"&&(D+=p.delta.text)}),I(p=>{const d=p.type==="message_stop";return{id:this.params.keyName,name:`${this.serviceName} ${D}`,value:`${D}`,isError:!1,description:d?O:Wr,disabled:!d}}))},this.colors={primary:"#AE5630",secondary:"#fff"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[Anthropic]"),this.errorPrefix=g.red.bold("[Anthropic]"),this.anthropic=new Tn({apiKey:this.params.config.ANTHROPIC_KEY})}generateCommitMessage$(){return H(this.generateMessage()).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}async generateMessage(){try{const t=this.params.stagedDiff.diff,{locale:r,generate:n,type:s,prompt:o,logging:u}=this.params.config,a=this.params.config["max-length"],l=`${Q(r,a,s,o)}
|
|
69
|
-
${ie(n)}`,f={max_tokens:this.params.config["max-tokens"],temperature:this.params.config.temperature,system:l,messages:[{role:"user",content:t}],model:this.params.config.ANTHROPIC_MODEL},D=(await this.anthropic.messages.create(f)).content.map(({text:p})=>p).join("");return u&&L("Anthropic",t,l,D),j(this.sanitizeMessage(D,this.params.config.type,n))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}generateStreamCommitMessage$(){return this.generateStreamChoice$().pipe(qt((t,r)=>{if(r.description===O){const o=j(this.sanitizeMessage(r.value,this.params.config.type,this.params.config.generate)),u=this.params.stagedDiff.diff,{locale:a,generate:i,type:l,prompt:f,logging:c}=this.params.config,D=this.params.config["max-length"],d=`${Q(a,D,l,f)}
|
|
69
|
+
${ie(n)}`,f={max_tokens:this.params.config["max-tokens"],temperature:this.params.config.temperature,system:l,messages:[{role:"user",content:`Here are diff: ${t}`}],model:this.params.config.ANTHROPIC_MODEL},D=(await this.anthropic.messages.create(f)).content.map(({text:p})=>p).join("");return u&&L("Anthropic",t,l,D),j(this.sanitizeMessage(D,this.params.config.type,n))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}generateStreamCommitMessage$(){return this.generateStreamChoice$().pipe(qt((t,r)=>{if(r.description===O){const o=j(this.sanitizeMessage(r.value,this.params.config.type,this.params.config.generate)),u=this.params.stagedDiff.diff,{locale:a,generate:i,type:l,prompt:f,logging:c}=this.params.config,D=this.params.config["max-length"],d=`${Q(a,D,l,f)}
|
|
70
70
|
${ie(i)}`;return c&&L("Anthropic",u,d,r.value),!o||o.length===0?[{id:`${this.params.keyName}_${O}_0`,name:`${this.serviceName} Failed to extract messages from response`,value:"Failed to extract messages from response",isError:!0,description:O,disabled:!0}]:o.map((m,C)=>({id:`${this.params.keyName}_${O}_${C}`,name:`${this.serviceName} ${m}`,value:`${m}`,isError:!1,description:O,disabled:!1}))}return t.find(o=>o.id===r.id)?[...t.map(o=>r.id===o.id?r:o)]:[{...r}]},[]),T(t=>t),R(this.handleError$))}}const{hasOwnProperty:Ot}=Object.prototype,Le=typeof process<"u"&&process.platform==="win32"?`\r
|
|
71
71
|
`:`
|
|
72
72
|
`,Mt=(e,t)=>{const r=[];let n="";typeof t=="string"?t={section:t,whitespace:!1}:(t=t||Object.create(null),t.whitespace=t.whitespace===!0);const s=t.whitespace?" = ":"=";for(const o of Object.keys(e)){const u=e[o];if(u&&Array.isArray(u))for(const a of u)n+=ce(o+"[]")+s+ce(a)+Le;else u&&typeof u=="object"?r.push(o):n+=ce(o)+s+ce(u)+Le}t.section&&n.length&&(n="["+ce(t.section)+"]"+Le+n);for(const o of r){const u=cn(o).join("\\."),a=(t.section?t.section+".":"")+u,{whitespace:i}=t,l=Mt(e[o],{section:a,whitespace:i});n.length&&l.length&&(n+=Le),n+=l}return n},cn=e=>e.replace(/\1/g,"LITERAL\\1LITERAL").replace(/\\\./g,"").split(/\./).map(t=>t.replace(/\1/g,"\\.").replace(/\2LITERAL\\1LITERAL\2/g,"")),Dn=e=>{const t=Object.create(null);let r=t,n=null;const s=/^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i,o=e.split(/[\r\n]+/g);for(const a of o){if(!a||a.match(/^\s*[;#]/))continue;const i=a.match(s);if(!i)continue;if(i[1]!==void 0){if(n=Ne(i[1]),n==="__proto__"){r=Object.create(null);continue}r=t[n]=t[n]||Object.create(null);continue}const l=Ne(i[2]),f=l.length>2&&l.slice(-2)==="[]",c=f?l.slice(0,-2):l;if(c==="__proto__")continue;const D=i[3]?Ne(i[4]):!0,p=D==="true"||D==="false"||D==="null"?JSON.parse(D):D;f&&(Ot.call(r,c)?Array.isArray(r[c])||(r[c]=[r[c]]):r[c]=[]),Array.isArray(r[c])?r[c].push(p):r[c]=p}const u=[];for(const a of Object.keys(t)){if(!Ot.call(t,a)||typeof t[a]!="object"||Array.isArray(t[a]))continue;const i=cn(a);r=t;const l=i.pop(),f=l.replace(/\\\./g,".");for(const c of i)c!=="__proto__"&&((!Ot.call(r,c)||typeof r[c]!="object")&&(r[c]=Object.create(null)),r=r[c]);r===t&&f===l||(r[f]=t[a],u.push(a))}for(const a of u)delete t[a];return t},ln=e=>e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"),ce=e=>typeof e!="string"||e.match(/[=\r\n]/)||e.match(/^\[/)||e.length>1&&ln(e)||e!==e.trim()?JSON.stringify(e):e.split(";").join("\\;").split("#").join("\\#"),Ne=(e,t)=>{if(e=(e||"").trim(),ln(e)){e.charAt(0)==="'"&&(e=e.slice(1,-1));try{e=JSON.parse(e)}catch{}}else{let r=!1,n="";for(let s=0,o=e.length;s<o;s++){const u=e.charAt(s);if(r)"\\;#".indexOf(u)!==-1?n+=u:n+="\\"+u,r=!1;else{if(";#".indexOf(u)!==-1)break;u==="\\"?r=!0:n+=u}}return r&&(n+="\\"),n.trim()}return e};var ia={parse:Dn,decode:Dn,stringify:Mt,encode:Mt,safe:ce,unsafe:Ne},fn=te(ia);const pn=e=>x.lstat(e).then(()=>!0,()=>!1),aa=["","conventional","gitmoji"],St="http://localhost:11434",{hasOwnProperty:ca}=Object.prototype,W=(e,t)=>ca.call(e,t),E=(e,t,r)=>{if(!t)throw new b(`Invalid config property ${e}: ${r}`)},dn={confirm(e){return e?typeof e=="boolean"?e:(E("confirm",/^(?:true|false)$/.test(e),"Must be a boolean"),e==="true"):!1},prompt(e){return e||""},locale(e){return e?(E("locale",e,"Cannot be empty"),E("locale",/^[a-z-]+$/i.test(e),"Must be a valid locale (letters and dashes/underscores). You can consult the list of codes in: https://wikipedia.org/wiki/List_of_ISO_639-1_codes"),e):"en"},generate(e){if(!e)return 1;E("generate",/^\d+$/.test(e),"Must be an integer");const t=Number(e);return E("generate",t>0,"Must be greater than 0"),E("generate",t<=5,"Must be less or equal to 5"),t},type(e){return e?(E("type",aa.includes(e),"Invalid commit type"),e):"conventional"},proxy(e){if(!(!e||e.length===0))return E("proxy",/^https?:\/\//.test(e),"Must be a valid URL"),e},timeout(e){if(!e)return 1e4;E("timeout",/^\d+$/.test(e),"Must be an integer");const t=Number(e);return E("timeout",t>=500,"Must be greater than 500ms"),t},temperature(e){if(!e)return .7;E("temperature",/^(2|\d)(\.\d{1,2})?$/.test(e),"Must be decimal between 0 and 2");const t=Number(e);return E("temperature",t>0,"Must be greater than 0"),E("temperature",t<=2,"Must be less than or equal to 2"),t},"max-length"(e){if(!e)return 50;E("max-length",/^\d+$/.test(e),"Must be an integer");const t=Number(e);return E("max-length",t>=20,"Must be greater than 20 characters"),t},"max-tokens"(e){return e?(E("max-tokens",/^\d+$/.test(e),"Must be an integer"),Number(e)):200},logging(e){return e?typeof e=="boolean"?e:(E("logging",/^(?:true|false)$/.test(e),"Must be a boolean(true or false)"),e==="true"):!1}},mn={OPENAI_KEY(e){return e||""},OPENAI_MODEL(e){return!e||e.length===0?"gpt-3.5-turbo":e},OPENAI_URL(e){return e?(E("OPENAI_URL",/^https?:\/\//.test(e),"Must be a valid URL"),e):"https://api.openai.com"},OPENAI_PATH(e){return e||"/v1/chat/completions"},HUGGING_COOKIE(e){return e||""},HUGGING_MODEL(e){return!e||e.length===0?"mistralai/Mixtral-8x7B-Instruct-v0.1":(E("HUGGING_MODEL",["CohereForAI/c4ai-command-r-plus","meta-llama/Meta-Llama-3-70B-Instruct","HuggingFaceH4/zephyr-orpo-141b-A35b-v0.1","mistralai/Mixtral-8x7B-Instruct-v0.1","NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO","google/gemma-1.1-7b-it","mistralai/Mistral-7B-Instruct-v0.2","microsoft/Phi-3-mini-4k-instruct"].includes(e),"Invalid model type of HuggingFace chat"),e)},CLOVAX_COOKIE(e){return e||""},GEMINI_KEY(e){return e||""},GEMINI_MODEL(e){return!e||e.length===0?"gemini-1.5-flash-latest":(E("GEMINI_MODEL",["gemini-1.5-flash-latest","gemini-pro"].includes(e),"Invalid model type of Gemini"),e)},ANTHROPIC_MODEL(e){return!e||e.length===0?"claude-3-haiku-20240307":(E("ANTHROPIC_MODEL",["claude-2.1","claude-2.0","claude-instant-1.2","claude-3-haiku-20240307","claude-3-sonnet-20240229","claude-3-opus-20240229"].includes(e),"Invalid model type of Anthropic"),e)},ANTHROPIC_KEY(e){return e||""},MISTRAL_KEY(e){return e||""},MISTRAL_MODEL(e){return!e||e.length===0?"mistral-tiny":(E("MISTRAL_MODEL",["open-mistral-7b","mistral-tiny-2312","mistral-tiny","open-mixtral-8x7b","mistral-small-2312","mistral-small","mistral-small-2402","mistral-small-latest","mistral-medium-latest","mistral-medium-2312","mistral-medium","mistral-large-latest","mistral-large-2402","mistral-embed"].includes(e),"Invalid model type of Mistral AI"),e)},OLLAMA_MODEL(e){return e?(typeof e=="string"?e?.split(","):e).map(r=>r.trim()).filter(r=>!!r&&r.length>0):[]},OLLAMA_HOST(e){return e?(E("OLLAMA_HOST",/^https?:\/\//.test(e),"Must be a valid URL"),e):St},OLLAMA_TIMEOUT(e){if(!e)return 1e5;E("OLLAMA_TIMEOUT",/^\d+$/.test(e),"Must be an integer");const t=Number(e);return E("OLLAMA_TIMEOUT",t>=500,"Must be greater than 500ms"),t},OLLAMA_STREAM(e){return e?typeof e=="boolean"?e:(E("OLLAMA_STREAM",/^(?:true|false)$/.test(e),"Must be a boolean(true or false)"),e==="true"):!1},COHERE_KEY(e){return e||""},COHERE_MODEL(e){return!e||e.length===0?"command":(E("COHERE_MODEL",["command","command-nightly","command-light","command-light-nightly"].includes(e),"Invalid model type of Cohere"),e)}},It=q.join(He.homedir(),".aicommit2"),hn=async()=>{if(!await pn(It))return Object.create(null);const t=await x.readFile(It,"utf8");let r=fn.parse(t);return W(r,"OLLAMA_MODEL")&&(r={...r,OLLAMA_MODEL:typeof r.OLLAMA_MODEL=="string"?[r.OLLAMA_MODEL]:r.OLLAMA_MODEL}),r},Pt=async(e,t)=>{const r=await hn(),n={},s={...dn,...mn};for(const o of Object.keys(s)){const u=s[o],a=e?.[o]??r[o];if(t)try{n[o]=u(a)}catch{}else n[o]=u(a)}return n},Da=async e=>{const t=await hn(),r={...dn,...mn};for(const[n,s]of e){if(!W(r,n))throw new b(`Invalid config property: ${n}`);const o=r[n](s);t[n]=o}await x.writeFile(It,fn.stringify(t),"utf8")};class M{constructor(t={}){if(!t.method)throw new Error("method should be defined!");if(!t.baseURL)throw new Error("baseURL should be defined!");this.config={...t},this.axiosInstance=Wn.create(this.config)}setHeaders(t){return this.config.headers=t,this}setParams(t){return this.config.params=t,this}setBody(t){return this.config.data=t,this}setMethod(t){return this.config.method=t,this}async execute(){try{return await this.axiosInstance.request(this.config)}catch(t){throw t}}}class la extends Y{constructor(t){super(t),this.params=t,this.host="https://clova-x.naver.com",this.cookie="",this.colors={primary:"#00db9b",secondary:"#fff"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[CLOVA X]"),this.errorPrefix=g.red.bold("[CLOVA X]"),this.cookie=this.params.config.CLOVAX_COOKIE}generateCommitMessage$(){return H(this.generateMessage()).pipe(T(t=>S(t)),I((t,r)=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}async generateMessage(){try{const{locale:t,generate:r,type:n,prompt:s,logging:o}=this.params.config,u=this.params.config["max-length"],a=this.params.stagedDiff.diff,i=this.buildPrompt(t,a,r,u,n,s);await this.getAllConversationIds();const l=await this.sendMessage(i),{conversationId:f,allText:c}=this.parseSendMessageResult(l);return await this.deleteConversation(f),o&&L("CLOVA X",a,i,c),j(this.sanitizeMessage(c,this.params.config.type,r))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}async getAllConversationIds(){const r=(await new M({method:"GET",baseURL:`${this.host}/api/v1/conversations`,timeout:this.params.config.timeout}).setHeaders({Cookie:this.cookie}).setParams({page:0,size:50,sort:"turnUpdatedTime,DESC"}).execute()).data;if(!r||!r.content)throw new Error("No content on conversations ClovaX");return r.content.length===0?[]:r.content.map(s=>s.conversationId||"").filter(s=>!!s)}async sendMessage(t){const r={text:t,action:"new"},n=new zn;return n.set("form",new Yn([JSON.stringify(r)],{type:"application/json"})),(await new M({method:"POST",baseURL:`${this.host}/api/v1/generate`,timeout:this.params.config.timeout}).setHeaders({"Content-Type":"multipart/form-data","Content-Length":this.getContentLength(n),Cookie:this.cookie}).setBody(n).execute()).data}parseSendMessageResult(t){const r=/data:{(.*)}/g,n=t.match(r);if(!n)throw new Error("Failed to extract object from generated text");const s=n.map(i=>i.trim().replace(/data:/g,""));if(!s||s.length===0)throw new Error("Cannot extract message");let o="",u="",a="";if(s.map(i=>{try{return JSON.parse(i)}catch{return null}}).filter(i=>!!i).forEach(i=>{if(W(i,"conversationId")){o=i.conversationId;return}if(W(i,"text")){u+=i.text;return}if(W(i,"error")){a=`${i.error}: ${i.type||i.message||""}`;return}}),a)throw new Error(a);if(!o)throw new Error("No conversationId!");if(!u)throw new Error("No allText!");return{conversationId:o,allText:u}}async deleteConversation(t){return(await new M({method:"DELETE",baseURL:`${this.host}/api/v1/conversation/${t}`,timeout:this.params.config.timeout}).setHeaders({Cookie:this.cookie}).execute()).data}getContentLength(t){return Array.from(t.entries(),([r,n])=>({[r]:{ContentLength:typeof n=="string"?n.length:n.size}}))}}class fa extends Y{constructor(t){super(t),this.params=t,this.handleError$=r=>{const n=/"message":\s*"([^"]*)"/,s=r.message.match(n);let o=r?.body?.message;s&&s[1]&&(o=s[1]);const u=`${r.statusCode} ${o}`;return G({name:`${this.errorPrefix} ${u}`,value:o,isError:!0,disabled:!0})},this.colors={primary:"#D18EE2",secondary:"#fff"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[Cohere]"),this.errorPrefix=g.red.bold("[Cohere]"),this.cohere=new Vn({token:this.params.config.COHERE_KEY})}generateCommitMessage$(){return H(this.generateMessage()).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}async generateMessage(){try{const t=this.params.stagedDiff.diff,{locale:r,generate:n,type:s,prompt:o,logging:u}=this.params.config,a=this.params.config["max-length"],i=this.buildPrompt(r,t,n,a,s,o),l=this.params.config["max-tokens"],c=(await this.cohere.generate({prompt:i,maxTokens:l,temperature:this.params.config.temperature,model:this.params.config.COHERE_MODEL})).generations.map(D=>D.text).join("");return u&&L("Cohere",t,i,c),j(this.sanitizeMessage(c,this.params.config.type,n))}catch(t){const r=t;throw r instanceof Xn?new b("Request timed out error!"):r}}}class pa extends Y{constructor(t){super(t),this.params=t,this.handleError$=r=>{const n=r.message||r.toString(),s=/(\[.*?\]\s*[^[]*)/g,o=[...n.matchAll(s)],u=[];o.forEach(i=>u.push(i[1]));const a=u[1]||"An error occurred";return G({name:`${this.errorPrefix} ${a}`,value:a,isError:!0,disabled:!0})},this.colors={primary:"#0077FF",secondary:"#fff"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[Gemini]"),this.errorPrefix=g.red.bold("[Gemini]"),this.genAI=new Jn(this.params.config.GEMINI_KEY)}generateCommitMessage$(){return H(this.generateMessage()).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}async generateMessage(){try{const t=this.params.stagedDiff.diff,{locale:r,generate:n,type:s,prompt:o,logging:u}=this.params.config,a=this.params.config["max-length"],i=this.buildPrompt(r,t,n,a,s,o),l=this.params.config["max-tokens"],p=(await(await this.genAI.getGenerativeModel({model:this.params.config.GEMINI_MODEL,generationConfig:{maxOutputTokens:l,temperature:this.params.config.temperature}}).generateContent(i)).response).text();return u&&L("Gemini",t,i,p),j(this.sanitizeMessage(p,this.params.config.type,n))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}}class da extends Y{constructor(t){super(t),this.params=t,this.host="https://huggingface.co",this.cookie="",this.colors={primary:"#FED21F",secondary:"#000"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[HuggingFace]"),this.errorPrefix=g.red.bold("[HuggingFace]"),this.cookie=this.params.config.HUGGING_COOKIE}generateCommitMessage$(){return H(this.generateMessage()).pipe(T(t=>S(t)),I((t,r)=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}async generateMessage(){try{const t=this.getFullPrompt();await this.prepareNewConversation();const{conversationId:r}=await this.getNewConversationId();await this.prepareConversationEvent(r);const{lastMessageId:n}=await this.getConversationInfo(r),s=await this.sendMessage(r,t,n);await this.deleteConversation(r);const{generate:o}=this.params.config;return j(this.sanitizeHuggingMessage(s,this.params.config.type,o))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}sanitizeHuggingMessage(t,r,n){const s=/{[^{}]*}/g,o=t.match(s);if(!o)throw new Error("Failed to extract object from generated text");let u=null;o.forEach((i,l)=>{try{const f=JSON.parse(i);W(f,"type")&&f.type==="finalAnswer"&&(u=f)}catch{}});const a=this.getFullPrompt();if(!u||!W(u,"text"))throw this.params.config.logging&&L("HuggingFace",this.params.stagedDiff.diff,a,t),new Error("Cannot parse finalAnswer");return this.params.config.logging&&L("HuggingFace",this.params.stagedDiff.diff,a,u.text),this.sanitizeMessage(u.text,r,n)}async prepareNewConversation(){return(await new M({method:"POST",baseURL:`${this.host}/api/event`}).setHeaders({"content-type":"application/json",Cookie:this.cookie}).setBody({d:"huggingface.co",n:"pageview",r:"https://huggingface.co/chat/",u:"https://huggingface.co/chat/"}).execute()).data}async prepareConversationEvent(t){return(await new M({method:"POST",baseURL:`${this.host}/api/event`}).setHeaders({"content-type":"application/json",Cookie:this.cookie}).setBody({d:"huggingface.co",n:"pageview",r:"https://huggingface.co/chat/",u:`https://huggingface.co/chat/conversation/${t}`}).execute()).data}async getNewConversationId(){const t=await new M({method:"POST",baseURL:`${this.host}/chat/conversation`,timeout:this.params.config.timeout}).setHeaders({"content-type":"application/json",Cookie:this.cookie,Accept:"*/*",Connection:"keep-alive",Host:"huggingface.co",Origin:"https://huggingface.co"}).setBody({model:this.params.config.HUGGING_MODEL,preprompt:""}).execute();if(!t.data||!t.data.conversationId)throw new Error("No conversationId on Hugging service");return t.data}async getConversationInfo(t){const n=(await new M({method:"GET",baseURL:`${this.host}/chat/conversation/${t}/__data.json`,timeout:this.params.config.timeout}).setParams({"x-sveltekit-invalidated":"11"}).setHeaders({"Content-Type":"application/json",Cookie:this.cookie,Accept:"*/*",Connection:"keep-alive",Referer:"https://huggingface.co/chat/"}).execute()).data;if(!n||!n.nodes||n.nodes.length===0)throw new Error("No Nodes on conversation info");if(!n.nodes[1]||!n.nodes[1].data||n.nodes[1].data.length===0||!n.nodes[1].data[3])throw new Error("No data on node");const u=n.nodes[1]?.data[3];return{conversationInfo:n,lastMessageId:u}}async deleteConversation(t){return await new M({method:"DELETE",baseURL:`${this.host}/chat/conversation/${t}`,timeout:this.params.config.timeout}).setHeaders({Cookie:this.cookie}).execute(),(await new M({method:"GET",baseURL:`${this.host}/chat/__data.json`,timeout:this.params.config.timeout}).setParams({"x-sveltekit-trailing-slash":"1","x-sveltekit-invalidated":"10"}).setHeaders({"Content-Type":"application/json",Cookie:this.cookie,Accept:"*/*",Connection:"keep-alive",Referer:"https://huggingface.co/chat/"}).execute()).data}async sendMessage(t,r,n){return(await new M({method:"POST",baseURL:`${this.host}/chat/conversation/${t}`,timeout:this.params.config.timeout}).setHeaders({"content-type":"application/json",Cookie:this.cookie,authority:"huggingface.co",accept:"*/*",origin:"https://huggingface.co"}).setBody({files:[],id:n,inputs:r,is_continue:!1,is_retry:!1,use_cache:!1}).execute()).data}getFullPrompt(){const{locale:t,generate:r,type:n,prompt:s}=this.params.config,o=this.params.config["max-length"],u=this.params.stagedDiff.diff;return this.buildPrompt(t,u,r,o,n,s)}}class ma extends Y{constructor(t){super(t),this.params=t,this.host="https://api.mistral.ai",this.apiKey="",this.handleError$=r=>{const n=r.message?.replace(/(\r\n|\n|\r)/gm,"")||"An error occurred";return G({name:`${this.errorPrefix} ${n}`,value:n,isError:!0,disabled:!0})},this.colors={primary:"#FC4A0A",secondary:"#fff"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[MistralAI]"),this.errorPrefix=g.red.bold("[MistralAI]"),this.apiKey=this.params.config.MISTRAL_KEY}generateCommitMessage$(){return H(this.generateMessage()).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}async generateMessage(){try{const t=this.params.stagedDiff.diff,{locale:r,generate:n,type:s,prompt:o,logging:u}=this.params.config,a=this.params.config["max-length"],i=this.buildPrompt(r,t,n,a,s,o);await this.checkAvailableModels();const l=await this.createChatCompletions(i);return u&&L("MistralAI",t,i,l),j(this.sanitizeMessage(l,this.params.config.type,n))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}async checkAvailableModels(){if((await this.getAvailableModels()).includes(this.params.config.MISTRAL_MODEL))return!0;throw new Error("Invalid model type of Mistral AI")}async getAvailableModels(){return(await new M({method:"GET",baseURL:`${this.host}/v1/models`,timeout:this.params.config.timeout}).setHeaders({Authorization:`Bearer ${this.apiKey}`,"content-type":"application/json"}).execute()).data.data.filter(r=>r.object==="model").map(r=>r.id)}async createChatCompletions(t){const n=(await new M({method:"POST",baseURL:`${this.host}/v1/chat/completions`,timeout:this.params.config.timeout}).setHeaders({Authorization:`Bearer ${this.apiKey}`,"content-type":"application/json"}).setBody({model:this.params.config.MISTRAL_MODEL,messages:[{role:"user",content:t}],temperature:this.params.config.temperature,top_p:1,max_tokens:this.params.config["max-tokens"],stream:!1,safe_prompt:!1,random_seed:Ai(10,1e3)}).execute()).data;if(!n.choices||n.choices.length===0||!n.choices[0].message?.content)throw new Error("No Content on response. Please open a Bug report");return n.choices[0].message.content}}class ha extends Y{constructor(t){super(t),this.params=t,this.host=St,this.model="",this.handleError$=r=>{if(r.response&&r.response.data?.error)return G({name:`${this.errorPrefix} ${r.response.data?.error}`,value:r.response.data?.error,isError:!0,disabled:!0});const n=r.message?.replace(/(\r\n|\n|\r)/gm,"")||"An error occurred";return G({name:`${this.errorPrefix} ${n}`,value:n,isError:!0,disabled:!0})},this.generateStreamChoice$=()=>{const n=`${Q(this.params.config.locale,this.params.config["max-length"],this.params.config.type,this.params.config.prompt)}
|
|
73
|
-
${ie(this.params.config.generate)}`,s=this.ollama.chat({model:this.model,messages:[{role:"system",content:n},{role:"user",content:`${this.params.stagedDiff.diff}`}],stream:!0,options:{temperature:this.params.config.temperature}});let o="";return S(Yr(s)).pipe(Kt(u=>o+=u.message.content),I(u=>({id:`Ollama_${this.model}`,name:`${this.serviceName} ${o}`,value:`${o}`,isError:!1,description:u.done?O:Wr,disabled:!u.done})))},this.colors={primary:"#FFF",secondary:"#000"},this.model=this.params.keyName,this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold(`[${zr(this.model)}]`),this.errorPrefix=g.red.bold(`[${zr(this.model)}]`),this.host=this.params.config.OLLAMA_HOST||St,this.ollama=new Zn({host:this.host})}generateCommitMessage$(){return this.params.config.OLLAMA_STREAM?this.generateStreamCommitMessage$():H(this.generateMessage()).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}generateStreamCommitMessage$(){return H(this.checkIsAvailableOllama()).pipe(Pn(()=>this.generateStreamChoice$()),qt((t,r)=>{if(r.description===O){const{type:o,generate:u,logging:a}=this.params.config;if(a){const f=this.createSystemPrompt();L("Ollama",this.params.stagedDiff.diff,f,r.value)}const i=j(this.sanitizeMessage(r.value,o,u));return!i||i.length===0?[{id:`Ollama_${this.model}_${O}_0`,name:`${this.serviceName} Failed to extract messages from response`,value:"Failed to extract messages from response",isError:!0,description:O,disabled:!0}]:i.map((f,c)=>({id:`Ollama_${this.model}_${O}_${c}`,name:`${this.serviceName} ${f}`,value:`${f}`,isError:!1,description:O,disabled:!1}))}return t.find(o=>o.id===r.id)?[...t.map(o=>r.id===o.id?r:o)]:[{...r}]},[]),T(t=>t),R(this.handleError$))}async generateMessage(){try{await this.checkIsAvailableOllama();const t=await this.createChatCompletions(),{type:r,generate:n,logging:s}=this.params.config,o=this.createSystemPrompt();return s&&L(`Ollama_${this.model}`,this.params.stagedDiff.diff,o,t),j(this.sanitizeMessage(t,r,n))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}async checkIsAvailableOllama(){try{return(await new M({method:"GET",baseURL:`${this.host}`,timeout:this.params.config.OLLAMA_TIMEOUT}).execute()).data}catch(t){throw t.code==="ECONNREFUSED"?new b(`Error connecting to ${this.host}. Please run Ollama or check host`):t}}async createChatCompletions(){const t=this.createSystemPrompt();return(await this.ollama.chat({model:this.model,messages:[{role:"system",content:t},{role:"user",content
|
|
73
|
+
${ie(this.params.config.generate)}`,s=this.ollama.chat({model:this.model,messages:[{role:"system",content:n},{role:"user",content:`${this.params.stagedDiff.diff}`}],stream:!0,options:{temperature:this.params.config.temperature}});let o="";return S(Yr(s)).pipe(Kt(u=>o+=u.message.content),I(u=>({id:`Ollama_${this.model}`,name:`${this.serviceName} ${o}`,value:`${o}`,isError:!1,description:u.done?O:Wr,disabled:!u.done})))},this.colors={primary:"#FFF",secondary:"#000"},this.model=this.params.keyName,this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold(`[${zr(this.model)}]`),this.errorPrefix=g.red.bold(`[${zr(this.model)}]`),this.host=this.params.config.OLLAMA_HOST||St,this.ollama=new Zn({host:this.host})}generateCommitMessage$(){return this.params.config.OLLAMA_STREAM?this.generateStreamCommitMessage$():H(this.generateMessage()).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}generateStreamCommitMessage$(){return H(this.checkIsAvailableOllama()).pipe(Pn(()=>this.generateStreamChoice$()),qt((t,r)=>{if(r.description===O){const{type:o,generate:u,logging:a}=this.params.config;if(a){const f=this.createSystemPrompt();L("Ollama",this.params.stagedDiff.diff,f,r.value)}const i=j(this.sanitizeMessage(r.value,o,u));return!i||i.length===0?[{id:`Ollama_${this.model}_${O}_0`,name:`${this.serviceName} Failed to extract messages from response`,value:"Failed to extract messages from response",isError:!0,description:O,disabled:!0}]:i.map((f,c)=>({id:`Ollama_${this.model}_${O}_${c}`,name:`${this.serviceName} ${f}`,value:`${f}`,isError:!1,description:O,disabled:!1}))}return t.find(o=>o.id===r.id)?[...t.map(o=>r.id===o.id?r:o)]:[{...r}]},[]),T(t=>t),R(this.handleError$))}async generateMessage(){try{await this.checkIsAvailableOllama();const t=await this.createChatCompletions(),{type:r,generate:n,logging:s}=this.params.config,o=this.createSystemPrompt();return s&&L(`Ollama_${this.model}`,this.params.stagedDiff.diff,o,t),j(this.sanitizeMessage(t,r,n))}catch(t){const r=t;throw r.code==="ENOTFOUND"?new b(`Error connecting to ${r.hostname} (${r.syscall})`):r}}async checkIsAvailableOllama(){try{return(await new M({method:"GET",baseURL:`${this.host}`,timeout:this.params.config.OLLAMA_TIMEOUT}).execute()).data}catch(t){throw t.code==="ECONNREFUSED"?new b(`Error connecting to ${this.host}. Please run Ollama or check host`):t}}async createChatCompletions(){const t=this.createSystemPrompt();return(await this.ollama.chat({model:this.model,messages:[{role:"system",content:t},{role:"user",content:`Here are diff: ${this.params.stagedDiff.diff}`}],stream:!1,options:{temperature:this.params.config.temperature}})).message.content}createSystemPrompt(){return`${Q(this.params.config.locale,this.params.config["max-length"],this.params.config.type,this.params.config.prompt)}
|
|
74
74
|
${ie(this.params.config.generate)}`}}class ga extends Y{constructor(t){super(t),this.params=t,this.handleError$=r=>{let n="An error occurred";if(r.message){n=r.message.split(`
|
|
75
75
|
`)[0];const s=this.extractJSONFromError(r.message);n+=`: ${s.error.message}`}return G({name:`${this.errorPrefix} ${n}`,value:n,isError:!0,disabled:!0})},this.colors={primary:"#74AA9C",secondary:"#FFF"},this.serviceName=g.bgHex(this.colors.primary).hex(this.colors.secondary).bold("[ChatGPT]"),this.errorPrefix=g.red.bold("[ChatGPT]")}generateCommitMessage$(){return H(sa(this.params.config.OPENAI_URL,this.params.config.OPENAI_PATH,this.params.config.OPENAI_KEY,this.params.config.OPENAI_MODEL,this.params.config.locale,this.params.stagedDiff.diff,this.params.config.generate,this.params.config["max-length"],this.params.config.type,this.params.config.timeout,this.params.config["max-tokens"],this.params.config.temperature,this.params.config.prompt,this.params.config.logging,this.params.config.proxy)).pipe(T(t=>S(t)),I(t=>({name:`${this.serviceName} ${t}`,value:t,isError:!1})),R(this.handleError$))}extractJSONFromError(t){const r=/[{[]{1}([,:{}[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}/gis,n=t.match(r);return n?Object.assign({},...n.map(s=>JSON.parse(s))):{error:{message:"Unknown error"}}}}class gn{constructor(t,r){this.config=t,this.stagedDiff=r}createAIRequests$(t){return S(t).pipe(zt(r=>{const n={config:this.config,stagedDiff:this.stagedDiff,keyName:r};switch(r){case _.OPEN_AI:return z.create(ga,n).generateCommitMessage$();case _.GEMINI:return z.create(pa,n).generateCommitMessage$();case _.ANTHROPIC:return z.create(ua,n).generateCommitMessage$();case _.HUGGING:return z.create(da,n).generateCommitMessage$();case _.CLOVA_X:return z.create(la,n).generateCommitMessage$();case _.MISTRAL:return z.create(ma,n).generateCommitMessage$();case _.OLLAMA:return S(this.config.OLLAMA_MODEL).pipe(zt(o=>{const u={...n,keyName:o};return z.create(ha,u).generateCommitMessage$()}));case _.COHERE:return z.create(fa,n).generateCommitMessage$();default:const s=g.red.bold(`[${r}]`);return G({name:s+" Invalid AI type",value:"Invalid AI type",isError:!0,disabled:!0})}}))}}const Cn=async()=>{const{stdout:e,failed:t}=await ue("git",["rev-parse","--show-toplevel"],{reject:!1});if(t)throw new b("The current directory must be a Git repository!");return e},_t=e=>`:(exclude)${e}`,En=["package-lock.json","pnpm-lock.yaml","*.lock","*.gif","*.png"].map(_t),Fn=async e=>{const t=["diff","--cached","--diff-algorithm=minimal"],{stdout:r}=await ue("git",[...t,"--name-only",...En,...e?e.map(_t):[]]);if(!r)return null;const{stdout:n}=await ue("git",[...t,...En,...e?e.map(_t):[]]);return{files:r.split(`
|
|
76
76
|
`),diff:n}},Ca=e=>`Detected ${e.length.toLocaleString()} staged file${e.length>1?"s":""}`;class we{constructor(){this.title="aicommit2"}printTitle(){console.log(Qn.textSync(this.title,{font:"Small"}))}displaySpinner(t){return Ge(t).start()}stopSpinner(t){t.stop(),t.clear()}printStagedFiles(t){console.log(g.bold.green("\u2714 ")+g.bold(`${Ca(t.files)}:`)),console.log(`${t.files.map(r=>` ${r}`).join(`
|