"use client"; // Team roster for a mission. Fetches the mission's team (via // /api/teams/{id}) and lists each claw with its role + a link that // hands the operator over to AGENT tier with that claw selected — // where the existing WorkingOnNow / ReasoningStream / metrics live. import { useEffect, useState } from "react"; import { ArrowUpRight, User } from "lucide-react"; const mono = "ui-monospace, SFMono-Regular, SF Mono, Menlo, Monaco, Consolas, monospace"; interface Member { claw_id: string; role: string; node_id?: string; } interface TeamDetail { name?: string; members: Member[]; } interface Claw { id: string; name: string; job_title?: string | null; } export function MissionTeamTab({ teamId, onOpenClaw, }: { teamId: string | null; onOpenClaw?: (clawId: string) => void; }) { const [team, setTeam] = useState(null); const [claws, setClaws] = useState>({}); const [error, setError] = useState(null); useEffect(() => { if (!teamId) { // eslint-disable-next-line react-hooks/set-state-in-effect setTeam(null); return; } let alive = true; (async () => { try { const [tRes, cRes] = await Promise.all([ fetch(`/api/teams/${teamId}`), fetch(`/api/team/claws`), ]); if (!tRes.ok) throw new Error(`team ${tRes.status}`); const detail = (await tRes.json()) as TeamDetail; const clawList = cRes.ok ? ((await cRes.json()) as Claw[]) : []; if (!alive) return; setTeam(detail); setClaws(Object.fromEntries(clawList.map((c) => [c.id, c]))); } catch (e) { if (alive) setError(e instanceof Error ? e.message : "load failed"); } })(); return () => { alive = false; }; }, [teamId]); if (!teamId) { return (
No team yet. Launch the mission to materialize a team from the picked template.
); } if (error) { return
{error}
; } if (!team) { return (
Loading…
); } return (
{team.name ?? "Team"} · {team.members.length} member {team.members.length === 1 ? "" : "s"}
{team.members.length === 0 ? (
Team has no members yet (orchestrator may still be materializing).
) : ( team.members.map((m) => { const claw = claws[m.claw_id]; return (
{claw?.name ?? `claw ${m.claw_id.slice(0, 8)}`}
{m.role}
{onOpenClaw && ( )}
); }) )}
); }