From 28aa5da16df7414f72cc267acd6273c52722efe1 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Sun, 16 Nov 2025 22:57:34 +0000 Subject: [PATCH] Add tool output visibility preferences --- src/App.tsx | 11 +++++++++- src/components/tool-call.tsx | 40 +++++++++++++++++++++++------------ src/lib/hooks/use-commands.ts | 36 ++++++++++++++++++++++++++++++- src/lib/storage.ts | 2 ++ src/stores/preferences.tsx | 21 ++++++++++++++++++ 5 files changed, 94 insertions(+), 16 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index ae5cf3f7..2692caab 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -41,7 +41,14 @@ import { const App: Component = () => { const { isDark } = useTheme() - const { preferences, addRecentFolder, toggleShowThinkingBlocks, setDiffViewMode } = useConfig() + const { + preferences, + addRecentFolder, + toggleShowThinkingBlocks, + setDiffViewMode, + setToolOutputExpansion, + setDiagnosticsExpansion, + } = useConfig() const [escapeInDebounce, setEscapeInDebounce] = createSignal(false) const [launchErrorBinary, setLaunchErrorBinary] = createSignal(null) const [isAdvancedSettingsOpen, setIsAdvancedSettingsOpen] = createSignal(false) @@ -195,6 +202,8 @@ const App: Component = () => { preferences, toggleShowThinkingBlocks, setDiffViewMode, + setToolOutputExpansion, + setDiagnosticsExpansion, handleNewInstanceRequest, handleCloseInstance, handleNewSession, diff --git a/src/components/tool-call.tsx b/src/components/tool-call.tsx index e4b55523..754bdf96 100644 --- a/src/components/tool-call.tsx +++ b/src/components/tool-call.tsx @@ -347,7 +347,9 @@ export default function ToolCall(props: ToolCallProps) { const { isDark } = useTheme() const toolCallId = () => props.toolCallId || props.toolCall?.id || "" const expanded = () => isToolCallExpanded(toolCallId()) - const [initializedId, setInitializedId] = createSignal(null) + const toolOutputDefaultExpanded = createMemo(() => (preferences().toolOutputExpansion || "expanded") === "expanded") + const diagnosticsDefaultExpanded = createMemo(() => (preferences().diagnosticsExpansion || "expanded") === "expanded") + const [appliedPreference, setAppliedPreference] = createSignal(null) const pendingPermission = createMemo(() => props.toolCall.pendingPermission) const permissionDetails = createMemo(() => pendingPermission()?.permission) const isPermissionActive = createMemo(() => pendingPermission()?.active === true) @@ -357,7 +359,7 @@ export default function ToolCall(props: ToolCallProps) { }) const [permissionSubmitting, setPermissionSubmitting] = createSignal(false) const [permissionError, setPermissionError] = createSignal(null) - const [diagnosticsExpanded, setDiagnosticsExpanded] = createSignal(true) + const [diagnosticsExpanded, setDiagnosticsExpanded] = createSignal(diagnosticsDefaultExpanded()) const diagnosticsEntries = createMemo(() => { const tool = props.toolCall?.tool || "" const state = props.toolCall?.state @@ -365,13 +367,18 @@ export default function ToolCall(props: ToolCallProps) { return extractDiagnostics(tool, state) }) - - let scrollContainerRef: HTMLDivElement | undefined - let toolCallRootRef: HTMLDivElement | undefined - - const handleScrollRendered = () => { + createEffect(() => { + const preferred = diagnosticsDefaultExpanded() + setDiagnosticsExpanded((prev) => (prev === preferred ? prev : preferred)) + }) + + let scrollContainerRef: HTMLDivElement | undefined + let toolCallRootRef: HTMLDivElement | undefined + + const handleScrollRendered = () => { + + const id = toolCallId() - const id = toolCallId() if (!id || !scrollContainerRef) return restoreScrollState(id, scrollContainerRef) } @@ -395,13 +402,18 @@ export default function ToolCall(props: ToolCallProps) { createEffect(() => { const id = toolCallId() - if (!id || initializedId() === id) return + if (!id) return + const toolName = props.toolCall?.tool || "" + const desiredExpansion = toolName === "read" ? false : toolOutputDefaultExpanded() + if (appliedPreference() === desiredExpansion) return + setToolCallExpanded(id, desiredExpansion) + setAppliedPreference(desiredExpansion) + }) - const tool = props.toolCall?.tool || "" - const shouldExpand = tool !== "read" - - setToolCallExpanded(id, shouldExpand) - setInitializedId(id) + createEffect(() => { + const id = toolCallId() + if (!id) return + setAppliedPreference((prev) => (prev === null ? prev : null)) }) createEffect(() => { diff --git a/src/lib/hooks/use-commands.ts b/src/lib/hooks/use-commands.ts index 3f2104c2..f8a7d49a 100644 --- a/src/lib/hooks/use-commands.ts +++ b/src/lib/hooks/use-commands.ts @@ -1,6 +1,6 @@ import { createSignal, onMount } from "solid-js" import type { Accessor } from "solid-js" -import type { Preferences } from "../../stores/preferences" +import type { Preferences, ExpansionPreference } from "../../stores/preferences" import { createCommandRegistry, type Command } from "../commands" import { instances, activeInstanceId, setActiveInstanceId } from "../../stores/instances" import { @@ -17,6 +17,8 @@ export interface UseCommandsOptions { preferences: Accessor toggleShowThinkingBlocks: () => void setDiffViewMode: (mode: "split" | "unified") => void + setToolOutputExpansion: (mode: ExpansionPreference) => void + setDiagnosticsExpansion: (mode: ExpansionPreference) => void handleNewInstanceRequest: () => void handleCloseInstance: (instanceId: string) => Promise handleNewSession: (instanceId: string) => Promise @@ -377,6 +379,38 @@ export function useCommands(options: UseCommandsOptions) { action: () => options.setDiffViewMode("unified"), }) + commandRegistry.register({ + id: "tool-output-default-visibility", + label: () => { + const mode = options.preferences().toolOutputExpansion || "expanded" + return `Tool Outputs Default · ${mode === "expanded" ? "Expanded" : "Collapsed"}` + }, + description: "Toggle default expansion for tool outputs", + category: "System", + keywords: ["tool", "output", "expand", "collapse"], + action: () => { + const mode = options.preferences().toolOutputExpansion || "expanded" + const next: ExpansionPreference = mode === "expanded" ? "collapsed" : "expanded" + options.setToolOutputExpansion(next) + }, + }) + + commandRegistry.register({ + id: "diagnostics-default-visibility", + label: () => { + const mode = options.preferences().diagnosticsExpansion || "expanded" + return `Diagnostics Default · ${mode === "expanded" ? "Expanded" : "Collapsed"}` + }, + description: "Toggle default expansion for diagnostics output", + category: "System", + keywords: ["diagnostics", "expand", "collapse"], + action: () => { + const mode = options.preferences().diagnosticsExpansion || "expanded" + const next: ExpansionPreference = mode === "expanded" ? "collapsed" : "expanded" + options.setDiagnosticsExpansion(next) + }, + }) + commandRegistry.register({ id: "help", label: "Show Help", diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 1113c6e2..856223fb 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -83,6 +83,8 @@ export class FileStorage { modelRecents: [], agentModelSelections: {}, diffViewMode: "split", + toolOutputExpansion: "expanded", + diagnosticsExpansion: "expanded", }, recentFolders: [], opencodeBinaries: [], diff --git a/src/stores/preferences.tsx b/src/stores/preferences.tsx index cea78690..89266ae9 100644 --- a/src/stores/preferences.tsx +++ b/src/stores/preferences.tsx @@ -12,6 +12,7 @@ export interface AgentModelSelections { } export type DiffViewMode = "split" | "unified" +export type ExpansionPreference = "expanded" | "collapsed" export interface Preferences { showThinkingBlocks: boolean @@ -20,6 +21,8 @@ export interface Preferences { modelRecents?: ModelPreference[] agentModelSelections?: AgentModelSelections diffViewMode?: DiffViewMode + toolOutputExpansion?: ExpansionPreference + diagnosticsExpansion?: ExpansionPreference } export interface OpenCodeBinary { @@ -41,6 +44,8 @@ const defaultPreferences: Preferences = { modelRecents: [], agentModelSelections: {}, diffViewMode: "split", + toolOutputExpansion: "expanded", + diagnosticsExpansion: "expanded", } const [preferences, setPreferences] = createSignal(defaultPreferences) @@ -117,6 +122,16 @@ function setDiffViewMode(mode: DiffViewMode): void { updatePreferences({ diffViewMode: mode }) } +function setToolOutputExpansion(mode: ExpansionPreference): void { + if (preferences().toolOutputExpansion === mode) return + updatePreferences({ toolOutputExpansion: mode }) +} + +function setDiagnosticsExpansion(mode: ExpansionPreference): void { + if (preferences().diagnosticsExpansion === mode) return + updatePreferences({ diagnosticsExpansion: mode }) +} + function toggleShowThinkingBlocks(): void { updatePreferences({ showThinkingBlocks: !preferences().showThinkingBlocks }) } @@ -230,6 +245,8 @@ interface ConfigContextValue { opencodeBinaries: typeof opencodeBinaries toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks setDiffViewMode: typeof setDiffViewMode + setToolOutputExpansion: typeof setToolOutputExpansion + setDiagnosticsExpansion: typeof setDiagnosticsExpansion addRecentFolder: typeof addRecentFolder removeRecentFolder: typeof removeRecentFolder addOpenCodeBinary: typeof addOpenCodeBinary @@ -253,6 +270,8 @@ const configContextValue: ConfigContextValue = { opencodeBinaries, toggleShowThinkingBlocks, setDiffViewMode, + setToolOutputExpansion, + setDiagnosticsExpansion, addRecentFolder, removeRecentFolder, addOpenCodeBinary, @@ -315,4 +334,6 @@ export { setAgentModelPreference, getAgentModelPreference, setDiffViewMode, + setToolOutputExpansion, + setDiagnosticsExpansion, }