From 9a2453e062b52d861404bd28fb29037b52b8e01d Mon Sep 17 00:00:00 2001 From: Dylan Trotter Date: Tue, 3 Nov 2026 19:10:04 +0000 Subject: [PATCH 1/2] team-setup: tidy the checklist layout (BB-225) Two-column checklist rows with a fixed-width action column, the step mark level with a fixed-height title line, one primary button plus a link for Claude/Codex, and in-progress panels full width below the row. Merging to bb-plugins main moves the bb-server pin, builds a new bb-server image and stages a restart on every developer's server. --- plugins/team-setup/app.tsx | 302 ++++++++++++++++++++----------------- 1 file changed, 161 insertions(+), 141 deletions(-) diff --git a/plugins/team-setup/app.tsx b/plugins/team-setup/app.tsx index 3d961ed..223c9ea 100644 --- a/plugins/team-setup/app.tsx +++ b/plugins/team-setup/app.tsx @@ -65,7 +65,7 @@ function useVisiblePolling(refetch: () => void, active: boolean, intervalMs: num function StepMark({ state }: { state: StepState }) { const name = state === "done" ? "CircleCheck" : "Circle"; const tone = state === "done" ? "text-success" : state === "todo" ? "text-muted-foreground" : "text-muted-foreground/60"; - return ; + return ; } const STEP_TITLES: Record = { @@ -98,25 +98,37 @@ function Step({ children, action, about, + panel, }: { state: StepState; title: string; children: React.ReactNode; action?: React.ReactNode; about?: React.ReactNode; + panel?: React.ReactNode; }) { return (
  • - -
    -
    -

    {title}

    - {action} -
    -
    - {about} - {children} + + + +
    + {/* Two columns, both top aligned: title and paragraph on the left, a + fixed-width action column on the right that every row keeps so + the right edge lines up. Narrow windows stack the action under + the whole left column rather than wrapping it under the title. */} +
    +
    +

    {title}

    +
    + {about} + {children} +
    +
    +
    {action}
    + {/* In-progress panels (device code, paste box) span the row width. */} + {panel ?
    {panel}
    : null}
  • ); @@ -310,7 +322,7 @@ function Checklist({ mode }: { mode: ChecklistMode }) { } action={ ai.available && claude === null && codex === null ? ( -
    +
    -
    ) : null } + panel={ + <> + {claude !== null ? ( +
    { + e.preventDefault(); + if (pasted.trim() === "") return; + void run("claude-complete", async () => { + await rpc.call("claudeComplete", { sessionId: claude.sessionId, pasted: pasted.trim() }); + setClaude(null); + setPasted(""); + refetch(); + }); + }} + > +

    Sign in at claude.ai, then paste the code from its final page here.

    +
    + + setPasted(e.target.value)} + /> + + +
    +
    + ) : null} + {codex !== null ? ( +
    +

    Open the verification page, sign in to ChatGPT, and enter this code.

    + +
    + + Waiting for you to approve… + +
    +
    + ) : null} + + } > {!ai.available ? (

    {ai.message ?? "Account Pool is unavailable."} Account Pool settings

    @@ -346,63 +419,6 @@ function Checklist({ mode }: { mode: ChecklistMode }) { ) : (

    Agents run on your own Claude or ChatGPT subscription through the Account Pool. One is enough; add both to fall back.

    )} - {claude !== null ? ( -
    { - e.preventDefault(); - if (pasted.trim() === "") return; - void run("claude-complete", async () => { - await rpc.call("claudeComplete", { sessionId: claude.sessionId, pasted: pasted.trim() }); - setClaude(null); - setPasted(""); - refetch(); - }); - }} - > -

    Sign in at claude.ai, then paste the code from its final page here.

    -
    - - setPasted(e.target.value)} - /> - - -
    -
    - ) : null} - {codex !== null ? ( -
    -

    Open the verification page, sign in to ChatGPT, and enter this code.

    - -
    - - Waiting for you to approve… - -
    -
    - ) : null} {codexError !== null ?

    {codexError}

    : null} @@ -434,6 +450,26 @@ function Checklist({ mode }: { mode: ChecklistMode }) { ) ) : null } + panel={ + github.pending !== null ? ( +
    +

    Enter this code on GitHub.

    + +
    + + Waiting for you to approve… + +
    +
    + ) : null + } > {github.status === "logged in" ? (

    @@ -446,24 +482,6 @@ function Checklist({ mode }: { mode: ChecklistMode }) { ) : (

    Machines clone and push as you. The sign-in happens on this server, once: GitHub shows you a code, you approve it, and bb forwards the login to every machine.

    )} - {github.pending !== null ? ( -
    -

    Enter this code on GitHub.

    - -
    - - Waiting for you to approve… - -
    -
    - ) : null} {github.lastError !== null && github.pending === null ?

    {github.lastError}

    : null} @@ -617,6 +635,62 @@ function Checklist({ mode }: { mode: ChecklistMode }) { ) : null } + panel={ + figmaStatus.pending || figma !== null ? ( +
    { + e.preventDefault(); + if (figmaPasted.trim() === "") return; + void run("figma-complete", async () => { + const result = await rpc.call("figmaComplete", { url: figmaPasted.trim() }); + if (!result.ok) { + setFigmaError(result.message ?? "The sign-in did not complete."); + return; + } + setFigma(null); + setFigmaPasted(""); + setFigmaError(null); + refetch(); + }); + }} + > +

    + Open the URL, approve the sign-in, then paste the http://localhost:…/callback address from the page it + lands on. The page itself will not load; only the address is needed. +

    +
    + + setFigmaPasted(e.target.value)} + /> + + +
    +
    + ) : null + } > {!figmaStatus.available ? (

    {figmaStatus.message ?? "Figma is unavailable."}

    @@ -630,60 +704,6 @@ function Checklist({ mode }: { mode: ChecklistMode }) {

    Give Claude Code design context from a Figma link. Figma's remote MCP server signs in with your browser; skip this if you do not use Figma.

    )} {figmaStatus.available && figmaStatus.message !== null ?

    {figmaStatus.message}

    : null} - {figmaStatus.pending || figma !== null ? ( -
    { - e.preventDefault(); - if (figmaPasted.trim() === "") return; - void run("figma-complete", async () => { - const result = await rpc.call("figmaComplete", { url: figmaPasted.trim() }); - if (!result.ok) { - setFigmaError(result.message ?? "The sign-in did not complete."); - return; - } - setFigma(null); - setFigmaPasted(""); - setFigmaError(null); - refetch(); - }); - }} - > -

    - Open the URL, approve the sign-in, then paste the http://localhost:…/callback address from the page it - lands on. The page itself will not load; only the address is needed. -

    -
    - - setFigmaPasted(e.target.value)} - /> - - -
    -
    - ) : null} {figmaError !== null ?

    {figmaError}

    : null} From 068595edb2c2cf1987025bb981dfe53daf53ba21 Mon Sep 17 00:00:00 2001 From: Dylan Trotter Date: Tue, 3 Nov 2026 19:14:04 +0000 Subject: [PATCH 2/2] team-setup: render the Claude/Codex panel wrapper only when a flow is open (BB-225) Review round 1 suggestion: the always-truthy fragment added the outer gap (8 px) to the row even with no sign-in in progress. --- plugins/team-setup/app.tsx | 118 +++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/plugins/team-setup/app.tsx b/plugins/team-setup/app.tsx index 223c9ea..5a0b109 100644 --- a/plugins/team-setup/app.tsx +++ b/plugins/team-setup/app.tsx @@ -342,65 +342,67 @@ function Checklist({ mode }: { mode: ChecklistMode }) { ) : null } panel={ - <> - {claude !== null ? ( -
    { - e.preventDefault(); - if (pasted.trim() === "") return; - void run("claude-complete", async () => { - await rpc.call("claudeComplete", { sessionId: claude.sessionId, pasted: pasted.trim() }); - setClaude(null); - setPasted(""); - refetch(); - }); - }} - > -

    Sign in at claude.ai, then paste the code from its final page here.

    -
    - - setPasted(e.target.value)} - /> - - -
    -
    - ) : null} - {codex !== null ? ( -
    -

    Open the verification page, sign in to ChatGPT, and enter this code.

    - -
    - - Waiting for you to approve… - + claude !== null || codex !== null ? ( + <> + {claude !== null ? ( +
    { + e.preventDefault(); + if (pasted.trim() === "") return; + void run("claude-complete", async () => { + await rpc.call("claudeComplete", { sessionId: claude.sessionId, pasted: pasted.trim() }); + setClaude(null); + setPasted(""); + refetch(); + }); + }} + > +

    Sign in at claude.ai, then paste the code from its final page here.

    +
    + + setPasted(e.target.value)} + /> + + +
    +
    + ) : null} + {codex !== null ? ( +
    +

    Open the verification page, sign in to ChatGPT, and enter this code.

    + +
    + + Waiting for you to approve… + +
    -
    - ) : null} - + ) : null} + + ) : null } > {!ai.available ? (