Skip to content

Fix sidebar PR badge detection for workspace branches - #1896

Merged
austinywang merged 2 commits into
mainfrom
issue-1893-sidebar-pr-status
Mar 21, 2026
Merged

austinywang merged 2 commits into
mainfrom
issue-1893-sidebar-pr-status

Conversation

@austinywang

@austinywang austinywang commented Mar 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add regression coverage for GitHub remote ordering and PR probe selection
  • probe PRs with gh pr list --state all --head <branch> instead of gh pr view, which misses cross-repo heads
  • check prioritized GitHub remotes so workspace branches can resolve PR open and PR merged badges reliably

Testing

  • ./scripts/reload.sh --tag fix-1893-pr-badge

Fixes #1893


Summary by cubic

Fixes #1893 by reliably detecting sidebar PR badges for workspace branches across multiple GitHub remotes and cross-repo heads. We now probe PRs by branch and prioritize upstream over origin for better accuracy.

  • Bug Fixes
    • Probe with gh pr list --state all --head <branch> instead of gh pr view to include cross-repo heads.
    • Check all GitHub remotes from git remote -v, prioritize upstream then origin, and dedupe slugs before probing.
    • Select the preferred PR when multiple exist: Open > Merged > Closed; tie-break by latest updatedAt, then highest number.
    • More robust errors: non-zero gh exits are transient; no PRs return not found; removed fragile stderr matching.
    • Added unit tests for remote ordering and PR selection.

Written for commit a8cfa3b. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Improved pull request detection to work with multiple Git remotes; automatically prioritizes upstream and origin.
    • Enhanced PR selection logic that prefers open PRs over merged/closed, then chooses most recently updated PR.
  • Bug Fixes

    • More robust handling of invalid or malformed pull request data.
  • Tests

    • Added comprehensive test coverage for multi-remote PR detection and selection logic.

@vercel

vercel Bot commented Mar 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 21, 2026 2:40am

@coderabbitai

coderabbitai Bot commented Mar 21, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR enhances GitHub PR probing in TabManager by introducing multi-repository support, implementing a new PR selection algorithm prioritized by status and recency, and improving error handling. The changes replace the single-repo slug model with a priority-ordered multi-slug system and switch from pr view to pr list for better PR discovery across multiple git remotes.

Changes

Cohort / File(s) Summary
Core PR Probing & Selection Logic
Sources/TabManager.swift
Replaces GitHubPullRequestViewItem with GitHubPullRequestProbeItem (adds updatedAt: String? and Equatable). Reworks workspacePullRequestSnapshot() to probe multiple candidate repo slugs and return the first .resolved PR, tracking transient failures. Changes gh command from pr view to pr list --state all. Adds preferredPullRequest(from:) function that filters invalid candidates and selects based on priority: status (OPEN > MERGED > CLOSED), then updatedAt, then PR number. Removes string-based stderr detection for "no pull requests found".
Multi-Repository Discovery
Sources/TabManager.swift
Adds githubRepositorySlugs(fromGitRemoteVOutput:) and githubRepositorySlugs(directory:) to discover multiple candidate repo slugs from git remotes. Adds githubRemotePriority(_:) to order remotes (upstream, origin, then others) and deduplicate slugs across remotes.
Test Coverage
cmuxTests/TabManagerUnitTests.swift
Introduces new @MainActor test suite TabManagerPullRequestProbeTests with four test methods covering: remote slug discovery with prioritization and deduplication, PR selection preference for OPEN over MERGED/CLOSED, selection by most recent updatedAt within same status, and filtering of malformed candidates with invalid state or URL.

Possibly related PRs

  • #1570: Modifies TabManager's GitHub PR probing and repo-slug resolution logic alongside this PR

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Poem

🐰 Hops through remotes with upstream cheer,
Finds the freshest PR that's here!
Open first, then merged with care,
Multi-repo slugs everywhere! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix sidebar PR badge detection for workspace branches' accurately and concisely describes the main change—fixing PR badge detection for workspace branches—and is directly related to the primary objective of resolving issue #1893.
Description check ✅ Passed The PR description follows the template with a clear Summary section, Testing section with reproduction steps, and includes a checklist. However, the Checklist items show incomplete status (all unchecked), and Demo Video and Review Trigger sections are missing.
Linked Issues check ✅ Passed The code changes fully address issue #1893's requirements: probe PRs with gh pr list instead of gh pr view, prioritize GitHub remotes (upstream then origin), select preferred PR by status and updatedAt, and add unit test coverage for remote ordering and PR selection logic.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing PR badge detection: GitHubPullRequestProbeItem data model, multi-remote probing with prioritization, PR selection logic, and comprehensive test coverage—no unrelated modifications present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-1893-sidebar-pr-status

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes sidebar PR badge detection for workspace branches by switching from gh pr view (which missed cross-repository heads) to gh pr list --state all --head <branch>, and by probing multiple GitHub remotes in priority order (upstream → origin → others), deduplicating by slug. When multiple PRs match a branch, a preferredPullRequest selector ranks them by status priority (OPEN > MERGED > CLOSED), then by recency (updatedAt), then by PR number.

