diff --git a/apps/desktop/src/components/assistant-ui/tool-approval.tsx b/apps/desktop/src/components/assistant-ui/tool-approval.tsx
index 6a3dc6c0d9c..d355fda77fc 100644
--- a/apps/desktop/src/components/assistant-ui/tool-approval.tsx
+++ b/apps/desktop/src/components/assistant-ui/tool-approval.tsx
@@ -16,6 +16,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
import { useI18n } from '@/i18n'
import { triggerHaptic } from '@/lib/haptics'
import { ChevronDown, Loader2 } from '@/lib/icons'
+import { cn } from '@/lib/utils'
import { $gateway } from '@/store/gateway'
import { notifyError } from '@/store/notifications'
import { $approvalRequest, type ApprovalRequest, clearApprovalRequest } from '@/store/prompts'
@@ -60,9 +61,15 @@ const ApprovalBar: FC<{ request: ApprovalRequest }> = ({ request }) => {
// "Always allow" persists the pattern to ~/.hermes/config.yaml permanently, so
// it goes through a confirm step rather than firing straight from the menu.
const [confirmAlways, setConfirmAlways] = useState(false)
+ // The pending tool row only shows a single truncated line of the command, and
+ // a pending row can't be expanded (no result yet), so the full command was
+ // previously only reachable via the "Always allow" modal. Let the user reveal
+ // it inline instead — "expand, Run" (2 clicks) rather than the modal dance.
+ const [showCommand, setShowCommand] = useState(false)
const busy = submitting !== null
// false when the backend won't honor a permanent allow (tirith warning) → hide "Always allow".
const allowPermanent = request.allowPermanent !== false
+ const hasCommand = request.command.trim().length > 0
const respond = useCallback(
async (choice: ApprovalChoice) => {
@@ -119,70 +126,89 @@ const ApprovalBar: FC<{ request: ApprovalRequest }> = ({ request }) => {
}, [confirmAlways, respond])
return (
-
-
+
+
+
+
+
+
+
+
+
+
+ void respond('session')}>{copy.allowSession}
+ {allowPermanent && (
+ {
+ // Defer one tick so the menu fully unmounts before the dialog
+ // mounts — otherwise Radix's focus-return races the dialog and
+ // dismisses it via onInteractOutside.
+ setTimeout(() => setConfirmAlways(true), 0)
+ }}
+ >
+ {copy.alwaysAllowMenu}
+
+ )}
+ void respond('deny')} variant="destructive">
+ {copy.reject}
+
+
+
+
+
-
-
-
-
-
-
- void respond('session')}>{copy.allowSession}
- {allowPermanent && (
- {
- // Defer one tick so the menu fully unmounts before the dialog
- // mounts — otherwise Radix's focus-return races the dialog and
- // dismisses it via onInteractOutside.
- setTimeout(() => setConfirmAlways(true), 0)
- }}
- >
- {copy.alwaysAllowMenu}
-
- )}
- void respond('deny')} variant="destructive">
- {copy.reject}
-
-
-
+
+ {hasCommand && (
+
+ )}
-
+ {showCommand && hasCommand && (
+
+ {request.command.trim()}
+
+ )}