Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7da7265
docs: specify Tools Hub maintenance refactor
brsbl Jul 22, 2026
1b2563e
refactor(app): split skills registry and browse UI
brsbl Jul 22, 2026
568ed00
refactor(shared-ui): split resource list modules
brsbl Jul 22, 2026
9562a2e
refactor(server): split skills registry layers
brsbl Jul 22, 2026
b341115
refactor(app): extract plugin capabilities
brsbl Jul 22, 2026
eceec18
refactor(app): finish SkillsView decomposition
brsbl Jul 22, 2026
d1e293f
Merge remote-tracking branch 'origin/main' into bb/spec-tools-hub-ref…
brsbl Jul 22, 2026
764b714
chore: keep refactor spec local
brsbl Jul 22, 2026
11ec543
refactor: tighten Tools Hub module boundaries
brsbl Jul 23, 2026
b0ccf28
refactor: share skills registry contracts
brsbl Jul 23, 2026
0c62ddc
feat(skills): create from registry reference
brsbl Jul 23, 2026
3b00870
fix(skills): harden reference creation prompt
brsbl Jul 23, 2026
0ba3573
refactor(tools): unify hub navigation and browse surfaces
brsbl Jul 23, 2026
a40c982
refactor(tools): remove redundant hub layers
brsbl Jul 23, 2026
f26f9a5
fix(tools): preserve lifecycle error messages
brsbl Jul 23, 2026
d60b41c
refactor(tools): simplify hub state and contracts
brsbl Jul 23, 2026
69329a3
refactor(tools): consolidate hub ownership
brsbl Jul 23, 2026
445607c
fix(tools): preserve collection tab activation
brsbl Jul 23, 2026
09cc237
perf(skills): avoid resolving sources while browsing
brsbl Jul 23, 2026
90280f6
feat(skills): prioritize create from reference
brsbl Jul 23, 2026
5adb6d6
fix(skills): shorten create action label
brsbl Jul 23, 2026
e78bbb2
fix(skills): clarify and align reference action
brsbl Jul 23, 2026
7257513
fix(skills): present fork and save as sibling actions
brsbl Jul 23, 2026
aa30482
fix(ui): use git fork icon for fork actions
brsbl Jul 23, 2026
08fa2b7
fix(skills): quiet save icon action
brsbl Jul 23, 2026
5984df2
refactor(skills): make fork the sole registry action
brsbl Jul 23, 2026
6ce10a3
refactor(skills): rename installed collection to library
brsbl Jul 23, 2026
c2a6333
chore(registry): refresh icon manifest
brsbl Jul 23, 2026
bc7ba73
fix(skills): preserve route and install contracts
brsbl Jul 23, 2026
735fb0b
test(skills): preserve registry install response
brsbl Jul 23, 2026
a018e53
fix(skills): quiet fork action
brsbl Jul 23, 2026
7afc0b7
fix(sidebar): align section trailing actions
brsbl Jul 23, 2026
7167a17
fix(skills): enrich registry cards with stars
brsbl Jul 23, 2026
6356e76
fix(skills): restore browse card descriptions
brsbl Jul 23, 2026
6572316
refactor(tools): define detail page contracts
brsbl Jul 23, 2026
fca3c37
fix(skills): inset browse card descriptions
brsbl Jul 23, 2026
b53b6ec
fix(tools): widen browse card descriptions
brsbl Jul 23, 2026
5d1bc7c
refactor(tools): remove unnecessary detail models
brsbl Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions apps/app/src/App.legacy-skill-route.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// @vitest-environment jsdom

import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it } from "vitest";
import { MemoryRouter, Route, Routes, useLocation } from "react-router-dom";
import { LegacySkillDetailRedirect } from "./App";
import {
LEGACY_TOOLS_SKILL_DETAIL_ROUTE_PATH,
TOOLS_SKILL_DETAIL_ROUTE_PATH,
} from "./lib/route-paths";

function LocationPath() {
return <span>{useLocation().pathname}</span>;
}

