diff --git a/apps/app/src/components/plugin/management/BrowsePluginsTab.test.tsx b/apps/app/src/components/plugin/management/BrowsePluginsTab.test.tsx
index b94b048c5..32f16ab51 100644
--- a/apps/app/src/components/plugin/management/BrowsePluginsTab.test.tsx
+++ b/apps/app/src/components/plugin/management/BrowsePluginsTab.test.tsx
@@ -37,6 +37,17 @@ const INCOMPATIBLE_ENTRY: PluginCatalogSearchEntry = {
incompatibleReason: "Requires a newer BB version",
};
+const GITHUB_ENTRY: PluginCatalogSearchEntry = {
+ ...MEMORY_ENTRY,
+ entryId: "github",
+ pluginId: "github",
+ displayName: "GitHub",
+ description: "Browse GitHub issues and pull requests in BB.",
+ icon: "Github",
+ category: "Developer tools",
+ source: "builtin:github",
+};
+
const INSTALLED_MEMORY_PLUGIN = {
id: "memory",
source: "builtin:memory",
@@ -79,7 +90,7 @@ describe("BrowsePluginsTab", () => {
}
if (url === "/api/v1/plugin-catalog/search?q=") {
return jsonResponse({
- results: [MEMORY_ENTRY, INCOMPATIBLE_ENTRY],
+ results: [MEMORY_ENTRY, INCOMPATIBLE_ENTRY, GITHUB_ENTRY],
});
}
if (url === "/api/v1/plugins") {
@@ -109,6 +120,10 @@ describe("BrowsePluginsTab", () => {
expect(
screen.getByRole("textbox", { name: "Search plugins" }),
).toBeTruthy();
+ const githubGrid = screen
+ .getByRole("button", { name: "Open GitHub details" })
+ .closest('[class*="auto-fill"]');
+ expect(githubGrid?.className).toContain("auto-fill");
expect(screen.queryByText(MEMORY_ENTRY.source)).toBeNull();
expect(screen.getByText("Requires a newer BB version")).toBeTruthy();
diff --git a/apps/app/src/components/plugin/management/BrowsePluginsTab.tsx b/apps/app/src/components/plugin/management/BrowsePluginsTab.tsx
index ee43ba069..9022eb2a1 100644
--- a/apps/app/src/components/plugin/management/BrowsePluginsTab.tsx
+++ b/apps/app/src/components/plugin/management/BrowsePluginsTab.tsx
@@ -136,7 +136,9 @@ export function BrowsePluginsTab({
{category}
-
+
{categoryEntries.map((entry) => (
+ ) : skill.scope === "plugin" ? (
+
+ }
+ accessibleLabel={`${skill.name} is included with ${includedPluginDescription(skill)}`}
+ />
) : undefined
}
description={description}
@@ -315,7 +327,7 @@ export function SkillsOverview({
normalizedQuery === "" && providerFilters.length === 0
? "No skills in your library."
: normalizedQuery === ""
- ? "No skills match these agents."
+ ? "No skills match these providers."
: `No skills match "${query}"`
}
/>
@@ -367,7 +379,7 @@ export function SkillsOverview({
controls={
<>
{
});
expect(markup).not.toContain("claude-skill");
expect(markup).toContain("Review the current diff.");
- expect(markup).toContain('aria-label="Agent: 1 selected"');
+ expect(markup).toContain('aria-label="Provider: 1 selected"');
expect(markup).toContain("Sort");
expect(markup).toContain('role="tab"');
expect(markup).toContain("Library");
@@ -269,6 +269,25 @@ describe("SkillsOverview", () => {
);
});
+ it("labels skills bundled with plugins", () => {
+ const markup = render({
+ skills: [
+ makeSkill({
+ name: "automations",
+ provider: null,
+ scope: "plugin",
+ pluginId: "automations",
+ manageable: false,
+ }),
+ ],
+ });
+
+ expect(markup).toContain(">Plugin<");
+ expect(markup).toContain(
+ 'aria-label="automations is included with Automations (bb plugin)"',
+ );
+ });
+
it("renders browse content as the active full-page collection mode", () => {
const registrySkill = makeRegistrySkill({ installs: 123_456, stars: 654 });
const markup = renderToStaticMarkup(
@@ -317,7 +336,7 @@ describe("SkillsOverview", () => {
);
fireEvent.pointerDown(
- screen.getByRole("button", { name: "Agent: 1 selected" }),
+ screen.getByRole("button", { name: "Provider: 1 selected" }),
);
await waitFor(() => {
@@ -358,13 +377,13 @@ describe("SkillsOverview", () => {
await waitFor(() => {
expect(
- screen.getByRole("button", { name: "Agent: 1 selected" }),
+ screen.getByRole("button", { name: "Provider: 1 selected" }),
).toBeTruthy();
expect(screen.queryByText("codex-skill")).toBeNull();
});
fireEvent.pointerDown(
- screen.getByRole("button", { name: "Agent: 1 selected" }),
+ screen.getByRole("button", { name: "Provider: 1 selected" }),
);
const bbFilter = screen.getByRole("menuitemcheckbox", { name: "bb" });
expect(bbFilter.getAttribute("aria-checked")).toBe("true");
@@ -396,7 +415,7 @@ describe("SkillsOverview", () => {
);
fireEvent.pointerDown(
- screen.getByRole("button", { name: "Agent: 1 selected" }),
+ screen.getByRole("button", { name: "Provider: 1 selected" }),
);
fireEvent.click(screen.getByRole("menuitemcheckbox", { name: "bb" }));
fireEvent.click(