Teams UI: deploy scope selector + TeamWizard + Team page
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled

The "+" deploy flow now opens a scope selector (Single / Team / Company-soon /
Org-soon). Single = the existing CreateClawForm. Team = TeamWizard: pick a
baseline topology (from the catalog + role distribution), set size, auto-staff
editable claw cards (name / role / model / persona), preview the topology
graph, then POST /api/teams → land on the Team page.

Team page (/teams/[id]): topology SVG + claw roster (each links to its chat) +
a Run panel that drives the team on the durable runner with live SSE progress
(reuses the topology-run streaming). /teams list page + a Teams nav entry.

lint + typecheck + next build clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-18 13:17:30 -07:00
co-authored by Claude Opus 4.8
parent 8123a27bcf
commit bba18a4687
7 changed files with 575 additions and 7 deletions
@@ -0,0 +1,50 @@
"use client";
// The deploy ladder entry: choose a scale (single / team / company / org) then
// branch into the matching wizard. Single = max fidelity; Team = a baseline
// topology staffed with templated claws. Company/Org are next rungs.
import { useState } from "react";
import { CreateClawForm } from "./CreateClawForm";
import { TeamWizard } from "./TeamWizard";
type Scope = "choose" | "single" | "team";
const TIERS: { key: Scope; title: string; blurb: string; soon?: boolean }[] = [
{ key: "single", title: "Single claw", blurb: "One agent, crafted by you — maximum control & fidelity." },
{ key: "team", title: "Team", blurb: "A baseline topology staffed with templated claws." },
{ key: "company" as Scope, title: "Company", blurb: "A topology of teams.", soon: true },
{ key: "org" as Scope, title: "Organization", blurb: "Multiple company templates.", soon: true },
];
export function DeployWizard() {
const [scope, setScope] = useState<Scope>("choose");
if (scope === "single") return <CreateClawForm />;
if (scope === "team") return <TeamWizard />;
return (
<div className="grid w-full max-w-2xl grid-cols-1 gap-3 sm:grid-cols-2">
{TIERS.map((t) => (
<button
key={t.title}
type="button"
disabled={t.soon}
onClick={() => !t.soon && setScope(t.key)}
className={`rounded-xl border p-4 text-left transition-colors ${
t.soon
? "border-border/60 opacity-50"
: "border-border hover:border-coral hover:bg-surface-warm"
}`}
>
<p className="text-sm font-semibold text-foreground">
{t.title}
{t.soon ? <span className="ml-2 text-xxs text-muted-foreground">soon</span> : null}
</p>
<p className="mt-1 text-xs text-muted-foreground">{t.blurb}</p>
</button>
))}
</div>
);
}