Key changes:

  • GitHubPullRequestViewItem → GitHubPullRequestProbeItem (added updatedAt, Equatable, internal access for testability)
  • New githubRepositorySlugs(fromGitRemoteVOutput:) parses git remote -v and returns slugs in priority order, deduplicating repos that appear under multiple remote names
  • prErrorIndicatesNoPullRequest stderr-parsing heuristic removed in favour of relying on gh pr list returning an empty JSON array on exit 0 when no PRs exist
  • Four new unit tests covering remote ordering/deduplication and PR preference selection

Issues found:

  • The guard let candidateStatus / currentStatus inside isPreferred is dead code because the outer preferredPullRequest loop pre-validates every candidate; if it ever fires silently, return false produces a subtle keep-current-best result that could be hard to debug
  • When result.stdout is nil, the existing parseFail debug-log label fires rather than a more descriptive noOutput label, which can be confusing during log triage
  • No test for preferredPullRequest(from: []) returning nil, or for the case where all candidates are malformed

Confidence Score: 4/5

  • This PR is safe to merge; the logic change is well-reasoned and backed by targeted unit tests, with only minor style-level issues.
  • The core replacement of gh pr view with gh pr list is correct and removes fragile stderr-pattern parsing. Multi-remote prioritization and deduplication are clearly tested. No functional bugs were found. Points deducted for one dead-code guard inside isPreferred (potential future debugging trap), a slightly misleading debug log in the nil-stdout path, and missing edge-case tests for the empty/all-malformed inputs to preferredPullRequest.
  • No files require special attention; the minor issues are all confined to debug logging and non-critical test coverage gaps.

Important Files Changed

Filename Overview
Sources/TabManager.swift Core logic change: replaces gh pr view (single result, missed cross-repo heads) with gh pr list --state all --head (returns array), adds multi-remote prioritization (upstream→origin→others, deduplicated by slug), and a preferredPullRequest selector that ranks by status priority (OPEN > MERGED > CLOSED), recency, then PR number. One dead-code guard inside isPreferred and a potentially misleading debug-log label when stdout is nil are minor style issues; no functional bugs found.
cmuxTests/TabManagerUnitTests.swift New TabManagerPullRequestProbeTests class adds four unit tests covering remote slug ordering/deduplication and PR preference selection; tests are well-targeted at the newly exposed static methods. Missing coverage for all-malformed and empty-list edge cases in preferredPullRequest.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["workspacePullRequestSnapshot(dir, branch)"] --> B["githubRepositorySlugs(dir)\ngit remote -v"]
    B --> C{Any slugs?}
    C -- No --> D[.unsupportedRepository]
    C -- Yes --> E["Loop over repoSlugs\n(upstream → origin → others)"]
    E --> F["workspacePullRequestSnapshot\n(dir, branch, repoSlug)\ngh pr list --repo R --state all --head B"]
    F --> G{exit code 0?}
    G -- No --> H[".transientFailure\nsawTransientFailure = true"]
    G -- Yes --> I["decodeJSON\n[GitHubPullRequestProbeItem]"]
    I --> J{Parse OK?}
    J -- No --> H
    J -- Yes --> K["preferredPullRequest(from: items)\nrank: OPEN > MERGED > CLOSED\nthen updatedAt desc\nthen number desc"]
    K --> L{Found?}
    L -- No --> M[".notFound → continue to next slug"]
    L -- Yes --> N["validate state + URL"]
    N --> O{Valid?}
    O -- No --> H
    O -- Yes --> P[".resolved(SidebarPullRequestState)"]
    P --> Q[Return immediately]
    M --> E
    H --> E
    E -- All slugs exhausted --> R{sawTransientFailure?}
    R -- Yes --> S[.transientFailure]
    R -- No --> T[.notFound]
Loading

Last reviewed commit: "fix: detect sidebar ..."

