diff --git a/supacode/Clients/Github/GithubCLIClient.swift b/supacode/Clients/Github/GithubCLIClient.swift index f64ed10e..acfb6bc7 100644 --- a/supacode/Clients/Github/GithubCLIClient.swift +++ b/supacode/Clients/Github/GithubCLIClient.swift @@ -1190,7 +1190,7 @@ nonisolated private func makeBatchPullRequestsQuery( let escapedBranch = escapeGraphQLString(branch) let orderBy = "orderBy: {field: UPDATED_AT, direction: DESC}" let selection = """ - \(alias): pullRequests(first: 5, states: [OPEN, MERGED], headRefName: \"\(escapedBranch)\", \(orderBy)) { + \(alias): pullRequests(first: 5, states: [OPEN, MERGED, CLOSED], headRefName: \"\(escapedBranch)\", \(orderBy)) { nodes { number title diff --git a/supacode/Features/Repositories/Views/PullRequestBadgeView.swift b/supacode/Features/Repositories/Views/PullRequestBadgeView.swift index db1821ee..1dcaca7f 100644 --- a/supacode/Features/Repositories/Views/PullRequestBadgeView.swift +++ b/supacode/Features/Repositories/Views/PullRequestBadgeView.swift @@ -3,6 +3,7 @@ import SwiftUI enum PullRequestBadgeStyle { static let mergedColor = Color.purple static let openColor = Color.green + static let closedColor = Color.red static let queuedColor = Color.brown static func style(state: String?, number: Int?, isQueued: Bool = false) -> (text: String, color: Color)? { @@ -14,6 +15,8 @@ enum PullRequestBadgeStyle { return (text: number.map { "#\($0)" } ?? "MERGED", color: mergedColor) case "OPEN": return (text: number.map { "#\($0)" } ?? "OPEN", color: isQueued ? queuedColor : openColor) + case "CLOSED": + return (text: number.map { "#\($0)" } ?? "CLOSED", color: closedColor) default: return nil } @@ -26,6 +29,8 @@ enum PullRequestBadgeStyle { return url == nil ? "Pull request merged" : "Open merged pull request on GitHub" case "OPEN": return url == nil ? "Pull request open" : "Open pull request on GitHub" + case "CLOSED": + return url == nil ? "Pull request closed" : "Open closed pull request on GitHub" default: return url == nil ? "Pull request" : "Open pull request on GitHub" } diff --git a/supacode/Features/Repositories/Views/PullRequestStatusButton.swift b/supacode/Features/Repositories/Views/PullRequestStatusButton.swift index c19cc288..6219541f 100644 --- a/supacode/Features/Repositories/Views/PullRequestStatusButton.swift +++ b/supacode/Features/Repositories/Views/PullRequestStatusButton.swift @@ -76,6 +76,11 @@ struct PullRequestStatusModel: Equatable { self.statusChecks = [] return } + if state == "CLOSED" { + self.detailText = nil + self.statusChecks = [] + return + } let isDraft = pullRequest.isDraft let prefix = isDraft ? "(Drafted) " : "" let mergeReadiness = PullRequestMergeReadiness(pullRequest: pullRequest) @@ -116,6 +121,7 @@ struct PullRequestStatusModel: Equatable { guard number != nil else { return false } - return state?.uppercased() != "CLOSED" + let s = state?.uppercased() + return s != nil && s != "UNKNOWN" } } diff --git a/supacode/Features/Repositories/Views/WorktreeRow.swift b/supacode/Features/Repositories/Views/WorktreeRow.swift index 5de0524e..dee38940 100644 --- a/supacode/Features/Repositories/Views/WorktreeRow.swift +++ b/supacode/Features/Repositories/Views/WorktreeRow.swift @@ -278,6 +278,11 @@ private struct WorktreeRowInfoView: View { var segment = AttributedString("Merged") segment.foregroundColor = PullRequestBadgeStyle.mergedColor result.append(segment) + } else if pullRequestState == "CLOSED" { + appendSeparator() + var segment = AttributedString("Closed") + segment.foregroundColor = PullRequestBadgeStyle.closedColor + result.append(segment) } else if isQueued { // A queued PR is mid-merge, so the queue state takes priority over the // merge-readiness label. -- 2.51.2 From 02ec6b9b20bd1d8dd00d4d26d55faa5c4afe290c Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 24 Jun 2026 22:52:05 +0800 Subject: [PATCH 2/4] Add CLOSED to cross-repo batch PR query makeCrossRepoBatchQuery was still using states: [OPEN, MERGED], missing CLOSED PRs. This caused closed PRs to briefly appear then disappear when the cross-repo refresh path kicked in. Both PR query paths now include CLOSED: - makeBatchPullRequestsQuery (single-repo) - makeCrossRepoBatchQuery (cross-repo, actual code path used) Signed-off-by: Alex --- supacode/Clients/Github/GithubCLIClient.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supacode/Clients/Github/GithubCLIClient.swift b/supacode/Clients/Github/GithubCLIClient.swift index acfb6bc7..25988a1e 100644 --- a/supacode/Clients/Github/GithubCLIClient.swift +++ b/supacode/Clients/Github/GithubCLIClient.swift @@ -578,7 +578,7 @@ nonisolated private func makeCrossRepoBatchQuery( branchAliasMap[branchAlias] = branch let escapedBranch = escapeGraphQLString(branch) let pullRequestsArgs = - "first: 5, states: [OPEN, MERGED], headRefName: \"\(escapedBranch)\", \(orderBy)" + "first: 5, states: [OPEN, MERGED, CLOSED], headRefName: \"\(escapedBranch)\", \(orderBy)" let selection = """ \(branchAlias): pullRequests(\(pullRequestsArgs)) { nodes { -- 2.51.2 From 7c55fe1d90b6df1a1d9c4c9aba07d6aac62c3dbf Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 24 Jun 2026 22:57:29 +0800 Subject: [PATCH 3/4] Fix SwiftLint identifier_name violation in shouldDisplay Variable name 's' was too short (minimum 3 chars). Rename to 'uppercasedState' to satisfy the lint rule. Signed-off-by: Alex --- .../Features/Repositories/Views/PullRequestStatusButton.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supacode/Features/Repositories/Views/PullRequestStatusButton.swift b/supacode/Features/Repositories/Views/PullRequestStatusButton.swift index 6219541f..2c0f84b2 100644 --- a/supacode/Features/Repositories/Views/PullRequestStatusButton.swift +++ b/supacode/Features/Repositories/Views/PullRequestStatusButton.swift @@ -121,7 +121,7 @@ struct PullRequestStatusModel: Equatable { guard number != nil else { return false } - let s = state?.uppercased() - return s != nil && s != "UNKNOWN" + let uppercasedState = state?.uppercased() + return uppercasedState != nil && uppercasedState != "UNKNOWN" } } -- 2.51.2 From 79a3243043921e312c9cea45bdbbe246a9eb96f2 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 25 Jun 2026 09:38:47 +0800 Subject: [PATCH 4/4] Change closed PR color from red to orange Red overlaps with error semantics (conflicts, failed checks, blocked). A closed PR is a terminal/informational state, not an error, so orange keeps it visible without competing with failure states. Signed-off-by: Alex --- supacode/Features/Repositories/Views/PullRequestBadgeView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supacode/Features/Repositories/Views/PullRequestBadgeView.swift b/supacode/Features/Repositories/Views/PullRequestBadgeView.swift index 1dcaca7f..466e239b 100644 --- a/supacode/Features/Repositories/Views/PullRequestBadgeView.swift +++ b/supacode/Features/Repositories/Views/PullRequestBadgeView.swift @@ -3,7 +3,7 @@ import SwiftUI enum PullRequestBadgeStyle { static let mergedColor = Color.purple static let openColor = Color.green - static let closedColor = Color.red + static let closedColor = Color.orange static let queuedColor = Color.brown static func style(state: String?, number: Int?, isQueued: Bool = false) -> (text: String, color: Color)? {