@coderot-ai/cli 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/dist/coderot.js +19 -19
  2. package/package.json +1 -1
package/dist/coderot.js CHANGED
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import{existsSync as Fn,mkdirSync as An,readFileSync as kn,rmSync as Mn}from"node:fs";import{join as D}from"node:path";import{parseArgs as Tn}from"node:util";import{z as t}from"zod";var _=1,pe=t.strictObject({name:t.string(),kind:t.string(),start:t.int().positive(),end:t.int().positive(),depth:t.int().nonnegative(),lambda:t.boolean(),cyclomatic:t.int().positive(),cognitive:t.int().nonnegative(),sloc:t.int().nonnegative(),parameters:t.int().nonnegative(),nesting:t.int().nonnegative()}),me=t.strictObject({kind:t.enum(["line","block","doc"]),start:t.int().positive(),end:t.int().positive()}),ue=t.strictObject({parsed:t.boolean(),functions:t.array(pe),unmeasuredFunctions:t.int().nonnegative(),errorLines:t.array(t.int().positive()),inactiveLines:t.int().nonnegative(),sloc:t.int().nonnegative(),comments:t.array(me)}),fe=t.strictObject({path:t.string(),start:t.int().positive(),end:t.int().positive()}),de=t.strictObject({locations:t.array(fe).min(2)}),ge=t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),files:t.array(t.strictObject({path:t.string(),blob:t.string(),test:t.boolean()})),skipped:t.strictObject({generated:t.int().nonnegative(),vendored:t.int().nonnegative(),excluded:t.int().nonnegative()}),markup:t.record(t.string(),t.strictObject({files:t.int().nonnegative(),lines:t.int().nonnegative()})),agentFiles:t.array(t.string()),clones:t.array(de).optional()}),Ct=t.strictObject({reviewers:t.int().nonnegative(),approved:t.boolean(),inline:t.int().nonnegative(),conversation:t.int().nonnegative(),botInline:t.int().nonnegative()}),he=t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),files:t.array(t.strictObject({path:t.string(),added:t.int().nonnegative(),deleted:t.int().nonnegative(),ai:t.record(t.string(),t.int().positive()).optional()})),ai:t.array(t.strictObject({source:t.enum(["git-ai","trailer","bot","branch"]),agent:t.string()})),authors:t.array(t.string()),agentFiles:t.boolean(),lineLevel:t.boolean(),title:t.string().optional(),fix:t.boolean(),reverts:t.string().optional(),fixed:t.array(t.string()).optional(),pr:t.strictObject({number:t.int().positive(),files:t.int().nonnegative(),added:t.int().nonnegative(),deleted:t.int().nonnegative(),commits:t.int().nonnegative().optional(),review:Ct.optional()}).optional()}),Nn=t.strictObject({schemaVersion:t.literal(_),...ge.shape,blobs:t.record(t.string(),ue)}),Et=t.strictObject({schemaVersion:t.literal(_),commits:t.array(he)}),rt=e=>e.reduce((n,s)=>n+s,0);var st=t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),title:t.string(),pr:t.int().positive().optional(),size:t.int().nonnegative().optional(),review:Ct.optional(),agents:t.array(t.string()),fix:t.boolean(),added:t.int().nonnegative(),deleted:t.int().nonnegative()}),it=t.strictObject({count:t.int().nonnegative(),medianSize:t.int().nonnegative(),large:t.int().nonnegative(),fixes:t.int().nonnegative(),settled:t.int().nonnegative(),fixedLater:t.int().nonnegative(),reviewKnown:t.int().nonnegative(),noHumanReview:t.int().nonnegative(),approvedNoComment:t.int().nonnegative(),growth:t.int(),growthLines:t.int().nonnegative(),growthTrimmed:t.int(),growthLinesTrimmed:t.int().nonnegative()}),$t=t.record(t.enum(["ai","other"]),it),Ln=t.strictObject({schemaVersion:t.literal(_),repo:t.string(),snapshots:t.array(t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),sloc:t.int().nonnegative(),testSloc:t.int().nonnegative(),cognitive:t.int().nonnegative(),duplicated:t.int().nonnegative().optional()})),months:t.array(t.strictObject({month:t.string(),commits:t.int().nonnegative(),aiCommits:t.int().nonnegative(),added:t.int().nonnegative(),aiAdded:t.int().nonnegative(),agents:t.record(t.string(),t.int().positive()),attributed:t.int().nonnegative(),prs:$t})),jumps:t.array(t.strictObject({metric:t.enum(["complexity","duplication"]),from:t.int().nonnegative(),to:t.int().nonnegative(),files:t.array(t.strictObject({path:t.string(),delta:t.int()})),commits:t.array(st)})),folders:t.array(t.strictObject({path:t.string(),sloc:t.array(t.int().nonnegative()),cognitive:t.array(t.int().nonnegative()),commits:t.int().nonnegative(),aiCommits:t.int().nonnegative()})),hotspots:t.array(t.strictObject({path:t.string(),commits:t.int().positive(),aiCommits:t.int().nonnegative(),cognitive:t.int().nonnegative()})),prs:$t,prsBy:t.record(t.enum(["large","small","fixed","unfixed","recent","human","unknown"]),it),prsByAgent:t.record(t.string(),it),biggest:t.array(st),worstSince:t.iso.datetime(),worst:t.array(t.strictObject({path:t.string(),before:t.int().nonnegative().optional(),after:t.int().nonnegative(),from:t.strictObject({path:t.string(),how:t.enum(["renamed","copied","moved"])}).optional(),commits:t.array(st)})),lookSince:t.int().nonnegative(),look:t.array(t.strictObject({folder:t.string(),rise:t.int().positive(),commits:t.int().nonnegative(),aiCommits:t.int().nonnegative(),file:t.strictObject({path:t.string(),before:t.int().nonnegative().optional(),after:t.int().nonnegative()}).optional()}))});import{readFile as Xe}from"node:fs/promises";import{join as Ze,posix as tn}from"node:path";import{parse as en}from"yaml";import{z as N}from"zod";import{execFile as ye,execFileSync as be,spawn as we}from"node:child_process";import{mkdirSync as ve,mkdtempSync as xe,readFileSync as Se,rmSync as $e,writeFileSync as Ce}from"node:fs";import{tmpdir as Ee}from"node:os";import{dirname as Oe,extname as J,join as X}from"node:path";import{createInterface as je}from"node:readline";import{fileURLToPath as Pt}from"node:url";import{promisify as Pe}from"node:util";import{parseSync as Fe,visitorKeys as Ft}from"oxc-parser";var At=new Set([".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"]),kt=e=>J(e)===".cs"||At.has(J(e)),Ae=/(^|\/)(node_modules|bower_components|vendor|third[-_]?party|wwwroot\/lib(_npm)?)\//i,ke=/(^|\/)(obj|dist)\/|\.(designer|generated|g|g\.i)\.cs$|(^|\/)TemporaryGeneratedFile_[^/]*$|\.min\.[cm]?js$/i,Me=/^\uFEFF?(\s|\/\/.*|\/\*[\s\S]*?\*\/|#.*)*/,Te=/<auto-?generated|@generated|(file|content) (is|was) (auto-?|automatically )?generated|^\W*generated (by|from)|^(?=.*do not (edit|modify))(?=.*(generated|copied|from )).*/im,Re=/^\/\/[#@] sourceMappingURL=|^\/\*! For license information please see \S+ \*\//m,Ne=new Set([".razor",".cshtml",".vue",".svelte",".astro"]),Le=/(^|\/)((\w+[-_])?(tests?|__tests__|e2e)|(tests?|e2e)[-_]\w+)\/|\.(test|spec)[.-][^/]*$|Tests?(\.cs$|\/)/;function Z(e,n,s={}){return s.vendored??Ae.test(e)?"vendored":s.generated??ke.test(e)?"generated":Ne.has(J(e))?"markup":kt(e)?s.generated===void 0&&(Te.test(n.match(Me)[0])||At.has(J(e))&&Re.test(n))?"generated":Le.test(e)?"test":"code":"other"}async function Mt(e,n,s={}){if(!kt(e))throw new Error(`Unsupported file type: ${e}`);let o=J(e)===".cs"?await Ge(n,s.csharpSymbols??[]):Je(e,n),l=o.functions.filter(r=>!o.errorLines.some(p=>r.start<=p&&p<=r.end));return{...o,functions:l,unmeasuredFunctions:o.functions.length-l.length}}function Tt(){G?.stdin.end(),G=void 0}var Ie=Pt(import.meta.resolve("jscpd/run-jscpd.js"));async function Rt(e){if(!e.length)return[];let n=xe(X(Ee(),"coderot-dup-"));try{for(let c of e)ve(Oe(X(n,"src",c.path)),{recursive:!0}),Ce(X(n,"src",c.path),c.source);await Pe(ye)(process.execPath,[Ie,"src","-f","csharp,typescript,tsx,javascript,jsx","--cross-formats","typescript,tsx;javascript,jsx","-k","50","-l","5","--mode","weak","--ignore-pattern","using\\s+(static\\s+)?[\\w.]+(\\s*=\\s*[\\w.<>]+)?;,\\[assembly:[^\\]]*\\]","--no-gitignore","-r","json","-o","out","-s"],{cwd:n});let{duplicates:s}=JSON.parse(Se(X(n,"out","jscpd-report.json"),"utf8")),o=c=>({path:c.name.replaceAll("\\","/"),start:c.start,end:c.end}),l=c=>`${c.path}:${c.start}-${c.end}`,r=new Map;for(let c of s){let[a,h]=[o(c.firstFile),o(c.secondFile)],[m,u]=[r.get(l(a))??[a],r.get(l(h))??[h]];if(m===u)continue;let b=[...m,...u];for(let g of b)r.set(l(g),b)}let p=(c,a)=>c.path<a.path?-1:c.path>a.path?1:c.start-a.start;return[...new Set(r.values())].map(c=>({locations:c.sort(p)})).sort((c,a)=>p(c.locations[0],a.locations[0]))}finally{$e(n,{recursive:!0,force:!0})}}var _e=Pt(new URL("./roslyn/bin/Release/net8.0/Coderot.Roslyn.dll",import.meta.url)),K=new Map,G,De=0,at;function ze(){if(at??=[...He().matchAll(/^Microsoft\.NETCore\.App (\S+)/gm)].map(s=>s[1]),!at.some(s=>Number(s.split(".")[0])>=8))throw new Error(`C# files need the .NET runtime 8 or newer (found: ${at.join(", ")||"none"}). In GitHub Actions: actions/setup-dotnet`);let e=s=>{G===n&&(G=void 0);for(let o of K.values())o.reject(s);K.clear()},n=we("dotnet",[_e],{stdio:["pipe","pipe","inherit"]});return n.on("error",e),n.on("exit",s=>e(new Error(`C# sidecar exited with code ${s}`))),je({input:n.stdout}).on("line",s=>{let{id:o,...l}=JSON.parse(s);K.get(o)?.resolve(l),K.delete(o)}),n}function He(){try{return be("dotnet",["--list-runtimes"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}catch{return""}}function Ge(e,n){G??=ze();let s=De++;return new Promise((o,l)=>{K.set(s,{resolve:o,reject:l}),G.stdin.write(JSON.stringify({id:s,source:e,symbols:n})+`
3
- `)})}var ct=new Set(["FunctionDeclaration","FunctionExpression","ArrowFunctionExpression"]),Ot=new Set(["MethodDefinition","TSAbstractMethodDefinition","Property","PropertyDefinition"]),lt=new Set(["IfStatement","ConditionalExpression","SwitchStatement","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","CatchClause"]),Be=new Set(["IfStatement","ConditionalExpression","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","CatchClause","LogicalExpression"]),We=new Set(["IfStatement","SwitchStatement","TryStatement","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","WithStatement"]),qe=e=>Be.has(e.type)||e.type==="SwitchCase"&&e.test||e.type==="AssignmentExpression"&&["&&=","||=","??="].includes(e.operator),Ue=(e,n,s)=>e.type==="IfStatement"?n==="consequent"||n==="alternate"&&s?.type!=="IfStatement":e.type==="ConditionalExpression"?n!=="test":e.type==="SwitchStatement"?n==="cases":lt.has(e.type)&&n==="body",jt=e=>e.type==="LogicalExpression"&&e.operator!=="??",Ke=(e,n)=>n?e.type==="MemberExpression"&&e.object.type==="ThisExpression"&&!e.computed?(e.property.type==="PrivateIdentifier"?"#":"")+e.property.name:void 0:e.type==="Identifier"?e.name:void 0;function Nt(e){return lt.has(e.type)?!0:ct.has(e.type)?!1:(Ft[e.type]??[]).some(n=>[e[n]].flat().some(s=>s&&Nt(s)))}function Je(e,n){let{program:s,errors:o,comments:l}=Fe(e,n,/\.[mc]?js$/.test(e)?{lang:"jsx"}:{}),r=[0];for(let i=0;i<n.length;i++)n[i]===`
4
- `&&r.push(i+1);let p=i=>{let d=0,y=r.length-1;for(;d<y;){let $=d+y+1>>1;r[$]<=i?d=$:y=$-1}return d+1},c=i=>n.slice(i.start,i.end),a=[],h=0;for(let i of l)a.push(n.slice(h,i.start),n.slice(i.start,i.end).replace(/[^\n]/g,"")),h=i.end;let m=[0];for(let i of[...a,n.slice(h)].join("").split(`
5
- `))m.push(m.at(-1)+(/\S/.test(i)?1:0));let u=[],b=new Set,g=new Set,f=i=>i.type==="ParenthesizedExpression"?f(i.expression):jt(i)?(b.add(i),[...f(i.left),i.operator,...f(i.right)]):[],v=(i,d,y,$,F,w,C=0,L=0)=>{(i.type==="ClassDeclaration"||i.type==="ClassExpression")&&($=i.id?.name??"<anonymous>"),(i.type==="StaticBlock"||(d.type==="PropertyDefinition"||d.type==="AccessorProperty")&&d.value===i)&&([F,w]=[!1,void 0]);let T=!1;if(ct.has(i.type)&&i.body){let j=Ot.has(d.type)?d:null,A=j?.kind==="get"||j?.kind==="set",R=i.type==="ArrowFunctionExpression"||i.type==="FunctionExpression"&&!A&&!j?.method&&j?.type!=="MethodDefinition";if(!(R&&F)){let x=j?.kind==="constructor"?$:A?`${c(j.key)}.${j.kind}`:i.id?.name??(j&&c(j.key))??(d.type==="VariableDeclarator"?d.id.name??c(d.id):d.type==="AssignmentExpression"?c(d.left):"<anonymous>"),O=j??i,[E,k]=[p(O.start),p(O.end)],H=i.params.filter(U=>U.type!=="Identifier"||U.name!=="this").length;w={name:x,kind:j?.type??i.type,start:E,end:k,depth:y,lambda:R,cyclomatic:1,cognitive:0,sloc:m[k]-m[E-1],parameters:H,nesting:0},u.push(w),T=!0,F=Nt(i.body)}}let q=i.type==="IfStatement"&&d.type==="IfStatement"&&d.alternate===i,z=T?0:L+(We.has(i.type)&&!q?1:0);w&&(w.nesting=Math.max(w.nesting,z),qe(i)&&w.cyclomatic++,i.type==="IfStatement"?w.cognitive+=(q?1:1+C)+(i.alternate&&i.alternate.type!=="IfStatement"?1:0):lt.has(i.type)?w.cognitive+=1+C:(i.type==="BreakStatement"||i.type==="ContinueStatement")&&i.label?w.cognitive++:jt(i)&&!b.has(i)?w.cognitive+=f(i).filter((j,A,R)=>j!==R[A-1]).length:i.type==="CallExpression"&&Ke(i.callee,Ot.has(w.kind))===w.name&&!g.has(w)&&(g.add(w),w.cognitive++));let Y=T?0:ct.has(i.type)?C+1:C;for(let j of Ft[i.type]??[]){let A=i[j],R=Y+(Ue(i,j,A)?1:0);if(Array.isArray(A))for(let x of A)x&&v(x,i,y+(T?1:0),$,F,w,R,z);else A&&v(A,i,y+(T?1:0),$,F,w,R,z)}};v(s,s,0,"",!1);let S=!(o.length&&!s.body.length);return{parsed:S,functions:u,errorLines:o.map(i=>p(i.labels[0]?.start??0)),inactiveLines:0,sloc:S?m.at(-1):0,comments:S?l.map(i=>({kind:i.type==="Line"?"line":/^\*[^*/]/.test(i.value)?"doc":"block",start:p(i.start),end:p(i.end)})):[]}}import{execFile as Ve,spawn as Qe}from"node:child_process";import{promisify as Ye}from"node:util";var P=(e,...n)=>pt(e,"",...n);async function pt(e,n,...s){let o=Ye(Ve)("git",s,{cwd:e,encoding:"utf8",maxBuffer:1073741824});return o.child.stdin.on("error",()=>{}).end(n),(await o).stdout}function Lt(e){let n=Qe("git",["cat-file","--batch"],{cwd:e,stdio:["pipe","pipe","inherit"]}),s=[],o=p=>s.splice(0).forEach(c=>c.reject(p));n.on("error",o),n.on("exit",p=>o(new Error(`git cat-file exited with code ${p}`)));let l=new Promise(p=>n.on("close",p)),r=Buffer.alloc(0);return n.stdout.on("data",p=>{r=Buffer.concat([r,p]);for(let c;(c=r.indexOf(10))>=0;){let a=r.subarray(0,c).toString();if(a.endsWith(" missing")){s.shift()?.reject(new Error(`git object ${a}`)),r=r.subarray(c+1);continue}let h=Number(a.split(" ")[2]);if(r.length<c+h+2)return;s.shift()?.resolve(r.subarray(c+1,c+1+h)),r=r.subarray(c+h+2)}}),{read:p=>new Promise((c,a)=>{s.push({resolve:c,reject:a}),n.stdin.write(p+`
6
- `)}),close:()=>(n.stdin.end(),l)}}var V=N.array(N.string()).default([]),tt=N.strictObject({include:V,exclude:V,tests:V,ai:N.record(N.string(),N.strictObject({emails:V,branches:V})).default({}),since:N.string().optional(),interval:N.string().optional()});async function It(e){let n=Ze((await P(e,"rev-parse","--show-toplevel")).trim(),".coderot.yml"),s=await Xe(n,"utf8").catch(l=>l.code==="ENOENT"?"":Promise.reject(l)),o=tt.safeParse(en(s)??{});if(!o.success)throw new Error(`${n}:
7
- ${N.prettifyError(o.error)}`);return o.data}async function mt(e,n,s){let o=(await pt(e,s.join("\0"),"check-attr","--stdin","-z",`--source=${n}`,"linguist-generated","linguist-vendored")).split("\0"),l=new Map;for(let r=0;r+2<o.length;r+=3){if(o[r+2]==="unspecified")continue;let p=l.get(o[r])??{};p[o[r+1]==="linguist-generated"?"generated":"vendored"]=!["unset","false"].includes(o[r+2]),l.set(o[r],p)}return l}function et(e,n,s,o){let l=Z(n,s,o),r=p=>p.some(c=>tn.matchesGlob(n,c));return l==="generated"||l==="vendored"?l:r(e.exclude)||e.include.length&&!r(e.include)?"excluded":l==="code"&&r(e.tests)?"test":l}var ut="author { __typename login }",Dt=`reviews(first: 50, after: $after) { pageInfo { hasNextPage endCursor } nodes { ${ut} state comments { totalCount } } }`,nn=`commits { totalCount } ${ut} ${Dt} comments(first: 100) { nodes { ${ut} } }`,_t=e=>!e||e.__typename==="Bot"||/(bot|\[bot\])$/i.test(e.login);function zt(e,n){let s=new Map(n.flatMap(o=>o.pr?.review?[[o.pr.number,o.pr]]:[]));for(let o of e){let l=o.pr&&s.get(o.pr.number);l&&Object.assign(o.pr,{review:l.review,commits:o.pr.commits??l.commits})}}async function Ht(e,n,s,o="https://api.github.com/graphql"){let[l,r]=n.split("/"),p=async(u,b=null,g=0)=>{let f=await fetch(o,{method:"POST",headers:{authorization:`bearer ${s}`,"content-type":"application/json"},body:JSON.stringify({query:`query($owner: String!, $name: String!, $after: String) { repository(owner: $owner, name: $name) { ${u} } }`,variables:{owner:l,name:r,after:b}})});if((f.status===403||f.status===429)&&g<4&&/rate limit/i.test(await f.text()))return await new Promise(i=>setTimeout(i,Number(f.headers.get("retry-after")??60*2**g)*1e3)),p(u,b,g+1);if(!f.ok)throw new Error(`HTTP ${f.status}`);let v=await f.json(),S=v.errors?.find(i=>i.type!=="NOT_FOUND")?.message??(v.data?.repository?void 0:`no repository ${n}`);if(S)throw new Error(S);return v.data.repository},c=async u=>{let b;try{b=await p(u.map((g,f)=>`p${f}: pullRequest(number: ${g.pr.number}) { ${nn} }`).join(" "))}catch(g){if(u.length===1||!/^HTTP 50[24]$/.test(g.message))throw g;let f=Math.ceil(u.length/2);return await c(u.slice(0,f)),c(u.slice(f))}for(let[g,f]of u.entries()){let v=b[`p${g}`];if(!v)continue;let S=v.reviews.nodes;for(let y=v.reviews.pageInfo;y.hasNextPage;){let $=(await p(`p0: pullRequest(number: ${f.pr.number}) { ${Dt} }`,y.endCursor)).p0.reviews;S.push(...$.nodes),y=$.pageInfo}let i=y=>!_t(y)&&y.login!==v.author?.login,d=S.filter(y=>i(y.author));f.pr.commits??=v.commits.totalCount,f.pr.review={reviewers:new Set(d.map(y=>y.author.login)).size,approved:d.some(y=>y.state==="APPROVED"),inline:rt(d.map(y=>y.comments.totalCount)),conversation:v.comments.nodes.filter(y=>i(y.author)).length,botInline:rt(S.filter(y=>_t(y.author)).map(y=>y.comments.totalCount))}}},a=e.filter(u=>u.pr&&!u.pr.review),h=[];for(let u=0;u<a.length;u+=50)h.push(a.slice(u,u+50));let m;await Promise.all(Array.from({length:4},async()=>{for(let u;!m&&(u=h.shift());)await c(u).catch(b=>{m??=b.message})})),m&&console.warn(`Commits per squash merge and review attention left out for ${a.filter(u=>!u.pr.review).length} of ${a.length} PRs (${m}). In GitHub Actions, give the workflow \`pull-requests: read\``)}import{createHash as hn}from"node:crypto";import{closeSync as yn,openSync as bn,writeSync as B}from"node:fs";import{availableParallelism as wn}from"node:os";import{extname as wt}from"node:path";import{createHash as sn}from"node:crypto";var ft={"claude-code":{emails:["noreply@anthropic.com","claude[bot]@users.noreply.github.com"],branches:["claude/"],tools:["claude","claude-web"]},"copilot-cli":{emails:["223556219+copilot@users.noreply.github.com"],branches:[],tools:["github-copilot-cli"]},"copilot-coding-agent":{emails:["198982749+copilot@users.noreply.github.com"],branches:["copilot/"],tools:[]},"copilot-review":{emails:["175728472+copilot@users.noreply.github.com"],branches:[],tools:[]},copilot:{emails:["copilot@users.noreply.github.com","copilot@github.com"],branches:[],tools:["github-copilot","copilot"]},cursor:{emails:["cursoragent@cursor.com","cursor[bot]@users.noreply.github.com"],branches:["cursor/"],tools:["cursor","cursor-agent"]},codex:{emails:["noreply@openai.com","codex@openai.com","chatgpt-codex-connector[bot]@users.noreply.github.com"],branches:["codex/"],tools:["codex","codex-cloud"]},gemini:{emails:["noreply@google.com","gemini-code-assist[bot]@users.noreply.github.com"],branches:[],tools:["gemini"]},aider:{emails:["aider@aider.chat","noreply@aider.chat"],branches:[],tools:[]},openhands:{emails:["openhands@all-hands.dev"],branches:[],tools:[]},devin:{emails:["devin-ai-integration[bot]@users.noreply.github.com"],branches:["devin/"],tools:["devin"]},charlie:{emails:["charlie@charlielabs.ai","charliecreates[bot]@users.noreply.github.com"],branches:[],tools:[]},grok:{emails:["noreply@x.ai"],branches:[],tools:[]},"muse-spark":{emails:["noreply@meta.com"],branches:[],tools:[]},jules:{emails:["google-labs-jules[bot]@users.noreply.github.com"],branches:[],tools:[]},"amazon-q":{emails:["amazon-q-developer[bot]@users.noreply.github.com"],branches:[],tools:[]},"factory-droid":{emails:["factory-droid[bot]@users.noreply.github.com","droid@factory.ai"],branches:[],tools:["droid"]}};var dt=(e,n)=>e.get(n.toLowerCase())??e.get(n.toLowerCase().replace(/^\d+\+/,"")),rn=(e,n)=>e.toLowerCase()==="copilot@github.com"&&n>=Date.UTC(2026,3,15)/1e3&&n<Date.UTC(2026,4,20)/1e3,an=[["AGENTS.md",/(^|\/)AGENTS?\.md$/],["Claude Code",/(^|\/)CLAUDE(\.local)?\.md$|^\.claude\//],["GitHub Copilot",/^\.github\/(copilot-instructions\.md$|instructions\/|prompts\/|chatmodes\/|agents\/|workflows\/copilot-setup-steps\.ya?ml$)/],["Gemini",/(^|\/)GEMINI\.md$|^\.gemini\//],["Cursor",/^\.cursorrules$|^\.cursor\/rules\//],["Windsurf",/^\.windsurfrules$|^\.windsurf\/rules\//],["Cline",/^\.clinerules(\/|$)/],["Roo Code",/^\.roorules$|^\.roo\/rules/],["Kiro",/^\.kiro\/steering\//],["Junie",/^\.junie\/guidelines\.md$/],["Aider",/^\.aider\.conf\.ya?ml$/],["Continue",/^\.continue\/rules\//],["Amazon Q",/^\.amazonq\/rules\//],["Augment",/^\.augment-guidelines$|^\.augment\/rules\//],["Warp",/(^|\/)WARP\.md$/],["MCP servers",/^\.mcp\.json$/]],gt=e=>an.some(([,n])=>n.test(e)),cn=e=>sn("sha256").update(e.toLowerCase().replace(/^\d+\+/,"")).digest("hex"),ln=new Map(Object.entries(ft).flatMap(([e,n])=>n.tools.map(s=>[s,e])));function pn(e){let[n="",s=""]=e.split(/^---$/m),o;try{o=JSON.parse(s)}catch{return}if(!String(o?.schema_version).startsWith("authorship/3."))return;let l={...o.prompts,...o.sessions},r={},p="";for(let c of n.split(`
8
- `)){let[,a="",h=""]=/^ (\S+) ([\d,-]+)$/.exec(c)??[];if(!a){c&&c[0]!==" "&&(p=c.replace(/^"(.*)"$/,"$1"));continue}let m=l[a.split("::")[0]]?.agent_id?.tool;if(typeof m!="string")continue;let u=ln.get(m)??m,b=r[p]??={};for(let g of h.split(",")){let[f=0,v=f]=g.split("-").map(Number);b[u]=(b[u]??0)+v-f+1}}return r}function mn(e){return/^(?:Merge pull request #\d+ from [^\s/]+\/(\S+)|Merged in (\S+) \(pull request|Merge branch '([^']+)'|Merge remote-tracking branch '[^/']+\/([^']+)')/.exec(e)?.slice(1).find(Boolean)}function Gt(e){let n=/^Merge pull request #(\d+) from |\(#(\d+)\)$/.exec(e);return n?Number(n.slice(1).find(Boolean)):void 0}var ht=(e,n)=>(/^Merge pull request #\d+ from /.test(e)?n.split(`
9
- `)[0]:e).replace(/ \(#\d+\)$/,"").trim(),Bt=(e,n)=>ht(e,n).replace(/^(\[[^\]]*\]\s*)*/,""),Wt=(e,n)=>/^((bug|hot)?fix(es|ed|ing)?|bugs?|revert(s|ed)?)\b/i.test(Bt(e,n)),qt=(e,n)=>/^revert\b/i.test(Bt(e,n))?/This reverts commit ([0-9a-f]{40,64})/.exec(n)?.[1]:void 0;async function Ut(e,n,s={}){if(!n.length)return;let o=[...Object.entries(ft),...Object.entries(s)],l=new Map(o.flatMap(([a,h])=>h.emails.map(m=>[m.toLowerCase(),a])));await P(e,"rev-parse","-q","--verify","refs/notes/ai").catch(()=>"")||await P(e,"fetch","-q","origin","refs/notes/ai:refs/notes/ai").catch(()=>{});let r=(await P(e,"log","-1","--format=%P",n.at(-1).commit)).trim().split(" ")[0],p=new Map;for(let a of(await P(e,"log","--notes=ai","--format=%x01%H %P%x02%at%x02%ae%x02%ce%x02%N%x02%B","HEAD",...r?[`^${r}`]:[])).split("").slice(1)){let[h="",m="",u="",b="",g="",f=""]=a.split(""),[v="",...S]=h.trim().split(" "),i=g.trim()?pn(g):void 0;g.trim()&&!i&&console.warn(`The Git AI note on ${v} isn't authorship/3.x, so it's left out`);let d=[];for(let w of[u,b]){let C=dt(l,w);C&&d.push({source:"bot",agent:C})}let y=[...f.matchAll(/^co-authored-by:.*<([^>]+)>/gim)].map(([,w=""])=>w);for(let w of y){let C=dt(l,w);C&&!rn(w,Number(m))&&d.push({source:"trailer",agent:C})}let $=[u,...y].filter(w=>w&&!dt(l,w)&&!w.includes("[bot]")).map(cn),F=mn(f);for(let[w,C]of o)F&&C.branches.some(L=>F.startsWith(L))&&d.push({source:"branch",agent:w});p.set(v,{parents:S,signals:d,people:$,lines:i})}let c=new Set(n.map(a=>a.commit));for(let a of n.toReversed()){let{parents:h,signals:m,people:u}=p.get(a.commit),b=[...m],g=new Set(u),f=[],v=!0,S=d=>{d.lines?f.push(d.lines):d.parents.length<2&&(v=!1)};S(p.get(a.commit));let i=0;for(let d=h.slice(1),y;y=d.pop();)c.has(y)||!p.has(y)||(c.add(y),i++,b.push(...p.get(y).signals),p.get(y).people.forEach($=>g.add($)),S(p.get(y)),d.push(...p.get(y).parents));a.lineLevel=v&&f.length>0;for(let d of a.files){let y={};for(let w of f)for(let[C,L]of Object.entries(w[d.path]??{}))y[C]=(y[C]??0)+L;let $=Math.min(1,d.added/Object.values(y).reduce((w,C)=>w+C,0)),F=Object.entries(y).map(([w,C])=>[w,Math.floor(C*$)]).filter(([,w])=>w>0);F.length&&(d.ai=Object.fromEntries(F)),b.push(...F.map(([w])=>({source:"git-ai",agent:w})))}a.ai=b.filter((d,y)=>b.findIndex($=>$.source===d.source&&$.agent===d.agent)===y),a.authors=[...g].sort(),a.pr&&h.length>1&&(a.pr.commits=i)}}import{posix as un}from"node:path";var Kt=[[/^net(\d{2,3})$/,"NETFRAMEWORK","NET",["20","35","40","45","451","452","46","461","462","47","471","472","48","481"]],[/^netstandard(\d\.\d)$/,"NETSTANDARD","NETSTANDARD",["1.0","1.1","1.2","1.3","1.4","1.5","1.6","2.0","2.1"]],[/^netcoreapp(\d\.\d)$/,"NETCOREAPP","NETCOREAPP",["1.0","1.1","2.0","2.1","2.2","3.0","3.1"]]],Jt=(e,n)=>n.map(s=>`${e}${s.replace(".","_")}_OR_GREATER`);function fn(e){let n=e.trim().toLowerCase(),s=/^net(\d+)\.(\d+)(?:-([a-z]+))?/.exec(n);if(s&&Number(s[1])>=5){let o=Number(s[1]);return{rank:1e3+o,symbols:["NET",`NET${o}_${s[2]}`,"NETCOREAPP",...Array.from({length:o-4},(l,r)=>`NET${r+5}_0_OR_GREATER`),...Jt("NETCOREAPP",Kt[2][3]),...s[3]?[s[3].toUpperCase()]:[]]}}for(let[o,[l,r,p,c]]of Kt.entries()){let a=c.indexOf(l.exec(n)?.[1]??"");if(a>=0)return{rank:o*100+a,symbols:[r,p+c[a].replace(".","_"),...Jt(p,c.slice(0,a+1))]}}}function dn(e){e=e.replace(/<!--[\s\S]*?-->/g,"");let n=o=>/\bCondition\s*=\s*"([^"]*)"/.exec(o)?.[1],s=[];for(let[,o,l]of e.matchAll(/<PropertyGroup\b([^>]*?)(?<!\/)>([\s\S]*?)<\/PropertyGroup>/g))for(let[,r,p,c]of l.matchAll(/<(\w+)\b([^>]*?)>([^<]*)<\/\1>/g))s.push({name:r.toLowerCase(),value:c.trim(),conditions:[n(o),n(p)].filter(a=>a!==void 0)});return{assignments:s,imports:[...e.matchAll(/<Import\b[^>]*?\bProject\s*=\s*"([^"]*)"/g)].map(o=>o[1])}}var yt=new Map,bt=(e,n,s,o=0)=>e.replace(/\$\((\w+)\)/g,(l,r)=>n.get(r.toLowerCase())??(o<8?bt(s.get(r.toLowerCase())??"",n,s,o+1):"")),gn=e=>e.split(/\s+or\s+/i).some(n=>n.split(/\s+and\s+/i).every(s=>{let o=/^[\s(]*'([^']*)'\s*(==|!=)\s*'([^']*)'[\s)]*$/.exec(s);return!!o&&o[1].trim().toLowerCase()===o[3].trim().toLowerCase()==(o[2]==="==")}));function Vt(e,n,s){let o=new Map(n);for(let{assignments:l}of e)for(let r of l)!n.has(r.name)&&r.conditions.every(p=>gn(bt(p,o,s)))&&o.set(r.name,bt(r.value,o,s));return o}var I=e=>e.slice(0,Math.max(e.lastIndexOf("/"),0)),Qt=(e,n)=>e?`${e}/${n}`:n;function*Yt(e){for(;;){if(yield e,!e)return;e=I(e)}}var Xt=new Map([["configuration","Release"],["platform","AnyCPU"]]);async function Zt(e,n){let s=new Map;await Promise.all([...e].filter(([a])=>/\.(csproj|props|targets)$/.test(a)).map(async([a,h])=>{yt.has(h)||yt.set(h,dn(await n(h))),s.set(a,yt.get(h))}));let o=new Map,l=new Map;for(let a of e.keys())if(a.endsWith(".csproj")&&!l.has(I(a))&&l.set(I(a),a),!!a.endsWith(".props"))for(let h of s.get(a).assignments)!h.conditions.length&&!o.has(h.name)&&o.set(h.name,h.value);let r=(a,h)=>[...Yt(a)].map(m=>Qt(m,h)).find(m=>s.has(m)),p=(a,h)=>{if(!a||h.has(a)||!s.has(a))return[];h.add(a);let m=I(a);return[...s.get(a).imports.flatMap(u=>{let b=/Directory\.Build\.(props|targets)/i.exec(u);if(b&&u.includes("$("))return m?p(r(I(m),b[0]),h):[];let g=u.replace(/\$\(MSBuildThisFileDirectory\)/gi,"").replaceAll("\\","/");return g.includes("$(")?[]:p(un.normalize(Qt(m,g)),h)}),s.get(a)]},c=new Map;return a=>{let h=[...Yt(I(a))].map(d=>l.get(d)).find(d=>d),m=I(h||a);if(c.has(m))return c.get(m);let u=new Set,b=[...p(r(m,"Directory.Build.props"),u),...p(h,u),...p(r(m,"Directory.Build.targets"),u)],g=Vt(b,Xt,o),[f]=(g.get("targetframeworks")||g.get("targetframework")||"").split(";").map(d=>({t:d.trim(),f:fn(d)})).filter(d=>d.f).sort((d,y)=>y.f.rank-d.f.rank),S=((f?Vt(b,new Map([...Xt,["targetframework",f.t]]),o):g).get("defineconstants")??"").split(/[;,]/).map(d=>d.trim()).filter(d=>/^\w+$/.test(d)),i=[...new Set(["RELEASE","TRACE",...f?.f.symbols??[],...S])].sort();return c.set(m,i),i}}var vn={d:86400,w:7*86400,m:365/12*86400,y:365*86400};function W(e){let n=/^(\d+)([dwmy])$/.exec(e);if(!n)throw new Error(`Expected a duration like 90d, 1w, 12m or 1y, got "${e}"`);return Number(n[1])*vn[n[2]]}async function xn(e,n,s){let o=(await P(e,"log","--first-parent","--format=%H %ct","HEAD")).trim().split(`
10
- `).map(p=>({commit:p.slice(0,p.indexOf(" ")),time:Number(p.slice(p.indexOf(" ")+1))})),l=o[0].time,r=new Map;for(let p=l;p>=l-n;p-=s){let c=o.find(a=>a.time<=p);c&&r.set(c.commit,c)}return[...r.values()]}var Sn=/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|packages\.lock\.json)$/;async function $n(e,n,s,o=tt.parse({}),l=0,r=!1){let p=/^0{40}$|^0{64}$/.test(s??""),c;s&&!p&&(c=(await P(e,"rev-parse","--verify",`${s}^{commit}`).catch(()=>"")).trim(),(await P(e,"log","--first-parent","--format=%H","HEAD")).trim().split(`
11
- `).includes(c)||(console.warn(`--since-commit ${s} isn't on HEAD's first-parent history (a force push?), so churn covers the time window`),c=void 0));let a=[],h=[],m=(await P(e,"log","--first-parent","--diff-merges=first-parent","--numstat","-z",...c?[`^${c}`]:p?[]:[`--since=${n}`],"--format=%x01%H %ct %B","HEAD")).split("\0");for(let g=0;g<m.length;g++){let f=/^\x01(\w+) (\d+) ([^\n]*?)\s*(?:\n|$)(.*)$/s.exec(m[g]);if(f){let y=Gt(f[3]);a.push({commit:f[1],committedAt:new Date(Number(f[2])*1e3).toISOString(),files:[],ai:[],lineLevel:!1,authors:[],agentFiles:!1,fix:Wt(f[3],f[4]),reverts:qt(f[3],f[4]),...r&&{title:ht(f[3],f[4])}}),y&&(a.at(-1).pr={number:y,files:0,added:0,deleted:0});continue}let[,v,S,i]=/^\n?(\d+|-)\t(\d+|-)\t(.*)$/s.exec(m[g])??[];if(!v||!S)continue;let d=i||m[g+=2];gt(d)&&(a.at(-1).agentFiles=!0),!(v==="-"||Number(v)+Number(S)===0)&&h.push({c:a.at(-1),path:d,added:Number(v),deleted:Number(S)})}let u=h.length?await mt(e,"HEAD",[...new Set(h.map(g=>g.path))]):new Map;for(let{c:g,path:f,added:v,deleted:S}of h){let i=et(o,f,"",u.get(f));(i==="code"||i==="test")&&g.files.push({path:f,added:v,deleted:S}),g.pr&&i!=="generated"&&i!=="vendored"&&i!=="excluded"&&!Sn.test(f)&&(g.pr.files++,g.pr.added+=v,g.pr.deleted+=S)}let b=a.filter(g=>g.fix&&Date.parse(g.committedAt)/1e3>=l);return await Promise.all(Array.from({length:wn()},async()=>{for(let g;g=b.pop();)g.fixed=await Cn(e,g,new Set(g.files.filter(f=>et(o,f.path,"",u.get(f.path))==="code").map(f=>f.path)))})),a}async function Cn(e,n,s){let o=new Map,l="",r="",p=!1;if(s.size){for(let m of(await P(e,"-c","core.quotePath=false","diff-tree","-p","-U0","-M","--no-prefix","--diff-merges=first-parent","--root",n.commit)).split(`
12
- `))if(m.startsWith("diff --git "))[p,l,r]=[!0,"",""];else if(p&&m.startsWith("--- "))l=m.slice(4).replace(/\t$/,"");else if(p&&m.startsWith("+++ "))r=m.slice(4).replace(/\t$/,"");else if(m.startsWith("@@ ")){p=!1;let[,u,b="1"]=/^@@ -(\d+)(?:,(\d+))? /.exec(m)??[];l!=="/dev/null"&&s.has(r==="/dev/null"?l:r)&&b!=="0"&&(o.get(l)??o.set(l,[]).get(l)).push(`${u},+${b}`)}}let c=Date.parse(n.committedAt)/1e3-30*86400,a=new Set,h=new Set;for(let[m,u]of o)for(let b=0;b<u.length;b+=1e3){let g="";for(let f of(await P(e,"blame","--first-parent","--porcelain",`--since=${c}`,...u.slice(b,b+1e3).flatMap(v=>["-L",v]),`${n.commit}^`,"--",m)).split(`
13
- `)){let v=/^([0-9a-f]{40,64}) \d+ \d+/.exec(f);v?a.add(g=v[1]):f==="boundary"&&h.add(g)}}return[...a].filter(m=>!h.has(m))}var En=e=>e.split(`
2
+ import{existsSync as Rn,mkdirSync as Tn,readFileSync as Nn,rmSync as Ln}from"node:fs";import{join as D}from"node:path";import{parseArgs as In}from"node:util";import{z as t}from"zod";var _=1,me=t.strictObject({name:t.string(),kind:t.string(),start:t.int().positive(),end:t.int().positive(),depth:t.int().nonnegative(),lambda:t.boolean(),cyclomatic:t.int().positive(),cognitive:t.int().nonnegative(),sloc:t.int().nonnegative(),parameters:t.int().nonnegative(),nesting:t.int().nonnegative()}),ue=t.strictObject({kind:t.enum(["line","block","doc"]),start:t.int().positive(),end:t.int().positive()}),fe=t.strictObject({parsed:t.boolean(),functions:t.array(me),unmeasuredFunctions:t.int().nonnegative(),errorLines:t.array(t.int().positive()),inactiveLines:t.int().nonnegative(),sloc:t.int().nonnegative(),comments:t.array(ue)}),de=t.strictObject({path:t.string(),start:t.int().positive(),end:t.int().positive()}),ge=t.strictObject({locations:t.array(de).min(2)}),he=t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),files:t.array(t.strictObject({path:t.string(),blob:t.string(),test:t.boolean()})),skipped:t.strictObject({generated:t.int().nonnegative(),vendored:t.int().nonnegative(),excluded:t.int().nonnegative()}),markup:t.record(t.string(),t.strictObject({files:t.int().nonnegative(),lines:t.int().nonnegative()})),agentFiles:t.array(t.string()),clones:t.array(ge).optional()}),Ct=t.strictObject({reviewers:t.int().nonnegative(),approved:t.boolean(),inline:t.int().nonnegative(),conversation:t.int().nonnegative(),botInline:t.int().nonnegative()}),ye=t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),files:t.array(t.strictObject({path:t.string(),added:t.int().nonnegative(),deleted:t.int().nonnegative(),ai:t.record(t.string(),t.int().positive()).optional()})),ai:t.array(t.strictObject({source:t.enum(["git-ai","trailer","bot","branch"]),agent:t.string()})),authors:t.array(t.string()),agentFiles:t.boolean(),lineLevel:t.boolean(),title:t.string().optional(),fix:t.boolean(),reverts:t.string().optional(),fixed:t.array(t.string()).optional(),pr:t.strictObject({number:t.int().positive(),files:t.int().nonnegative(),added:t.int().nonnegative(),deleted:t.int().nonnegative(),commits:t.int().nonnegative().optional(),review:Ct.optional()}).optional()}),Dn=t.strictObject({schemaVersion:t.literal(_),...he.shape,blobs:t.record(t.string(),fe)}),Et=t.strictObject({schemaVersion:t.literal(_),commits:t.array(ye)}),rt=e=>e.reduce((n,s)=>n+s,0);var st=t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),title:t.string(),pr:t.int().positive().optional(),size:t.int().nonnegative().optional(),review:Ct.optional(),agents:t.array(t.string()),fix:t.boolean(),added:t.int().nonnegative(),deleted:t.int().nonnegative()}),it=t.strictObject({count:t.int().nonnegative(),medianSize:t.int().nonnegative(),large:t.int().nonnegative(),fixes:t.int().nonnegative(),settled:t.int().nonnegative(),fixedLater:t.int().nonnegative(),reviewKnown:t.int().nonnegative(),noHumanReview:t.int().nonnegative(),approvedNoComment:t.int().nonnegative(),growth:t.int(),growthLines:t.int().nonnegative(),growthTrimmed:t.int(),growthLinesTrimmed:t.int().nonnegative()}),$t=t.record(t.enum(["ai","other"]),it),zn=t.strictObject({schemaVersion:t.literal(_),repo:t.string(),snapshots:t.array(t.strictObject({commit:t.string(),committedAt:t.iso.datetime(),sloc:t.int().nonnegative(),testSloc:t.int().nonnegative(),cognitive:t.int().nonnegative(),duplicated:t.int().nonnegative().optional()})),months:t.array(t.strictObject({month:t.string(),commits:t.int().nonnegative(),aiCommits:t.int().nonnegative(),added:t.int().nonnegative(),aiAdded:t.int().nonnegative(),agents:t.record(t.string(),t.int().positive()),attributed:t.int().nonnegative(),prs:$t})),jumps:t.array(t.strictObject({metric:t.enum(["complexity","duplication"]),from:t.int().nonnegative(),to:t.int().nonnegative(),files:t.array(t.strictObject({path:t.string(),delta:t.int()})),commits:t.array(st)})),folders:t.array(t.strictObject({path:t.string(),sloc:t.array(t.int().nonnegative()),cognitive:t.array(t.int().nonnegative()),commits:t.int().nonnegative(),aiCommits:t.int().nonnegative()})),hotspots:t.array(t.strictObject({path:t.string(),commits:t.int().positive(),aiCommits:t.int().nonnegative(),cognitive:t.int().nonnegative()})),prs:$t,prsBy:t.record(t.enum(["large","small","fixed","unfixed","recent","human","unknown"]),it),prsByAgent:t.record(t.string(),it),biggest:t.array(st),worstSince:t.iso.datetime(),worst:t.array(t.strictObject({path:t.string(),before:t.int().nonnegative().optional(),after:t.int().nonnegative(),from:t.strictObject({path:t.string(),how:t.enum(["renamed","copied","moved"])}).optional(),commits:t.array(st)})),lookSince:t.int().nonnegative(),look:t.array(t.strictObject({folder:t.string(),rise:t.int().positive(),commits:t.int().nonnegative(),aiCommits:t.int().nonnegative(),file:t.strictObject({path:t.string(),before:t.int().nonnegative().optional(),after:t.int().nonnegative()}).optional()}))});import{readFile as Ze}from"node:fs/promises";import{join as tn,posix as en}from"node:path";import{parse as nn}from"yaml";import{z as N}from"zod";import{execFile as be,execFileSync as we,spawn as ve}from"node:child_process";import{mkdirSync as xe,mkdtempSync as Se,readFileSync as $e,rmSync as Ce,writeFileSync as Ee}from"node:fs";import{tmpdir as Oe}from"node:os";import{dirname as je,extname as J,join as X}from"node:path";import{createInterface as Pe}from"node:readline";import{fileURLToPath as Pt}from"node:url";import{promisify as Fe}from"node:util";import{parseSync as Ae,visitorKeys as Ft}from"oxc-parser";var At=new Set([".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs"]),kt=e=>J(e)===".cs"||At.has(J(e)),ke=/(^|\/)(node_modules|bower_components|vendor|third[-_]?party|wwwroot\/lib(_npm)?)\//i,Me=/(^|\/)(obj|dist)\/|\.(designer|generated|g|g\.i)\.cs$|(^|\/)TemporaryGeneratedFile_[^/]*$|\.min\.[cm]?js$/i,Re=/^\uFEFF?(\s|\/\/.*|\/\*[\s\S]*?\*\/|#.*)*/,Te=/<auto-?generated|@generated|(file|content) (is|was) (auto-?|automatically )?generated|^\W*generated (by|from)|^(?=.*do not (edit|modify))(?=.*(generated|copied|from )).*/im,Ne=/^\/\/[#@] sourceMappingURL=|^\/\*! For license information please see \S+ \*\//m,Le=new Set([".razor",".cshtml",".vue",".svelte",".astro"]),Ie=/(^|\/)((\w+[-_])?(tests?|__tests__|e2e)|(tests?|e2e)[-_]\w+)\/|\.(test|spec)[.-][^/]*$|Tests?(\.cs$|\/)/;function Z(e,n,s={}){return s.vendored??ke.test(e)?"vendored":s.generated??Me.test(e)?"generated":Le.has(J(e))?"markup":kt(e)?s.generated===void 0&&(Te.test(n.match(Re)[0])||At.has(J(e))&&Ne.test(n))?"generated":Ie.test(e)?"test":"code":"other"}async function Mt(e,n,s={}){if(!kt(e))throw new Error(`Unsupported file type: ${e}`);let o=J(e)===".cs"?await Be(n,s.csharpSymbols??[]):Ve(e,n),c=o.functions.filter(r=>!o.errorLines.some(p=>r.start<=p&&p<=r.end));return{...o,functions:c,unmeasuredFunctions:o.functions.length-c.length}}function Rt(){G?.stdin.end(),G=void 0}var _e=Pt(import.meta.resolve("jscpd/run-jscpd.js"));async function Tt(e){if(!e.length)return[];let n=Se(X(Oe(),"coderot-dup-"));try{for(let l of e)xe(je(X(n,"src",l.path)),{recursive:!0}),Ee(X(n,"src",l.path),l.source);await Fe(be)(process.execPath,[_e,"src","-f","csharp,typescript,tsx,javascript,jsx","--cross-formats","typescript,tsx;javascript,jsx","-k","50","-l","5","--mode","weak","--ignore-pattern","using\\s+(static\\s+)?[\\w.]+(\\s*=\\s*[\\w.<>]+)?;,\\[assembly:[^\\]]*\\]","--no-gitignore","-r","json","-o","out","-s"],{cwd:n});let{duplicates:s}=JSON.parse($e(X(n,"out","jscpd-report.json"),"utf8")),o=l=>({path:l.name.replaceAll("\\","/"),start:l.start,end:l.end}),c=l=>`${l.path}:${l.start}-${l.end}`,r=new Map;for(let l of s){let[a,h]=[o(l.firstFile),o(l.secondFile)],[m,u]=[r.get(c(a))??[a],r.get(c(h))??[h]];if(m===u)continue;let b=[...m,...u];for(let g of b)r.set(c(g),b)}let p=(l,a)=>l.path<a.path?-1:l.path>a.path?1:l.start-a.start;return[...new Set(r.values())].map(l=>({locations:l.sort(p)})).sort((l,a)=>p(l.locations[0],a.locations[0]))}finally{Ce(n,{recursive:!0,force:!0})}}var De=Pt(new URL("./roslyn/bin/Release/net8.0/Coderot.Roslyn.dll",import.meta.url)),K=new Map,G,ze=0,at;function He(){if(at??=[...Ge().matchAll(/^Microsoft\.NETCore\.App (\S+)/gm)].map(s=>s[1]),!at.some(s=>Number(s.split(".")[0])>=8))throw new Error(`C# files need the .NET runtime 8 or newer (found: ${at.join(", ")||"none"}). In GitHub Actions: actions/setup-dotnet`);let e=s=>{G===n&&(G=void 0);for(let o of K.values())o.reject(s);K.clear()},n=ve("dotnet",[De],{stdio:["pipe","pipe","inherit"]});return n.on("error",e),n.on("exit",s=>e(new Error(`C# sidecar exited with code ${s}`))),Pe({input:n.stdout}).on("line",s=>{let{id:o,...c}=JSON.parse(s);K.get(o)?.resolve(c),K.delete(o)}),n}function Ge(){try{return we("dotnet",["--list-runtimes"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}catch{return""}}function Be(e,n){G??=He();let s=ze++;return new Promise((o,c)=>{K.set(s,{resolve:o,reject:c}),G.stdin.write(JSON.stringify({id:s,source:e,symbols:n})+`
3
+ `)})}var ct=new Set(["FunctionDeclaration","FunctionExpression","ArrowFunctionExpression"]),Ot=new Set(["MethodDefinition","TSAbstractMethodDefinition","Property","PropertyDefinition"]),lt=new Set(["IfStatement","ConditionalExpression","SwitchStatement","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","CatchClause"]),We=new Set(["IfStatement","ConditionalExpression","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","CatchClause","LogicalExpression"]),qe=new Set(["IfStatement","SwitchStatement","TryStatement","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","WithStatement"]),Ue=e=>We.has(e.type)||e.type==="SwitchCase"&&e.test||e.type==="AssignmentExpression"&&["&&=","||=","??="].includes(e.operator),Ke=(e,n,s)=>e.type==="IfStatement"?n==="consequent"||n==="alternate"&&s?.type!=="IfStatement":e.type==="ConditionalExpression"?n!=="test":e.type==="SwitchStatement"?n==="cases":lt.has(e.type)&&n==="body",jt=e=>e.type==="LogicalExpression"&&e.operator!=="??",Je=(e,n)=>n?e.type==="MemberExpression"&&e.object.type==="ThisExpression"&&!e.computed?(e.property.type==="PrivateIdentifier"?"#":"")+e.property.name:void 0:e.type==="Identifier"?e.name:void 0;function Nt(e){return lt.has(e.type)?!0:ct.has(e.type)?!1:(Ft[e.type]??[]).some(n=>[e[n]].flat().some(s=>s&&Nt(s)))}function Ve(e,n){let{program:s,errors:o,comments:c}=Ae(e,n,/\.[mc]?js$/.test(e)?{lang:"jsx"}:{}),r=[0];for(let i=0;i<n.length;i++)n[i]===`
4
+ `&&r.push(i+1);let p=i=>{let d=0,y=r.length-1;for(;d<y;){let $=d+y+1>>1;r[$]<=i?d=$:y=$-1}return d+1},l=i=>n.slice(i.start,i.end),a=[],h=0;for(let i of c)a.push(n.slice(h,i.start),n.slice(i.start,i.end).replace(/[^\n]/g,"")),h=i.end;let m=[0];for(let i of[...a,n.slice(h)].join("").split(`
5
+ `))m.push(m.at(-1)+(/\S/.test(i)?1:0));let u=[],b=new Set,g=new Set,f=i=>i.type==="ParenthesizedExpression"?f(i.expression):jt(i)?(b.add(i),[...f(i.left),i.operator,...f(i.right)]):[],v=(i,d,y,$,F,w,C=0,L=0)=>{(i.type==="ClassDeclaration"||i.type==="ClassExpression")&&($=i.id?.name??"<anonymous>"),(i.type==="StaticBlock"||(d.type==="PropertyDefinition"||d.type==="AccessorProperty")&&d.value===i)&&([F,w]=[!1,void 0]);let R=!1;if(ct.has(i.type)&&i.body){let j=Ot.has(d.type)?d:null,k=j?.kind==="get"||j?.kind==="set",T=i.type==="ArrowFunctionExpression"||i.type==="FunctionExpression"&&!k&&!j?.method&&j?.type!=="MethodDefinition";if(!(T&&F)){let x=j?.kind==="constructor"?$:k?`${l(j.key)}.${j.kind}`:i.id?.name??(j&&l(j.key))??(d.type==="VariableDeclarator"?d.id.name??l(d.id):d.type==="AssignmentExpression"?l(d.left):"<anonymous>"),O=j??i,[E,M]=[p(O.start),p(O.end)],H=i.params.filter(U=>U.type!=="Identifier"||U.name!=="this").length;w={name:x,kind:j?.type??i.type,start:E,end:M,depth:y,lambda:T,cyclomatic:1,cognitive:0,sloc:m[M]-m[E-1],parameters:H,nesting:0},u.push(w),R=!0,F=Nt(i.body)}}let q=i.type==="IfStatement"&&d.type==="IfStatement"&&d.alternate===i,z=R?0:L+(qe.has(i.type)&&!q?1:0);w&&(w.nesting=Math.max(w.nesting,z),Ue(i)&&w.cyclomatic++,i.type==="IfStatement"?w.cognitive+=(q?1:1+C)+(i.alternate&&i.alternate.type!=="IfStatement"?1:0):lt.has(i.type)?w.cognitive+=1+C:(i.type==="BreakStatement"||i.type==="ContinueStatement")&&i.label?w.cognitive++:jt(i)&&!b.has(i)?w.cognitive+=f(i).filter((j,k,T)=>j!==T[k-1]).length:i.type==="CallExpression"&&Je(i.callee,Ot.has(w.kind))===w.name&&!g.has(w)&&(g.add(w),w.cognitive++));let Y=R?0:ct.has(i.type)?C+1:C;for(let j of Ft[i.type]??[]){let k=i[j],T=Y+(Ke(i,j,k)?1:0);if(Array.isArray(k))for(let x of k)x&&v(x,i,y+(R?1:0),$,F,w,T,z);else k&&v(k,i,y+(R?1:0),$,F,w,T,z)}};v(s,s,0,"",!1);let S=!(o.length&&!s.body.length);return{parsed:S,functions:u,errorLines:o.map(i=>p(i.labels[0]?.start??0)),inactiveLines:0,sloc:S?m.at(-1):0,comments:S?c.map(i=>({kind:i.type==="Line"?"line":/^\*[^*/]/.test(i.value)?"doc":"block",start:p(i.start),end:p(i.end)})):[]}}import{execFile as Qe,spawn as Ye}from"node:child_process";import{promisify as Xe}from"node:util";var P=(e,...n)=>pt(e,"",...n);async function pt(e,n,...s){let o=Xe(Qe)("git",s,{cwd:e,encoding:"utf8",maxBuffer:1073741824});return o.child.stdin.on("error",()=>{}).end(n),(await o).stdout}function Lt(e){let n=Ye("git",["cat-file","--batch"],{cwd:e,stdio:["pipe","pipe","inherit"]}),s=[],o=p=>s.splice(0).forEach(l=>l.reject(p));n.on("error",o),n.on("exit",p=>o(new Error(`git cat-file exited with code ${p}`)));let c=new Promise(p=>n.on("close",p)),r=Buffer.alloc(0);return n.stdout.on("data",p=>{r=Buffer.concat([r,p]);for(let l;(l=r.indexOf(10))>=0;){let a=r.subarray(0,l).toString();if(a.endsWith(" missing")){s.shift()?.reject(new Error(`git object ${a}`)),r=r.subarray(l+1);continue}let h=Number(a.split(" ")[2]);if(r.length<l+h+2)return;s.shift()?.resolve(r.subarray(l+1,l+1+h)),r=r.subarray(l+h+2)}}),{read:p=>new Promise((l,a)=>{s.push({resolve:l,reject:a}),n.stdin.write(p+`
6
+ `)}),close:()=>(n.stdin.end(),c)}}var V=N.array(N.string()).default([]),tt=N.strictObject({include:V,exclude:V,tests:V,ai:N.record(N.string(),N.strictObject({emails:V,branches:V})).default({}),since:N.string().optional(),interval:N.string().optional()});async function It(e){let n=tn((await P(e,"rev-parse","--show-toplevel")).trim(),".coderot.yml"),s=await Ze(n,"utf8").catch(c=>c.code==="ENOENT"?"":Promise.reject(c)),o=tt.safeParse(nn(s)??{});if(!o.success)throw new Error(`${n}:
7
+ ${N.prettifyError(o.error)}`);return o.data}async function mt(e,n,s){let o=(await pt(e,s.join("\0"),"check-attr","--stdin","-z",`--source=${n}`,"linguist-generated","linguist-vendored")).split("\0"),c=new Map;for(let r=0;r+2<o.length;r+=3){if(o[r+2]==="unspecified")continue;let p=c.get(o[r])??{};p[o[r+1]==="linguist-generated"?"generated":"vendored"]=!["unset","false"].includes(o[r+2]),c.set(o[r],p)}return c}function et(e,n,s,o){let c=Z(n,s,o),r=p=>p.some(l=>en.matchesGlob(n,l));return c==="generated"||c==="vendored"?c:r(e.exclude)||e.include.length&&!r(e.include)?"excluded":c==="code"&&r(e.tests)?"test":c}var ut="author { __typename login }",Dt=`reviews(first: 50, after: $after) { pageInfo { hasNextPage endCursor } nodes { ${ut} state comments { totalCount } } }`,on=`commits { totalCount } ${ut} ${Dt} comments(first: 100) { nodes { ${ut} } }`,_t=e=>!e||e.__typename==="Bot"||/(bot|\[bot\])$/i.test(e.login);function zt(e,n){let s=new Map(n.flatMap(o=>o.pr?.review?[[o.pr.number,o.pr]]:[]));for(let o of e){let c=o.pr&&s.get(o.pr.number);c&&Object.assign(o.pr,{review:c.review,commits:o.pr.commits??c.commits})}}async function Ht(e,n,s,o="https://api.github.com/graphql"){let[c,r]=n.split("/"),p=async(u,b=null,g=0)=>{let f=await fetch(o,{method:"POST",headers:{authorization:`bearer ${s}`,"content-type":"application/json"},body:JSON.stringify({query:`query($owner: String!, $name: String!, $after: String) { repository(owner: $owner, name: $name) { ${u} } }`,variables:{owner:c,name:r,after:b}})});if((f.status===403||f.status===429)&&g<4&&/rate limit/i.test(await f.text()))return await new Promise(i=>setTimeout(i,Number(f.headers.get("retry-after")??60*2**g)*1e3)),p(u,b,g+1);if(!f.ok)throw new Error(`HTTP ${f.status}`);let v=await f.json(),S=v.errors?.find(i=>i.type!=="NOT_FOUND")?.message??(v.data?.repository?void 0:`no repository ${n}`);if(S)throw new Error(S);return v.data.repository},l=async u=>{let b;try{b=await p(u.map((g,f)=>`p${f}: pullRequest(number: ${g.pr.number}) { ${on} }`).join(" "))}catch(g){if(u.length===1||!/^HTTP 50[24]$/.test(g.message))throw g;let f=Math.ceil(u.length/2);return await l(u.slice(0,f)),l(u.slice(f))}for(let[g,f]of u.entries()){let v=b[`p${g}`];if(!v)continue;let S=v.reviews.nodes;for(let y=v.reviews.pageInfo;y.hasNextPage;){let $=(await p(`p0: pullRequest(number: ${f.pr.number}) { ${Dt} }`,y.endCursor)).p0.reviews;S.push(...$.nodes),y=$.pageInfo}let i=y=>!_t(y)&&y.login!==v.author?.login,d=S.filter(y=>i(y.author));f.pr.commits??=v.commits.totalCount,f.pr.review={reviewers:new Set(d.map(y=>y.author.login)).size,approved:d.some(y=>y.state==="APPROVED"),inline:rt(d.map(y=>y.comments.totalCount)),conversation:v.comments.nodes.filter(y=>i(y.author)).length,botInline:rt(S.filter(y=>_t(y.author)).map(y=>y.comments.totalCount))}}},a=e.filter(u=>u.pr&&!u.pr.review),h=[];for(let u=0;u<a.length;u+=50)h.push(a.slice(u,u+50));let m;await Promise.all(Array.from({length:4},async()=>{for(let u;!m&&(u=h.shift());)await l(u).catch(b=>{m??=b.message})})),m&&console.warn(`Commits per squash merge and review attention left out for ${a.filter(u=>!u.pr.review).length} of ${a.length} PRs (${m}). In GitHub Actions, give the workflow \`pull-requests: read\``)}import{createHash as yn}from"node:crypto";import{closeSync as bn,existsSync as wn,openSync as vn,readdirSync as xn,writeSync as B}from"node:fs";import{availableParallelism as Sn}from"node:os";import{extname as wt,join as $n}from"node:path";import{createHash as rn}from"node:crypto";var ft={"claude-code":{emails:["noreply@anthropic.com","claude[bot]@users.noreply.github.com"],branches:["claude/"],tools:["claude","claude-web"]},"copilot-cli":{emails:["223556219+copilot@users.noreply.github.com"],branches:[],tools:["github-copilot-cli"]},"copilot-coding-agent":{emails:["198982749+copilot@users.noreply.github.com"],branches:["copilot/"],tools:[]},"copilot-review":{emails:["175728472+copilot@users.noreply.github.com"],branches:[],tools:[]},copilot:{emails:["copilot@users.noreply.github.com","copilot@github.com"],branches:[],tools:["github-copilot","copilot"]},cursor:{emails:["cursoragent@cursor.com","cursor[bot]@users.noreply.github.com"],branches:["cursor/"],tools:["cursor","cursor-agent"]},codex:{emails:["noreply@openai.com","codex@openai.com","chatgpt-codex-connector[bot]@users.noreply.github.com"],branches:["codex/"],tools:["codex","codex-cloud"]},gemini:{emails:["noreply@google.com","gemini-code-assist[bot]@users.noreply.github.com"],branches:[],tools:["gemini"]},aider:{emails:["aider@aider.chat","noreply@aider.chat"],branches:[],tools:[]},openhands:{emails:["openhands@all-hands.dev"],branches:[],tools:[]},devin:{emails:["devin-ai-integration[bot]@users.noreply.github.com"],branches:["devin/"],tools:["devin"]},charlie:{emails:["charlie@charlielabs.ai","charliecreates[bot]@users.noreply.github.com"],branches:[],tools:[]},grok:{emails:["noreply@x.ai"],branches:[],tools:[]},"muse-spark":{emails:["noreply@meta.com"],branches:[],tools:[]},jules:{emails:["google-labs-jules[bot]@users.noreply.github.com"],branches:[],tools:[]},"amazon-q":{emails:["amazon-q-developer[bot]@users.noreply.github.com"],branches:[],tools:[]},"factory-droid":{emails:["factory-droid[bot]@users.noreply.github.com","droid@factory.ai"],branches:[],tools:["droid"]}};var dt=(e,n)=>e.get(n.toLowerCase())??e.get(n.toLowerCase().replace(/^\d+\+/,"")),an=(e,n)=>e.toLowerCase()==="copilot@github.com"&&n>=Date.UTC(2026,3,15)/1e3&&n<Date.UTC(2026,4,20)/1e3,cn=[["AGENTS.md",/(^|\/)AGENTS?\.md$/],["Claude Code",/(^|\/)CLAUDE(\.local)?\.md$|^\.claude\//],["GitHub Copilot",/^\.github\/(copilot-instructions\.md$|instructions\/|prompts\/|chatmodes\/|agents\/|workflows\/copilot-setup-steps\.ya?ml$)/],["Gemini",/(^|\/)GEMINI\.md$|^\.gemini\//],["Cursor",/^\.cursorrules$|^\.cursor\/rules\//],["Windsurf",/^\.windsurfrules$|^\.windsurf\/rules\//],["Cline",/^\.clinerules(\/|$)/],["Roo Code",/^\.roorules$|^\.roo\/rules/],["Kiro",/^\.kiro\/steering\//],["Junie",/^\.junie\/guidelines\.md$/],["Aider",/^\.aider\.conf\.ya?ml$/],["Continue",/^\.continue\/rules\//],["Amazon Q",/^\.amazonq\/rules\//],["Augment",/^\.augment-guidelines$|^\.augment\/rules\//],["Warp",/(^|\/)WARP\.md$/],["MCP servers",/^\.mcp\.json$/]],gt=e=>cn.some(([,n])=>n.test(e)),ln=e=>rn("sha256").update(e.toLowerCase().replace(/^\d+\+/,"")).digest("hex"),pn=new Map(Object.entries(ft).flatMap(([e,n])=>n.tools.map(s=>[s,e])));function mn(e){let[n="",s=""]=e.split(/^---$/m),o;try{o=JSON.parse(s)}catch{return}if(!String(o?.schema_version).startsWith("authorship/3."))return;let c={...o.prompts,...o.sessions},r={},p="";for(let l of n.split(`
8
+ `)){let[,a="",h=""]=/^ (\S+) ([\d,-]+)$/.exec(l)??[];if(!a){l&&l[0]!==" "&&(p=l.replace(/^"(.*)"$/,"$1"));continue}let m=c[a.split("::")[0]]?.agent_id?.tool;if(typeof m!="string")continue;let u=pn.get(m)??m,b=r[p]??={};for(let g of h.split(",")){let[f=0,v=f]=g.split("-").map(Number);b[u]=(b[u]??0)+v-f+1}}return r}function un(e){return/^(?:Merge pull request #\d+ from [^\s/]+\/(\S+)|Merged in (\S+) \(pull request|Merge branch '([^']+)'|Merge remote-tracking branch '[^/']+\/([^']+)')/.exec(e)?.slice(1).find(Boolean)}function Gt(e){let n=/^Merge pull request #(\d+) from |\(#(\d+)\)$/.exec(e);return n?Number(n.slice(1).find(Boolean)):void 0}var ht=(e,n)=>(/^Merge pull request #\d+ from /.test(e)?n.split(`
9
+ `)[0]:e).replace(/ \(#\d+\)$/,"").trim(),Bt=(e,n)=>ht(e,n).replace(/^(\[[^\]]*\]\s*)*/,""),Wt=(e,n)=>/^((bug|hot)?fix(es|ed|ing)?|bugs?|revert(s|ed)?)\b/i.test(Bt(e,n)),qt=(e,n)=>/^revert\b/i.test(Bt(e,n))?/This reverts commit ([0-9a-f]{40,64})/.exec(n)?.[1]:void 0;async function Ut(e,n,s={}){if(!n.length)return;let o=[...Object.entries(ft),...Object.entries(s)],c=new Map(o.flatMap(([a,h])=>h.emails.map(m=>[m.toLowerCase(),a])));await P(e,"rev-parse","-q","--verify","refs/notes/ai").catch(()=>"")||await P(e,"fetch","-q","origin","refs/notes/ai:refs/notes/ai").catch(()=>{});let r=(await P(e,"log","-1","--format=%P",n.at(-1).commit)).trim().split(" ")[0],p=new Map;for(let a of(await P(e,"log","--notes=ai","--format=%x01%H %P%x02%at%x02%ae%x02%ce%x02%N%x02%B","HEAD",...r?[`^${r}`]:[])).split("").slice(1)){let[h="",m="",u="",b="",g="",f=""]=a.split(""),[v="",...S]=h.trim().split(" "),i=g.trim()?mn(g):void 0;g.trim()&&!i&&console.warn(`The Git AI note on ${v} isn't authorship/3.x, so it's left out`);let d=[];for(let w of[u,b]){let C=dt(c,w);C&&d.push({source:"bot",agent:C})}let y=[...f.matchAll(/^co-authored-by:.*<([^>]+)>/gim)].map(([,w=""])=>w);for(let w of y){let C=dt(c,w);C&&!an(w,Number(m))&&d.push({source:"trailer",agent:C})}let $=[u,...y].filter(w=>w&&!dt(c,w)&&!w.includes("[bot]")).map(ln),F=un(f);for(let[w,C]of o)F&&C.branches.some(L=>F.startsWith(L))&&d.push({source:"branch",agent:w});p.set(v,{parents:S,signals:d,people:$,lines:i})}let l=new Set(n.map(a=>a.commit));for(let a of n.toReversed()){let{parents:h,signals:m,people:u}=p.get(a.commit),b=[...m],g=new Set(u),f=[],v=!0,S=d=>{d.lines?f.push(d.lines):d.parents.length<2&&(v=!1)};S(p.get(a.commit));let i=0;for(let d=h.slice(1),y;y=d.pop();)l.has(y)||!p.has(y)||(l.add(y),i++,b.push(...p.get(y).signals),p.get(y).people.forEach($=>g.add($)),S(p.get(y)),d.push(...p.get(y).parents));a.lineLevel=v&&f.length>0;for(let d of a.files){let y={};for(let w of f)for(let[C,L]of Object.entries(w[d.path]??{}))y[C]=(y[C]??0)+L;let $=Math.min(1,d.added/Object.values(y).reduce((w,C)=>w+C,0)),F=Object.entries(y).map(([w,C])=>[w,Math.floor(C*$)]).filter(([,w])=>w>0);F.length&&(d.ai=Object.fromEntries(F)),b.push(...F.map(([w])=>({source:"git-ai",agent:w})))}a.ai=b.filter((d,y)=>b.findIndex($=>$.source===d.source&&$.agent===d.agent)===y),a.authors=[...g].sort(),a.pr&&h.length>1&&(a.pr.commits=i)}}import{posix as fn}from"node:path";var Kt=[[/^net(\d{2,3})$/,"NETFRAMEWORK","NET",["20","35","40","45","451","452","46","461","462","47","471","472","48","481"]],[/^netstandard(\d\.\d)$/,"NETSTANDARD","NETSTANDARD",["1.0","1.1","1.2","1.3","1.4","1.5","1.6","2.0","2.1"]],[/^netcoreapp(\d\.\d)$/,"NETCOREAPP","NETCOREAPP",["1.0","1.1","2.0","2.1","2.2","3.0","3.1"]]],Jt=(e,n)=>n.map(s=>`${e}${s.replace(".","_")}_OR_GREATER`);function dn(e){let n=e.trim().toLowerCase(),s=/^net(\d+)\.(\d+)(?:-([a-z]+))?/.exec(n);if(s&&Number(s[1])>=5){let o=Number(s[1]);return{rank:1e3+o,symbols:["NET",`NET${o}_${s[2]}`,"NETCOREAPP",...Array.from({length:o-4},(c,r)=>`NET${r+5}_0_OR_GREATER`),...Jt("NETCOREAPP",Kt[2][3]),...s[3]?[s[3].toUpperCase()]:[]]}}for(let[o,[c,r,p,l]]of Kt.entries()){let a=l.indexOf(c.exec(n)?.[1]??"");if(a>=0)return{rank:o*100+a,symbols:[r,p+l[a].replace(".","_"),...Jt(p,l.slice(0,a+1))]}}}function gn(e){e=e.replace(/<!--[\s\S]*?-->/g,"");let n=o=>/\bCondition\s*=\s*"([^"]*)"/.exec(o)?.[1],s=[];for(let[,o,c]of e.matchAll(/<PropertyGroup\b([^>]*?)(?<!\/)>([\s\S]*?)<\/PropertyGroup>/g))for(let[,r,p,l]of c.matchAll(/<(\w+)\b([^>]*?)>([^<]*)<\/\1>/g))s.push({name:r.toLowerCase(),value:l.trim(),conditions:[n(o),n(p)].filter(a=>a!==void 0)});return{assignments:s,imports:[...e.matchAll(/<Import\b[^>]*?\bProject\s*=\s*"([^"]*)"/g)].map(o=>o[1])}}var yt=new Map,bt=(e,n,s,o=0)=>e.replace(/\$\((\w+)\)/g,(c,r)=>n.get(r.toLowerCase())??(o<8?bt(s.get(r.toLowerCase())??"",n,s,o+1):"")),hn=e=>e.split(/\s+or\s+/i).some(n=>n.split(/\s+and\s+/i).every(s=>{let o=/^[\s(]*'([^']*)'\s*(==|!=)\s*'([^']*)'[\s)]*$/.exec(s);return!!o&&o[1].trim().toLowerCase()===o[3].trim().toLowerCase()==(o[2]==="==")}));function Vt(e,n,s){let o=new Map(n);for(let{assignments:c}of e)for(let r of c)!n.has(r.name)&&r.conditions.every(p=>hn(bt(p,o,s)))&&o.set(r.name,bt(r.value,o,s));return o}var I=e=>e.slice(0,Math.max(e.lastIndexOf("/"),0)),Qt=(e,n)=>e?`${e}/${n}`:n;function*Yt(e){for(;;){if(yield e,!e)return;e=I(e)}}var Xt=new Map([["configuration","Release"],["platform","AnyCPU"]]);async function Zt(e,n){let s=new Map;await Promise.all([...e].filter(([a])=>/\.(csproj|props|targets)$/.test(a)).map(async([a,h])=>{yt.has(h)||yt.set(h,gn(await n(h))),s.set(a,yt.get(h))}));let o=new Map,c=new Map;for(let a of e.keys())if(a.endsWith(".csproj")&&!c.has(I(a))&&c.set(I(a),a),!!a.endsWith(".props"))for(let h of s.get(a).assignments)!h.conditions.length&&!o.has(h.name)&&o.set(h.name,h.value);let r=(a,h)=>[...Yt(a)].map(m=>Qt(m,h)).find(m=>s.has(m)),p=(a,h)=>{if(!a||h.has(a)||!s.has(a))return[];h.add(a);let m=I(a);return[...s.get(a).imports.flatMap(u=>{let b=/Directory\.Build\.(props|targets)/i.exec(u);if(b&&u.includes("$("))return m?p(r(I(m),b[0]),h):[];let g=u.replace(/\$\(MSBuildThisFileDirectory\)/gi,"").replaceAll("\\","/");return g.includes("$(")?[]:p(fn.normalize(Qt(m,g)),h)}),s.get(a)]},l=new Map;return a=>{let h=[...Yt(I(a))].map(d=>c.get(d)).find(d=>d),m=I(h||a);if(l.has(m))return l.get(m);let u=new Set,b=[...p(r(m,"Directory.Build.props"),u),...p(h,u),...p(r(m,"Directory.Build.targets"),u)],g=Vt(b,Xt,o),[f]=(g.get("targetframeworks")||g.get("targetframework")||"").split(";").map(d=>({t:d.trim(),f:dn(d)})).filter(d=>d.f).sort((d,y)=>y.f.rank-d.f.rank),S=((f?Vt(b,new Map([...Xt,["targetframework",f.t]]),o):g).get("defineconstants")??"").split(/[;,]/).map(d=>d.trim()).filter(d=>/^\w+$/.test(d)),i=[...new Set(["RELEASE","TRACE",...f?.f.symbols??[],...S])].sort();return l.set(m,i),i}}var Cn={d:86400,w:7*86400,m:365/12*86400,y:365*86400};function W(e){let n=/^(\d+)([dwmy])$/.exec(e);if(!n)throw new Error(`Expected a duration like 90d, 1w, 12m or 1y, got "${e}"`);return Number(n[1])*Cn[n[2]]}async function En(e,n,s){let o=(await P(e,"log","--first-parent","--format=%H %ct","HEAD")).trim().split(`
10
+ `).map(p=>({commit:p.slice(0,p.indexOf(" ")),time:Number(p.slice(p.indexOf(" ")+1))})),c=o[0].time,r=new Map;for(let p=c;p>=c-n;p-=s){let l=o.find(a=>a.time<=p);l&&r.set(l.commit,l)}return[...r.values()]}var On=/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|packages\.lock\.json)$/;async function jn(e,n,s,o=tt.parse({}),c=0,r=!1){let p=/^0{40}$|^0{64}$/.test(s??""),l;s&&!p&&(l=(await P(e,"rev-parse","--verify",`${s}^{commit}`).catch(()=>"")).trim(),(await P(e,"log","--first-parent","--format=%H","HEAD")).trim().split(`
11
+ `).includes(l)||(console.warn(`--since-commit ${s} isn't on HEAD's first-parent history (a force push?), so churn covers the time window`),l=void 0));let a=[],h=[],m=(await P(e,"log","--first-parent","--diff-merges=first-parent","--numstat","-z",...l?[`^${l}`]:p?[]:[`--since=${n}`],"--format=%x01%H %ct %B","HEAD")).split("\0");for(let g=0;g<m.length;g++){let f=/^\x01(\w+) (\d+) ([^\n]*?)\s*(?:\n|$)(.*)$/s.exec(m[g]);if(f){let y=Gt(f[3]);a.push({commit:f[1],committedAt:new Date(Number(f[2])*1e3).toISOString(),files:[],ai:[],lineLevel:!1,authors:[],agentFiles:!1,fix:Wt(f[3],f[4]),reverts:qt(f[3],f[4]),...r&&{title:ht(f[3],f[4])}}),y&&(a.at(-1).pr={number:y,files:0,added:0,deleted:0});continue}let[,v,S,i]=/^\n?(\d+|-)\t(\d+|-)\t(.*)$/s.exec(m[g])??[];if(!v||!S)continue;let d=i||m[g+=2];gt(d)&&(a.at(-1).agentFiles=!0),!(v==="-"||Number(v)+Number(S)===0)&&h.push({c:a.at(-1),path:d,added:Number(v),deleted:Number(S)})}let u=h.length?await mt(e,"HEAD",[...new Set(h.map(g=>g.path))]):new Map;for(let{c:g,path:f,added:v,deleted:S}of h){let i=et(o,f,"",u.get(f));(i==="code"||i==="test")&&g.files.push({path:f,added:v,deleted:S}),g.pr&&i!=="generated"&&i!=="vendored"&&i!=="excluded"&&!On.test(f)&&(g.pr.files++,g.pr.added+=v,g.pr.deleted+=S)}let b=a.filter(g=>g.fix&&Date.parse(g.committedAt)/1e3>=c);return await Promise.all(Array.from({length:Sn()},async()=>{for(let g;g=b.pop();)g.fixed=await Pn(e,g,new Set(g.files.filter(f=>et(o,f.path,"",u.get(f.path))==="code").map(f=>f.path)))})),a}async function Pn(e,n,s){let o=new Map,c="",r="",p=!1;if(s.size){for(let m of(await P(e,"-c","core.quotePath=false","diff-tree","-p","-U0","-M","--no-prefix","--diff-merges=first-parent","--root",n.commit)).split(`
12
+ `))if(m.startsWith("diff --git "))[p,c,r]=[!0,"",""];else if(p&&m.startsWith("--- "))c=m.slice(4).replace(/\t$/,"");else if(p&&m.startsWith("+++ "))r=m.slice(4).replace(/\t$/,"");else if(m.startsWith("@@ ")){p=!1;let[,u,b="1"]=/^@@ -(\d+)(?:,(\d+))? /.exec(m)??[];c!=="/dev/null"&&s.has(r==="/dev/null"?c:r)&&b!=="0"&&(o.get(c)??o.set(c,[]).get(c)).push(`${u},+${b}`)}}let l=Date.parse(n.committedAt)/1e3-30*86400,a=new Set,h=new Set;for(let[m,u]of o)for(let b=0;b<u.length;b+=1e3){let g="";for(let f of(await P(e,"blame","--first-parent","--porcelain",`--since=${l}`,...u.slice(b,b+1e3).flatMap(v=>["-L",v]),`${n.commit}^`,"--",m)).split(`
13
+ `)){let v=/^([0-9a-f]{40,64}) \d+ \d+/.exec(f);v?a.add(g=v[1]):f==="boundary"&&h.add(g)}}return[...a].filter(m=>!h.has(m))}var Fn=e=>e.split(`
14
14
  `).length-(e.endsWith(`
15
- `)?1:0);function vt(e,n){let s=bn(e,"w");try{let o=(r,p)=>JSON.stringify(r,null,2).replaceAll(`
15
+ `)?1:0);function vt(e,n){let s=vn(e,"w");try{let o=(r,p)=>JSON.stringify(r,null,2).replaceAll(`
16
16
  `,`
17
- `+" ".repeat(p)),l=Object.keys(n).filter(r=>n[r]!==void 0);B(s,`{
18
- `),l.forEach((r,p)=>{let c=n[r],a=p<l.length-1?`,
17
+ `+" ".repeat(p)),c=Object.keys(n).filter(r=>n[r]!==void 0);B(s,`{
18
+ `),c.forEach((r,p)=>{let l=n[r],a=p<c.length-1?`,
19
19
  `:`
20
- `,h=typeof c!="object"||c===null?[]:Array.isArray(c)?c.map(m=>["",m]):Object.entries(c).map(([m,u])=>[`${JSON.stringify(m)}: `,u]);if(!h.length)return B(s,` ${JSON.stringify(r)}: ${o(c,1)}${a}`);B(s,` ${JSON.stringify(r)}: ${Array.isArray(c)?"[":"{"}
20
+ `,h=typeof l!="object"||l===null?[]:Array.isArray(l)?l.map(m=>["",m]):Object.entries(l).map(([m,u])=>[`${JSON.stringify(m)}: `,u]);if(!h.length)return B(s,` ${JSON.stringify(r)}: ${o(l,1)}${a}`);B(s,` ${JSON.stringify(r)}: ${Array.isArray(l)?"[":"{"}
21
21
  `),h.forEach(([m,u],b)=>B(s,` ${m}${o(u,2)}${b<h.length-1?",":""}
22
- `)),B(s,` ${Array.isArray(c)?"]":"}"}${a}`)}),B(s,`}
23
- `)}finally{yn(s)}}async function te(e,n,s,o,l,r=tt.parse({}),p=!1){if(l==="")throw new Error("--since-commit requires a commit SHA");if((await P(e,"rev-parse","--is-shallow-repository")).trim()==="true")throw new Error("This is a shallow clone, so its history is missing. Fetch all of it: in GitHub Actions, set `fetch-depth: 0` on actions/checkout");let c=new Map,a=new Map,h=Lt(e),m=async u=>(await h.read(u)).toString("utf8");try{let u=await xn(e,l?0:n,s),b=-1;for(let{commit:v,time:S}of u){let i=new Map,d=[];for(let x of(await P(e,"ls-tree","-r","-z","--full-tree",v)).split("\0")){let[,O,E,k]=/^(\d+) blob (\w+)\t(.*)$/s.exec(x)??[];k&&gt(k)&&d.push(k),E&&k&&O!=="120000"&&i.set(k,E)}let y=[...i].filter(([x])=>/(^|\/)\.gitattributes$/.test(x)),$=(await Promise.all(y.map(([,x])=>m(x)))).some(x=>x.includes("linguist-"))?await mt(e,v,[...i.keys()]):new Map,F=await Zt(i,m),w=[],C=new Map,L=[],T={generated:0,vendored:0,excluded:0};for(let[x,O]of i){let E=et(r,x,"",$.get(x));if((E==="generated"||E==="vendored"||E==="excluded")&&T[E]++,E==="markup"&&(a.has(O)||a.set(O,m(O).then(En)),L.push({ext:wt(x),lines:a.get(O)})),E!=="code"&&E!=="test")continue;let k=wt(x)===".cs"?F(x):void 0,H=O+wt(x)+(k?":"+hn("sha256").update(k.join(";")).digest("hex").slice(0,8):"");!c.has(H)&&!C.has(H)&&C.set(H,m(O).then(U=>Z(x,U,$.get(x))==="generated"?void 0:Mt(x,U,{csharpSymbols:k}))),w.push({path:x,blob:H,test:E==="test",sha:O})}let q={};for(let[x,O]of C){let E=await O;E&&(q[x]=E),c.set(x,!!E)}let z=[],Y=[];for(let{sha:x,...O}of w){if(!c.get(O.blob)){T.generated++;continue}z.push(O),Y.push({path:O.path,sha:x})}let j={};for(let{ext:x,lines:O}of L){let E=j[x]??={files:0,lines:0};E.files++,E.lines+=await O}let A=Math.floor((u[0].time-S)/W("1m")),R=A===b?void 0:await Rt(await Promise.all(Y.map(async x=>({path:x.path,source:await m(x.sha)}))));b=A,await o({schemaVersion:_,commit:v,committedAt:new Date(S*1e3).toISOString(),files:z,skipped:T,markup:j,agentFiles:d,clones:R,blobs:q})}let g=u.at(-1).time,f=await $n(e,g-W("90d"),l,r,l?0:g-W("31d"),p);return await Ut(e,f,r.ai),f}finally{Tt(),await h.close()}}import{readFileSync as On}from"node:fs";import{gzipSync as jn}from"node:zlib";var ee=(e=process.env)=>e.CODEROT_API??"https://api.coderot.ai";async function Pn(e=process.env){if(e.CODEROT_TOKEN)return e.CODEROT_TOKEN;if(!e.ACTIONS_ID_TOKEN_REQUEST_URL)throw new Error("No credentials for coderot: in GitHub Actions, add `id-token: write` to the workflow's permissions; in other CIs, set CODEROT_TOKEN to the repo's upload token");let n=await fetch(`${e.ACTIONS_ID_TOKEN_REQUEST_URL}&audience=coderot`,{headers:{authorization:`bearer ${e.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}});if(!n.ok)throw new Error(`GitHub's OIDC token: HTTP ${n.status} ${await n.text()}`);return(await n.json()).value}async function ne(e,n={},s=5e3){for(let o=1;;o++){let l=await Pn().then(r=>fetch(e,{...n,headers:{...n.headers,authorization:`Bearer ${r}`}})).catch(r=>r);if(o===3||l instanceof Response&&l.status<500){if(l instanceof Error)throw l;if(!l.ok)throw new Error(`${e}: HTTP ${l.status} ${await l.text()}`);return l}await new Promise(r=>setTimeout(r,s*o))}}async function oe(e=ee(),n){return(await(await ne(`${e}/v1/reports/head`,{},n)).json()).commit}async function se(e,n=ee(),s){for(let o of e){let l=jn(On(o)),r={"content-encoding":"gzip","content-type":"application/json"};await ne(`${n}/v1/reports`,{method:"POST",body:l,headers:r},s),console.log(`sent ${o} (${Math.round(l.length/1024)} kB)`)}}var{positionals:re,values:M}=Tn({allowPositionals:!0,options:{since:{type:"string"},interval:{type:"string"},"since-commit":{type:"string"},out:{type:"string",default:"report"},titles:{type:"boolean",default:!1}}}),ot=re[0]==="ci";if(re[0]!=="analyze"&&!ot)throw new Error(`Usage: coderot analyze [--since 12m] [--interval 1w] [--since-commit <sha>] [--out report] [--titles]
24
- coderot ci [--since 12m] [--interval 1w] [--out report] [--titles]`);var nt=ot?await oe()??void 0:M["since-commit"];ot&&console.log(nt?`coderot has commits up to ${nt}: analyzing the ones after it`:"First run: backfilling");var xt=await It(process.cwd());Mn(D(M.out,"snapshots"),{recursive:!0,force:!0});An(D(M.out,"snapshots"),{recursive:!0});var St=[],ae=0,ce=0,le=0,Q=await te(process.cwd(),W(M.since??xt.since??"12m"),W(M.interval??xt.interval??"1w"),e=>{St.push(D(M.out,"snapshots",`${e.committedAt.slice(0,10)}-${e.commit.slice(0,7)}.json`)),vt(St.at(-1),e),ae++||(ce=e.files.length),le+=Object.keys(e.blobs).length},nt,xt,M.titles),ie=Et.safeParse(JSON.parse(Fn(D(M.out,"commits.json"))?kn(D(M.out,"commits.json"),"utf8"):"{}"));ie.success&&zt(Q,ie.data.commits);process.env.GITHUB_TOKEN&&process.env.GITHUB_REPOSITORY&&await Ht(Q,process.env.GITHUB_REPOSITORY,process.env.GITHUB_TOKEN);vt(D(M.out,"commits.json"),{schemaVersion:_,commits:Q});console.log(`${ae} snapshots, ${ce} files at HEAD, ${le} file versions analyzed, ${Q.filter(e=>e.ai.length).length} of ${Q.length} commits with AI signals${nt?" (incremental)":""} \u2192 ${M.out}`);ot&&await se([...St,D(M.out,"commits.json")]);
22
+ `)),B(s,` ${Array.isArray(l)?"]":"}"}${a}`)}),B(s,`}
23
+ `)}finally{bn(s)}}function te(e){let n=(s,o)=>!wn(s)||xn(s).every(c=>c.startsWith(".")||o.test(c));return n(e,/^(snapshots|commits\.json)$/)&&n($n(e,"snapshots"),/^\d{4}-\d\d-\d\d-[0-9a-f]{7}\.json$/)}async function ee(e,n,s,o,c,r=tt.parse({}),p=!1){if(c==="")throw new Error("--since-commit requires a commit SHA");if((await P(e,"rev-parse","--is-shallow-repository")).trim()==="true")throw new Error("This is a shallow clone, so its history is missing. Fetch all of it: in GitHub Actions, set `fetch-depth: 0` on actions/checkout");let l=new Map,a=new Map,h=Lt(e),m=async u=>(await h.read(u)).toString("utf8");try{let u=await En(e,c?0:n,s),b=-1;for(let{commit:v,time:S}of u){let i=new Map,d=[];for(let x of(await P(e,"ls-tree","-r","-z","--full-tree",v)).split("\0")){let[,O,E,M]=/^(\d+) blob (\w+)\t(.*)$/s.exec(x)??[];M&&gt(M)&&d.push(M),E&&M&&O!=="120000"&&i.set(M,E)}let y=[...i].filter(([x])=>/(^|\/)\.gitattributes$/.test(x)),$=(await Promise.all(y.map(([,x])=>m(x)))).some(x=>x.includes("linguist-"))?await mt(e,v,[...i.keys()]):new Map,F=await Zt(i,m),w=[],C=new Map,L=[],R={generated:0,vendored:0,excluded:0};for(let[x,O]of i){let E=et(r,x,"",$.get(x));if((E==="generated"||E==="vendored"||E==="excluded")&&R[E]++,E==="markup"&&(a.has(O)||a.set(O,m(O).then(Fn)),L.push({ext:wt(x),lines:a.get(O)})),E!=="code"&&E!=="test")continue;let M=wt(x)===".cs"?F(x):void 0,H=O+wt(x)+(M?":"+yn("sha256").update(M.join(";")).digest("hex").slice(0,8):"");!l.has(H)&&!C.has(H)&&C.set(H,m(O).then(U=>Z(x,U,$.get(x))==="generated"?void 0:Mt(x,U,{csharpSymbols:M}))),w.push({path:x,blob:H,test:E==="test",sha:O})}let q={};for(let[x,O]of C){let E=await O;E&&(q[x]=E),l.set(x,!!E)}let z=[],Y=[];for(let{sha:x,...O}of w){if(!l.get(O.blob)){R.generated++;continue}z.push(O),Y.push({path:O.path,sha:x})}let j={};for(let{ext:x,lines:O}of L){let E=j[x]??={files:0,lines:0};E.files++,E.lines+=await O}let k=Math.floor((u[0].time-S)/W("1m")),T=k===b?void 0:await Tt(await Promise.all(Y.map(async x=>({path:x.path,source:await m(x.sha)}))));b=k,await o({schemaVersion:_,commit:v,committedAt:new Date(S*1e3).toISOString(),files:z,skipped:R,markup:j,agentFiles:d,clones:T,blobs:q})}let g=u.at(-1).time,f=await jn(e,g-W("90d"),c,r,c?0:g-W("31d"),p);return await Ut(e,f,r.ai),f}finally{Rt(),await h.close()}}import{readFileSync as An}from"node:fs";import{gzipSync as kn}from"node:zlib";var ne=(e=process.env)=>e.CODEROT_API??"https://api.coderot.ai";async function Mn(e=process.env){if(e.CODEROT_TOKEN)return e.CODEROT_TOKEN;if(!e.ACTIONS_ID_TOKEN_REQUEST_URL)throw new Error("No credentials for coderot: in GitHub Actions, add `id-token: write` to the workflow's permissions; in other CIs, set CODEROT_TOKEN to the repo's upload token");let n=await fetch(`${e.ACTIONS_ID_TOKEN_REQUEST_URL}&audience=coderot`,{headers:{authorization:`bearer ${e.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}});if(!n.ok)throw new Error(`GitHub's OIDC token: HTTP ${n.status} ${await n.text()}`);return(await n.json()).value}async function oe(e,n={},s=5e3){for(let o=1;;o++){let c=await Mn().then(r=>fetch(e,{...n,headers:{...n.headers,authorization:`Bearer ${r}`}})).catch(r=>r);if(o===3||c instanceof Response&&c.status<500){if(c instanceof Error)throw c;if(!c.ok)throw new Error(`${e}: HTTP ${c.status} ${await c.text()}`);return c}await new Promise(r=>setTimeout(r,s*o))}}async function se(e=ne(),n){return(await(await oe(`${e}/v1/reports/head`,{},n)).json()).commit}async function ie(e,n=ne(),s){for(let o of e){let c=kn(An(o)),r={"content-encoding":"gzip","content-type":"application/json"};await oe(`${n}/v1/reports`,{method:"POST",body:c,headers:r},s),console.log(`sent ${o} (${Math.round(c.length/1024)} kB)`)}}var{positionals:ae,values:A}=In({allowPositionals:!0,options:{since:{type:"string"},interval:{type:"string"},"since-commit":{type:"string"},out:{type:"string",default:"report"},titles:{type:"boolean",default:!1}}}),ot=ae[0]==="ci";if(ae[0]!=="analyze"&&!ot)throw new Error(`Usage: coderot analyze [--since 12m] [--interval 1w] [--since-commit <sha>] [--out report] [--titles]
24
+ coderot ci [--since 12m] [--interval 1w] [--out report] [--titles]`);var nt=ot?await se()??void 0:A["since-commit"];ot&&console.log(nt?`coderot has commits up to ${nt}: analyzing the ones after it`:"First run: backfilling");var xt=await It(process.cwd());if(!te(A.out))throw new Error(`${A.out} holds files coderot didn't write: pick another folder with --out`);Ln(D(A.out,"snapshots"),{recursive:!0,force:!0});Tn(D(A.out,"snapshots"),{recursive:!0});var St=[],ce=0,le=0,pe=0,Q=await ee(process.cwd(),W(A.since??xt.since??"12m"),W(A.interval??xt.interval??"1w"),e=>{St.push(D(A.out,"snapshots",`${e.committedAt.slice(0,10)}-${e.commit.slice(0,7)}.json`)),vt(St.at(-1),e),ce++||(le=e.files.length),pe+=Object.keys(e.blobs).length},nt,xt,A.titles),re=Et.safeParse(JSON.parse(Rn(D(A.out,"commits.json"))?Nn(D(A.out,"commits.json"),"utf8"):"{}"));re.success&&zt(Q,re.data.commits);process.env.GITHUB_TOKEN&&process.env.GITHUB_REPOSITORY&&await Ht(Q,process.env.GITHUB_REPOSITORY,process.env.GITHUB_TOKEN);vt(D(A.out,"commits.json"),{schemaVersion:_,commits:Q});console.log(`${ce} snapshots, ${le} files at HEAD, ${pe} file versions analyzed, ${Q.filter(e=>e.ai.length).length} of ${Q.length} commits with AI signals${nt?" (incremental)":""} \u2192 ${A.out}`);ot&&await ie([...St,D(A.out,"commits.json")]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderot-ai/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Code health and AI attribution from a repo's git history, for coderot.ai",
5
5
  "license": "Elastic-2.0",
6
6
  "homepage": "https://coderot.ai",