import { Trans, useLingui } from "@lingui/react/macro"; import type { Bot, Routine, RunActivityRow, Space } from "@rakazo/contracts"; import { projectThreads } from "@rakazo/core"; import { BotAvatar, Button, cn } from "@rakazo/ui-web"; import { Clock, FolderOpen, GitBranch, Pencil, Plus, Settings, Target } from "lucide-react"; import type { ReactNode } from "react"; import { useState } from "react"; import { ProjectIcon } from "../../components/project-icon"; import { isNeedsYouStatus } from "../../lib/agent-activity"; import { useRunActivity } from "../../lib/run-activity"; import { ActivityRow } from "../ActivityList"; import { RoutineListRow } from "../RoutineEditor"; import { FALLBACK_BOT_COLOR } from "./shell-types"; type Section = "needsYou" | "running" | "done"; /** * The coordinator's view of its project: project identity, mission goal, context badges, * project specialist roster, sub-thread creation launcher, and delegated task activity. */ export function ProjectOverview({ spaceId, space, coordinator, routines = [], runningRoutineId, togglingRoutineId, onToggleRoutineActive, onOpenRoutine, onStopRun, onOpenRun, onOpenBot, onOpenNewInquiry, onEditProject, }: { spaceId: string; space?: Space; coordinator?: { threadId: string; botId?: string }; routines?: readonly Routine[]; runningRoutineId?: string | null; togglingRoutineId?: string | null; onToggleRoutineActive?: (routine: Routine, active: boolean) => void; onOpenRoutine?: (routine: Routine) => void; onStopRun?: () => void; onOpenRun: (run: RunActivityRow) => void; onOpenBot?: (botId: string) => void; onOpenNewInquiry?: () => void; onEditProject?: () => void; }) { const { t } = useLingui(); const activity = useRunActivity(); const threads = projectThreads(activity, { spaceId, coordinator }); // null until the user picks; "none" once they closed every group. const [open, setOpen] = useState
(null); const sections: { id: Section; runs: RunActivityRow[]; label: ReactNode; tone: string }[] = [ { id: "needsYou", runs: threads.needsYou, label: Needs you, tone: "text-warning", }, { id: "running", runs: threads.running, label: Running, tone: "text-foreground", }, { id: "done", runs: threads.done, label: Done, tone: "text-muted-foreground" }, ]; const visible = sections.filter((section) => section.runs.length > 0); const isProjectSpace = Boolean(space && !space.isDefault); // If not a project space and no runs, keep hidden if (!isProjectSpace && visible.length === 0) return null; // Waiting or actively running threads start open automatically so progress is visible right away. const shown = open ?? (threads.needsYou.length > 0 ? "needsYou" : threads.running.length > 0 ? "running" : null); const current = visible.find((section) => section.id === shown); const folderPath = space?.workspace?.path; const gitRemote = space?.workspace?.git?.remoteUrl; const goal = space?.goal; const projectBots = space?.bots ?? []; const coordinatorWorking = projectBots.some( (member) => member.status && member.status !== "idle" && member.status !== "ready" && member.status !== "done", ) || activity.active.some((row) => row.spaceId === spaceId); return (
{isProjectSpace && space ? (
{space.name} {onEditProject ? ( ) : null}
{onOpenNewInquiry ? ( ) : null}
{goal ? (
{goal}
) : onEditProject ? ( ) : null} {folderPath || gitRemote ? (
{folderPath ? (
{folderPath}
) : null} {gitRemote ? ( {gitRemote.replace(/^https?:\/\/(www\.)?github\.com\//, "")} ) : null}
) : null} {projectBots.length > 0 ? (
Team
{projectBots.map((member) => { const displayName = member.name === "Chief" || member.name === "Projektkoordinator" ? "Projektmanager" : member.name; const isWorking = Boolean( member.status && member.status !== "idle" && member.status !== "ready" && member.status !== "done", ); return ( ); })}
) : null}
) : null} {visible.length > 0 ? (
{visible.map((section) => ( ))}
{current ? (
{current.runs.map((run) => ( onOpenRun(run)} /> ))}
) : null}
) : isProjectSpace ? ( coordinatorWorking ? (
) : (
No runs yet
) ) : null} {isProjectSpace ? (
Routines
{routines.length > 0 ? (
{routines.map((routine) => ( onToggleRoutineActive?.(routine, next)} onOpen={() => onOpenRoutine?.(routine)} onStop={() => onStopRun?.()} /> ))}
) : (
Just ask in the chat whenever something should happen regularly.
)}
) : null}
); } /** * 1:1 Agent overview in the side panel: agent identity & status, active and recent * task runs for this specific agent, and its scheduled routines. */ export function AgentOverview({ bot, running = false, routines = [], runningRoutineId, togglingRoutineId, onToggleRoutineActive, onOpenRoutine, onAddRoutine, onStopRun, onOpenRun, onOpenSettings, }: { bot: Bot; running?: boolean; routines?: readonly Routine[]; runningRoutineId?: string | null; togglingRoutineId?: string | null; onToggleRoutineActive?: (routine: Routine, active: boolean) => void; onOpenRoutine?: (routine: Routine) => void; onAddRoutine?: () => void; onStopRun?: () => void; onOpenRun: (run: RunActivityRow) => void; onOpenSettings?: () => void; }) { const { t } = useLingui(); const { active: allActiveRuns, recent: allRecentRuns } = useRunActivity(); const botActiveRuns = allActiveRuns.filter((run) => run.botId === bot.id); const botRecentRuns = allRecentRuns.filter((run) => run.botId === bot.id); const needsYouCount = botActiveRuns.filter((run) => isNeedsYouStatus(run.status)).length; const isWorking = running || botActiveRuns.length > 0; return (
{/* Agent Identity & Status Card */}
{bot.name} {bot.title ? ( {bot.title} ) : null}
{needsYouCount > 0 ? ( Needs you ) : isWorking ? ( Working ) : ( Ready )}
{onOpenSettings ? ( ) : null}
{bot.description ? (

{bot.description}

) : null}
{/* Agent Runs & Tasks */}
Run history
{botActiveRuns.length > 0 ? (
Now
{botActiveRuns.map((run) => ( onOpenRun(run)} /> ))}
) : null} {botRecentRuns.length > 0 ? (
{botActiveRuns.length > 0 ? (
Recent
) : null} {botRecentRuns.slice(0, 8).map((run) => ( onOpenRun(run)} /> ))}
) : botActiveRuns.length === 0 ? (
No runs yet
) : null}
{/* Scheduled Routines for this 1:1 Agent */}
Routines {onAddRoutine ? ( ) : null}
{routines.length > 0 ? (
{routines.map((routine) => ( onToggleRoutineActive?.(routine, next)} onOpen={() => onOpenRoutine?.(routine)} onStop={() => onStopRun?.()} /> ))}
) : (
Just ask in the chat whenever something should happen regularly.
)}
); }