From 6bb0c3b53dcd3cb01993456647c04482149d620f Mon Sep 17 00:00:00 2001 From: Patrick Lee Date: Sun, 9 Aug 2026 20:54:30 -0400 Subject: [PATCH 1/2] fix: don't show missing provider CLIs as updates in the sidebar badge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A provider CLI that is not installed produced a machine issue ('X CLI not installed') that the sidebar badge rendered as a brand chip with the aria-label 'X update available', even though there is no installed version to update. Codex was affected the same way as Claude Code. The badge now only surfaces issues where the CLI is actually installed and stale (needsUpdate or versionUnsupported). Missing installs remain visible in Settings → Updates, which already renders the install prompt. --- .../sidebar/SidebarUpdatesBadge.test.tsx | 59 +++++++++++++++++++ .../sidebar/SidebarUpdatesBadge.tsx | 9 +++ 2 files changed, 68 insertions(+) diff --git a/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx b/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx index 586d9575cb..0d48ae3d89 100644 --- a/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx +++ b/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx @@ -52,6 +52,34 @@ function providerIssue( }; } +function missingInstallIssue( + provider: ProviderCliKey, + displayName: string, +): ProviderCliIssue { + return { + provider, + status: { + displayName, + executableName: provider, + executablePath: null, + installed: false, + installSource: "notInstalled", + currentVersion: null, + latestVersion: "1.1.0", + minimumSupportedVersion: null, + npmPackageName: `@example/${provider}`, + npmGlobalPackageVersion: null, + installAction: null, + needsUpdate: false, + versionUnsupported: false, + }, + action: null, + title: `${displayName} CLI not installed`, + description: `Install ${displayName} so bb can start ${displayName} sessions.`, + fingerprint: `${provider}:missing:1.1.0`, + }; +} + function host(id: string): Host { return { id, @@ -137,6 +165,37 @@ describe("SidebarUpdatesBadge", () => { ).toBe("Claude Code update available"); }); + it("renders no provider chip when a CLI is not installed", () => { + renderBadge({ + machines: [ + machine({ + issues: [missingInstallIssue("claudeCode", "Claude Code")], + }), + ], + }); + + expect( + screen.queryByTestId("sidebar-updates-badge-providers"), + ).toBeNull(); + expect(screen.queryByTestId("sidebar-updates-badge-bb")).toBeNull(); + }); + + it("still shows the bb chip when the only provider issue is a missing CLI", () => { + renderBadge({ + appUpdateAvailable: true, + machines: [ + machine({ + issues: [missingInstallIssue("codex", "Codex")], + }), + ], + }); + + expect(screen.getByTestId("sidebar-updates-badge-bb")).toBeTruthy(); + expect( + screen.queryByTestId("sidebar-updates-badge-providers"), + ).toBeNull(); + }); + it("renders one mark per provider in a stable order when the same CLI is stale on several machines", () => { renderBadge({ appUpdateAvailable: true, diff --git a/apps/app/src/components/sidebar/SidebarUpdatesBadge.tsx b/apps/app/src/components/sidebar/SidebarUpdatesBadge.tsx index 46c253b75f..56f97a42bd 100644 --- a/apps/app/src/components/sidebar/SidebarUpdatesBadge.tsx +++ b/apps/app/src/components/sidebar/SidebarUpdatesBadge.tsx @@ -57,6 +57,10 @@ interface StaleProvider { * protocol) and the agent CLIs, which carry their own brand marks so it is * clear which agent is stale without hovering. Both chips open the * consolidated Settings → Updates view. + * + * A CLI that is not installed at all is not an update and gets no chip here: + * there is no installed version to stale against, and the Settings → Updates + * page already surfaces the install prompt for it. */ export function SidebarUpdatesBadge({ onNavigate }: SidebarUpdatesBadgeProps) { const inventory = useUpdateInventory(); @@ -70,9 +74,14 @@ export function SidebarUpdatesBadge({ onNavigate }: SidebarUpdatesBadgeProps) { stuckDaemonCount; // One mark per provider, even when the same CLI is stale on several machines. + // Missing CLIs are install prompts, not updates: skip them so the chip never + // claims an update is available for a CLI that isn't installed. const staleProvidersByKey = new Map(); for (const machine of inventory.machines) { for (const issue of machine.issues) { + if (!issue.status.installed) { + continue; + } if (!staleProvidersByKey.has(issue.provider)) { staleProvidersByKey.set(issue.provider, { provider: issue.provider, From 1afc37d412e1edf8330426906d6fbc0b1a90f5ec Mon Sep 17 00:00:00 2001 From: Sawyer Hood Date: Mon, 10 Aug 2026 15:18:13 +0000 Subject: [PATCH 2/2] style(app): format sidebar update badge tests --- .../src/components/sidebar/SidebarUpdatesBadge.test.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx b/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx index 0d48ae3d89..776b06ec36 100644 --- a/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx +++ b/apps/app/src/components/sidebar/SidebarUpdatesBadge.test.tsx @@ -174,9 +174,7 @@ describe("SidebarUpdatesBadge", () => { ], }); - expect( - screen.queryByTestId("sidebar-updates-badge-providers"), - ).toBeNull(); + expect(screen.queryByTestId("sidebar-updates-badge-providers")).toBeNull(); expect(screen.queryByTestId("sidebar-updates-badge-bb")).toBeNull(); }); @@ -191,9 +189,7 @@ describe("SidebarUpdatesBadge", () => { }); expect(screen.getByTestId("sidebar-updates-badge-bb")).toBeTruthy(); - expect( - screen.queryByTestId("sidebar-updates-badge-providers"), - ).toBeNull(); + expect(screen.queryByTestId("sidebar-updates-badge-providers")).toBeNull(); }); it("renders one mark per provider in a stable order when the same CLI is stale on several machines", () => {