From f7b2191ff3a379b4dea9c65c81f38e8563932c1f Mon Sep 17 00:00:00 2001
From: Val Alexander
Date: Wed, 1 Apr 2026 08:50:33 -0500
Subject: [PATCH] Collapse tool call details in the UI
- Hide sensitive command arguments and full file paths in collapsed work entries
- Simplify file diff, workspace, and toast labels to reduce path leakage
---
apps/web/src/components/ChatView.tsx | 3 +-
apps/web/src/components/DiffPanel.tsx | 5 +-
apps/web/src/components/GitActionsControl.tsx | 1 -
apps/web/src/components/Sidebar.tsx | 1 -
apps/web/src/components/WorkspaceFileTree.tsx | 3 --
.../src/components/chat/MessagesTimeline.tsx | 50 ++++++++++++-------
6 files changed, 34 insertions(+), 29 deletions(-)
diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx
index 8272abe33..8d607965a 100644
--- a/apps/web/src/components/ChatView.tsx
+++ b/apps/web/src/components/ChatView.tsx
@@ -4993,8 +4993,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
onPaste={onComposerPaste}
placeholder={
isComposerApprovalState
- ? (activePendingApproval?.detail ??
- "Resolve this approval request to continue")
+ ? "Resolve this approval request to continue"
: activePendingProgress
? "Type your own answer, or leave this blank to use the selected option"
: showPlanFollowUpPrompt && activeProposedPlan
diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx
index 98deb8199..afda09800 100644
--- a/apps/web/src/components/DiffPanel.tsx
+++ b/apps/web/src/components/DiffPanel.tsx
@@ -208,7 +208,7 @@ function DiffFileSection(props: {
{hasNonZeroStat(stats) && (
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx
index 4b3a5bebf..0201d51ae 100644
--- a/apps/web/src/components/GitActionsControl.tsx
+++ b/apps/web/src/components/GitActionsControl.tsx
@@ -933,7 +933,6 @@ export default function GitActionsControl({ gitCwd, activeThreadId }: GitActions
loading: { title: "Opening file...", data: threadToastData },
success: () => ({
title: "Opened conflicted file",
- description: filePath,
data: threadToastData,
}),
error: (error) => ({
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
index bcb84319c..78eb08342 100644
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -798,7 +798,6 @@ export default function Sidebar() {
toastManager.add({
type: "success",
title: "Path copied",
- description: ctx.path,
});
},
onError: (error) => {
diff --git a/apps/web/src/components/WorkspaceFileTree.tsx b/apps/web/src/components/WorkspaceFileTree.tsx
index bad8adf25..16b396eb6 100644
--- a/apps/web/src/components/WorkspaceFileTree.tsx
+++ b/apps/web/src/components/WorkspaceFileTree.tsx
@@ -62,7 +62,6 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
toastManager.add({
type: "success",
title: "Path copied",
- description: ctx.path,
});
},
onError: (error) => {
@@ -436,7 +435,6 @@ const WorkspaceSearchResultRow = memo(function WorkspaceSearchResultRow(props: {
props.onOpenFile(props.entry.path, { metaKey: event.metaKey, ctrlKey: event.ctrlKey });
}}
onContextMenu={handleContextMenu}
- title={props.entry.path}
>
{isDirectory ? (
@@ -697,7 +695,6 @@ const WorkspaceFileRow = memo(function WorkspaceFileRow(props: {
props.onOpenFile(props.entry.path, { metaKey: event.metaKey, ctrlKey: event.ctrlKey })
}
onContextMenu={handleContextMenu}
- title={props.entry.path}
>
,
) {
- if (workEntry.command) return workEntry.command;
- if (workEntry.detail) return workEntry.detail;
+ if (workEntry.command) {
+ // Only show the base command name (first token), not arguments or subcommands.
+ const baseCommand = workEntry.command.trim().split(/\s+/)[0];
+ return baseCommand || null;
+ }
+ // Intentionally skip workEntry.detail — it may contain serialized tool inputs
+ // with full file paths, environment info, or other sensitive data.
if ((workEntry.changedFiles?.length ?? 0) === 0) return null;
- const [firstPath] = workEntry.changedFiles ?? [];
- if (!firstPath) return null;
- return workEntry.changedFiles!.length === 1
- ? firstPath
- : `${firstPath} +${workEntry.changedFiles!.length - 1} more`;
+ const basenames = workEntry.changedFiles!.map((p) => p.split("/").pop() ?? p);
+ const [first] = basenames;
+ if (!first) return null;
+ return basenames.length === 1 ? first : `${first} +${basenames.length - 1} more`;
}
function workEntryIcon(workEntry: TimelineWorkEntry): LucideIcon {
@@ -1083,26 +1095,27 @@ const SimpleWorkEntryRow = memo(function SimpleWorkEntryRow(props: {
workToneClass(workEntry.tone),
preview ? "text-muted-foreground/70" : "",
)}
- title={displayText}
>
{heading}
- {preview && - {preview}}
+ {preview && – {preview}}
{hasChangedFiles && !previewIsChangedFiles && (
- {workEntry.changedFiles?.slice(0, 4).map((filePath) => (
-
- {filePath}
-
- ))}
+ {workEntry.changedFiles?.slice(0, 4).map((filePath) => {
+ const basename = filePath.split("/").pop() ?? filePath;
+ return (
+
+ {basename}
+
+ );
+ })}
{(workEntry.changedFiles?.length ?? 0) > 4 && (
+{(workEntry.changedFiles?.length ?? 0) - 4}
@@ -1157,7 +1170,6 @@ const CollapsedWorkEntryGroup = memo(function CollapsedWorkEntryGroup(props: {
{preview ?? heading}