"use client" import { CheckCircle2, Circle, Play, AlertTriangle, ChevronRight } from "lucide-react" import { cn } from "@/lib/utils" import { getLiveWorkspaceIndex, useSFWorkspaceState, type RiskLevel } from "@/lib/sf-workspace-store" import { getMilestoneStatus, getSliceStatus, type ItemStatus } from "@/lib/workspace-status" const StatusIcon = ({ status, size = "default", }: { status: ItemStatus size?: "default" | "large" }) => { const sizeClass = size === "large" ? "h-5 w-5" : "h-4 w-4" if (status === "done") { return } if (status === "in-progress") { return } return } const RiskBadge = ({ risk }: { risk: RiskLevel }) => { return ( {risk === "high" && } {risk} ) } export function Roadmap() { const workspace = useSFWorkspaceState() const liveWorkspace = getLiveWorkspaceIndex(workspace) const milestones = liveWorkspace?.milestones ?? [] const activeScope = liveWorkspace?.active ?? {} const workspaceFreshness = workspace.live.freshness.workspace.stale ? "stale" : workspace.live.freshness.workspace.status return (

Roadmap

Project milestone structure with slices and dependencies

Workspace freshness: {workspaceFreshness}

{workspace.bootStatus === "loading" && (
Loading workspace…
)} {workspace.bootStatus === "ready" && milestones.length === 0 && (
No milestones found. Create a milestone with /sf to get started.
)}
{milestones.map((milestone) => { const milestoneStatus = getMilestoneStatus(milestone, activeScope) const doneSlices = milestone.slices.filter((s) => s.done).length const totalTasks = milestone.slices.reduce((acc, s) => acc + s.tasks.length, 0) const doneTasks = milestone.slices.reduce((acc, s) => acc + s.tasks.filter((t) => t.done).length, 0) return (
{milestone.id} {milestone.title}
{doneSlices}/{milestone.slices.length} slices
{doneTasks}/{totalTasks} tasks
{milestone.slices.map((slice) => { const sliceStatus = getSliceStatus(milestone.id, slice, activeScope) const sliceDoneTasks = slice.tasks.filter((t) => t.done).length const sliceTotalTasks = slice.tasks.length return (
{slice.id} {slice.title} {slice.risk && } {slice.depends && slice.depends.length > 0 && ( depends on {slice.depends.join(", ")} )}
0 ? `${(sliceDoneTasks / sliceTotalTasks) * 100}%` : "0%", }} />
{sliceDoneTasks}/{sliceTotalTasks}
) })}
) })}
) }