import { MessageSquare, X, ChevronDown } from "lucide-react";
import type { TaskDetail } from "../api";
import { Markdown } from "./Markdown";
import { Badge, statusVariant } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from "@/components/ui/collapsible";
import { cn } from "@/lib/utils";
import { formatEastern } from "@/lib/time";
interface Props {
detail: TaskDetail | null;
loading: boolean;
error: string | null;
onClose: () => void;
}
function fmtDuration(s: number | null): string {
if (s == null) return "—";
if (s < 60) return `${s.toFixed(1)}s`;
if (s < 3600) return `${(s / 60).toFixed(1)}m`;
return `${(s / 3600).toFixed(1)}h`;
}
function fmtCost(usd: number): string {
return usd > 0 ? `$${usd.toFixed(4)}` : "—";
}
// Right-hand drawer: a task's journey through the pipeline (vertical timeline of
// task_transitions) plus Q&A, review verdicts, plan summary, and total spend.
export function TaskDrawer({ detail, loading, error, onClose }: Props) {
if (!detail && !loading && !error) return null;
const isWaiting = detail?.ok && detail.status === "waiting_human";
const isClarifyGate =
isWaiting && detail?.current_phase === "clarify";
return (
{detail.task}
Partial history — recorded since the v3 ledger; earlier
steps are reconstructed.
Input requested
{isClarifyGate
? "The pipeline needs clarification before planning."
: "The pipeline is awaiting a human decision to proceed."}
Answer in Slack{" "}
#agent-team
Timeline
Task history
{detail.short_id}
spend {fmtCost(detail.total_usd)}
{detail.timeline.map((step, i) => {
const open = step.exited_at == null;
const isLast = i === detail.timeline.length - 1;
return (
{title}
{JSON.stringify(plan, null, 2)}
);
}
return (
{name}
{steps.length > 0 && (