@@ -44,6 +44,8 @@ function normalizeReviewerLogin(login: string): string {
4444 *
4545 * Trigger model: initial review events plus explicit re-request only.
4646 * Re-requested reviews run only when kodiai itself is the requested reviewer.
47+ * Additionally, a team-based re-request is supported for the special team slug/name "ai-review"
48+ * to enable UI-only re-review without a comment.
4749 * Clones the repo, builds a review prompt, runs Claude via the executor,
4850 * and optionally submits a silent approval if no issues were found.
4951 */
@@ -57,6 +59,8 @@ export function createReviewHandler(deps: {
5759} ) : void {
5860 const { eventRouter, jobQueue, workspaceManager, githubApp, executor, logger } = deps ;
5961
62+ const rereviewTeamSlugs = new Set ( [ "ai-review" ] ) ;
63+
6064 async function handleReview ( event : WebhookEvent ) : Promise < void > {
6165 const payload = event . payload as unknown as
6266 | PullRequestOpenedEvent
@@ -110,6 +114,10 @@ export function createReviewHandler(deps: {
110114 typeof requestedTeam ?. name === "string"
111115 ? requestedTeam . name
112116 : undefined ;
117+ const requestedTeamSlug =
118+ typeof ( requestedTeam as { slug ?: unknown } | undefined ) ?. slug === "string"
119+ ? ( requestedTeam as { slug : string } ) . slug
120+ : undefined ;
113121 const appSlug = githubApp . getAppSlug ( ) ;
114122 const normalizedAppSlug = normalizeReviewerLogin ( appSlug ) ;
115123
@@ -144,18 +152,38 @@ export function createReviewHandler(deps: {
144152 "Accepted review_requested event for kodiai reviewer" ,
145153 ) ;
146154 } else if ( requestedTeamName ) {
155+ const normalizedTeamName = requestedTeamName . trim ( ) . toLowerCase ( ) ;
156+ const normalizedTeamSlug = ( requestedTeamSlug ?? "" ) . trim ( ) . toLowerCase ( ) ;
157+ const matchedTeam = rereviewTeamSlugs . has ( normalizedTeamSlug ) || rereviewTeamSlugs . has ( normalizedTeamName ) ;
158+
159+ if ( ! matchedTeam ) {
160+ logger . info (
161+ {
162+ ...baseLog ,
163+ gate : "review_requested_reviewer" ,
164+ gateResult : "skipped" ,
165+ skipReason : "team-only-request" ,
166+ requestedReviewer : null ,
167+ requestedTeam : requestedTeamName ,
168+ requestedTeamSlug : requestedTeamSlug ?? null ,
169+ } ,
170+ "Skipping review_requested event because only a non-rereview team was requested" ,
171+ ) ;
172+ return ;
173+ }
174+
147175 logger . info (
148176 {
149177 ...baseLog ,
150178 gate : "review_requested_reviewer" ,
151- gateResult : "skipped" ,
152- skipReason : "team-only-request" ,
179+ gateResult : "accepted" ,
153180 requestedReviewer : null ,
154181 requestedTeam : requestedTeamName ,
182+ requestedTeamSlug : requestedTeamSlug ?? null ,
183+ rereviewTeam : true ,
155184 } ,
156- "Skipping review_requested event because only a team was requested " ,
185+ "Accepted review_requested event for rereview team" ,
157186 ) ;
158- return ;
159187 } else {
160188 logger . warn (
161189 {
0 commit comments