diff --git a/frontend/src/landing/public/ao-logo.png b/frontend/src/landing/public/ao-logo.png
index b8b0a57e..a77e2fd2 100644
Binary files a/frontend/src/landing/public/ao-logo.png and b/frontend/src/landing/public/ao-logo.png differ
diff --git a/frontend/src/renderer/assets/ao-logo.png b/frontend/src/renderer/assets/ao-logo.png
index b8b0a57e..a7b47ff8 100644
Binary files a/frontend/src/renderer/assets/ao-logo.png and b/frontend/src/renderer/assets/ao-logo.png differ
diff --git a/frontend/src/renderer/assets/dashboard-logo.png b/frontend/src/renderer/assets/dashboard-logo.png
new file mode 100644
index 00000000..034eddfa
Binary files /dev/null and b/frontend/src/renderer/assets/dashboard-logo.png differ
diff --git a/frontend/src/renderer/assets/orchestrator-logo.png b/frontend/src/renderer/assets/orchestrator-logo.png
new file mode 100644
index 00000000..2212ae9e
Binary files /dev/null and b/frontend/src/renderer/assets/orchestrator-logo.png differ
diff --git a/frontend/src/renderer/components/ShellTopbar.tsx b/frontend/src/renderer/components/ShellTopbar.tsx
index 1041b7f6..79abe6db 100644
--- a/frontend/src/renderer/components/ShellTopbar.tsx
+++ b/frontend/src/renderer/components/ShellTopbar.tsx
@@ -1,10 +1,9 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useNavigate, useParams } from "@tanstack/react-router";
-import { GitBranch, LayoutDashboard, PanelRightClose, PanelRightOpen, Square } from "lucide-react";
+import { GitBranch, PanelRightClose, PanelRightOpen, Square } from "lucide-react";
import { useState } from "react";
import {
findProjectOrchestrator,
- isOrchestratorSession,
sessionIsActive,
workerDisplayStatus,
type WorkerDisplayStatus,
@@ -14,7 +13,8 @@ import { useWorkspaceQuery, workspaceQueryKey } from "../hooks/useWorkspaceQuery
import { apiClient, apiErrorMessage } from "../lib/api-client";
import { spawnOrchestrator } from "../lib/spawn-orchestrator";
import { useUiStore } from "../stores/ui-store";
-import { OrchestratorIcon } from "./icons";
+import dashboardLogo from "../assets/dashboard-logo.png";
+import orchestratorLogo from "../assets/orchestrator-logo.png";
import { cn } from "../lib/utils";
const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);
@@ -57,7 +57,7 @@ export function ShellTopbar() {
? all.flatMap((workspace) => workspace.sessions).find((s) => s.id === params.sessionId)
: undefined;
const isSessionRoute = Boolean(params.sessionId);
- const isOrchestrator = session ? isOrchestratorSession(session) : false;
+ const isOrchestrator = session?.kind === "orchestrator";
// Project in scope: the session's workspace wins over the route param so the
// cross-project /sessions/$sessionId route still resolves a crumb. A
// projectId that no longer resolves (stale route after the project was
@@ -106,7 +106,7 @@ export function ShellTopbar() {
·
-
+
Orchestrator
@@ -139,20 +139,20 @@ export function ShellTopbar() {
style={noDragStyle}
type="button"
>
-
+
Open Kanban
) : (
)}
{/* Kill control sits beside the orchestrator link for active workers —
@@ -191,7 +191,7 @@ export function ShellTopbar() {
style={noDragStyle}
type="button"
>
-
+
Orchestrator
) : (
@@ -203,7 +203,7 @@ export function ShellTopbar() {
style={noDragStyle}
type="button"
>
-
+
{isSpawning ? "Spawning…" : "Spawn Orchestrator"}
)
diff --git a/frontend/src/renderer/components/Sidebar.tsx b/frontend/src/renderer/components/Sidebar.tsx
index d964bbd0..6594707d 100644
--- a/frontend/src/renderer/components/Sidebar.tsx
+++ b/frontend/src/renderer/components/Sidebar.tsx
@@ -1,17 +1,6 @@
import { useQueryClient } from "@tanstack/react-query";
import { useNavigate, useParams, useRouterState } from "@tanstack/react-router";
-import {
- ChevronRight,
- GitPullRequest,
- LayoutDashboard,
- Moon,
- MoreVertical,
- Plus,
- Search,
- Settings,
- Sun,
- Trash2,
-} from "lucide-react";
+import { ChevronRight, GitPullRequest, Moon, MoreVertical, Plus, Search, Settings, Sun, Trash2 } from "lucide-react";
import { useState } from "react";
import {
attentionZone,
@@ -52,8 +41,9 @@ import {
useSidebar,
} from "./ui/sidebar";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
-import { OrchestratorIcon } from "./icons";
import aoLogo from "../assets/ao-logo.png";
+import dashboardLogo from "../assets/dashboard-logo.png";
+import orchestratorLogo from "../assets/orchestrator-logo.png";
import { cn } from "../lib/utils";
import { useUiStore } from "../stores/ui-store";
@@ -492,7 +482,7 @@ function ProjectItem({
onClick={() => selection.goProject(workspace.id)}
type="button"
>
-
+
Dashboard
@@ -506,7 +496,7 @@ function ProjectItem({
onClick={() => void openOrchestrator()}
type="button"
>
-
+
diff --git a/frontend/src/renderer/components/icons.tsx b/frontend/src/renderer/components/icons.tsx
deleted file mode 100644
index 88276f66..00000000
--- a/frontend/src/renderer/components/icons.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import type { SVGProps } from "react";
-
-// Orchestrator mark: a parent node fanning out to three child nodes, drawn in
-// lucide's 24x24 stroke style so it drops into the same slots as the lucide
-// icons (size comes from `className`/the parent's `[&_svg]:size-*`). Lucide has
-// no 1-parent / 3-child hierarchy glyph, so we author this one to match the
-// org-chart icon called for in the design.
-export function OrchestratorIcon({ className, ...props }: SVGProps) {
- return (
-
- );
-}
diff --git a/frontend/src/renderer/types/workspace.test.ts b/frontend/src/renderer/types/workspace.test.ts
index 6845c37c..886f279e 100644
--- a/frontend/src/renderer/types/workspace.test.ts
+++ b/frontend/src/renderer/types/workspace.test.ts
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import {
attentionZone,
findProjectOrchestrator,
+ isOrchestratorSession,
sessionIsActive,
sessionNeedsAttention,
toAgentProvider,
@@ -46,6 +47,18 @@ describe("toSessionStatus", () => {
});
});
+describe("isOrchestratorSession", () => {
+ it("lets explicit worker kind override an orchestrator-looking id", () => {
+ const worker = sessionWith({ id: "project-orchestrator", kind: "worker" });
+ expect(isOrchestratorSession(worker)).toBe(false);
+ });
+
+ it("keeps the id suffix fallback for legacy sessions without kind", () => {
+ const orchestrator = sessionWith({ id: "project-orchestrator", kind: undefined });
+ expect(isOrchestratorSession(orchestrator)).toBe(true);
+ });
+});
+
describe("workerDisplayStatus", () => {
it("prefers an explicit displayStatus override", () => {
expect(workerDisplayStatus(sessionWith({ status: "ci_failed", displayStatus: "done" }))).toBe("done");
diff --git a/frontend/src/renderer/types/workspace.ts b/frontend/src/renderer/types/workspace.ts
index d401f48b..c9cc22f0 100644
--- a/frontend/src/renderer/types/workspace.ts
+++ b/frontend/src/renderer/types/workspace.ts
@@ -120,7 +120,8 @@ export function workerDisplayStatus(session: WorkspaceSession): WorkerDisplaySta
}
export function isOrchestratorSession(session: WorkspaceSession): boolean {
- return session.kind === "orchestrator" || session.id.endsWith("-orchestrator");
+ if (session.kind) return session.kind === "orchestrator";
+ return session.id.endsWith("-orchestrator");
}
/**