From c9db6e9a1fe181fad2259689ef4ad9a5e89fbd5b Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:47:42 +1000 Subject: [PATCH] fix(app): show running shell command (#38080) Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> --- .../session-timeline-lifecycle-state.spec.ts | 17 +++++++++++++++++ .../session-ui/src/components/basic-tool.tsx | 5 +++-- .../session-ui/src/components/message-part.tsx | 3 ++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/app/e2e/regression/session-timeline-lifecycle-state.spec.ts b/packages/app/e2e/regression/session-timeline-lifecycle-state.spec.ts index 3e2b171bca..b303071c87 100644 --- a/packages/app/e2e/regression/session-timeline-lifecycle-state.spec.ts +++ b/packages/app/e2e/regression/session-timeline-lifecycle-state.spec.ts @@ -32,6 +32,23 @@ for (const expanded of [false, true]) { }) } +test("shows and expands a running shell command without shimmering it", async ({ page }) => { + const id = "prt_shell_running_command" + const command = "sleep 10 && echo done" + await setupTimeline(page, { + messages: [userMessage(), assistantMessage([shell(id, "running", "still running", command)], { completed: false })], + settings: { shellToolPartsExpanded: false }, + }) + + const tool = page.locator(`[data-timeline-part-id="${id}"]`) + await expect(tool.locator('[data-component="text-shimmer"]')).toHaveAttribute("data-active", "true") + await expect(tool.locator('[data-component="shell-submessage"]')).toHaveText(command) + await expect(tool.locator('[data-component="shell-submessage"] [data-component="text-shimmer"]')).toHaveCount(0) + await tool.locator('[data-slot="collapsible-trigger"]').click() + await expect(tool.locator('[data-slot="collapsible-trigger"]')).toHaveAttribute("aria-expanded", "true") + await expect(tool.locator('[data-slot="bash-pre"]')).toContainText("still running") +}) + test("transitions thinking and hidden reasoning through busy to idle", async ({ page }) => { const reasoningID = "prt_reasoning_hidden" const assistant = assistantMessage([reasoningPart(reasoningID, "## Inspecting stability")], { completed: false }) diff --git a/packages/session-ui/src/components/basic-tool.tsx b/packages/session-ui/src/components/basic-tool.tsx index a3ce5c13b5..2b73db24ed 100644 --- a/packages/session-ui/src/components/basic-tool.tsx +++ b/packages/session-ui/src/components/basic-tool.tsx @@ -32,6 +32,7 @@ export interface BasicToolProps { open?: boolean onOpenChange?: (open: boolean) => void forceOpen?: boolean + allowOpenWhilePending?: boolean defer?: boolean locked?: boolean animated?: boolean @@ -176,7 +177,7 @@ export function BasicTool(props: BasicToolProps) { }) const handleOpenChange = (value: boolean) => { - if (pending()) return + if (pending() && !props.allowOpenWhilePending) return if (props.locked && !value) return setOpen(value) } @@ -247,7 +248,7 @@ export function BasicTool(props: BasicToolProps) { - + diff --git a/packages/session-ui/src/components/message-part.tsx b/packages/session-ui/src/components/message-part.tsx index 601d7839ef..ce2f7b25c3 100644 --- a/packages/session-ui/src/components/message-part.tsx +++ b/packages/session-ui/src/components/message-part.tsx @@ -2126,13 +2126,14 @@ ToolRegistry.register({ (
- +