import { useNavigate, useParams, useRouterState } from "@tanstack/react-router"; import { ChevronRight, GitPullRequest, Moon, Plus, Search, Settings, Sun, Waypoints } from "lucide-react"; import { useState } from "react"; import { attentionZone, sessionIsActive, type WorkspaceSession, type WorkspaceSummary, workerSessions, } from "../types/workspace"; import { aoBridge } from "../lib/bridge"; import { useEventsConnection } from "../hooks/useEventsConnection"; import { useResizable } from "../hooks/useResizable"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "./ui/dropdown-menu"; import { Sidebar as SidebarRoot, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarTrigger, useSidebar, } from "./ui/sidebar"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; import { cn } from "../lib/utils"; import { useUiStore } from "../stores/ui-store"; // The macOS hiddenInset traffic lights and the fixed TitlebarNav overlay live // in the full-width topbar's left inset (_shell renders the bar above the // sidebar row); the sidebar itself starts below the 56px header, so its border // never crosses the titlebar strip. const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.userAgent); const noDragStyle = isMac ? ({ WebkitAppRegion: "no-drag" } as React.CSSProperties) : undefined; type SidebarProps = { daemonStatus: { state: string; message?: string }; workspaceError?: string; workspaces: WorkspaceSummary[]; onCreateProject: (input: { path: string }) => Promise; onNewWorker: (projectId: string) => void; }; // Selection state comes from the URL: which project/session is active is the // route params, and clicks navigate rather than mutate a store. function useSelection() { const navigate = useNavigate(); const params = useParams({ strict: false }) as { projectId?: string; sessionId?: string }; const pathname = useRouterState({ select: (state) => state.location.pathname }); return { isHome: pathname === "/", activeProjectId: params.projectId, activeSessionId: params.sessionId, goHome: () => void navigate({ to: "/" }), goPrs: () => void navigate({ to: "/prs" }), goSettings: (projectId: string) => void navigate({ to: "/projects/$projectId/settings", params: { projectId } }), goProject: (projectId: string) => void navigate({ to: "/projects/$projectId", params: { projectId } }), goSession: (projectId: string, sessionId: string) => void navigate({ to: "/projects/$projectId/sessions/$sessionId", params: { projectId, sessionId } }), }; } // agent-orchestrator's SessionDot: 6px dot, neutral grey at rest, orange + // breathe while the agent is working. Other attention zones stay neutral here // (the board carries the richer colour coding). function SessionDot({ session }: { session: WorkspaceSession }) { const working = attentionZone(session) === "working"; return (