diff --git a/site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsx b/site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsx
index ead619fb7e..d086f81eb8 100644
--- a/site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsx
+++ b/site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsx
@@ -2031,14 +2031,13 @@ export const ToolDisplayModesFromPreferences: Story = {
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- expect(canvas.getByText("pnpm test")).toBeVisible();
+ const commandOutputButton = canvas.getByRole("button", {
+ name: "Expand command",
+ });
+ expect(commandOutputButton).toHaveTextContent("Ran pnpm test");
expect(canvas.queryByText("tests passed")).not.toBeInTheDocument();
expect(canvas.getByText(/Edited config\.ts/)).toBeVisible();
expect(canvas.queryAllByTestId("edit-file-diff")).toHaveLength(0);
-
- const commandOutputButton = canvas.getByRole("button", {
- name: "Expand command output",
- });
expect(commandOutputButton).toHaveAttribute("aria-expanded", "false");
await userEvent.click(commandOutputButton);
await waitFor(() => {
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx
index 2400d856ab..bfdf822268 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.stories.tsx
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
-import { expect, screen, userEvent, within } from "storybook/test";
+import { userEvent, within } from "storybook/test";
import { ExecuteTool } from "./ExecuteTool";
const longCommand =
@@ -30,6 +30,13 @@ export const ShortCommand: Story = {
command: "git status",
output: "",
},
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ const summaryButton = await canvas.findByRole("button", {
+ name: "Expand command",
+ });
+ await userEvent.click(summaryButton);
+ },
};
export const RunningWithoutCommand: Story = {
@@ -38,31 +45,26 @@ export const RunningWithoutCommand: Story = {
status: "running",
output: "",
},
- play: async ({ canvasElement }) => {
- const canvas = within(canvasElement);
- expect(canvas.queryByText("$")).not.toBeInTheDocument();
- expect(
- canvas.queryByRole("button", { name: "Copy command" }),
- ).not.toBeInTheDocument();
- },
};
export const LongCommand: Story = {
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
args: {
command: longCommand,
output: "",
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const command = canvas.getByText(longCommand);
- expect(command).toBeVisible();
- expect(
- canvas.queryByRole("button", { name: longCommand }),
- ).not.toBeInTheDocument();
- await userEvent.hover(command);
- expect(
- await screen.findByRole("tooltip", undefined, { timeout: 2000 }),
- ).toHaveTextContent(longCommand);
+ const summaryButton = await canvas.findByRole("button", {
+ name: "Expand command",
+ });
+ await userEvent.click(summaryButton);
},
};
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx
index 602053992c..6620a39229 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ExecuteTool.tsx
@@ -6,7 +6,6 @@ import {
LayersIcon,
LoaderIcon,
OctagonXIcon,
- TerminalIcon,
TriangleAlertIcon,
} from "lucide-react";
import type React from "react";
@@ -79,13 +78,10 @@ const ExecuteToolInner: React.FC = ({
outputInitiallyOpen,
}) => {
const hasCommand = command.trim().length > 0;
- const hasOutput = output.length > 0;
const isRunning = status === "running";
const showFailureIndicator = isError && !isRunning;
const [outputOpen, setOutputOpen] = useState(outputInitiallyOpen);
- const outputToggleLabel = outputOpen
- ? "Collapse command output"
- : "Expand command output";
+ const outputToggleLabel = outputOpen ? "Collapse command" : "Expand command";
const durationLabel = formatShellDurationMs(durationMs);
if (!hasCommand) {
@@ -93,36 +89,20 @@ const ExecuteToolInner: React.FC = ({
}
return (
-
-
-
- {hasOutput ? (
-
- ) : (
-
-
-
- )}
-
-
- {command}
-
-
+
+
{isRunning && (
@@ -174,8 +154,12 @@ const ExecuteToolInner: React.FC = ({
className="-my-0.5 size-6 p-0 opacity-0 transition-opacity hover:bg-surface-tertiary group-hover/exec:opacity-100"
/>
- {hasOutput && outputOpen && (
-
+ {outputOpen && (
+
)}
);
@@ -188,9 +172,8 @@ const ShellCommandLine: React.FC<{
}> = ({ command, durationLabel, expanded }) => {
return (
<>
-
- {command}
+ Ran {command}
{durationLabel && (
@@ -209,24 +192,35 @@ const ShellCommandLine: React.FC<{
);
};
-const ShellOutputBody: React.FC<{
+const ShellTranscriptBody: React.FC<{
+ command: string;
output: string;
isError: boolean;
-}> = ({ output, isError }) => {
+}> = ({ command, output, isError }) => {
return (
-
+
+
+ $
+ {" "}
+ {command}
+
+ {output.length > 0 && (
+
+ {output}
+
)}
- >
- {output}
-
+
);
};
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.stories.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.stories.tsx
index fc8b23793c..802d114658 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.stories.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.stories.tsx
@@ -99,7 +99,7 @@ export const ExecuteError: Story = {
expect(canvas.getByRole("img", { name: "Command failed" })).toBeVisible();
expect(canvas.queryByText("exit 1")).not.toBeInTheDocument();
await userEvent.click(
- canvas.getByRole("button", { name: "Expand command output" }),
+ canvas.getByRole("button", { name: "Expand command" }),
);
await waitFor(() => {
expect(canvas.getByText(/error line 1/)).toBeVisible();
@@ -144,13 +144,16 @@ export const ExecuteAlwaysCollapsed: Story = {
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- expect(canvas.getByText(executeCommand)).toBeVisible();
+ const commandButton = canvas.getByRole("button", {
+ name: "Expand command",
+ });
+ expect(commandButton).toHaveTextContent(`Ran ${executeCommand}`);
expect(canvas.queryByText("exit 0")).not.toBeInTheDocument();
expect(canvas.queryByText("2 lines")).not.toBeInTheDocument();
expect(
canvas.queryByText(/From github\.com:coder\/coder/),
).not.toBeInTheDocument();
- await userEvent.click(canvas.getByText(executeCommand));
+ await userEvent.click(commandButton);
await waitFor(() => {
expect(canvas.getByText(/From github\.com:coder\/coder/)).toBeVisible();
});
@@ -174,11 +177,11 @@ export const ExecuteLongCommandCollapsed: Story = {
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const command = canvas.getByText(longExecuteCommand);
- expect(command).toBeVisible();
- expect(
- canvas.queryByRole("button", { name: longExecuteCommand }),
- ).not.toBeInTheDocument();
+ const commandButton = canvas.getByRole("button", {
+ name: "Expand command",
+ });
+ expect(commandButton).toHaveTextContent(`Ran ${longExecuteCommand}`);
+ expect(commandButton).toHaveAttribute("aria-expanded", "false");
expect(canvas.queryByText("exit 0")).not.toBeInTheDocument();
expect(canvas.getByText("47.2s")).toBeVisible();
expect(canvas.queryByText("61 lines")).not.toBeInTheDocument();