From 50e941aa6aab2de202d525723f4b94b31d21302a Mon Sep 17 00:00:00 2001 From: rektide Date: Fri, 26 Dec 2025 20:43:24 -0500 Subject: [PATCH 1/4] export with current thinking/details visibility settings --- EXPORT_CHANGES.md | 95 +++++++++++++++++++ .../src/cli/cmd/tui/routes/session/index.tsx | 16 +++- 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 EXPORT_CHANGES.md diff --git a/EXPORT_CHANGES.md b/EXPORT_CHANGES.md new file mode 100644 index 00000000000..dbd50199383 --- /dev/null +++ b/EXPORT_CHANGES.md @@ -0,0 +1,95 @@ +# Summary of Changes + +## Issue + +The issue #4609 requested that opencode export functionality be enhanced to include: + +1. Thinking/reasoning parts (currently abbreviated/missing) +2. Detailed tool use information including inputs and outputs (currently only shows tool names) + +The export should respect the user's current settings for: + +- `showThinking` - whether reasoning parts are displayed +- `showDetails` - whether tool details (inputs/outputs) are displayed + +## Changes Made + +### File Modified + +`packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` (lines 815-831) + +### What Changed + +The session export function now: + +1. **Includes reasoning parts when `showThinking()` is true** + - When `showThinking()` returns true, reasoning parts are exported with the heading "_Thinking:_" + - When `showThinking()` returns false, reasoning parts are skipped entirely + - This matches the user's current view settings + +2. **Includes tool details when `showDetails()` is true** + - Tool inputs: Exported as formatted JSON under "**Input:**" heading + - Tool outputs: Exported as code blocks under "**Output:**" heading (when status is "completed") + - Tool errors: Exported as code blocks under "**Error:**" heading (when status is "error") + - When `showDetails()` is false, only the tool name is exported (original behavior) + +### Export Format Examples + +#### With both settings enabled (showThinking=true, showDetails=true): + +```markdown +## Assistant + +_Thinking:_ + +I need to read the file first to understand what changes are needed. +``` + +Tool: read + +**Input:** + +```json +{ + "filePath": "src/app.ts" +} +``` + +**Output:** + +``` +file contents here... +``` + +--- + +```` + +#### With both settings disabled (showThinking=false, showDetails=false): +```markdown +## Assistant + +```` + +Tool: read + +``` + +--- +``` + +## Testing + +- Created unit tests to verify the logic correctly handles all combinations of settings +- All type checks pass +- Export respects user's current view settings + +## User Impact + +Users will now see exports that match exactly what they see in their current session view: + +- If they have thinking visible, exports include reasoning +- If they have tool details visible, exports include tool inputs/outputs +- If they have both hidden, exports remain minimal (original behavior) + +This gives users full control over how detailed their exports are, addressing the feature request in issue #4609. diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 177c43a463a..1d75f6ba1be 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -826,8 +826,22 @@ export function Session() { for (const part of parts) { if (part.type === "text" && !part.synthetic) { transcript += `${part.text}\n\n` + } else if (part.type === "reasoning") { + if (showThinking()) { + transcript += `_Thinking:_\n\n${part.text}\n\n` + } } else if (part.type === "tool") { - transcript += `\`\`\`\nTool: ${part.tool}\n\`\`\`\n\n` + transcript += `\`\`\`\nTool: ${part.tool}\n` + if (showDetails() && part.state.input) { + transcript += `\n**Input:**\n\`\`\`json\n${JSON.stringify(part.state.input, null, 2)}\n\`\`\`` + } + if (showDetails() && part.state.status === "completed" && part.state.output) { + transcript += `\n**Output:**\n\`\`\`\n${part.state.output}\n\`\`\`` + } + if (showDetails() && part.state.status === "error" && part.state.error) { + transcript += `\n**Error:**\n\`\`\`\n${part.state.error}\n\`\`\`` + } + transcript += `\n\`\`\`\n\n` } } From 7c3611532a9a4778eb4424ff4818903e57b28bd0 Mon Sep 17 00:00:00 2001 From: rektide Date: Fri, 26 Dec 2025 20:48:26 -0500 Subject: [PATCH 2/4] copy with current thinking/details visibility settings --- EXPORT_CHANGES.md | 35 ++++++++++++------- .../src/cli/cmd/tui/routes/session/index.tsx | 16 ++++++++- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/EXPORT_CHANGES.md b/EXPORT_CHANGES.md index dbd50199383..baffa350e9f 100644 --- a/EXPORT_CHANGES.md +++ b/EXPORT_CHANGES.md @@ -7,20 +7,21 @@ The issue #4609 requested that opencode export functionality be enhanced to incl 1. Thinking/reasoning parts (currently abbreviated/missing) 2. Detailed tool use information including inputs and outputs (currently only shows tool names) -The export should respect the user's current settings for: +The export should respect user's current settings for: - `showThinking` - whether reasoning parts are displayed - `showDetails` - whether tool details (inputs/outputs) are displayed ## Changes Made -### File Modified +### Files Modified -`packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` (lines 815-831) +1. `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` (lines 815-831) - Export command +2. `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` (lines 773-789) - Copy command ### What Changed -The session export function now: +Both the session export and copy functions now: 1. **Includes reasoning parts when `showThinking()` is true** - When `showThinking()` returns true, reasoning parts are exported with the heading "_Thinking:_" @@ -31,9 +32,19 @@ The session export function now: - Tool inputs: Exported as formatted JSON under "**Input:**" heading - Tool outputs: Exported as code blocks under "**Output:**" heading (when status is "completed") - Tool errors: Exported as code blocks under "**Error:**" heading (when status is "error") - - When `showDetails()` is false, only the tool name is exported (original behavior) + - When `showDetails()` is false, only the tool name is exported/copied (original behavior) -### Export Format Examples +## Commands Affected + +### 1. `/export` (session.export) + +Exports the full session transcript to a markdown file with the same level of detail as the user's current view. + +### 2. `/copy` (session.copy) + +Copies the full session transcript to the clipboard with the same level of detail as the user's current view. + +### Export/Copy Format Examples #### With both settings enabled (showThinking=true, showDetails=true): @@ -82,14 +93,14 @@ Tool: read - Created unit tests to verify the logic correctly handles all combinations of settings - All type checks pass -- Export respects user's current view settings +- Both export and copy commands respect user's current view settings ## User Impact -Users will now see exports that match exactly what they see in their current session view: +Users will now see exports and clipboard copies that match exactly what they see in their current session view: -- If they have thinking visible, exports include reasoning -- If they have tool details visible, exports include tool inputs/outputs -- If they have both hidden, exports remain minimal (original behavior) +- If they have thinking visible, exported/copied content includes reasoning +- If they have tool details visible, exported/copied content includes tool inputs/outputs +- If they have both hidden, exported/copied content remains minimal (original behavior) -This gives users full control over how detailed their exports are, addressing the feature request in issue #4609. +This gives users full control over how detailed their exports and clipboard copies are, addressing the feature request in issue #4609. diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 1d75f6ba1be..c4438941be0 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -784,8 +784,22 @@ export function Session() { for (const part of parts) { if (part.type === "text" && !part.synthetic) { transcript += `${part.text}\n\n` + } else if (part.type === "reasoning") { + if (showThinking()) { + transcript += `_Thinking:_\n\n${part.text}\n\n` + } } else if (part.type === "tool") { - transcript += `\`\`\`\nTool: ${part.tool}\n\`\`\`\n\n` + transcript += `\`\`\`\nTool: ${part.tool}\n` + if (showDetails() && part.state.input) { + transcript += `\n**Input:**\n\`\`\`json\n${JSON.stringify(part.state.input, null, 2)}\n\`\`\`` + } + if (showDetails() && part.state.status === "completed" && part.state.output) { + transcript += `\n**Output:**\n\`\`\`\n${part.state.output}\n\`\`\`` + } + if (showDetails() && part.state.status === "error" && part.state.error) { + transcript += `\n**Error:**\n\`\`\`\n${part.state.error}\n\`\`\`` + } + transcript += `\n\`\`\`\n\n` } } From 02f2723c8e67fc635548dc5c3cd8191b21f6283d Mon Sep 17 00:00:00 2001 From: rektide Date: Fri, 26 Dec 2025 20:56:37 -0500 Subject: [PATCH 3/4] remove EXPORT_CHANGES.md file --- EXPORT_CHANGES.md | 106 ---------------------------------------------- 1 file changed, 106 deletions(-) delete mode 100644 EXPORT_CHANGES.md diff --git a/EXPORT_CHANGES.md b/EXPORT_CHANGES.md deleted file mode 100644 index baffa350e9f..00000000000 --- a/EXPORT_CHANGES.md +++ /dev/null @@ -1,106 +0,0 @@ -# Summary of Changes - -## Issue - -The issue #4609 requested that opencode export functionality be enhanced to include: - -1. Thinking/reasoning parts (currently abbreviated/missing) -2. Detailed tool use information including inputs and outputs (currently only shows tool names) - -The export should respect user's current settings for: - -- `showThinking` - whether reasoning parts are displayed -- `showDetails` - whether tool details (inputs/outputs) are displayed - -## Changes Made - -### Files Modified - -1. `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` (lines 815-831) - Export command -2. `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` (lines 773-789) - Copy command - -### What Changed - -Both the session export and copy functions now: - -1. **Includes reasoning parts when `showThinking()` is true** - - When `showThinking()` returns true, reasoning parts are exported with the heading "_Thinking:_" - - When `showThinking()` returns false, reasoning parts are skipped entirely - - This matches the user's current view settings - -2. **Includes tool details when `showDetails()` is true** - - Tool inputs: Exported as formatted JSON under "**Input:**" heading - - Tool outputs: Exported as code blocks under "**Output:**" heading (when status is "completed") - - Tool errors: Exported as code blocks under "**Error:**" heading (when status is "error") - - When `showDetails()` is false, only the tool name is exported/copied (original behavior) - -## Commands Affected - -### 1. `/export` (session.export) - -Exports the full session transcript to a markdown file with the same level of detail as the user's current view. - -### 2. `/copy` (session.copy) - -Copies the full session transcript to the clipboard with the same level of detail as the user's current view. - -### Export/Copy Format Examples - -#### With both settings enabled (showThinking=true, showDetails=true): - -```markdown -## Assistant - -_Thinking:_ - -I need to read the file first to understand what changes are needed. -``` - -Tool: read - -**Input:** - -```json -{ - "filePath": "src/app.ts" -} -``` - -**Output:** - -``` -file contents here... -``` - ---- - -```` - -#### With both settings disabled (showThinking=false, showDetails=false): -```markdown -## Assistant - -```` - -Tool: read - -``` - ---- -``` - -## Testing - -- Created unit tests to verify the logic correctly handles all combinations of settings -- All type checks pass -- Both export and copy commands respect user's current view settings - -## User Impact - -Users will now see exports and clipboard copies that match exactly what they see in their current session view: - -- If they have thinking visible, exported/copied content includes reasoning -- If they have tool details visible, exported/copied content includes tool inputs/outputs -- If they have both hidden, exported/copied content remains minimal (original behavior) - -This gives users full control over how detailed their exports and clipboard copies are, addressing the feature request in issue #4609. From 6a035fcb823a22bf856ed7e5ef2e06cbb7b11023 Mon Sep 17 00:00:00 2001 From: rektide Date: Fri, 26 Dec 2025 22:20:36 -0500 Subject: [PATCH 4/4] export options dialog --- .../src/cli/cmd/tui/routes/session/index.tsx | 26 +-- .../cli/cmd/tui/ui/dialog-export-options.tsx | 152 ++++++++++++++++++ 2 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index c4438941be0..d85a3307a65 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -52,7 +52,6 @@ import { DialogMessage } from "./dialog-message" import type { PromptInfo } from "../../component/prompt/history" import { iife } from "@/util/iife" import { DialogConfirm } from "@tui/ui/dialog-confirm" -import { DialogPrompt } from "@tui/ui/dialog-prompt" import { DialogTimeline } from "./dialog-timeline" import { DialogForkFromTimeline } from "./dialog-fork-from-timeline" import { DialogSessionRename } from "../../component/dialog-session-rename" @@ -68,6 +67,7 @@ import { Footer } from "./footer.tsx" import { usePromptRef } from "../../context/prompt" import { Filesystem } from "@/util/filesystem" import { DialogSubagent } from "./dialog-subagent.tsx" +import { DialogExportOptions } from "../../ui/dialog-export-options" addDefaultParsers(parsers.parsers) @@ -826,6 +826,14 @@ export function Session() { const sessionData = session() const sessionMessages = messages() + const defaultFilename = `session-${sessionData.id.slice(0, 8)}.md` + + const options = await DialogExportOptions.show(dialog, defaultFilename, showThinking(), showDetails()) + + if (options === null) return + + const { filename: customFilename, thinking: includeThinking, toolDetails: includeToolDetails } = options + let transcript = `# ${sessionData.title}\n\n` transcript += `**Session ID:** ${sessionData.id}\n` transcript += `**Created:** ${new Date(sessionData.time.created).toLocaleString()}\n` @@ -841,18 +849,18 @@ export function Session() { if (part.type === "text" && !part.synthetic) { transcript += `${part.text}\n\n` } else if (part.type === "reasoning") { - if (showThinking()) { + if (includeThinking) { transcript += `_Thinking:_\n\n${part.text}\n\n` } } else if (part.type === "tool") { transcript += `\`\`\`\nTool: ${part.tool}\n` - if (showDetails() && part.state.input) { + if (includeToolDetails && part.state.input) { transcript += `\n**Input:**\n\`\`\`json\n${JSON.stringify(part.state.input, null, 2)}\n\`\`\`` } - if (showDetails() && part.state.status === "completed" && part.state.output) { + if (includeToolDetails && part.state.status === "completed" && part.state.output) { transcript += `\n**Output:**\n\`\`\`\n${part.state.output}\n\`\`\`` } - if (showDetails() && part.state.status === "error" && part.state.error) { + if (includeToolDetails && part.state.status === "error" && part.state.error) { transcript += `\n**Error:**\n\`\`\`\n${part.state.error}\n\`\`\`` } transcript += `\n\`\`\`\n\n` @@ -862,14 +870,6 @@ export function Session() { transcript += `---\n\n` } - // Prompt for optional filename - const customFilename = await DialogPrompt.show(dialog, "Export filename", { - value: `session-${sessionData.id.slice(0, 8)}.md`, - }) - - // Cancel if user pressed escape - if (customFilename === null) return - // Save to file in current working directory const exportDir = process.cwd() const filename = customFilename.trim() diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx new file mode 100644 index 00000000000..7543a7785e7 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx @@ -0,0 +1,152 @@ +import { TextareaRenderable, TextAttributes } from "@opentui/core" +import { useTheme } from "../context/theme" +import { useDialog, type DialogContext } from "./dialog" +import { createStore } from "solid-js/store" +import { onMount, Show, type JSX } from "solid-js" +import { useKeyboard } from "@opentui/solid" + +export type DialogExportOptionsProps = { + defaultFilename: string + defaultThinking: boolean + defaultToolDetails: boolean + onConfirm?: (options: { filename: string; thinking: boolean; toolDetails: boolean }) => void + onCancel?: () => void +} + +export function DialogExportOptions(props: DialogExportOptionsProps) { + const dialog = useDialog() + const { theme } = useTheme() + let textarea: TextareaRenderable + const [store, setStore] = createStore({ + thinking: props.defaultThinking, + toolDetails: props.defaultToolDetails, + active: "filename" as "filename" | "thinking" | "toolDetails", + }) + + useKeyboard((evt) => { + if (evt.name === "return") { + props.onConfirm?.({ + filename: textarea.plainText, + thinking: store.thinking, + toolDetails: store.toolDetails, + }) + } + if (evt.name === "tab") { + const order: Array<"filename" | "thinking" | "toolDetails"> = ["filename", "thinking", "toolDetails"] + const currentIndex = order.indexOf(store.active) + const nextIndex = (currentIndex + 1) % order.length + setStore("active", order[nextIndex]) + evt.preventDefault() + } + if (evt.name === "space") { + if (store.active === "thinking") setStore("thinking", !store.thinking) + if (store.active === "toolDetails") setStore("toolDetails", !store.toolDetails) + evt.preventDefault() + } + }) + + onMount(() => { + dialog.setSize("medium") + setTimeout(() => { + textarea.focus() + }, 1) + textarea.gotoLineEnd() + }) + + const toggleOption = (key: "thinking" | "toolDetails") => { + setStore(key, !store[key]) + } + + return ( + + + + Export Options + + esc + + + + Filename: + +