From 60c5a82c8530b12cdba4ef5194c3d01de742ce92 Mon Sep 17 00:00:00 2001 From: alt-glitch Date: Tue, 9 Jun 2026 07:18:48 +0000 Subject: [PATCH] opentui(copy): mask chrome/gutters so free-form copy is clean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit selectable masking (free-code noSelect model) so a free-form drag over an agent turn yields CLEAN pasteable content — no labels, summaries, carets, or annotations. Newly masked (selectable={false}): - toolPart: the whole collapsed header row (name + args-preview + duration + "(N lines)") summary; the "args"/"output" section labels; the args overflow "… +N more"; the "… omitted N" / "… +N more lines" truncation notes. - messageLine: the streaming caret (▍) — a cursor glyph, not content. - reasoningPart: the collapsible-section header label (Thinking/Thought + title). - composer: the completion dropdown rows + the "Tab complete · Esc dismiss" hint. Kept selectable (real content): assistant markdown, tool args values + output body, user/system message text. --- ui-tui-opentui-v2/src/view/composer.tsx | 9 +++++++-- ui-tui-opentui-v2/src/view/messageLine.tsx | 3 ++- ui-tui-opentui-v2/src/view/reasoningPart.tsx | 5 ++++- ui-tui-opentui-v2/src/view/toolPart.tsx | 21 ++++++++++++++------ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/ui-tui-opentui-v2/src/view/composer.tsx b/ui-tui-opentui-v2/src/view/composer.tsx index 6ab8033afff..b9328ffa7e7 100644 --- a/ui-tui-opentui-v2/src/view/composer.tsx +++ b/ui-tui-opentui-v2/src/view/composer.tsx @@ -178,15 +178,20 @@ export function Composer(props: { paddingRight: 1 }} > + {/* the completion dropdown is transient input chrome (menu rows + the + key-hint) — not transcript content — so it's excluded from mouse + selection (item 4). */} {(c, i) => ( - + {c.display || c.text} {c.meta ? ` ${c.meta}` : ''} )} - Tab complete · Esc dismiss + + Tab complete · Esc dismiss + {/* prompt glyph + textarea — the glyph (item 3) marks the input line so the diff --git a/ui-tui-opentui-v2/src/view/messageLine.tsx b/ui-tui-opentui-v2/src/view/messageLine.tsx index 8ca6f4d6e9f..0fa345506e8 100644 --- a/ui-tui-opentui-v2/src/view/messageLine.tsx +++ b/ui-tui-opentui-v2/src/view/messageLine.tsx @@ -61,7 +61,8 @@ export function MessageLine(props: { message: Message }) { } > - + + {/* streaming caret — a cursor glyph, not content (item 4) */} diff --git a/ui-tui-opentui-v2/src/view/reasoningPart.tsx b/ui-tui-opentui-v2/src/view/reasoningPart.tsx index e5ba311ef45..a1690915d06 100644 --- a/ui-tui-opentui-v2/src/view/reasoningPart.tsx +++ b/ui-tui-opentui-v2/src/view/reasoningPart.tsx @@ -50,7 +50,10 @@ export function ReasoningPart(props: { text: string; streaming?: boolean }) { {expanded() ? '▼' : '▶'} - + {/* the header is a collapsible-section LABEL (Thinking/Thought + title) + — chrome, not the reasoning body — so a free-form drag yields only + the markdown body below, not the section label (item 4). */} + {/* accent chevron marks it; muted label keeps reasoning in the dim, secondary tier alongside tool calls (Ink hierarchy). */} {label()} diff --git a/ui-tui-opentui-v2/src/view/toolPart.tsx b/ui-tui-opentui-v2/src/view/toolPart.tsx index 3292788ffba..6f44d1b25b3 100644 --- a/ui-tui-opentui-v2/src/view/toolPart.tsx +++ b/ui-tui-opentui-v2/src/view/toolPart.tsx @@ -103,7 +103,11 @@ export function ToolPart(props: { part: ToolPartState }) { - + {/* the whole header row is a collapsed SUMMARY (tool name + args-preview + + duration + "(N lines)") — chrome, not the copyable body — so a + free-form drag over a tool yields only the expanded output/args + content, never the header label (item 4). */} + {props.part.name} @@ -134,7 +138,8 @@ export function ToolPart(props: { part: ToolPartState }) { > - + {/* section label — chrome, not content (item 4) */} + args {/* parsed key: value lines (tidy), or raw argsText when unparseable */} @@ -158,14 +163,16 @@ export function ToolPart(props: { part: ToolPartState }) { )} ARGS_MAX}> - + {/* overflow annotation — chrome, not content (item 4) */} + {`… +${argEntries().length - ARGS_MAX} more`} - + {/* section label — chrome, not content (item 4) */} + output @@ -176,13 +183,15 @@ export function ToolPart(props: { part: ToolPartState }) { )} + {/* truncation annotations — chrome (the "… omitted N" / "… +N more + lines" notes are not part of the real output body) (item 4). */} - + {`… omitted ${props.part.omittedNote}`} 0 && !props.part.omittedNote}> - + {`… +${body().hiddenLines} more lines`}