newexpand-autopr
Version:
GitHub PR Automation CLI Tool with AI
327 lines (275 loc) • 108 kB
JavaScript
#!/usr/bin/env node
import {Command}from'commander';import ae from'i18next';import {readFileSync,existsSync,constants}from'fs';import Ao,{dirname,join,resolve}from'path';import {fileURLToPath}from'url';import B from'inquirer';import {homedir,tmpdir}from'os';import {writeFile,unlink,readFile,access,mkdir}from'fs/promises';import {z}from'zod';import {Octokit}from'octokit';import L from'winston';import {exec,execSync}from'child_process';import {promisify}from'util';import hr from'dotenv';import pt from'openai';import {minimatch}from'minimatch';var Nt=Object.defineProperty;var l=(o,r)=>Nt(o,"name",{value:r,configurable:true});var H=dirname(fileURLToPath(import.meta.url)),Kt={common:{cli:{description:"GitHub PR Automation CLI with AI features"}}},zt={common:{cli:{description:"AI \uAE30\uB2A5\uC744 \uAC16\uCD98 GitHub PR \uC790\uB3D9\uD654 CLI"}}};function Ht(){let o=[join(H,"locales"),join(H,"..","i18n","locales"),join(process.cwd(),"dist","i18n","locales"),join(H,"..","locales"),join(H,"..","..","locales"),join(process.cwd(),"dist","locales"),join(dirname(dirname(H)),"locales"),join(dirname(dirname(dirname(H))),"dist","locales")];for(let r of o)if(existsSync(join(r,"en.json")))return r;return console.warn("Warning: Could not find locales directory. Using default path."),join(H,"locales")}l(Ht,"findLocalesPath");function Fe(o){try{let r=Ht(),n=join(r,`${o}.json`);return JSON.parse(readFileSync(n,"utf-8"))}catch{return console.warn(`Warning: Could not load ${o}.json, using basic default translations.`),o==="ko"?zt:Kt}}l(Fe,"loadLocale");var Yt=Fe("en"),Wt=Fe("ko"),Ue=l(async(o="en")=>(await ae.init({lng:o,fallbackLng:"en",resources:{en:{translation:Yt},ko:{translation:Wt}},interpolation:{escapeValue:false}}),ae),"initializeI18n"),Ke=l(async o=>{await ae.changeLanguage(o);},"setLanguage"),e=ae.t.bind(ae),F=["en","ko"];var Y=z.object({name:z.string(),members:z.array(z.string()),rotationStrategy:z.enum(["round-robin","random","least-busy"]).default("round-robin")}),Jt=z.object({pattern:z.string(),reviewers:z.array(z.string())}),Vt=z.object({pattern:z.string(),type:z.enum(["feat","fix","refactor","docs","chore","test","release"]),draft:z.boolean().default(true),labels:z.array(z.string()).default([]),template:z.string().optional(),autoAssignReviewers:z.boolean().default(true),reviewers:z.array(z.string()).default([]),reviewerGroups:z.array(z.string()).default([])}),Xt=z.object({enabled:z.boolean().default(false),provider:z.enum(["openai","openrouter"]),apiKey:z.string().optional(),options:z.object({model:z.string().optional(),temperature:z.number().optional(),maxTokens:z.number().optional()}).optional()}),me=z.object({githubToken:z.string().optional(),language:z.enum(F).default("en")});z.object({developmentBranch:z.string().default("dev"),releasePRTitle:z.string().default("Release: {development} to {production}"),releasePRBody:z.string().default("Merge {development} branch into {production} for release")});var le=z.object({owner:z.string().optional(),repo:z.string().optional(),defaultBranch:z.string().default("main"),developmentBranch:z.string().default("dev"),releasePRTitle:z.string().optional(),releasePRBody:z.string().optional(),defaultReviewers:z.array(z.string()).default([]),autoPrEnabled:z.boolean().default(true),defaultLabels:z.array(z.string()).default([]),reviewerGroups:z.array(Y).default([]),filePatterns:z.array(Jt).default([]),branchPatterns:z.array(Vt).default([]),aiConfig:Xt.optional()}),ze=me.merge(le);var Je=join(homedir(),".autopr"),Ve=join(Je,"config.json"),Xe=".autopr.json",er={githubToken:"",language:"en"},tr={defaultBranch:"main",developmentBranch:"dev",defaultReviewers:[],autoPrEnabled:true,defaultLabels:[],reviewerGroups:[],filePatterns:[],branchPatterns:[{pattern:"feat/*",type:"feat",draft:true,labels:["feature"],template:"feature",autoAssignReviewers:true,reviewers:[],reviewerGroups:[]},{pattern:"fix/*",type:"fix",draft:true,labels:["bug"],template:"bugfix",autoAssignReviewers:true,reviewers:[],reviewerGroups:[]},{pattern:"refactor/*",type:"refactor",draft:true,labels:["refactor"],template:"refactor",autoAssignReviewers:true,reviewers:[],reviewerGroups:[]},{pattern:"docs/*",type:"docs",draft:false,labels:["documentation"],template:"docs",autoAssignReviewers:false,reviewers:[],reviewerGroups:[]},{pattern:"chore/*",type:"chore",draft:false,labels:["chore"],template:"chore",autoAssignReviewers:false,reviewers:[],reviewerGroups:[]},{pattern:"test/*",type:"test",draft:true,labels:["test"],template:"test",autoAssignReviewers:true,reviewers:[],reviewerGroups:[]},{pattern:"release/*",type:"release",draft:false,labels:["release"],template:"release",autoAssignReviewers:true,reviewers:[],reviewerGroups:[]}]};async function de(){try{let o=await readFile(Ve,"utf-8"),r=JSON.parse(o);return me.parse(r)}catch(o){if(o.code==="ENOENT")return er;throw new Error(e("config.error.load_global_failed",{error:String(o)}))}}l(de,"loadGlobalConfig");async function q(){try{let o=await readFile(Xe,"utf-8"),r=JSON.parse(o);return r.reviewerGroups&&(r.reviewerGroups=r.reviewerGroups.map(n=>Y.parse(n))),le.parse(r)}catch(o){if(o.code==="ENOENT")return tr;throw new Error(e("config.error.load_project_failed",{error:String(o)}))}}l(q,"loadProjectConfig");async function v(){let[o,r]=await Promise.all([de(),q()]);return ze.parse({...o,...r})}l(v,"loadConfig");async function rr(o){try{await mkdir(Je,{recursive:true}),await writeFile(Ve,JSON.stringify(o,null,2));}catch(r){throw new Error(e("config.error.save_global_failed",{error:String(r)}))}}l(rr,"saveGlobalConfig");async function ie(o){try{await writeFile(Xe,JSON.stringify(o,null,2));}catch(r){throw new Error(e("config.error.save_project_failed",{error:String(r)}))}}l(ie,"saveProjectConfig");async function or(o){let n={...await de(),...o},a=me.parse(n);return await rr(a),a}l(or,"updateGlobalConfig");async function Pe(o){let n={...await q(),...o};o.reviewerGroups&&(n.reviewerGroups=o.reviewerGroups.map(i=>Y.parse(i)));let a=le.parse(n);return await ie(a),a}l(Pe,"updateProjectConfig");async function Q(o){let{githubToken:r,language:n,...a}=o,i={...r&&{githubToken:r},...n&&{language:n}};return Object.keys(i).length>0&&await or(i),Object.keys(a).length>0&&await Pe(a),v()}l(Q,"updateConfig");var Z=z.object({number:z.number(),title:z.string(),body:z.string().nullable(),state:z.enum(["open","closed"]),draft:z.boolean(),user:z.object({login:z.string()}),created_at:z.string(),updated_at:z.string(),head:z.object({ref:z.string(),sha:z.string()}),base:z.object({ref:z.string(),sha:z.string()}),html_url:z.string(),mergeable:z.boolean().nullable().optional(),mergeable_state:z.string().optional(),merged:z.boolean().optional(),merged_at:z.string().nullable()}),Qe=z.object({name:z.string(),commit:z.object({sha:z.string(),url:z.string()})});z.enum(["UNKNOWN","MERGEABLE","CONFLICTING","CHECKING"]);var nr={error:0,warn:1,info:2,debug:3,verbose:4,section:5,step:6},Ze={error:{color:"red",symbol:"\u2716"},warn:{color:"yellow",symbol:"\u26A0"},info:{color:"cyan",symbol:"\u2139"},debug:{color:"gray",symbol:"\u{1F50D}"},verbose:{color:"white",symbol:"\u{1F4DD}"},section:{color:"magenta",symbol:"==="},step:{color:"green",symbol:"\u2192"}};L.addColors(Object.entries(Ze).reduce((o,[r,n])=>(o[r]=n.color,o),{}));var et=l(o=>{var r;return ((r=Ze[o])==null?void 0:r.symbol)||"\u2022"},"getLogSymbol"),ar=L.format.combine(L.format.timestamp({format:"HH:mm:ss"}),L.format.printf(o=>{let r=et(o.level);return o.level==="section"||o.level==="step"?`${r} ${o.message}`:`${r} ${o.timestamp} ${o.level}: ${o.message}`}),L.format.colorize({all:true})),W=L.createLogger({levels:nr,level:"step",format:ar,transports:[new L.transports.Console({format:L.format.combine(L.format.timestamp({format:"HH:mm:ss"}),L.format.printf(o=>{let r=et(o.level);return o.level==="section"||o.level==="step"?`${r} ${o.message}`:`${r} ${o.timestamp} ${o.level}: ${o.message}`}),L.format.colorize({all:true}))})]}),t={error:l((o,...r)=>W.error(o,...r),"error"),warn:l((o,...r)=>W.warn(o,...r),"warn"),info:l((o,...r)=>W.info(o,...r),"info"),debug:l((o,...r)=>W.debug(o,...r),"debug"),verbose:l((o,...r)=>W.verbose(o,...r),"verbose"),section:l((o,...r)=>W.log("section",o),"section"),step:l((o,...r)=>W.log("step",o),"step")};var pe=null,tt=new Map,rt=new Map;async function P(o){if(o)pe=new Octokit({auth:o});else if(!pe){let r=await v();if(!(r!=null&&r.githubToken))throw new Error(e("common.error.github_token"));pe=new Octokit({auth:r.githubToken});}return pe}l(P,"getOctokit");async function ke(o){try{return await new Octokit({auth:o}).rest.users.getAuthenticated(),true}catch{return false}}l(ke,"validateGitHubToken");async function ir(o){let r=await P(),{data:n}=await r.rest.pulls.get(o);if(n.mergeable===null){await new Promise(i=>setTimeout(i,1e3));let{data:a}=await r.rest.pulls.get(o);return {mergeable:a.mergeable,mergeableState:a.mergeable_state,hasConflicts:a.mergeable_state==="dirty"}}return {mergeable:n.mergeable,mergeableState:n.mergeable_state,hasConflicts:n.mergeable_state==="dirty"}}l(ir,"checkMergeability");async function ee(o){let r=`${o.owner}/${o.repo}/${o.pull_number}`,n=tt.get(r);if(n&&Date.now()-n.timestamp<5*60*1e3)return n.status;let a=await ir(o),i;return a.mergeable===null?i="CHECKING":a.hasConflicts?i="CONFLICTING":a.mergeable?i="MERGEABLE":i="UNKNOWN",tt.set(r,{status:i,timestamp:Date.now()}),i}l(ee,"getPullRequestStatus");async function ue(o){var n,a,i;let r=await P();try{let s=await r.rest.pulls.create({...o,maintainer_can_modify:true}),c=Z.parse(s.data),m=await ee({owner:o.owner,repo:o.repo,pull_number:c.number});return m==="CONFLICTING"?t.warn(e("common.warning.merge_conflict")):m==="CHECKING"&&t.warn(e("common.warning.merge_status_unknown")),c}catch(s){if(s.status===422){if((n=s.message)!=null&&n.includes("No commits between"))throw new Error(e("common.error.no_commits"));if((a=s.message)!=null&&a.includes("A pull request already exists"))throw new Error(e("common.error.pr_exists"));if((i=s.message)!=null&&i.includes("Base branch was modified"))throw new Error(e("common.error.base_modified"))}throw s}}l(ue,"createPullRequest");async function xe(o){let r=await P(),{page:n=1,per_page:a=30}=o;try{return (await r.rest.pulls.list({owner:o.owner,repo:o.repo,state:o.state,page:n,per_page:a})).data.map(c=>{let m=c.state==="closed"&&c.merged_at!==null;return Z.parse({...c,merged:m})})}catch(i){throw t.error(`PR \uBAA9\uB85D \uAC00\uC838\uC624\uAE30 \uC2E4\uD328: ${i instanceof Error?i.message:String(i)}`),i}}l(xe,"listPullRequests");async function O(o){let n=await(await P()).rest.pulls.get(o);return Z.parse(n.data)}l(O,"getPullRequest");async function ot(o){return (await(await P()).rest.repos.listBranches(o)).data.map(a=>Qe.parse(a))}l(ot,"listBranches");async function sr({owner:o,repo:r,pull_number:n,base:a}){let i=await P(),s=await O({owner:o,repo:r,pull_number:n});try{await i.rest.repos.merge({owner:o,repo:r,base:s.head.ref,head:a});let c=await i.rest.pulls.update({owner:o,repo:r,pull_number:n,base:a});return Z.parse(c.data)}catch(c){throw c.status===409?new Error(e("commands.merge.error.merge_conflict")):c.status===422?new Error(e("commands.merge.error.base_change_failed")):c}}l(sr,"updatePullRequestBase");async function U({owner:o,repo:r,pull_number:n,title:a,body:i,state:s,base:c,draft:m}){if(c)return sr({owner:o,repo:r,pull_number:n,base:c});let d=await P();if(m!==void 0){t.info("Updating PR draft status using GraphQL API...");let{repository:f}=await d.graphql(`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
id
}
}
}
`,{owner:o,repo:r,number:n}),u=f.pullRequest.id,w=m?"convertPullRequestToDraft":"markPullRequestReadyForReview";try{await d.graphql(`
mutation($id: ID!) {
${w}(input: {pullRequestId: $id}) {
pullRequest {
number
title
body
state
isDraft
url
baseRefName
headRefName
author {
login
}
}
}
}
`,{id:u});return (a||i||s)&&await d.rest.pulls.update({owner:o,repo:r,pull_number:n,...a&&{title:a},...i&&{body:i},...s&&{state:s}}),await O({owner:o,repo:r,pull_number:n})}catch(g){throw t.error("GraphQL Error:",g),g}}let p=await d.rest.pulls.update({owner:o,repo:r,pull_number:n,...a&&{title:a},...i&&{body:i},...s&&{state:s}});return Z.parse(p.data)}l(U,"updatePullRequest");async function se(o){await(await P()).rest.pulls.requestReviewers(o);}l(se,"addReviewers");async function nt({owner:o,repo:r,pull_number:n,merge_method:a="merge",commit_title:i,commit_message:s,delete_branch:c=false}){let m=await P();t.info(`[DEBUG] PR #${n} \uBCD1\uD569 \uC2DC\uC791`),t.info(`[DEBUG] \uC18C\uC720\uC790: ${o}, \uC800\uC7A5\uC18C: ${r}`),t.info(`[DEBUG] \uBCD1\uD569 \uBC29\uBC95: ${a}`);let d=await O({owner:o,repo:r,pull_number:n});if(t.info(`[DEBUG] PR \uC0C1\uD0DC: ${d.state}`),t.info(`[DEBUG] PR \uC81C\uBAA9: ${d.title}`),t.info(`[DEBUG] PR \uBE0C\uB79C\uCE58: ${d.head.ref} -> ${d.base.ref}`),d.state!=="open")throw t.error(`[DEBUG] PR\uC774 \uC5F4\uB824\uC788\uC9C0 \uC54A\uC74C: ${d.state}`),new Error(e("commands.merge.error.pr_closed"));let p=await ee({owner:o,repo:r,pull_number:n});if(t.info(`[DEBUG] \uBCD1\uD569 \uAC00\uB2A5 \uC0C1\uD0DC: ${p}`),p!=="MERGEABLE")throw t.error(`[DEBUG] PR\uC744 \uBCD1\uD569\uD560 \uC218 \uC5C6\uC74C: ${p}`),new Error(e("commands.merge.error.not_mergeable"));t.info("[DEBUG] \uBCD1\uD569 \uC2DC\uB3C4 \uC911...");try{await m.rest.pulls.merge({owner:o,repo:r,pull_number:n,merge_method:a,commit_title:i,commit_message:s}),t.info("[DEBUG] \uBCD1\uD569 \uC131\uACF5");}catch(f){throw t.error(`[DEBUG] \uBCD1\uD569 \uC2E4\uD328: ${f instanceof Error?f.message:String(f)}`),f}if(c){t.info(`[DEBUG] \uBE0C\uB79C\uCE58 \uC0AD\uC81C \uC2DC\uB3C4: ${d.head.ref}`);try{await m.rest.git.deleteRef({owner:o,repo:r,ref:`heads/${d.head.ref}`}),t.info("[DEBUG] \uBE0C\uB79C\uCE58 \uC0AD\uC81C \uC131\uACF5");}catch(f){t.warn(`[DEBUG] \uBE0C\uB79C\uCE58 \uC0AD\uC81C \uC2E4\uD328: ${f instanceof Error?f.message:String(f)}`),t.warn(e("commands.merge.warning.branch_delete_failed"));}}}l(nt,"mergePullRequest");async function te(o){let r=`${o.owner}/${o.repo}`,n=rt.get(r);if(n&&Date.now()-n.timestamp<15*60*1e3)return n.data;let s=(await(await P()).rest.repos.listCollaborators({...o,affiliation:"all"})).data;return rt.set(r,{data:s,timestamp:Date.now()}),s}l(te,"getCollaborators");async function at(o){let r=await te({owner:o.owner,repo:o.repo}),n=new Set(r.map(s=>s.login)),a=o.reviewers.filter(s=>n.has(s)),i=o.reviewers.filter(s=>!n.has(s));return i.length>0&&t.warn(e("common.warning.invalid_reviewers",{reviewers:i.join(", ")})),{valid:a,invalid:i}}l(at,"validateReviewers");async function it({owner:o,repo:r,username:n,permission:a}){await(await P()).rest.repos.addCollaborator({owner:o,repo:r,username:n,permission:a});}l(it,"inviteCollaborator");async function st({owner:o,repo:r,username:n}){await(await P()).rest.repos.removeCollaborator({owner:o,repo:r,username:n});}l(st,"removeCollaborator");async function ct({owner:o,repo:r,username:n}){try{let s=(await(await P()).rest.repos.listInvitations({owner:o,repo:r,per_page:100})).data.find(f=>{var u;return ((u=f.invitee)==null?void 0:u.login)===n});if(!s)return null;let c=new Date(s.created_at),m=new Date,d=new Date(c.getTime()+7*24*60*60*1e3),p;return m>d?p="expired":p=(await te({owner:o,repo:r})).some(w=>w.login===n)?"accepted":"pending",{status:p,invitedAt:s.created_at,expiresAt:d.toISOString()}}catch(a){throw a instanceof Error?new Error(e("common.error.get_invitation_status",{error:a.message})):a}}l(ct,"getInvitationStatus");async function mt({owner:o,repo:r}){try{let a=await(await P()).rest.repos.listInvitations({owner:o,repo:r,per_page:100}),i=await te({owner:o,repo:r});return a.data.map(s=>{var f;let c=new Date(s.created_at),m=new Date,d=new Date(c.getTime()+7*24*60*60*1e3),p;return m>d?p="expired":p=i.some(w=>{var g;return w.login===((g=s.invitee)==null?void 0:g.login)})?"accepted":"pending",{username:((f=s.invitee)==null?void 0:f.login)||"Unknown",status:p,invitedAt:s.created_at,expiresAt:d.toISOString()}})}catch(n){throw n instanceof Error?new Error(e("common.error.get_invitation_statuses",{error:n.message})):n}}l(mt,"getAllInvitationStatuses");async function lt(o,r,n){try{let a=await P(),{data:i}=await a.rest.pulls.get({owner:o,repo:r,pull_number:n}),{data:s}=await a.rest.pulls.listFiles({owner:o,repo:r,pull_number:n}),c=[];if(i.mergeable_state==="dirty")for(let m of s)m.status!=="removed"&&(m.status==="modified"||m.status==="added")&&c.push({filename:m.filename,status:"conflicted",additions:m.additions,deletions:m.deletions,changes:m.changes,conflictBlocks:[]});return {hasConflicts:c.length>0,conflicts:c}}catch(a){throw a instanceof Error?new Error(e("common.error.get_conflicts",{error:a.message})):a}}l(lt,"getPullRequestConflicts");async function fe(o){try{let r=await P(),{data:n}=await r.rest.repos.get(o);return !n.private}catch(r){return t.error("Failed to check draft PR availability:",r),false}}l(fe,"checkDraftPRAvailability");var Ae=promisify(exec),Ie="Ov23liOUU5SAXrmM5NAS";async function lr(){t.info(e("oauth.device_flow.initializing")),t.debug(e("oauth.device_flow.client_id",{clientId:Ie}));let o={client_id:Ie,scope:"repo read:user user:email"};t.debug(e("oauth.device_flow.request_data"),JSON.stringify(o,null,2));let r=await fetch("https://github.com/login/device/code",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","User-Agent":"AutoPR-CLI","X-GitHub-Api-Version":"2022-11-28"},body:JSON.stringify(o)});if(t.debug(e("oauth.device_flow.response_status"),r.status),t.debug(e("oauth.device_flow.response_headers"),JSON.stringify(Object.fromEntries(r.headers.entries()),null,2)),!r.ok){let a=await r.text();throw t.error(e("oauth.device_flow.error_response"),a),new Error(e("oauth.device_flow.init_failed",{status:r.status,error:a}))}let n=await r.json();return t.debug(e("oauth.device_flow.response_data"),JSON.stringify(n,null,2)),n}l(lr,"getDeviceCode");async function dr(o,r,n){let i=Date.now()+n*1e3;for(;Date.now()<i;)try{let s=await fetch("https://github.com/login/oauth/access_token",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","User-Agent":"AutoPR-CLI","X-GitHub-Api-Version":"2022-11-28"},body:JSON.stringify({client_id:Ie,device_code:o,grant_type:"urn:ietf:params:oauth:grant-type:device_code"})});if(!s.ok)throw new Error(e("oauth.token.request_failed",{status:s.status}));let c=await s.json();if(c.error){if(c.error==="authorization_pending"){await new Promise(m=>setTimeout(m,r*1e3));continue}if(c.error==="slow_down"){r+=5,await new Promise(m=>setTimeout(m,r*1e3));continue}throw c.error==="expired_token"?new Error(e("oauth.token.expired")):new Error(e("oauth.token.error",{error:c.error}))}if(!c.access_token)throw new Error(e("oauth.token.missing"));return c.access_token}catch(s){if(s instanceof Error&&s.message.includes("expired"))throw s;await new Promise(c=>setTimeout(c,r*1e3));}throw new Error(e("oauth.token.expired"))}l(dr,"pollForToken");async function Ee(){try{t.info(`
`+e("oauth.auth.starting"));let o=await lr();t.section("\u{1F510} GitHub \uC778\uC99D \uC548\uB0B4"),t.info(e("oauth.auth.instructions")),t.section("\u{1F4CB} \uC778\uC99D \uB2E8\uACC4"),t.step("1\uFE0F\u20E3 "+e("oauth.auth.open_url",{url:o.verification_uri})),t.step("2\uFE0F\u20E3 "+e("oauth.auth.enter_code",{code:o.user_code}));try{process.platform==="darwin"?await Ae(`open "${o.verification_uri}"`):process.platform==="win32"?await Ae(`start "${o.verification_uri}"`):await Ae(`xdg-open "${o.verification_uri}"`);}catch{t.warn(e("oauth.auth.browser_open_failed"));}t.section("\u23F3 \uC778\uC99D \uB300\uAE30 \uC911"),t.info(e("oauth.auth.waiting")),t.info(e("oauth.auth.time_limit",{minutes:Math.floor(o.expires_in/60)}));let r=await dr(o.device_code,o.interval,o.expires_in);await Q({githubToken:r}),t.info(`
`+e("oauth.auth.success"));}catch(o){throw o instanceof Error?new Error(e("oauth.auth.failed",{error:o.message})):o}}l(Ee,"setupOAuthCredentials");var E={BASE_URL:"https://openrouter.ai/api/v1",API_KEY:"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",DEFAULT_MODEL:"google/gemini-2.0-flash-exp:free",API_KEY_HASH:"6322e214e01c6c2e39e5dd5df755b8e22743cf2036235b7d431c1f223620e2d5"};var Se="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",he="https://openrouter.ai/api/v1/keys",$e=0,ge=null,pr=5*60*1e3;async function we(o){try{let r=o||E.API_KEY_HASH;t.debug("API \uD0A4 \uC815\uBCF4 \uC870\uD68C \uC2DC\uB3C4 \uC911...");let n=await fetch(`${he}/${r}`,{headers:{Authorization:`Bearer ${Se}`,"Content-Type":"application/json"}});if(!n.ok)throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${n.status} ${n.statusText}`);return await n.json()}catch(r){throw t.error("OpenRouter API \uD0A4 \uC815\uBCF4 \uC870\uD68C \uC2E4\uD328:",r),r}}l(we,"getKey");async function dt(o=0){try{let r=o>0?`${he}?offset=${o}`:he;t.debug("API \uD0A4 \uBAA9\uB85D \uC870\uD68C \uC2DC\uB3C4 \uC911...");let n=await fetch(r,{headers:{Authorization:`Bearer ${Se}`,"Content-Type":"application/json"}});if(!n.ok)throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${n.status} ${n.statusText}`);return await n.json()}catch(r){throw t.error("OpenRouter API \uD0A4 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328:",r),r}}l(dt,"listKeys");async function Te(o,r){try{t.debug(`API \uD0A4 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8 \uC2DC\uB3C4 \uC911... (${r?"\uBE44\uD65C\uC131\uD654":"\uD65C\uC131\uD654"})`);let n=await fetch(`${he}/${o}`,{method:"PATCH",headers:{Authorization:`Bearer ${Se}`,"Content-Type":"application/json"},body:JSON.stringify({disabled:r})});if(!n.ok)throw new Error(`API \uC694\uCCAD \uC2E4\uD328: ${n.status} ${n.statusText}`);return await n.json()}catch(n){throw t.error("OpenRouter API \uD0A4 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8 \uC2E4\uD328:",n),n}}l(Te,"updateKeyStatus");async function Be(){try{let o=Date.now();return ge!==null&&o-$e<pr?ge:(await we(E.API_KEY_HASH)).data.disabled?(await Te(E.API_KEY_HASH,false),$e=o,ge=true,true):($e=o,ge=false,false)}catch{return false}}l(Be,"ensureKeyActive");var J=class J{constructor(){this.aiConfig=null;this.openai=null;this.isInitialized=false;this.initializationPromise=null;this.lastKeyActivationCheck=0;this.KEY_ACTIVATION_CHECK_THRESHOLD=60*60*1e3;}static getInstance(){return J.instance||(J.instance=new J),J.instance}async checkKeyStatusIfNeeded(){var n;if(((n=this.aiConfig)==null?void 0:n.provider)!=="openrouter")return;let r=Date.now();if(r-this.lastKeyActivationCheck>this.KEY_ACTIVATION_CHECK_THRESHOLD){try{t.debug("API \uD0A4 \uC0C1\uD0DC \uC8FC\uAE30\uC801 \uD655\uC778 \uC911..."),await Be().catch(()=>{});}catch{}this.lastKeyActivationCheck=r;}}async initialize(r){if(this.initializationPromise)return this.initializationPromise;if(this.isInitialized){if(JSON.stringify(this.aiConfig)===JSON.stringify(r)){t.debug("AI\uAC00 \uC774\uBBF8 \uCD08\uAE30\uD654\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.");return}this.reset();}return this.initializationPromise=this._initialize(r),this.initializationPromise}async _initialize(r){try{r.provider==="openrouter"&&await this.checkOpenRouterKeyStatus();let a={openai:this.initializeOpenAI.bind(this),openrouter:this.initializeOpenRouter.bind(this)}[r.provider];if(!a)throw new Error(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 AI \uC81C\uACF5\uC790: ${r.provider}`);a(r),this.aiConfig=r,this.isInitialized=true,this.initializationPromise=null;}catch(n){throw this.reset(),t.error(e("ai.initialization.failed"),n),n}}async checkOpenRouterKeyStatus(){try{t.debug("OpenRouter API \uD0A4 \uC0C1\uD0DC \uD655\uC778 \uC911..."),await Be().catch(()=>{}),this.lastKeyActivationCheck=Date.now();}catch{}}initializeOpenAI(r){this.openai=new pt({apiKey:r.apiKey});}initializeOpenRouter(r){var n;this.openai=new pt({baseURL:E.BASE_URL,apiKey:r.apiKey||E.API_KEY}),r.options=r.options||{},r.options.model=((n=r.options)==null?void 0:n.model)||E.DEFAULT_MODEL;}reset(){this.openai=null,this.aiConfig=null,this.isInitialized=false,this.initializationPromise=null;}isEnabled(){return this.isInitialized&&!!this.aiConfig}getOpenAI(){if(!this.openai)throw new Error(e("ai.error.not_initialized"));return this.checkKeyStatusIfNeeded(),this.openai}getProvider(){var r;return ((r=this.aiConfig)==null?void 0:r.provider)||null}getModel(){var r,n;return (n=(r=this.aiConfig)==null?void 0:r.options)==null?void 0:n.model}static getDefaultModels(r){switch(r){case "openai":return ["gpt-4o","gpt-4o-mini","gpt-3.5-turbo"];case "openrouter":return [E.DEFAULT_MODEL];default:return []}}static getModelDescription(r){switch(r){case "claude-3-7-sonnet-latest":return e("ai.models.anthropic.claude_3_7_sonnet_latest.description");case "claude-3-5-sonnet-latest":return e("ai.models.anthropic.claude_3_5_sonnet_latest.description");case "claude-3-5-haiku-latest":return e("ai.models.anthropic.claude_3_5_haiku_latest.description");case "claude-3-opus-latest":return e("ai.models.anthropic.claude_3_opus_latest.description");case "claude-3-haiku-20240307":return e("ai.models.anthropic.claude_3_haiku_20240307.description");case "gpt-4":return e("ai.models.openai.gpt_4.description");case "gpt-3.5-turbo":return e("ai.models.openai.gpt_3_5_turbo.description");case "copilot-chat":return e("ai.models.github_copilot.copilot_chat.description");default:return ""}}};l(J,"AIManager");var V=J;async function _r(o){try{return await new pt({apiKey:o}).models.list(),true}catch{return t.warn(e("commands.init.error.model_fetch_failed")),false}}l(_r,"validateOpenAIKey");async function br(o,r){switch(o){case "openai":return await _r(r),V.getDefaultModels(o);default:return V.getDefaultModels(o)}}l(br,"getAvailableModels");async function vr(){let{provider:o}=await B.prompt([{type:"list",name:"provider",message:e("commands.init.prompts.select_ai_provider"),choices:[{name:"OpenRouter (Free Gemini Flash 2.0)",value:"openrouter"},{name:"OpenAI",value:"openai"}]}]);if(o==="openrouter")return t.info(e("commands.init.info.openrouter_selected")),{provider:"openrouter",apiKey:E.API_KEY,model:E.DEFAULT_MODEL};let n=(await B.prompt([{type:"password",name:"apiKey",message:e("commands.init.prompts.enter_api_key",{provider:o.toUpperCase()}),validate:l(c=>c.length>0,"validate")}])).apiKey,a=await br(o,n),s=(await B.prompt([{type:"list",name:"model",message:e("commands.init.prompts.select_model"),choices:a}])).model;return {provider:o,apiKey:n,model:s}}l(vr,"setupAIConfig");async function Cr(o){try{if(o.provider==="openrouter"){t.info(e("commands.init.info.openrouter_config_skipped"));return}let r="";try{await access(".env",constants.F_OK),r=await readFile(".env","utf-8");}catch{t.info(e("commands.init.info.creating_env"));}let n=hr.parse(r);n.AI_PROVIDER=o.provider,n.AI_API_KEY=o.apiKey,n.AI_MODEL=o.model;let a=Object.entries(n).map(([i,s])=>`${i}=${s}`).join(`
`);await writeFile(".env",a),t.info(e("commands.init.info.ai_config_saved"));}catch(r){throw t.error(e("commands.init.error.ai_config_save_failed",{error:r})),r}}l(Cr,"updateEnvFile");async function Pr(){try{let o=join(process.cwd(),".git","hooks");await mkdir(o,{recursive:true});let r=join(o,"post-checkout");await writeFile(r,`#!/bin/sh
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
npx autopr hook post-checkout "$BRANCH_NAME"
`,{mode:493});}catch(o){t.error(e("commands.init.error.git_hooks",{error:o}));}}l(Pr,"setupGitHooks");async function gt(){try{let o=await de(),r=await q(),n={};if(o.githubToken){let{updateToken:s}=await B.prompt([{type:"confirm",name:"updateToken",message:e("commands.init.prompts.update_token"),default:false}]);if(s){let{authMethod:c}=await B.prompt([{type:"list",name:"authMethod",message:e("commands.init.prompts.auth_method"),choices:[{name:e("commands.init.prompts.auth_choices.oauth"),value:"oauth"},{name:e("commands.init.prompts.auth_choices.manual"),value:"manual"}]}]);if(c==="oauth")try{await Ee();}catch(m){t.error(e("oauth.auth.failed",{error:m})),process.exit(1);}else {let{githubToken:m}=await B.prompt([{type:"password",name:"githubToken",message:e("commands.init.prompts.token"),validate:l(async d=>d?await ke(d)?true:e("commands.init.error.invalid_token"):false,"validate")}]);n.githubToken=m;}}else n.githubToken=o.githubToken;}else {let{authMethod:s}=await B.prompt([{type:"list",name:"authMethod",message:e("commands.init.prompts.auth_method"),choices:[{name:e("commands.init.prompts.auth_choices.oauth"),value:"oauth"},{name:e("commands.init.prompts.auth_choices.manual"),value:"manual"}]}]);if(s==="oauth")try{await Ee();}catch(c){t.error(e("oauth.auth.failed",{error:c})),process.exit(1);}else {let{githubToken:c}=await B.prompt([{type:"password",name:"githubToken",message:e("commands.init.prompts.token"),validate:l(async m=>m?await ke(m)?true:e("commands.init.error.invalid_token"):false,"validate")}]);n.githubToken=c;}}if(o.language){let{updateLanguage:s}=await B.prompt([{type:"confirm",name:"updateLanguage",message:e("commands.init.prompts.update_language",{language:o.language}),default:false}]);if(s){let{language:c}=await B.prompt([{type:"list",name:"language",message:e("commands.init.prompts.language"),choices:F,default:o.language}]);n.language=c;}else n.language=o.language;}else {let{language:s}=await B.prompt([{type:"list",name:"language",message:e("commands.init.prompts.language"),choices:F,default:"en"}]);n.language=s;}let{setupAI:a}=await B.prompt([{type:"confirm",name:"setupAI",message:e("commands.init.prompts.setup_ai"),default:true}]);if(a){let s=await vr();await Cr(s);let c={enabled:true,provider:s.provider,options:{model:s.model}};await Pe({aiConfig:c});}let i=await B.prompt([{type:"input",name:"defaultBranch",message:e("commands.init.prompts.default_branch"),default:r.defaultBranch||"main"},{type:"input",name:"developmentBranch",message:e("commands.init.prompts.development_branch"),default:r.developmentBranch||"dev"},{type:"input",name:"defaultReviewers",message:e("commands.init.prompts.reviewers"),default:r.defaultReviewers.join(", "),filter:l(s=>s.split(",").map(c=>c.trim()).filter(Boolean),"filter")}]);try{await Q({...n,defaultBranch:i.defaultBranch,developmentBranch:i.developmentBranch,releasePRTitle:"Release: {development} to {production}",releasePRBody:"Merge {development} branch into {production} for release",defaultReviewers:i.defaultReviewers}),t.info(e("commands.init.info.branch_strategy")),t.info(e("commands.init.info.production_branch_set",{branch:i.defaultBranch})),t.info(e("commands.init.info.development_branch_set",{branch:i.developmentBranch})),t.info(e("commands.init.info.release_template_set_automatically")),await Pr(),t.info(e("commands.init.info.hooks_setup_automatically")),t.info(e("common.success.init"));}catch(s){t.error(e("common.error.unknown"),s),process.exit(1);}}catch(o){t.error(e("common.error.unknown"),o),process.exit(1);}}l(gt,"initCommand");var ye=promisify(exec);async function A(){try{let{stdout:o}=await ye("git rev-parse --abbrev-ref HEAD"),r=o.trim(),{stdout:n}=await ye("git config --get remote.origin.url"),i=n.trim().match(/github\.com[:/]([^/]+)\/([^.]+)(?:\.git)?$/);if(!i)return null;let[,s,c]=i;return {owner:s,repo:c,currentBranch:r}}catch{return null}}l(A,"getCurrentRepoInfo");async function xr(){try{let{stdout:o}=await ye("git branch --format='%(refname:short)'");return o.split(`
`).filter(Boolean)}catch{return []}}l(xr,"getLocalBranches");async function Ar(){try{let{stdout:o}=await ye("git branch -r --format='%(refname:short)'");return o.split(`
`).filter(Boolean).map(r=>r.replace(/^origin\//,"")).filter(r=>r!=="HEAD")}catch{return []}}l(Ar,"getRemoteBranches");async function ht(){let o=await xr(),r=await Ar(),n=[...new Set([...o,...r])];return {local:o,remote:r,all:n}}l(ht,"getAllBranches");var Oe=class Oe{constructor(){this.OPENAI_MAX_CHUNK_TOKENS=1500;this.OPENAI_MAX_SUMMARY_TOKENS=1e3;this.OPENROUTER_MAX_CHUNK_TOKENS=4e3;this.OPENROUTER_MAX_SUMMARY_TOKENS=2e3;this.initialized=false;hr.config(),this.aiManager=V.getInstance();}async loadConfig(){let r=process.env.AI_PROVIDER,n=process.env.AI_API_KEY,a=process.env.AI_MODEL;return r==="openai"&&n&&a?{provider:"openai",apiKey:n,model:a}:{provider:"openrouter",apiKey:E.API_KEY,model:E.DEFAULT_MODEL}}async initialize(){try{if(this.initialized)return t.debug("AI \uAE30\uB2A5\uC774 \uC774\uBBF8 \uCD08\uAE30\uD654\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4."),true;let r=await this.loadConfig();if(!r)return t.debug("AI \uC124\uC815\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."),false;let{provider:n,apiKey:a,model:i}=r;return !n||!a?(t.debug("AI \uC81C\uACF5\uC790 \uB610\uB294 API \uD0A4\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4."),false):(await this.aiManager.initialize({provider:n,apiKey:a,options:{model:i}}),this.initialized=true,t.debug("AI \uAE30\uB2A5\uC774 \uCD08\uAE30\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4"),true)}catch(r){return t.error("AI \uAE30\uB2A5 \uCD08\uAE30\uD654 \uC2E4\uD328:",r),false}}isEnabled(){return this.aiManager.isEnabled()}getMaxTokens(r){return this.aiManager.getProvider()==="openrouter"?r==="chunk"?this.OPENROUTER_MAX_CHUNK_TOKENS:this.OPENROUTER_MAX_SUMMARY_TOKENS:r==="chunk"?this.OPENAI_MAX_CHUNK_TOKENS:this.OPENAI_MAX_SUMMARY_TOKENS}async chunkPRContent(r,n){let a=[],i=[],s="",c=n.split(`
`),m=0,d=this.getMaxTokens("chunk");for(let p of c){if(p.startsWith("diff --git")){m>d&&s&&(a.push({files:[...i],diff:s}),i=[],s="",m=0);let u=p.split(" ")[2].substring(2);r.includes(u)&&i.push(u);}let f=this.getApproximateTokenCount(p);m+f>d&&s&&(a.push({files:[...i],diff:s}),i=[],s="",m=0),s+=p+`
`,m+=f;}return s&&a.push({files:i,diff:s}),a}getApproximateTokenCount(r){return Math.ceil(r.split(/\s+/).length*1.3)}async processWithAI(r,n,a={}){var c,m;if(!this.aiManager.isEnabled())throw new Error(e("ai.error.not_initialized"));let i=this.aiManager.getProvider(),s=this.aiManager.getModel();if(!i||!s)throw new Error(e("ai.error.not_initialized"));try{let d=this.aiManager.getOpenAI(),p=[];return a.systemPrompt&&p.push({role:"system",content:a.systemPrompt}),p.push({role:"user",content:r}),((m=(c=(await d.chat.completions.create({model:s,messages:p,max_tokens:n,temperature:a.temperature??.7,top_p:a.top_p??1,presence_penalty:a.presence_penalty??0,frequency_penalty:a.frequency_penalty??0,response_format:a.response_format??{type:"text"},seed:a.seed,stream:false,stop:a.stop})).choices[0])==null?void 0:c.message)==null?void 0:m.content)||""}catch(d){throw t.error(e("ai.error.processing_failed"),d),d}}async generatePRDescription(r,n,a){try{let i=await this.chunkPRContent(r,n),s=[],c=`You are an expert code reviewer and technical writer. Your task is to analyze code changes and generate clear, comprehensive PR descriptions that:
1. Focus on the actual changes and their impact
2. Use professional and technical language
3. Organize information logically
4. Highlight important implementation details
5. Consider security and performance implications`;for(let m of i){let d=e("ai.prompts.pr_description.analyze",{files:m.files.join(", "),diffContent:m.diff,template:(a==null?void 0:a.template)||""}),p=await this.processWithAI(d,this.getMaxTokens("chunk"),{temperature:.7,presence_penalty:.1,frequency_penalty:.1,systemPrompt:c});s.push(p);}if(i.length>1){let m=`You are a technical documentation expert. Your task is to:
1. Combine multiple descriptions into a cohesive summary
2. Remove redundant information
3. Maintain technical accuracy
4. Ensure logical flow
5. Preserve all important implementation details`,d=e("ai.prompts.pr_description.summarize",{descriptions:s.join(`
`)});return await this.processWithAI(d,this.getMaxTokens("summary"),{temperature:.5,presence_penalty:.2,systemPrompt:m})}return s[0]}catch(i){throw t.error(e("ai.error.pr_description_failed"),i),i}}async generatePRTitle(r,n,a){try{let i=`You are a PR title generator. Your task is to:
1. Create concise and descriptive titles under 50 characters
2. Focus on the main change or feature
3. Use clear and professional language
4. Avoid generic descriptions
5. Follow the conventional commit format`,s=e("ai.prompts.pr_title.analyze",{files:r.join(", "),diffContent:n,type:a.type}),c=await this.processWithAI(s,100,{temperature:.3,presence_penalty:0,frequency_penalty:.2,systemPrompt:i});return `[${a.type.toUpperCase()}] ${c}`}catch(i){throw t.error(e("ai.error.pr_title_failed"),i),i}}async reviewCode(r){let n=`You are an expert code reviewer with deep knowledge of software development best practices. Your task is to:
1. Identify potential bugs and edge cases
2. Evaluate code quality and readability
3. Check for security vulnerabilities
4. Assess performance implications
5. Verify proper error handling
6. Suggest specific improvements
7. Consider test coverage
8. Look for architectural issues`,a=r.map(s=>{let c=e("ai.format.file.path",{path:s.path}),m=e("ai.format.file.content",{content:s.content});return `${c}
${m}`}).join(`
`),i=e("ai.prompts.code_review.analyze",{files:a});try{return await this.processWithAI(i,this.getMaxTokens("chunk"),{temperature:.6,presence_penalty:.1,frequency_penalty:.1,stop:["```"],systemPrompt:n})}catch(s){throw t.error(e("ai.error.code_review_failed"),s),s}}async suggestConflictResolution(r,n){let a=`You are a merge conflict resolution expert. Your task is to:
1. Analyze conflicts carefully
2. Consider the context and purpose of changes
3. Suggest the most appropriate resolution
4. Explain the reasoning behind suggestions
5. Highlight potential risks
6. Consider code functionality and integrity
7. Maintain consistent code style`,i=r.map(m=>{let d=e("ai.format.conflict.file",{file:m.file}),p=e("ai.format.conflict.content",{content:m.conflict});return `${d}
${p}`}).join(`
`),s=n?`
PR Title: ${n.title}
PR Description: ${n.description}
Changed Files:
${n.changedFiles.map(m=>`- ${m.filename} (additions: ${m.additions}, deletions: ${m.deletions}, changes: ${m.changes})`).join(`
`)}`:"",c=e("ai.prompts.conflict_resolution.analyze",{conflicts:i,context:s});try{return await this.processWithAI(c,this.getMaxTokens("chunk"),{temperature:.4,presence_penalty:0,frequency_penalty:.1,systemPrompt:a})}catch(m){throw t.error(e("ai.error.conflict_resolution_failed"),m),m}}async improveCommitMessage(r,n,a){let i=`You are a commit message improvement expert. Your task is to:
1. Create concise and impactful commit messages
2. Follow conventional commit format strictly
3. Maintain consistent terminology throughout the message
4. Focus on actual changes visible in the diff
5. Avoid redundancy and unnecessary details
6. Use appropriate language based on the user's locale
7. Prioritize user-facing changes
8. Keep technical details clear but brief
9. Include ALL changed files without exception
Format Guidelines:
- Follow the format specified in the prompt
- Keep subject line under 50 characters
- Use consistent terminology
- Focus on actual changes
- Avoid redundancy
- Include file names for specific changes`,s=e("ai.prompts.commit_message.analyze",{message:r,diff:n,files:(a==null?void 0:a.join(", "))||""});try{return await this.processWithAI(s,this.getMaxTokens("chunk"),{temperature:.4,presence_penalty:.1,frequency_penalty:.3,systemPrompt:i})}catch(c){throw t.error(e("ai.error.commit_message_failed"),c),c}}async generateDailyCommitSummary(r,n,a,i){let s=e("ai.prompts.daily_report_summary.system"),c=r.map(p=>{let f=p.files?p.files.map(u=>`- ${u.filename} (+${u.additions}/-${u.deletions})`).join(`
`):"\uD30C\uC77C \uC815\uBCF4 \uC5C6\uC74C";return `\uCEE4\uBC0B: ${p.sha.substring(0,7)}
\uC2DC\uAC04: ${new Date(p.date).toLocaleString()}
\uBA54\uC2DC\uC9C0: ${p.message}
\uBCC0\uACBD\uB41C \uD30C\uC77C:
${f}
`}).join(`
---
`),m=`
\uCEE4\uBC0B \uD1B5\uACC4:
- \uCD1D \uCEE4\uBC0B \uC218: ${i.totalCommits}
- \uBCC0\uACBD\uB41C \uD30C\uC77C: ${i.filesChanged}
- \uCD94\uAC00\uB41C \uB77C\uC778: ${i.additions}
- \uC0AD\uC81C\uB41C \uB77C\uC778: ${i.deletions}
${i.branches?`
\uBE0C\uB79C\uCE58\uBCC4 \uCEE4\uBC0B:`+Object.entries(i.branches).map(([p,f])=>`
- ${p}: ${f}`).join(""):""}
${i.fileTypes?`
\uD30C\uC77C \uC720\uD615\uBCC4 \uBCC0\uACBD:`+Object.entries(i.fileTypes).map(([p,f])=>`
- ${p}: ${f}`).join(""):""}
`,d=e("ai.prompts.daily_report_summary.prompt",{username:n,date:a,commitsInfo:r.length>0?c:"\uC774 \uAE30\uAC04\uC5D0 \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",statsInfo:m});try{return await this.processWithAI(d,this.getMaxTokens("summary"),{temperature:.5,presence_penalty:.2,frequency_penalty:.3,systemPrompt:s})}catch(p){throw t.error(e("ai.error.daily_report_failed"),p),p}}};l(Oe,"AIFeatures");var T=Oe;var Sr=".github/PULL_REQUEST_TEMPLATE",wt={en:{feature:`## Feature Description
What new feature did you add?
## Implementation Details
- [ ] New Feature 1
- [ ] New Feature 2
## Testing
- [ ] Unit Tests Added
- [ ] Integration Tests Performed
- [ ] E2E Tests (if needed)
## Screenshots (if UI changes)
Please attach screenshots if there are UI changes.
## Related Issues
- Related Issue Number: #
## Checklist
- [ ] Does the code follow conventions?
- [ ] Were new dependencies added?
- [ ] Are there performance impacts?
- [ ] Is documentation needed?`,bugfix:`## Bug Description
What bug did you fix?
## Root Cause
What was causing the bug?
## Solution
How did you fix it?
## Testing
- [ ] Bug reproduction case added
- [ ] Fix verified
- [ ] Regression tests
## Related Issues
- Bug Report: #
## Checklist
- [ ] No impact on other features?
- [ ] Logging or monitoring needed?
- [ ] Performance impact considered?`,refactor:`## Refactoring Description
What did you refactor?
## Reason for Change
Why was this refactoring needed?
## Major Changes
- [ ] Change 1
- [ ] Change 2
## Testing
- [ ] Existing tests pass
- [ ] New tests added (if needed)
## Performance Impact
Is there any impact on performance?
## Checklist
- [ ] All existing features work correctly?
- [ ] Code complexity reduced?
- [ ] Maintainability improved?`,docs:`## Documentation Changes
What documentation did you change?
## Reason for Change
Why was this change needed?
## Major Changes
- [ ] Change 1
- [ ] Change 2
## Checklist
- [ ] Spell-checked?
- [ ] All links work?
- [ ] Proper formatting?`,chore:`## Changes
What maintenance work was performed?
## Reason for Change
Why was this change needed?
## Scope
- [ ] Build System
- [ ] Dependencies
- [ ] Configuration Files
- [ ] Other
## Checklist
- [ ] No impact on existing features?
- [ ] CI/CD impact considered?`,test:`## Test Changes
What tests did you add/modify?
## Test Coverage
- [ ] Unit Tests
- [ ] Integration Tests
- [ ] E2E Tests
## Test Cases
- [ ] Test Case 1
- [ ] Test Case 2
## Checklist
- [ ] Test coverage improved?
- [ ] No conflicts with existing tests?
- [ ] Reasonable test execution time?`},ko:{feature:`## \uAE30\uB2A5 \uC124\uBA85
\uC5B4\uB5A4 \uC0C8\uB85C\uC6B4 \uAE30\uB2A5\uC744 \uCD94\uAC00\uD588\uB098\uC694?
## \uAD6C\uD604 \uB0B4\uC6A9
- [ ] \uC0C8\uB85C\uC6B4 \uAE30\uB2A5 1
- [ ] \uC0C8\uB85C\uC6B4 \uAE30\uB2A5 2
## \uD14C\uC2A4\uD2B8
- [ ] \uB2E8\uC704 \uD14C\uC2A4\uD2B8 \uCD94\uAC00
- [ ] \uD1B5\uD569 \uD14C\uC2A4\uD2B8 \uC218\uD589
- [ ] E2E \uD14C\uC2A4\uD2B8 (\uD544\uC694\uD55C \uACBD\uC6B0)
## \uC2A4\uD06C\uB9B0\uC0F7 (UI \uBCC0\uACBD\uC2DC)
\uBCC0\uACBD\uB41C UI\uAC00 \uC788\uB2E4\uBA74 \uC2A4\uD06C\uB9B0\uC0F7\uC744 \uCCA8\uBD80\uD574\uC8FC\uC138\uC694.
## \uAD00\uB828 \uC774\uC288
- \uAD00\uB828\uB41C \uC774\uC288 \uBC88\uD638: #
## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8
- [ ] \uCF54\uB4DC\uAC00 \uCEE8\uBCA4\uC158\uC744 \uC900\uC218\uD558\uB098\uC694?
- [ ] \uC0C8\uB85C\uC6B4 \uC758\uC874\uC131\uC774 \uCD94\uAC00\uB418\uC5C8\uB098\uC694?
- [ ] \uC131\uB2A5\uC5D0 \uC601\uD5A5\uC744 \uC8FC\uB294 \uBCC0\uACBD\uC0AC\uD56D\uC778\uAC00\uC694?
- [ ] \uBB38\uC11C\uD654\uAC00 \uD544\uC694\uD55C \uBD80\uBD84\uC774 \uC788\uB098\uC694?`,bugfix:`## \uBC84\uADF8 \uC124\uBA85
\uC5B4\uB5A4 \uBC84\uADF8\uB97C \uC218\uC815\uD588\uB098\uC694?
## \uC6D0\uC778
\uBC84\uADF8\uC758 \uC6D0\uC778\uC740 \uBB34\uC5C7\uC774\uC5C8\uB098\uC694?
## \uD574\uACB0 \uBC29\uBC95
\uC5B4\uB5BB\uAC8C \uD574\uACB0\uD588\uB098\uC694?
## \uD14C\uC2A4\uD2B8
- [ ] \uBC84\uADF8 \uC7AC\uD604 \uCF00\uC774\uC2A4 \uCD94\uAC00
- [ ] \uC218\uC815 \uC0AC\uD56D \uD14C\uC2A4\uD2B8
- [ ] \uD68C\uADC0 \uD14C\uC2A4\uD2B8
## \uAD00\uB828 \uC774\uC288
- \uBC84\uADF8 \uB9AC\uD3EC\uD2B8: #
## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8
- [ ] \uB2E4\uB978 \uAE30\uB2A5\uC5D0 \uC601\uD5A5\uC744 \uC8FC\uC9C0 \uC54A\uB098\uC694?
- [ ] \uB85C\uAE45\uC774\uB098 \uBAA8\uB2C8\uD130\uB9C1\uC774 \uD544\uC694\uD55C\uAC00\uC694?
- [ ] \uC131\uB2A5\uC5D0 \uC601\uD5A5\uC744 \uC8FC\uB294 \uBCC0\uACBD\uC0AC\uD56D\uC778\uAC00\uC694?`,refactor:`## \uB9AC\uD329\uD1A0\uB9C1 \uC124\uBA85
\uC5B4\uB5A4 \uBD80\uBD84\uC744 \uB9AC\uD329\uD1A0\uB9C1\uD588\uB098\uC694?
## \uBCC0\uACBD \uC774\uC720
\uC65C \uC774 \uB9AC\uD329\uD1A0\uB9C1\uC774 \uD544\uC694\uD588\uB098\uC694?
## \uC8FC\uC694 \uBCC0\uACBD \uC0AC\uD56D
- [ ] \uBCC0\uACBD \uC0AC\uD56D 1
- [ ] \uBCC0\uACBD \uC0AC\uD56D 2
## \uD14C\uC2A4\uD2B8
- [ ] \uAE30\uC874 \uD14C\uC2A4\uD2B8 \uD1B5\uACFC \uD655\uC778
- [ ] \uC0C8\uB85C\uC6B4 \uD14C\uC2A4\uD2B8 \uCD94\uAC00 (\uD544\uC694\uC2DC)
## \uC131\uB2A5 \uC601\uD5A5
\uC131\uB2A5\uC5D0 \uBBF8\uCE58\uB294 \uC601\uD5A5\uC774 \uC788\uB098\uC694?
## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8
- [ ] \uAE30\uC874 \uAE30\uB2A5\uC774 \uBAA8\uB450 \uC815\uC0C1 \uB3D9\uC791\uD558\uB098\uC694?
- [ ] \uCF54\uB4DC \uBCF5\uC7A1\uB3C4\uAC00 \uAC10\uC18C\uD588\uB098\uC694?
- [ ] \uC720\uC9C0\uBCF4\uC218\uC131\uC774 \uD5A5\uC0C1\uB418\uC5C8\uB098\uC694?`,docs:`## \uBB38\uC11C \uBCC0\uACBD \uC0AC\uD56D
\uC5B4\uB5A4 \uBB38\uC11C\uB97C \uBCC0\uACBD\uD588\uB098\uC694?
## \uBCC0\uACBD \uC774\uC720
\uC65C \uC774 \uBCC0\uACBD\uC774 \uD544\uC694\uD588\uB098\uC694?
## \uC8FC\uC694 \uBCC0\uACBD \uB0B4\uC6A9
- [ ] \uBCC0\uACBD \uB0B4\uC6A9 1
- [ ] \uBCC0\uACBD \uB0B4\uC6A9 2
## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8
- [ ] \uB9DE\uCDA4\uBC95 \uAC80\uC0AC\uB97C \uD588\uB098\uC694?
- [ ] \uB9C1\uD06C\uAC00 \uBAA8\uB450 \uC815\uC0C1 \uC791\uB3D9\uD558\uB098\uC694?
- [ ] \uD3EC\uB9F7\uD305\uC774 \uC62C\uBC14\uB978\uAC00\uC694?`,chore:`## \uBCC0\uACBD \uC0AC\uD56D
\uC5B4\uB5A4 \uC720\uC9C0\uBCF4\uC218 \uC791\uC5C5\uC744 \uC218\uD589\uD588\uB098\uC694?
## \uBCC0\uACBD \uC774\uC720
\uC65C \uC774 \uBCC0\uACBD\uC774 \uD544\uC694\uD588\uB098\uC694?
## \uC601\uD5A5 \uBC94\uC704
- [ ] \uBE4C\uB4DC \uC2DC\uC2A4\uD15C
- [ ] \uC758\uC874\uC131
- [ ] \uC124\uC815 \uD30C\uC77C
- [ ] \uAE30\uD0C0
## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8
- [ ] \uAE30\uC874 \uAE30\uB2A5\uC5D0 \uC601\uD5A5\uC774 \uC5C6\uB098\uC694?
- [ ] CI/CD\uC5D0 \uC601\uD5A5\uC774 \uC788\uB098\uC694?`,test:`## \uD14C\uC2A4\uD2B8 \uCD94\uAC00/\uC218\uC815 \uC0AC\uD56D
\uC5B4\uB5A4 \uD14C\uC2A4\uD2B8\uB97C \uCD94\uAC00/\uC218\uC815\uD588\uB098\uC694?
## \uD14C\uC2A4\uD2B8 \uBC94\uC704
- [ ] \uB2E8\uC704 \uD14C\uC2A4\uD2B8
- [ ] \uD1B5\uD569 \uD14C\uC2A4\uD2B8
- [ ] E2E \uD14C\uC2A4\uD2B8
## \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4
- [ ] \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 1
- [ ] \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 2
## \uCCB4\uD06C\uB9AC\uC2A4\uD2B8
- [ ] \uD14C\uC2A4\uD2B8 \uCEE4\uBC84\uB9AC\uC9C0\uAC00 \uD5A5\uC0C1\uB418\uC5C8\uB098\uC694?
- [ ] \uAE30\uC874 \uD14C\uC2A4\uD2B8\uC640 \uCDA9\uB3CC\uC774 \uC5C6\uB098\uC694?
- [ ] \uD14C\uC2A4\uD2B8 \uC2E4\uD589 \uC2DC\uAC04\uC774 \uC801\uC808\uD55C\uAC00\uC694?`}};async function yt(o){var r;try{let n=join(process.cwd(),Sr,`${o}.md`);return await readFile(n,"utf-8")}catch{let a=await v(),i=(a==null?void 0:a.language)||"en";return ((r=wt[i])==null?void 0:r[o])||wt[i].feature}}l(yt,"loadTemplate");function jr(o,r){let n=minimatch(o,r);return n?t.debug(e("common.branch_pattern.match_success",{branch:o,pattern:r})):t.debug(e("common.branch_pattern.match_fail",{branch:o,pattern:r})),n}l(jr,"matchBranchPattern");async function De(o){let r=await v();if(!r)return t.warn(e("common.branch_pattern.no_config")),null;t.debug(e("common.branch_pattern.matching_start")),t.debug(e("common.branch_pattern.current_branch",{branch:o})),t.debug(e("common.branch_pattern.available_patterns")),r.branchPatterns.forEach(a=>t.debug(e("common.branch_pattern.pattern_item",{pattern:a.pattern,type:a.type})));let n=r.branchPatterns.find(a=>jr(o,a.pattern));return n?(t.info(e("common.branch_pattern.matched_pattern")),t.info(e("common.branch_pattern.pattern_info",{pattern:n.pattern,type:n.type,draft:n.draft?e("common.branch_pattern.yes"):e("common.branch_pattern.no"),labels:n.labels.length>0?n.labels.join(", "):e("common.branch_pattern.none"),template:n.template||e("common.branch_pattern.default")}))):t.warn(e("common.branch_pattern.no_match")),n||null}l(De,"findMatchingPattern");async function Le(o,r){let n=o.split("/");if(n.length<2)return o;let i=n.slice(1).join("/").replace(/-/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").toLowerCase().replace(/\b\w/g,s=>s.toUpperCase());return `[${r.type.toUpperCase()}] ${i}`}l(Le,"generatePRTitle");async function Me(o){return o.template?await yt(o.template):[e("common.template.default.changes"),e("common.template.default.changes_placeholder"),"",e("common.template.default.tests"),e("common.template.default.unit_test"),e("common.template.default.integration_test"),"",e("common.template.default.reviewer_checklist"),e("common.template.default.code_clarity"),e("common.template.default.test_coverage"),e("common.template.default.performance")].join(`
`)}l(Me,"generatePRBody");async function Nr(o,r,n){let a=new Set;o.reviewers.forEach(m=>a.add(m));for(let m of o.reviewerGroups){let d=r.reviewerGroups.find(p=>p.name===m);if(d)switch(d.rotationStrategy){case "random":{let p=Math.floor(Math.random()*d.members.length);a.add(d.members[p]);break}case "round-robin":{try{let p=join(homedir(),".autopr","reviewer-state.json"),f={};try{let g=await readFile(p,"utf-8");f=JSON.parse(g);}catch(g){if