Comment thread Sources/TabManager.swift
Comment on lines +1559 to +1567
func isPreferred(
candidate: GitHubPullRequestProbeItem,
over current: GitHubPullRequestProbeItem
) -> Bool {
guard let candidateStatus = pullRequestStatus(from: candidate.state),
let currentStatus = pullRequestStatus(from: current.state) else {
return false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Redundant guard check — dead code path

The guard let candidateStatus / currentStatus inside isPreferred can never fail in practice. The outer loop in preferredPullRequest already validates every candidate with:

guard pullRequestStatus(from: pullRequest.state) != nil,
      URL(string: pullRequest.url) != nil else { continue }

before calling isPreferred. And currentBest was always first accepted via the same guard, so pullRequestStatus(from: current.state) is always non-nil too.

The return false branch is unreachable dead code. If it ever fires due to a future refactor, silently keeping the current best is a subtle outcome that could be hard to debug. Consider removing the guard entirely (since callers pre-validate), or add a assertionFailure / dlog to make the unexpected case explicit.

Comment thread Sources/TabManager.swift
Comment on lines 1491 to 1499
@@ -1486,6 +1499,16 @@ class TabManager: ObservableObject {
return .transientFailure

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Misleading parseFail log when stdout is nil

output is set to "" when result.stdout is nil. decodeJSON will fail to parse "" as [GitHubPullRequestProbeItem] (not valid JSON), so this guard trips and logs parseFail. But the real cause is that stdout was absent, not a malformed JSON payload. During debugging, a parseFail entry that has output=none in the log can be indistinguishable from a genuine parse error in a non-empty payload.

Consider differentiating the two cases:

let output = result.stdout ?? ""
guard !output.isEmpty else {
#if DEBUG
    dlog(
        "workspace.gitProbe.pr.noOutput dir=\(directory) branch=\(branch) " +
        "repo=\(repoSlug)"
    )
#endif
    return .transientFailure
}
guard let pullRequests = decodeJSON([GitHubPullRequestProbeItem].self, from: output) else {
#if DEBUG
    dlog(
        "workspace.gitProbe.pr.parseFail dir=\(directory) branch=\(branch) " +
        "repo=\(repoSlug) output=\(debugLogSnippet(output) ?? "none")"
    )
#endif
    return .transientFailure
}

Comment on lines +186 to +212
func testPreferredPullRequestIgnoresMalformedCandidates() {
let valid = TabManager.GitHubPullRequestProbeItem(
number: 1888,
state: "OPEN",
url: "https://github.com/manaflow-ai/cmux/pull/1888",
updatedAt: "2026-03-20T18:00:00Z"
)

XCTAssertEqual(
TabManager.preferredPullRequest(from: [
TabManager.GitHubPullRequestProbeItem(
number: 9999,
state: "WHATEVER",
url: "https://github.com/manaflow-ai/cmux/pull/9999",
updatedAt: "2026-03-21T18:00:00Z"
),
TabManager.GitHubPullRequestProbeItem(
number: 10000,
state: "OPEN",
url: "not a url",
updatedAt: "2026-03-21T18:00:00Z"
),
valid,
]),
valid
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing test case: all candidates malformed returns nil

testPreferredPullRequestIgnoresMalformedCandidates always includes at least one valid candidate. There is no test verifying that preferredPullRequest(from:) returns nil when every entry in the array is malformed (bad state + bad URL), and no test for the empty-input case preferredPullRequest(from: []).

Both are straightforward edge cases worth covering:

func testPreferredPullRequestReturnsNilForEmptyList() {
    XCTAssertNil(TabManager.preferredPullRequest(from: []))
}

func testPreferredPullRequestReturnsNilWhenAllCandidatesMalformed() {
    XCTAssertNil(
        TabManager.preferredPullRequest(from: [
            TabManager.GitHubPullRequestProbeItem(
                number: 1,
                state: "UNKNOWN",
                url: "not-a-url",
                updatedAt: nil
            ),
        ])
    )
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/TabManager.swift (1)

1437-1510: ⚠️ Potential issue | 🟠 Major

PR badges still stop updating after the initial probe window.

This new lookup still feeds the existing finite retry schedule, and that schedule clears on both .notFound and .resolved. If the PR is opened after the last retry, or an already-open PR is merged later, the sidebar badge stays stale until the branch/directory changes. Please keep a low-frequency re-probe alive while the workspace remains on the same branch.

Also applies to: 1533-1541

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/TabManager.swift` around lines 1437 - 1510, The probe currently
returns .notFound or .resolved which clears the finite retry schedule; change
the behavior so the workspace keeps a low-frequency re-probe while on the same
branch: either introduce a new enum case (e.g. .notFoundKeepProbing or
.keepProbing) or map the existing .notFound/.resolved returns to a non-terminal
status (e.g. .transientFailure) so the retry schedule is not cleared; update the
probe return points in the GitHub PR lookup function (the block that calls
runCommandResult, decodes via decodeJSON([GitHubPullRequestProbeItem].self,
from:), and uses preferredPullRequest(from:)) and the equivalent logic around
lines 1533-1541 to return the non-terminal status instead of .notFound/.resolved
so a low-frequency background re-probe continues while the workspace remains on
the same branch.
🧹 Nitpick comments (1)
cmuxTests/TabManagerUnitTests.swift (1)

120-213: Add one refresh-path regression.

These helper tests will still all pass if TabManager never re-probes after the initial window, so the user-visible “badge updates automatically” behavior is still uncovered. A single test that drives the actual refresh scheduling/state transition would make this fix much harder to regress.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxTests/TabManagerUnitTests.swift` around lines 120 - 213, Add a regression
test that verifies TabManager actually schedules and executes a subsequent
refresh (not just the initial probe): write a new test in
TabManagerUnitTests.swift that creates a TabManager with a test double/mock for
the network client or probe handler (or inject a mock scheduler) that counts
probe invocations, call the public method that starts probing (e.g.,
TabManager.startProbing() or the initializer that begins the probe cycle),
advance the test scheduler or run the loop to simulate the refresh interval (or
call TabManager.scheduleNextProbe()/TabManager.triggerScheduledProbe() if those
exist), and assert the probe was invoked at least twice to ensure the refresh
path runs; reference TabManager, the probing/start method, and the probe/network
client mock when locating where to inject the test double.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/TabManager.swift`:
- Around line 1786-1800: The loop that parses git remote lines only accepts
remotes where remoteKind == "(fetch)", so push-only GitHub remotes are ignored;
update the guard in the parsing block (the loop that builds slugByRemoteName) to
accept push remotes as well by allowing remoteKind == "(push)" in addition to
"(fetch)" (or accept both by testing for contains "fetch" or "push"), and ensure
you still call githubRepositorySlug(fromRemoteURL:) and populate
slugByRemoteName[remoteName] when a push remote yields a valid repoSlug.

---

Outside diff comments:
In `@Sources/TabManager.swift`:
- Around line 1437-1510: The probe currently returns .notFound or .resolved
which clears the finite retry schedule; change the behavior so the workspace
keeps a low-frequency re-probe while on the same branch: either introduce a new
enum case (e.g. .notFoundKeepProbing or .keepProbing) or map the existing
.notFound/.resolved returns to a non-terminal status (e.g. .transientFailure) so
the retry schedule is not cleared; update the probe return points in the GitHub
PR lookup function (the block that calls runCommandResult, decodes via
decodeJSON([GitHubPullRequestProbeItem].self, from:), and uses
preferredPullRequest(from:)) and the equivalent logic around lines 1533-1541 to
return the non-terminal status instead of .notFound/.resolved so a low-frequency
background re-probe continues while the workspace remains on the same branch.

---

Nitpick comments:
In `@cmuxTests/TabManagerUnitTests.swift`:
- Around line 120-213: Add a regression test that verifies TabManager actually
schedules and executes a subsequent refresh (not just the initial probe): write
a new test in TabManagerUnitTests.swift that creates a TabManager with a test
double/mock for the network client or probe handler (or inject a mock scheduler)
that counts probe invocations, call the public method that starts probing (e.g.,
TabManager.startProbing() or the initializer that begins the probe cycle),
advance the test scheduler or run the loop to simulate the refresh interval (or
call TabManager.scheduleNextProbe()/TabManager.triggerScheduledProbe() if those
exist), and assert the probe was invoked at least twice to ensure the refresh
path runs; reference TabManager, the probing/start method, and the probe/network
client mock when locating where to inject the test double.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fbb20c90-2f3f-4d3c-b883-8e070fdc3d6a

📥 Commits

Reviewing files that changed from the base of the PR and between 39c03c9 and a8cfa3b.

📒 Files selected for processing (2)
  • Sources/TabManager.swift
  • cmuxTests/TabManagerUnitTests.swift

Comment thread Sources/TabManager.swift
Comment on lines +1786 to +1800
for line in output.split(whereSeparator: \.isNewline) {
let parts = line.split(whereSeparator: \.isWhitespace)
guard parts.count >= 3 else { continue }

let remoteName = String(parts[0])
let remoteURL = String(parts[1])
let remoteKind = String(parts[2])
guard remoteKind == "(fetch)",
let repoSlug = githubRepositorySlug(fromRemoteURL: remoteURL) else {
continue
}

if slugByRemoteName[remoteName] == nil {
slugByRemoteName[remoteName] = repoSlug
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Accept GitHub push remotes here too.

This parser ignores "(push)" entries entirely. Repos that fetch from a mirror/non-GitHub remote but push to GitHub will still produce no slug here, so PR badges remain broken for that workspace configuration.

Possible fix
         for line in output.split(whereSeparator: \.isNewline) {
             let parts = line.split(whereSeparator: \.isWhitespace)
             guard parts.count >= 3 else { continue }

             let remoteName = String(parts[0])
             let remoteURL = String(parts[1])
             let remoteKind = String(parts[2])
-            guard remoteKind == "(fetch)",
+            guard remoteKind == "(fetch)" || remoteKind == "(push)",
                   let repoSlug = githubRepositorySlug(fromRemoteURL: remoteURL) else {
                 continue
             }

-            if slugByRemoteName[remoteName] == nil {
+            if slugByRemoteName[remoteName] == nil || remoteKind == "(fetch)" {
                 slugByRemoteName[remoteName] = repoSlug
             }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for line in output.split(whereSeparator: \.isNewline) {
let parts = line.split(whereSeparator: \.isWhitespace)
guard parts.count >= 3 else { continue }
let remoteName = String(parts[0])
let remoteURL = String(parts[1])
let remoteKind = String(parts[2])
guard remoteKind == "(fetch)",
let repoSlug = githubRepositorySlug(fromRemoteURL: remoteURL) else {
continue
}
if slugByRemoteName[remoteName] == nil {
slugByRemoteName[remoteName] = repoSlug
}
for line in output.split(whereSeparator: \.isNewline) {
let parts = line.split(whereSeparator: \.isWhitespace)
guard parts.count >= 3 else { continue }
let remoteName = String(parts[0])
let remoteURL = String(parts[1])
let remoteKind = String(parts[2])
guard remoteKind == "(fetch)" || remoteKind == "(push)",
let repoSlug = githubRepositorySlug(fromRemoteURL: remoteURL) else {
continue
}
if slugByRemoteName[remoteName] == nil || remoteKind == "(fetch)" {
slugByRemoteName[remoteName] = repoSlug
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/TabManager.swift` around lines 1786 - 1800, The loop that parses git
remote lines only accepts remotes where remoteKind == "(fetch)", so push-only
GitHub remotes are ignored; update the guard in the parsing block (the loop that
builds slugByRemoteName) to accept push remotes as well by allowing remoteKind
== "(push)" in addition to "(fetch)" (or accept both by testing for contains
"fetch" or "push"), and ensure you still call
githubRepositorySlug(fromRemoteURL:) and populate slugByRemoteName[remoteName]
when a push remote yields a valid repoSlug.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/TabManager.swift">

<violation number="1" location="Sources/TabManager.swift:1444">
P2: Add an explicit `--limit` to the `gh pr list` probe. The CLI defaults to 30 results, so the current query can miss the relevant PR and produce the wrong sidebar badge when many PRs match the head branch.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread Sources/TabManager.swift
Comment on lines +1444 to +1445
"--head", branch,
"--json", "number,state,url,updatedAt",

@cubic-dev-ai cubic-dev-ai Bot Mar 21, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add an explicit --limit to the gh pr list probe. The CLI defaults to 30 results, so the current query can miss the relevant PR and produce the wrong sidebar badge when many PRs match the head branch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/TabManager.swift, line 1444:

<comment>Add an explicit `--limit` to the `gh pr list` probe. The CLI defaults to 30 results, so the current query can miss the relevant PR and produce the wrong sidebar badge when many PRs match the head branch.</comment>

<file context>
@@ -1408,17 +1409,40 @@ class TabManager: ObservableObject {
                 "--repo", repoSlug,
-                "--json", "number,state,url",
+                "--state", "all",
+                "--head", branch,
+                "--json", "number,state,url,updatedAt",
             ],
</file context>
Suggested change
"--head", branch,
"--json", "number,state,url,updatedAt",
"--head", branch,
"--limit", "200",
"--json", "number,state,url,updatedAt",
Fix with Cubic

@austinywang
austinywang merged commit 5c4fab1 into main Mar 21, 2026
24 of 25 checks passed
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
* test: cover sidebar PR probe selection

* fix: detect sidebar PR badges across github remotes

This branch was successfully deployed

1 active deployment
Preview — a8cfa3be Deployed Mar 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sidebar does not show open or merged PRs for workspace branches

1 participant