feat(sidebar): improve PR checks and comments (#1134)

* feat(sidebar): improve PR checks and comments

Co-authored-by: Orca <help@stably.ai>

* fix(sidebar): classify bot comments via GitHub user.type instead of login heuristic

Third-party review bots like qodo-ai-reviewer, coderabbitai, and sonarcloud
don't follow the [bot] suffix or "bot"/"automation" substring convention, so
the regex-based detector misclassified them as human. Plumb REST
`user.type === 'Bot'` and GraphQL `author.__typename === 'Bot'` through to the
renderer as an authoritative isBot flag; fall back to the login heuristic only
when the data source can't report it.

Co-authored-by: Orca <help@stably.ai>

* fix(sidebar): allowlist AI review services that sign in as User accounts

qodo-ai-reviewer, coderabbitai, codium-ai and similar third-party review
services register as regular GitHub user accounts, so REST `user.type` is
"User" and their logins contain no "bot"/"automation" tokens. The previous
fix relied on the GitHub-reported type, which fails for these. Add an
explicit substring allowlist of known automation services so they still
land in the Bots tab.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
This commit is contained in:
Yasin Kavakli
2026-04-26 13:28:09 -07:00
committed by GitHub
co-authored by Orca Jinjing
parent 7720ed136c
commit fe6eecba0c
9 changed files with 348 additions and 54 deletions
+9 -6
View File
@@ -860,7 +860,7 @@ query($owner: String!, $repo: String!, $pr: Int!) {
comments(first: 100) {
nodes {
databaseId
author { login avatarUrl(size: 48) }
author { __typename login avatarUrl(size: 48) }
body
createdAt
url
@@ -932,7 +932,7 @@ export async function getPRComments(
// Parse issue comments (REST)
type RESTComment = {
id: number
user: { login: string; avatar_url: string } | null
user: { login: string; avatar_url: string; type?: string } | null
body: string
created_at: string
html_url: string
@@ -946,7 +946,8 @@ export async function getPRComments(
authorAvatarUrl: c.user?.avatar_url ?? '',
body: c.body ?? '',
createdAt: c.created_at,
url: c.html_url
url: c.html_url,
isBot: c.user?.type === 'Bot'
})
)
} else {
@@ -964,7 +965,7 @@ export async function getPRComments(
comments: {
nodes: {
databaseId: number
author: { login: string; avatarUrl: string } | null
author: { __typename?: string; login: string; avatarUrl: string } | null
body: string
createdAt: string
url: string
@@ -990,6 +991,7 @@ export async function getPRComments(
path: c.path,
threadId: thread.id,
isResolved: thread.isResolved,
isBot: c.author?.__typename === 'Bot',
// Why: GitHub nulls out line/startLine when the commented code is
// outdated (e.g. after a force-push). Fall back to originalLine which
// always preserves the line numbers from when the comment was created.
@@ -1006,7 +1008,7 @@ export async function getPRComments(
// since empty-body reviews (e.g. approvals with no comment) add noise.
type RESTReview = {
id: number
user: { login: string; avatar_url: string } | null
user: { login: string; avatar_url: string; type?: string } | null
body: string
state: string
submitted_at: string
@@ -1023,7 +1025,8 @@ export async function getPRComments(
authorAvatarUrl: r.user?.avatar_url ?? '',
body: r.body,
createdAt: r.submitted_at,
url: r.html_url
url: r.html_url,
isBot: r.user?.type === 'Bot'
})
)
} else {
+3 -2
View File
@@ -158,7 +158,7 @@ async function getIssueBodyAndComments(
}
type RESTComment = {
id: number
user: { login: string; avatar_url: string } | null
user: { login: string; avatar_url: string; type?: string } | null
body: string
created_at: string
html_url: string
@@ -170,7 +170,8 @@ async function getIssueBodyAndComments(
authorAvatarUrl: c.user?.avatar_url ?? '',
body: c.body ?? '',
createdAt: c.created_at,
url: c.html_url
url: c.html_url,
isBot: c.user?.type === 'Bot'
})
)
const assignees = (issue.assignees ?? []).map((a) => a.login)