aicommit2
Version:
A Reactive CLI that generates commit messages for Git and Jujutsu with various AI
2 lines (1 loc) • 6.12 kB
JavaScript
import u from"chalk";import T from"openai";import{concatMap as k,from as S,map as y,catchError as D}from"rxjs";import{fromPromise as v}from"rxjs/internal/observable/innerFrom";import{A as U,l as C,a as w,b as M,c as P,d as A,e as b}from"./ai.service-d8e94c3a.mjs";import{g as I,b as _}from"./cli-8ee62906.mjs";import"fs";import"path";import"@pacote/xxhash";import"winston";import"cleye";import"module";import"crypto";import"os";import"node:buffer";import"node:path";import"node:child_process";import"node:process";import"child_process";import"node:url";import"node:os";import"assert";import"events";import"node:fs";import"buffer";import"stream";import"util";import"node:util";import"inquirer";import"fs/promises";import"readline";import"figlet";import"gradient-string";import"ora";import"inquirer-reactive-list-prompt";import"winston-daily-rotate-file";import"axios";import"url";import"node:fs/promises";import"chokidar";import"rxjs/operators";class L extends U{constructor(t){super(t),this.params=t,this.generateStreamingCommitMessage$=()=>{const{generate:s,type:r}=this.params.config;return this.createStreamingCommitMessages$(o=>{this.streamChunks(o).catch(i=>o.error(i))},r,s)},this.streamChunks=async s=>{const r=this.params.stagedDiff.diff,{logging:o}=this.params.config,i=I(this.buildPromptOptions()),m=this.buildUserPrompt(r,"commit"),p=`${this.params.config.url||"https://api.deepseek.com"}/chat/completions`,c={Authorization:`Bearer ${this.params.config.key}`,"Content-Type":"application/json"};C(r,"commit","DeepSeek",this.effectiveModel(),p,c,o),w(r,"commit","DeepSeek",i,m,o);const a=this.buildCompletionPayload([{role:"system",content:i},{role:"user",content:m}],!0);M(r,"commit","DeepSeek",a,o);const l=Date.now();let d="";try{const $=await this.deepSeek.chat.completions.create(a,{timeout:this.params.config.timeout});for await(const g of $){const E=g.choices?.[0]?.delta?.content||"",R=g.choices?.[0]?.delta?.reasoning_content||"",f=`${E}${R}`;f&&(d+=f,s.next(f))}const x=Date.now()-l;P(r,"commit","DeepSeek",{streamed:!0,totalLength:d.length},o),A(r,"commit","DeepSeek",x,d,o),s.complete()}catch(h){b(r,"commit","DeepSeek",h,o),s.error(h)}},this.colors={primary:"#53a3f9",secondary:"#fff"},this.serviceName=u.bgHex(this.colors.primary).hex(this.colors.secondary).bold(`[DeepSeek${this.formatModelSuffix()}]`),this.errorPrefix=u.red.bold(`[DeepSeek${this.formatModelSuffix()}]`);const e=this.params.config.url||"https://api.deepseek.com";this.deepSeek=new T({baseURL:e,apiKey:this.params.config.key})}effectiveModel(){const t=this.params.config.model;return Array.isArray(t)&&t.length>0?t[0]:String(t||"")}modelDefaultsToThinking(t){const e=t.toLowerCase();return e==="deepseek-chat"?!1:!!(e==="deepseek-reasoner"||e.startsWith("deepseek-v4-")||e.startsWith("deepseek-r1"))}isDeepSeekV4Model(t){return t.toLowerCase().startsWith("deepseek-v4-")}resolveThinkingMode(){const t=this.effectiveModel(),e=this.params.config.thinking,s=this.params.config.reasoningEffort;return{thinking:e??this.modelDefaultsToThinking(t),reasoningEffort:s??"high"}}buildCompletionPayload(t,e){const{thinking:s,reasoningEffort:r}=this.resolveThinkingMode(),o=this.effectiveModel(),i={messages:t,model:o,max_tokens:this.params.config.maxTokens};return e&&(i.stream=!0),s?(i.thinking={type:"enabled"},i.reasoning_effort=r):(i.top_p=this.params.config.topP,i.temperature=this.params.config.temperature,this.isDeepSeekV4Model(o)&&(i.thinking={type:"disabled"})),i}getServiceSpecificErrorMessage(t){const e=t.message||"";return e.includes("API key")||e.includes("api_key")?"Invalid API key. Check your DeepSeek API key in configuration":e.includes("rate_limit")||e.includes("Rate limit")?"Rate limit exceeded. Wait a moment and try again, or upgrade your DeepSeek plan":e.includes("Invalid model type")?"Invalid model type. Prefer deepseek-v4-flash or deepseek-v4-pro. Legacy aliases deepseek-chat and deepseek-reasoner map to v4-flash non-thinking and thinking modes (may be deprecated by DeepSeek).":e.includes("model")||e.includes("Model")?"Model not found or not accessible. Check if the DeepSeek model name is correct":e.includes("overloaded")||e.includes("capacity")?"DeepSeek service is overloaded. Try again in a few minutes":e.includes("403")||e.includes("Forbidden")?"Access denied. Your API key may not have permission for this DeepSeek model":e.includes("404")||e.includes("Not Found")?"Model or endpoint not found. Check your DeepSeek model configuration":e.includes("500")||e.includes("Internal Server Error")?"DeepSeek server error. Try again later":null}generateCommitMessage$(){return this.params.config.stream||!1?this.generateStreamingCommitMessage$():v(this.generateMessage("commit")).pipe(k(e=>S(e)),y(this.formatAsChoice),D(this.handleError$))}generateCodeReview$(){return v(this.generateMessage("review")).pipe(k(t=>S(t)),y(this.formatCodeReviewAsChoice),D(this.handleError$))}async generateMessage(t){const e=this.params.stagedDiff.diff,{logging:s,generate:r,type:o}=this.params.config,i=this.buildPromptOptions(),m=t==="review"?_(i):I(i),n=this.buildUserPrompt(e,t),c=`${this.params.config.url||"https://api.deepseek.com"}/chat/completions`,a={Authorization:`Bearer ${this.params.config.key}`,"Content-Type":"application/json"};C(e,t,"DeepSeek",this.effectiveModel(),c,a,s),w(e,t,"DeepSeek",m,n,s);const l=await this.createChatCompletions(m,n,t);return t==="review"?this.parseCodeReview(l):this.parseMessage(l,o,r)}async createChatCompletions(t,e,s){const r=this.params.stagedDiff.diff,{logging:o}=this.params.config,i=this.buildCompletionPayload([{role:"system",content:t},{role:"user",content:e}],!1);M(r,s,"DeepSeek",i,o);const m=Date.now();try{const n=await this.deepSeek.chat.completions.create(i,{timeout:this.params.config.timeout}),p=Date.now()-m,c=n.choices?.[0];if(!c?.message)throw new Error("DeepSeek API returned invalid response structure");const a=c.message.content||c.message.reasoning_content||"";if(!a)throw new Error("DeepSeek API returned empty response");return P(r,s,"DeepSeek",n,o),A(r,s,"DeepSeek",p,a,o),a}catch(n){throw b(r,s,"DeepSeek",n,o),n}}}export{L as DeepSeekService};