@@ -5,7 +5,10 @@ type ReviewResult = {
55 output : string
66}
77
8- const REVIEW_PROVIDERS = ( process . env . REVIEW_PROVIDERS || "" ) . split ( "," ) . map ( ( p ) => p . trim ( ) ) . filter ( Boolean )
8+ const REVIEW_PROVIDERS = ( process . env . REVIEW_PROVIDERS || "" )
9+ . split ( "," )
10+ . map ( ( p ) => p . trim ( ) )
11+ . filter ( Boolean )
912const PR_NUMBER = process . env . PR_NUMBER || ""
1013const PR_TITLE = process . env . PR_TITLE || ""
1114const PR_BODY = process . env . PR_BODY || ""
@@ -25,7 +28,7 @@ async function buildPrompt(): Promise<string> {
2528 } catch ( e ) {
2629 console . log ( "Warning: Could not read AGENTS.md" )
2730 }
28-
31+
2932 return `REPO: ${ REPO }
3033PR NUMBER: ${ PR_NUMBER }
3134PR TITLE: ${ PR_TITLE }
@@ -71,7 +74,7 @@ IMPORTANT: Only create comments for actual issues. If the code follows all guide
7174
7275async function runReview ( provider : string , prompt : string ) : Promise < ReviewResult > {
7376 console . log ( `Starting review with provider: ${ provider } ` )
74-
77+
7578 try {
7679 const result = execSync ( `opencode run -m ${ provider } -- "${ prompt . replace ( / " / g, '\\"' ) } "` , {
7780 encoding : "utf8" ,
@@ -86,7 +89,7 @@ async function runReview(provider: string, prompt: string): Promise<ReviewResult
8689
8790async function synthesize ( reviews : ReviewResult [ ] ) : Promise < string > {
8891 const combined = reviews . map ( ( r ) => `## Review from ${ r . provider } \n\n${ r . output } ` ) . join ( "\n\n---\n\n" )
89- const providerList = reviews . map ( r => r . provider ) . join ( ", " )
92+ const providerList = reviews . map ( ( r ) => r . provider ) . join ( ", " )
9093 const synthesisPrompt = `You are an expert code reviewer. Synthesize these reviews into one comprehensive review following Claude Code's professional format.
9194
9295Rules:
@@ -149,7 +152,7 @@ Status: ⚠️ [Approve with Recommendations / Changes Requested / Approved]
149152**Positive Aspects** ✨
150153✅ [Positive aspect 1]
151154✅ [Positive aspect 2]
152- ✅ [Positive aspect 3]
155+ ✅ [Positive aspect 3]`
153156
154157 try {
155158 return execSync ( `opencode run -m opencode/big-pickle -- "${ synthesisPrompt . replace ( / " / g, '\\"' ) } "` , {
@@ -161,7 +164,6 @@ Status: ⚠️ [Approve with Recommendations / Changes Requested / Approved]
161164 return combined
162165 }
163166}
164- }
165167
166168let checklistCommentId : string | null = null
167169
@@ -171,28 +173,34 @@ async function postOrUpdateChecklist(status: string, completedTasks: string[] =
171173 "Read modified files" ,
172174 "Analyze security implications" ,
173175 "Review code quality and conventions" ,
174- "Provide comprehensive feedback"
176+ "Provide comprehensive feedback" ,
175177 ]
176178
177- const checklist = tasks . map ( task => {
178- const isCompleted = completedTasks . includes ( task )
179- return `${ isCompleted ? '✅' : '⏳' } ${ task } `
180- } ) . join ( '\n' )
179+ const checklist = tasks
180+ . map ( ( task ) => {
181+ const isCompleted = completedTasks . includes ( task )
182+ return `${ isCompleted ? "✅" : "⏳" } ${ task } `
183+ } )
184+ . join ( "\n" )
181185
182186 const body = `🤖 **Multi-Provider Code Review** ${ status } \n\n**Tasks:**\n${ checklist } `
183187
184- const escaped = body . replace ( / " / g, '\\"' ) . replace ( / \n / g, ' \\n' )
188+ const escaped = body . replace ( / " / g, '\\"' ) . replace ( / \n / g, " \\n" )
185189
186190 if ( checklistCommentId ) {
187- // Update existing comment
188- execSync ( `gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/${ REPO } /issues/comments/${ checklistCommentId } -f "body=${ escaped } "` , {
189- encoding : "utf8" ,
190- } )
191+ execSync (
192+ `gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/${ REPO } /issues/comments/${ checklistCommentId } -f "body=${ escaped } "` ,
193+ {
194+ encoding : "utf8" ,
195+ } ,
196+ )
191197 } else {
192- // Create new comment with specific author name
193- const result = execSync ( `gh api --method POST -H "Accept: application/vnd.github+json" -H "Authorization: token ${ { secrets. GITHUB_TOKEN } }" /repos/${ REPO } /issues/${ PR_NUMBER } /comments -f "body=${ escaped } "` , {
194- encoding : "utf8" ,
195- } )
198+ const result = execSync (
199+ `gh api --method POST -H "Accept: application/vnd.github+json" /repos/${ REPO } /issues/${ PR_NUMBER } /comments -f "body=${ escaped } "` ,
200+ {
201+ encoding : "utf8" ,
202+ } ,
203+ )
196204 const comment = JSON . parse ( result . toString ( ) )
197205 checklistCommentId = comment . id
198206 }
@@ -203,7 +211,7 @@ async function postFinalReview(synthesis: string, providerList: string, confiden
203211
204212**Tasks:**
205213✅ Read repository conventions
206- ✅ Read modified files
214+ ✅ Read modified files
207215✅ Analyze security implications
208216✅ Review code quality and conventions
209217✅ Provide comprehensive feedback
@@ -213,33 +221,32 @@ ${synthesis}
213221*Review generated by: ${ providerList } *
214222*Provider confidence scores: ${ confidenceString } *`
215223
216- const escaped = finalBody . replace ( / " / g, '\\"' ) . replace ( / \n / g, '\\n' )
217- execSync ( `gh api --method POST -H "Accept: application/vnd.github+json" /repos/${ REPO } /issues/${ PR_NUMBER } /comments -f "body=${ escaped } "` , {
218- encoding : "utf8" ,
219- } )
224+ const escaped = finalBody . replace ( / " / g, '\\"' ) . replace ( / \n / g, "\\n" )
225+ execSync (
226+ `gh api --method POST -H "Accept: application/vnd.github+json" /repos/${ REPO } /issues/${ PR_NUMBER } /comments -f "body=${ escaped } "` ,
227+ {
228+ encoding : "utf8" ,
229+ } ,
230+ )
220231}
221232
222233async function calculateConfidenceScores ( reviews : ReviewResult [ ] ) : Promise < Record < string , number > > {
223234 const scores : Record < string , number > = { }
224235
225- // Simple confidence scoring based on review length and content quality
226236 for ( const review of reviews ) {
227- let score = 0.5 // Base score
237+ let score = 0.5
228238
229- // Length factor (longer reviews tend to be more thorough)
230239 if ( review . output . length > 2000 ) score += 0.2
231240 else if ( review . output . length > 1000 ) score += 0.1
232241
233- // Content quality indicators
234- if ( review . output . includes ( 'security' ) || review . output . includes ( 'performance' ) ) score += 0.1
235- if ( review . output . includes ( 'suggestion' ) || review . output . includes ( 'recommend' ) ) score += 0.1
236- if ( review . output . includes ( 'line' ) || review . output . includes ( 'file' ) ) score += 0.1
242+ if ( review . output . includes ( "security" ) || review . output . includes ( "performance" ) ) score += 0.1
243+ if ( review . output . includes ( "suggestion" ) || review . output . includes ( "recommend" ) ) score += 0.1
244+ if ( review . output . includes ( "line" ) || review . output . includes ( "file" ) ) score += 0.1
237245
238- // Provider-specific adjustments
239- if ( review . provider . includes ( 'big-pickle' ) ) score += 0.1 // Reasoning model
240- if ( review . provider . includes ( 'grok-code' ) ) score += 0.1 // Code-specialized
241- if ( review . provider . includes ( 'minimax' ) ) score += 0.05 // General purpose
242- if ( review . provider . includes ( 'glm-4.7' ) ) score += 0.05 // Balanced
246+ if ( review . provider . includes ( "big-pickle" ) ) score += 0.1
247+ if ( review . provider . includes ( "grok-code" ) ) score += 0.1
248+ if ( review . provider . includes ( "minimax" ) ) score += 0.05
249+ if ( review . provider . includes ( "glm-4.7" ) ) score += 0.05
243250
244251 scores [ review . provider ] = Math . min ( Math . max ( score , 0.1 ) , 1.0 )
245252 }
@@ -253,21 +260,35 @@ async function main() {
253260 const prompt = await buildPrompt ( )
254261 console . log ( `Prompt built (${ prompt . length } chars), includes AGENTS.md: ${ INCLUDE_AGENTS } ` )
255262
256- const results = await Promise . all ( REVIEW_PROVIDERS . map ( ( provider ) => runReview ( provider , prompt ) ) )
263+ await postOrUpdateChecklist ( "🔍 Reading modified files..." , [ "Read repository conventions" ] )
257264
258- // Update checklist - analysis complete
259- await postOrUpdateChecklist ( "🔒 Analyzing security implications..." , [ "Read repository conventions" , "Read modified files" , "Analyze security implications" ] )
265+ await postOrUpdateChecklist ( "🔍 Analyzing security implications..." , [
266+ "Read repository conventions" ,
267+ "Read modified files" ,
268+ "Analyze security implications" ,
269+ ] )
260270
261- // Update checklist - code review
262- await postOrUpdateChecklist ( "🔍 Reviewing code quality and conventions..." , [ "Read repository conventions" , "Read modified files" , "Analyze security implications" , "Review code quality and conventions" ] )
271+ const results = await Promise . all ( REVIEW_PROVIDERS . map ( ( provider ) => runReview ( provider , prompt ) ) )
272+
273+ await postOrUpdateChecklist ( "🔍 Reviewing code quality and conventions..." , [
274+ "Read repository conventions" ,
275+ "Read modified files" ,
276+ "Analyze security implications" ,
277+ "Review code quality and conventions" ,
278+ ] )
263279
264280 console . log ( "\nAll reviews completed. Synthesizing..." )
265281
266- // Update checklist - synthesizing
267- await postOrUpdateChecklist ( "🤔 Providing comprehensive feedback..." , [ "Read repository conventions" , "Read modified files" , "Analyze security implications" , "Review code quality and conventions" , "Provide comprehensive feedback" ] )
282+ await postOrUpdateChecklist ( "🤔 Providing comprehensive feedback..." , [
283+ "Read repository conventions" ,
284+ "Read modified files" ,
285+ "Analyze security implications" ,
286+ "Review code quality and conventions" ,
287+ "Provide comprehensive feedback" ,
288+ ] )
268289
269290 const synthesis = await synthesize ( results )
270- const providerList = results . map ( r => r . provider ) . join ( ", " )
291+ const providerList = results . map ( ( r ) => r . provider ) . join ( ", " )
271292 const confidenceScores = await calculateConfidenceScores ( results )
272293 const confidenceString = Object . entries ( confidenceScores )
273294 . map ( ( [ provider , score ] ) => `${ provider } : ${ ( score * 100 ) . toFixed ( 0 ) } %` )
@@ -276,49 +297,11 @@ async function main() {
276297 console . log ( "\n=== SYNTHESIS COMPLETE ===\n" )
277298 console . log ( synthesis )
278299
279- // Post final comprehensive review
280300 await postFinalReview ( synthesis , providerList , confidenceString )
281301 console . log ( "\n✅ Final review posted to PR!" )
282302}
283303
284304main ( ) . catch ( ( error ) => {
285305 console . error ( "Error:" , error )
286306 process . exit ( 1 )
287- } )
288- } catch ( e ) {
289- return `Error with ${ provider } `
290- }
291- }
292-
293- async function synthesize ( reviews : string [ ] ) {
294- const combined = reviews . join ( "\n\n---\n\n" )
295- const synthesis = `Synthesize these code reviews into one comprehensive review. Combine overlapping feedback, highlight unique insights, remove duplicates:\n\n${ combined } `
296- try {
297- return execSync ( `opencode run -m opencode/big-pickle -- "${ synthesis } "` , {
298- encoding : "utf8" ,
299- timeout : 180000 ,
300- } )
301- } catch ( e ) {
302- return combined
303- }
304- }
305-
306- async function main ( ) {
307- console . log ( `Running ${ providers . length } parallel reviews...` )
308- const results = await Promise . all ( providers . map ( runReview ) )
309- console . log ( "Synthesizing results..." )
310- const final = await synthesize ( results )
311- console . log ( "\n=== SYNTHESIS ===\n" + final )
312-
313- // Post as PR comment
314- const escaped = final . replace ( / " / g, '\\"' ) . replace ( / \n / g, "\\n" )
315- execSync (
316- `gh api --method POST -H "Accept: application/vnd.github+json" /repos/${ repo } /issues/${ prNumber } /comments -f "body=${ escaped } "` ,
317- { encoding : "utf8" } ,
318- )
319- }
320-
321- main ( ) . catch ( ( e ) => {
322- console . error ( e )
323- process . exit ( 1 )
324307} )
0 commit comments