describe("LegacySkillDetailRedirect", () => {
afterEach(cleanup);

it("preserves old installed links while Library remains canonical", () => {
render(
<MemoryRouter initialEntries={["/tools/skills/installed/skill_abc123"]}>
<Routes>
<Route
path={LEGACY_TOOLS_SKILL_DETAIL_ROUTE_PATH}
element={<LegacySkillDetailRedirect />}
/>
<Route
path={TOOLS_SKILL_DETAIL_ROUTE_PATH}
element={<LocationPath />}
/>
</Routes>
</MemoryRouter>,
);

expect(screen.getByText("/tools/skills/library/skill_abc123")).toBeTruthy();
});
});
16 changes: 16 additions & 0 deletions apps/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
LEGACY_AUTOMATION_DETAIL_ROUTE_PATH,
LEGACY_AUTOMATIONS_ROUTE_PATH,
LEGACY_SKILLS_ROUTE_PATH,
LEGACY_TOOLS_SKILL_DETAIL_ROUTE_PATH,
PROJECT_ARCHIVED_ROUTE_PATH,
PROJECTLESS_ARCHIVED_ROUTE_PATH,
PROJECT_SETTINGS_ROUTE_PATH,
Expand All @@ -36,6 +37,7 @@ import {
TOOLS_SKILL_DETAIL_ROUTE_PATH,
getAutomationDetailRoutePath,
getSettingsRoutePath,
getSkillDetailRoutePath,
} from "./lib/route-paths";
import { AppCommandProvider } from "./components/commands/AppCommandProvider";
import { ToolsExperimentGate } from "./components/tools/ToolsExperimentGate";
Expand Down Expand Up @@ -75,6 +77,16 @@ function LegacyAutomationDetailRedirect() {
);
}

export function LegacySkillDetailRedirect() {
const { skillId } = useParams<{ skillId?: string }>();
return (
<Navigate
to={skillId ? getSkillDetailRoutePath({ skillId }) : SKILLS_ROUTE_PATH}
replace
/>
);
}

function AppRoutes() {
return (
<AppLayout>
Expand Down Expand Up @@ -127,6 +139,10 @@ function AppRoutes() {
path={TOOLS_SKILL_DETAIL_ROUTE_PATH}
element={<ToolsView />}
/>
<Route
path={LEGACY_TOOLS_SKILL_DETAIL_ROUTE_PATH}
element={<LegacySkillDetailRedirect />}
/>
<Route
path={TOOLS_REGISTRY_SKILLS_ROUTE_PATH}
element={<ToolsView />}
Expand Down
51 changes: 45 additions & 6 deletions apps/app/src/components/layout/AppLayout.tools-breadcrumbs.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
import { describe, expect, it } from "vitest";
import { resolveToolsBreadcrumbs } from "./AppLayout";
import {
resolveToolsBreadcrumbs,
TOOLS_NAV_ITEMS,
} from "@/components/tools/tools-navigation";

describe("resolveToolsBreadcrumbs", () => {
it("uses one section identity contract for navigation and page chrome", () => {
expect(
TOOLS_NAV_ITEMS.map(({ id, label, icon, to }) => ({
id,
label,
icon,
to,
})),
).toEqual([
{ id: "skills", label: "Skills", icon: "Zap", to: "/tools/skills" },
{
id: "plugins",
label: "Plugins",
icon: "ElectricPlugs",
to: "/tools/plugins",
},
{
id: "automations",
label: "Automations",
icon: "TimeSchedule",
to: "/tools/automations",
},
]);
});

it("includes the selected collection tab", () => {
expect(resolveToolsBreadcrumbs("/tools/skills")).toEqual([
{ label: "Skills", to: "/tools/skills" },
{ label: "Library" },
]);
expect(resolveToolsBreadcrumbs("/tools/skills", "?view=browse")).toEqual([
{ label: "Skills", to: "/tools/skills" },
{ label: "Browse" },
Expand All @@ -20,6 +52,17 @@ describe("resolveToolsBreadcrumbs", () => {
});

it("makes every detail ancestor clickable and keeps the resource passive", () => {
expect(
resolveToolsBreadcrumbs(
"/tools/skills/library/skill_abc123",
"",
"Example Skill",
),
).toEqual([
{ label: "Skills", to: "/tools/skills" },
{ label: "Library", to: "/tools/skills" },
{ label: "Example Skill" },
]);
expect(
resolveToolsBreadcrumbs(
"/tools/skills/registry/vercel-labs%2Fskills%2Ffind-skills",
Expand All @@ -35,11 +78,7 @@ describe("resolveToolsBreadcrumbs", () => {
{ label: "ui-patterns" },
]);
expect(
resolveToolsBreadcrumbs(
"/tools/plugins/ui-patterns",
"",
"UI Patterns",
),
resolveToolsBreadcrumbs("/tools/plugins/ui-patterns", "", "UI Patterns"),
).toEqual([
{ label: "Plugins", to: "/tools/plugins" },
{ label: "Installed", to: "/tools/plugins" },
Expand Down
Loading
Loading