diff --git a/app/[workspace]/project/[projectId]/(home)/plan/page.tsx b/app/[workspace]/project/[projectId]/(home)/plan/page.tsx index 713f5a06..d384542a 100644 --- a/app/[workspace]/project/[projectId]/(home)/plan/page.tsx +++ b/app/[workspace]/project/[projectId]/(home)/plan/page.tsx @@ -19,22 +19,45 @@ import { useCallback, useEffect, useState } from "react"; import { useParams } from "next/navigation"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; import { - Loader2, AlertCircle, Lightbulb, ListTodo, GitBranch, - Sparkles, Plus, Trash2, Check, RotateCcw, Pencil, X, + Loader2, AlertCircle, MessageSquare, ListTodo, GitBranch, + Target, Plus, Trash2, Check, RotateCcw, Pencil, X, Eye, FileText, } from "lucide-react"; interface Idea { id: string; text: string; createdAt: string } -interface Task { id: string; text: string; status: "open" | "done"; createdAt: string; doneAt?: string } +type TaskStatus = "open" | "in_progress" | "done" | "blocked"; +interface Task { + id: string; + title: string; + description?: string; + status: TaskStatus; + agent?: { runId: string; startedAt: string; finishedAt?: string; status: "queued" | "running" | "succeeded" | "failed" } | null; + createdAt: string; + startedAt?: string; + doneAt?: string; + // Legacy single-line tasks (pre-markdown migration) carry text instead of title. + text?: string; +} interface Decision { id: string; title: string; choice: string; why?: string; createdAt: string } interface Plan { - vision?: string; - ideas: Idea[]; + vision?: string; // stored as `vision` server-side, surfaced as "Objective" in the UI + ideas: Idea[]; // legacy bin — no longer surfaced; kept on the model for backward compat tasks: Task[]; decisions: Decision[]; } -type Section = "vision" | "ideas" | "tasks" | "decisions"; +interface Session { + id: string; + title: string; + summary: string | null; + messageCount: number; + updatedAt: string; + createdAt: string; +} + +type Section = "objective" | "sessions" | "tasks" | "decisions"; interface SectionDef { key: Section; @@ -44,10 +67,10 @@ interface SectionDef { } const SECTIONS: SectionDef[] = [ - { key: "vision", label: "Vision", icon: Sparkles, blurb: "What you're building, in one sentence." }, - { key: "tasks", label: "Tasks", icon: ListTodo, blurb: "What needs to happen next." }, - { key: "decisions", label: "Decisions", icon: GitBranch, blurb: "Choices already made — so we stop re-litigating them." }, - { key: "ideas", label: "Ideas", icon: Lightbulb, blurb: "Raw capture. Park half-thoughts here." }, + { key: "objective", label: "Objective", icon: Target, blurb: "What you're building, who it's for, and why." }, + { key: "tasks", label: "Tasks", icon: ListTodo, blurb: "What needs to happen next." }, + { key: "decisions", label: "Decisions", icon: GitBranch, blurb: "Choices already made — so we stop re-litigating them." }, + { key: "sessions", label: "Sessions", icon: MessageSquare, blurb: "Past chat sessions for this project." }, ]; // ────────────────────────────────────────────────── @@ -57,11 +80,13 @@ const SECTIONS: SectionDef[] = [ export default function PlanTab() { const params = useParams(); const projectId = params.projectId as string; + const workspace = params.workspace as string; const [plan, setPlan] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [active, setActive] = useState
("vision"); + const [active, setActive] = useState
("objective"); + const [sessionCount, setSessionCount] = useState(0); const load = useCallback(async () => { try { @@ -100,14 +125,103 @@ export default function PlanTab() { } const counts: Record = { - vision: plan.vision ? 1 : 0, - ideas: plan.ideas.length, - tasks: plan.tasks.filter((t) => t.status === "open").length, + objective: plan.vision ? 1 : 0, + sessions: sessionCount, + tasks: plan.tasks.filter((t) => t.status !== "done").length, decisions: plan.decisions.length, }; return (
+