diff --git a/packages/web/src/components/Dashboard.tsx b/packages/web/src/components/Dashboard.tsx
index 4bbfa520f..cd36c63ee 100644
--- a/packages/web/src/components/Dashboard.tsx
+++ b/packages/web/src/components/Dashboard.tsx
@@ -169,6 +169,10 @@ function DashboardInner({
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const isMobile = useMediaQuery(MOBILE_BREAKPOINT);
+ const debugParam = searchParams.get("debug");
+ const showDebugBundleButton =
+ !isMobile &&
+ (process.env.NODE_ENV === "development" || debugParam === "1" || debugParam === "true");
const showSidebar = projects.length >= 1;
const { showToast } = useToast();
const [doneExpanded, setDoneExpanded] = useState(false);
@@ -498,6 +502,7 @@ function DashboardInner({
{headerProjectLabel}
>
) : null}
+ {showDebugBundleButton ? : null}
{!allProjectsView && orchestratorHref ? (
@@ -549,7 +554,6 @@ function DashboardInner({
{isSpawningCurrentProject ? "Spawning..." : "Spawn Orchestrator"}
) : null}
- {!isMobile ? : null}
diff --git a/packages/web/src/components/__tests__/Dashboard.debugBundleVisibility.test.tsx b/packages/web/src/components/__tests__/Dashboard.debugBundleVisibility.test.tsx
new file mode 100644
index 000000000..216bd53e7
--- /dev/null
+++ b/packages/web/src/components/__tests__/Dashboard.debugBundleVisibility.test.tsx
@@ -0,0 +1,57 @@
+import { render, screen } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import { Dashboard } from "../Dashboard";
+
+let search = "";
+
+vi.mock("next/navigation", () => ({
+ useRouter: () => ({ push: vi.fn(), replace: vi.fn(), refresh: vi.fn() }),
+ usePathname: () => "/",
+ useSearchParams: () => new URLSearchParams(search),
+}));
+
+function mockDesktopViewport() {
+ Object.defineProperty(window, "matchMedia", {
+ writable: true,
+ value: (query: string) => ({
+ matches: !query.includes("max-width: 767px"),
+ media: query,
+ onchange: null,
+ addListener: () => {},
+ removeListener: () => {},
+ addEventListener: () => {},
+ removeEventListener: () => {},
+ dispatchEvent: () => false,
+ }),
+ });
+}
+
+describe("Dashboard debug bundle visibility", () => {
+ beforeEach(() => {
+ search = "";
+ mockDesktopViewport();
+ const eventSourceMock = {
+ onmessage: null,
+ onerror: null,
+ close: vi.fn(),
+ };
+ const eventSourceConstructor = vi.fn(() => eventSourceMock as unknown as EventSource);
+ global.EventSource = Object.assign(eventSourceConstructor, {
+ CONNECTING: 0,
+ OPEN: 1,
+ CLOSED: 2,
+ }) as unknown as typeof EventSource;
+ global.fetch = vi.fn();
+ });
+
+ it("hides debug bundle button by default", () => {
+ render();
+ expect(screen.queryByRole("button", { name: /Copy debug bundle for issue reports/i })).toBeNull();
+ });
+
+ it("shows debug bundle button when debug query flag is enabled", () => {
+ search = "debug=1";
+ render();
+ expect(screen.getByRole("button", { name: /Copy debug bundle for issue reports/i })).toBeInTheDocument();
+ });
+});