diff --git a/.gitignore b/.gitignore index 16f234a37..8ed8c0e1b 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,5 @@ plugins/posthog/local-skills/ # Symlinked copies of posthog, to make developing against those APIs easier posthog-sym +.pi-lens/ +Progress.md diff --git a/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.test.tsx b/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.test.tsx new file mode 100644 index 000000000..45b4ab475 --- /dev/null +++ b/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.test.tsx @@ -0,0 +1,60 @@ +import type { ToolCall } from "@features/sessions/types"; +import { render } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import { ExecuteToolView } from "./ExecuteToolView"; + +vi.mock("@phosphor-icons/react", () => ({ + Terminal: () => TerminalIcon, + Minus: () => MinusIcon, + Plus: () => PlusIcon, +})); + +vi.mock("@utils/path", () => ({ + compactHomePath: (p: string) => p, +})); + +const baseToolCall: ToolCall = { + toolCallId: "test-exec-1", + title: "Run tests", + kind: "execute", + status: "completed", + content: [], + locations: [], + rawInput: { + command: "pnpm test -- --run", + description: "Run tests", + }, +}; + +describe("ExecuteToolView", () => { + it("aligns icon vertically centered with text content", () => { + const { container } = render(); + // The outermost flex should use align="center" for consistent icon alignment + // Radix renders this as rt-r-ai-center + const outerFlex = container.querySelector(".min-w-0"); + expect(outerFlex?.className).toContain("rt-r-ai-center"); + }); + + it("applies min-w-0 to prevent text overflow", () => { + const { container } = render(); + const outerFlex = container.querySelector(".min-w-0"); + expect(outerFlex?.className).toContain("min-w-0"); + }); + + it("truncates long commands to prevent overflow", () => { + const longCommand = + "find /very/long/path -type f -name '*.ts' | xargs grep -l 'pattern' | head -100"; + const { container } = render( + , + ); + // Command text should have truncation class + // The command text should be in a truncated container + const truncatedContainer = container.querySelector(".truncate"); + expect(truncatedContainer).toBeTruthy(); + }); +}); diff --git a/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.tsx b/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.tsx index a0a80930a..e0d91254b 100644 --- a/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.tsx +++ b/apps/code/src/renderer/features/sessions/components/session-update/ExecuteToolView.tsx @@ -55,8 +55,8 @@ export function ExecuteToolView({ className={`group py-0.5 ${isExpandable ? "cursor-pointer" : ""}`} onClick={handleClick} > - - + + - {description && {description}} + {description && ( + {description} + )} {command && ( - + {truncateText(compactHomePath(command), MAX_COMMAND_LENGTH)} diff --git a/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.test.tsx b/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.test.tsx new file mode 100644 index 000000000..484bd8a9c --- /dev/null +++ b/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.test.tsx @@ -0,0 +1,43 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import { ThoughtView } from "./ThoughtView"; + +// Mock phosphor icons to avoid rendering issues in jsdom +vi.mock("@phosphor-icons/react", () => ({ + Brain: () => BrainIcon, + Plus: () => PlusIcon, + Minus: () => MinusIcon, +})); + +describe("ThoughtView", () => { + it("applies left padding consistent with other tool views (pl-3)", () => { + const { container } = render( + , + ); + // ThoughtView root should have pl-3 to align with AgentMessage and ToolCallBlock + const root = container.firstElementChild; + expect(root?.className).toContain("pl-3"); + }); + + it("renders the Thinking label", () => { + render(); + expect(screen.getByText("Thinking")).toBeInTheDocument(); + }); + + it("applies min-w-0 for text overflow containment", () => { + const { container } = render( + , + ); + const root = container.firstElementChild; + expect(root?.className).toContain("min-w-0"); + }); + + it("aligns icon vertically centered with text", () => { + const { container } = render( + , + ); + // The button should use flex with items-center for icon alignment + const button = container.querySelector("button"); + expect(button?.className).toContain("items-center"); + }); +}); diff --git a/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.tsx b/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.tsx index fb4f5e3c8..ab0ceeb26 100644 --- a/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.tsx +++ b/apps/code/src/renderer/features/sessions/components/session-update/ThoughtView.tsx @@ -26,7 +26,7 @@ export const ThoughtView = memo(function ThoughtView({ : contentLines.slice(0, COLLAPSED_LINE_COUNT).join("\n"); return ( - +