import { Link, createFileRoute } from "@tanstack/react-router" import { useQuery } from "@tanstack/react-query" import { useEffect, useState } from "react" import { ArrowLeft } from "lucide-react" import { PlanReview } from "@/components/agents/PlanReview" import { Skeleton } from "@/components/ui/skeleton" import { PlanApiError, getPlan } from "@/lib/plan" export const Route = createFileRoute("/agents/$threadId_/plan")({ component: PlanPage, }) function Centered({ children }: { children: React.ReactNode }) { return (
{children}
) } function BackLink({ threadId }: { threadId: string }) { return ( Back to conversation ) } function PlanPage() { const { threadId } = Route.useParams() // BlockNote + Yjs are browser-only; mount client-side before rendering. const [mounted, setMounted] = useState(false) useEffect(() => setMounted(true), []) const query = useQuery({ queryKey: ["plan", threadId], queryFn: () => getPlan(threadId), // The agent shares the link as soon as it enters plan mode, before the plan // is written — poll until the plan content is published. refetchInterval: (q) => (q.state.data?.markdown ? false : 2000), retry: (count, error) => !( error instanceof PlanApiError && (error.status === 401 || error.status === 404) ) && count < 3, }) if (!mounted || query.isLoading) { return ( ) } if (query.isError) { const status = query.error instanceof PlanApiError ? query.error.status : 0 return (

{status === 401 ? "Please sign in to view this plan." : "This plan could not be found."}

) } const plan = query.data if (!plan) { return ( ) } if (!plan.markdown.trim()) { return (

The agent is still writing the plan. This page will update automatically…

) } return (
) }