diff --git a/surfaces/gui/e2e/gallery.spec.ts b/surfaces/gui/e2e/gallery.spec.ts
index cf9d91c9..5aa46fbe 100644
--- a/surfaces/gui/e2e/gallery.spec.ts
+++ b/surfaces/gui/e2e/gallery.spec.ts
@@ -1,7 +1,6 @@
-// Settings ▸ Personas ▸ Gallery: the catalog lives in a screen-sized modal opened
-// from the Personas page (link → featured carousel + list → in-modal solo page →
-// informed install → Done lands back on Personas). Plus the page-level delete
-// affordance for non-builtin personas.
+// The Gallery entry point was removed from Settings ▸ Coworkers (owner 2026-08-21) —
+// coworkers install from GitHub / folder / zip. This file keeps the page-level
+// delete flow (now on the coworker detail page, UX-035).
import { expect } from "@playwright/test";
import { test } from "./fixtures";
@@ -10,91 +9,12 @@ async function openPersonas(page) {
await page.getByTestId("account-row").click();
await page.getByRole("button", { name: "Settings", exact: true }).click();
await page.getByRole("button", { name: "Coworkers", exact: true }).click();
- await expect(page.getByTestId("gallery-link")).toBeVisible();
}
-async function openGallery(page) {
+test("the Gallery entry point is gone from the Coworkers page", async ({ page }) => {
await openPersonas(page);
- await page.getByTestId("gallery-link").click();
- await expect(page.getByTestId("gallery-modal")).toBeVisible();
-}
-
-test("slow cloud: skeleton shows while the gallery loads, never a blank body", async ({
- page,
-}) => {
- // The real gallery is a cloud round-trip (Lambda + Dynamo) that can take seconds;
- // delay the mocked endpoints to assert the skeleton bridges the gap.
- await page.route("**/v1/cloud/status", async (route) => {
- await new Promise((r) => setTimeout(r, 1200));
- await route.fulfill({ json: { ok: true, signed_in: false } });
- });
- await openGallery(page);
- await expect(page.getByTestId("gallery-loading")).toBeVisible();
- await expect(page.getByTestId("gallery-loading")).toContainText("Loading the gallery");
- // Resolves into the real body (signed-out prompt here) once the cloud answers.
- await expect(page.getByTestId("gallery-signin")).toBeVisible({ timeout: 10_000 });
- await expect(page.getByTestId("gallery-loading")).toHaveCount(0);
-});
-
-test("signed out: modal prompts for sign-in, manual install path unaffected", async ({ page }) => {
- await openGallery(page);
- const prompt = page.getByTestId("gallery-signin");
- await expect(prompt).toContainText("needs a (free) cloud sign-in");
- await expect(prompt).toContainText("always works without an account");
- await expect(prompt.getByRole("button", { name: "Sign in" })).toBeVisible();
- // Esc closes; the Personas page (with its dir/Git importer) is still there.
- await page.keyboard.press("Escape");
- await expect(page.getByTestId("gallery-modal")).not.toBeVisible();
- // The manual installer (collapsed disclosure, UX-035) is still there.
- await page.getByTestId("install-disclosure").click();
- await expect(page.getByRole("button", { name: "Install", exact: true })).toBeVisible();
-});
-
-test("signed in: featured carousel + list; solo page installs informed; Done returns", async ({
- page,
-}) => {
- await openGallery(page);
- await page.getByTestId("gallery-signin").getByRole("button", { name: "Sign in" }).click();
-
- // Featured carousel holds the flagged persona; the list holds both.
- const featured = page.getByTestId("gallery-featured");
- await expect(featured).toBeVisible({ timeout: 10_000 });
- await expect(featured).toContainText("Sales Coworker");
- await expect(featured).not.toContainText("Recruiter");
- await expect(page.getByTestId("gallery-recruiter")).toContainText("View & install");
- await expect(page.getByTestId("gallery-team-teaser")).toContainText("coming soon");
-
- // Search narrows the list.
- await page.getByPlaceholder("Search coworkers").fill("recruit");
- await expect(page.getByTestId("gallery-sales")).not.toBeVisible();
- await page.getByPlaceholder("Search coworkers").fill("");
-
- // Solo page: pitch + manifest-derived capabilities BEFORE install.
- await page.getByTestId("gallery-sales").click();
- const detail = page.getByTestId("gallery-detail");
- await expect(detail).toContainText("Walk into every call already knowing the account");
- const caps = page.getByTestId("gallery-capabilities");
- await expect(caps).toContainText("verified from its manifest");
- await expect(caps).toContainText("files, search, todo");
- await expect(caps).toContainText("hubspot · core");
- await expect(caps).toContainText("read deals and contacts");
-
- await detail.getByRole("button", { name: "Install" }).click();
- await expect(detail).toContainText("disabled until you approve and enable it");
-
- // Done closes the modal, landing back on the Personas page.
- await detail.getByRole("button", { name: "Done" }).click();
- await expect(page.getByTestId("gallery-modal")).not.toBeVisible();
- await expect(page.getByTestId("gallery-link")).toBeVisible();
-});
-
-test("back link returns from the solo page to the catalog", async ({ page }) => {
- await openGallery(page);
- await page.getByTestId("gallery-signin").getByRole("button", { name: "Sign in" }).click();
- await page.getByTestId("gallery-sales").click({ timeout: 10_000 });
- await expect(page.getByTestId("gallery-detail")).toBeVisible();
- await page.getByRole("button", { name: "← Gallery" }).click();
- await expect(page.getByTestId("gallery-cards")).toBeVisible();
+ await expect(page.getByTestId("install-disclosure")).toBeVisible();
+ await expect(page.getByTestId("gallery-link")).toHaveCount(0);
});
test("delete: non-builtin personas removable after confirm; built-ins are not", async ({
diff --git a/surfaces/gui/src/App.tsx b/surfaces/gui/src/App.tsx
index 43fe271d..06e84090 100644
--- a/surfaces/gui/src/App.tsx
+++ b/surfaces/gui/src/App.tsx
@@ -2084,7 +2084,13 @@ export function App() {
setBoardDetailId(id);
setBoardOpen(true);
}}
- isLead={teamMembers.length > 0 || (!!curSession?.team && curSession.team.role !== "worker")}
+ /* team serializes as {} for plain sessions — lead-ness needs an actual
+ role, else every solo session loses its Progress panel (owner-hit
+ 2026-08-21: the rail showed nothing but "More"). */
+ isLead={
+ teamMembers.length > 0 ||
+ (curSession?.team?.role != null && curSession.team.role !== "worker")
+ }
teamMembers={teamMembers}
teamChatEnabled={!!curSession?.team?.chat_enabled}
teamChatUnread={curSession?.team?.chat_unread || 0}
diff --git a/surfaces/gui/src/components/PersonasTab.tsx b/surfaces/gui/src/components/PersonasTab.tsx
index 608b364b..dd03af99 100644
--- a/surfaces/gui/src/components/PersonasTab.tsx
+++ b/surfaces/gui/src/components/PersonasTab.tsx
@@ -27,14 +27,7 @@ const BTN_BORDERED =
const QUIET_ROW =
"w-full flex items-center gap-2 px-4 pt-2 mt-6 text-[12.5px] text-muted select-none";
-export function PersonasTab({
- onOpenPersona,
- onMeta,
-}: {
- onOpenPersona?: (id: string) => void;
- // Lets the section gate internal-build affordances (the Gallery entry point).
- onMeta?: (meta: { internal: boolean }) => void;
-}) {
+export function PersonasTab({ onOpenPersona }: { onOpenPersona?: (id: string) => void }) {
const [personas, setPersonas] = useState